198a429c5d702f81bd7a45397e14f9f3af3d7acd
[ardour.git] / libs / ardour / source_factory.cc
1 /*
2     Copyright (C) 2000-2006 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #ifdef WAF_BUILD
22 #include "libardour-config.h"
23 #endif
24
25 #include "pbd/error.h"
26 #include "pbd/convert.h"
27 #include "pbd/pthread_utils.h"
28 #include "pbd/stacktrace.h"
29
30 #include "ardour/source_factory.h"
31 #include "ardour/sndfilesource.h"
32 #include "ardour/silentfilesource.h"
33 #include "ardour/rc_configuration.h"
34 #include "ardour/smf_source.h"
35 #include "ardour/session.h"
36
37 #ifdef  HAVE_COREAUDIO
38 #define USE_COREAUDIO_FOR_FILES
39 #endif
40
41 #ifdef USE_COREAUDIO_FOR_FILES
42 #include "ardour/coreaudiosource.h"
43 #endif
44
45
46 #include "i18n.h"
47
48 using namespace ARDOUR;
49 using namespace std;
50 using namespace PBD;
51
52 sigc::signal<void,boost::shared_ptr<Source> > SourceFactory::SourceCreated;
53 Glib::Cond* SourceFactory::PeaksToBuild;
54 Glib::StaticMutex SourceFactory::peak_building_lock = GLIBMM_STATIC_MUTEX_INIT;
55 std::list<boost::weak_ptr<AudioSource> > SourceFactory::files_with_peaks;
56
57 static void
58 peak_thread_work ()
59 {
60         PBD::notify_gui_about_thread_creation (pthread_self(), string ("peakbuilder-") + to_string (pthread_self(), std::dec));
61
62         while (true) {
63
64                 SourceFactory::peak_building_lock.lock ();
65
66           wait:
67                 if (SourceFactory::files_with_peaks.empty()) {
68                         SourceFactory::PeaksToBuild->wait (SourceFactory::peak_building_lock);
69                 }
70
71                 if (SourceFactory::files_with_peaks.empty()) {
72                         goto wait;
73                 }
74
75                 boost::shared_ptr<AudioSource> as (SourceFactory::files_with_peaks.front().lock());
76                 SourceFactory::files_with_peaks.pop_front ();
77                 SourceFactory::peak_building_lock.unlock ();
78
79                 if (!as) {
80                         continue;
81                 }
82
83                 as->setup_peakfile ();
84         }
85 }
86
87 void
88 SourceFactory::init ()
89 {
90         PeaksToBuild = new Glib::Cond();
91
92         for (int n = 0; n < 2; ++n) {
93                 Glib::Thread::create (sigc::ptr_fun (::peak_thread_work), false);
94         }
95 }
96
97 int
98 SourceFactory::setup_peakfile (boost::shared_ptr<Source> s, bool async)
99 {
100         boost::shared_ptr<AudioSource> as (boost::dynamic_pointer_cast<AudioSource> (s));
101
102         if (as) {
103
104                 if (async) {
105
106                         Glib::Mutex::Lock lm (peak_building_lock);
107                         files_with_peaks.push_back (boost::weak_ptr<AudioSource> (as));
108                         PeaksToBuild->broadcast ();
109
110                 } else {
111
112                         if (as->setup_peakfile ()) {
113                                 error << string_compose("SourceFactory: could not set up peakfile for %1", as->name()) << endmsg;
114                                 return -1;
115                         }
116                 }
117         }
118
119         return 0;
120 }
121
122 boost::shared_ptr<Source>
123 SourceFactory::createSilent (Session& s, const XMLNode& node, nframes_t nframes, float sr)
124 {
125         boost::shared_ptr<Source> ret (new SilentFileSource (s, node, nframes, sr));
126         // no analysis data - the file is non-existent
127         SourceCreated (ret);
128         return ret;
129 }
130
131 boost::shared_ptr<Source>
132 SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
133 {
134         DataType type = DataType::AUDIO;
135         const XMLProperty* prop = node.property("type");
136
137         if (prop) {
138                 type = DataType (prop->value());
139         }
140
141         if (type == DataType::AUDIO) {
142
143                 try {
144
145                         boost::shared_ptr<Source> ret (new SndFileSource (s, node));
146                         if (setup_peakfile (ret, defer_peaks)) {
147                                 return boost::shared_ptr<Source>();
148                         }
149                         ret->check_for_analysis_data_on_disk ();
150                         SourceCreated (ret);
151                         return ret;
152                 }
153
154                 catch (failed_constructor& err) {
155
156 #ifdef USE_COREAUDIO_FOR_FILES
157
158                         /* this is allowed to throw */
159
160                         boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
161
162                         if (setup_peakfile (ret, defer_peaks)) {
163                                 return boost::shared_ptr<Source>();
164                         }
165
166                         ret->check_for_analysis_data_on_disk ();
167                         SourceCreated (ret);
168                         return ret;
169 #else
170                         throw; // rethrow
171 #endif
172                 }
173
174         } else if (type == DataType::MIDI) {
175                 boost::shared_ptr<Source> ret (new SMFSource (s, node));
176                 ret->check_for_analysis_data_on_disk ();
177                 SourceCreated (ret);
178                 return ret;
179         }
180
181         return boost::shared_ptr<Source>();
182 }
183
184 boost::shared_ptr<Source>
185 SourceFactory::createReadable (DataType type, Session& s, const string& path, bool embedded,
186                 int chn, Source::Flag flags, bool announce, bool defer_peaks)
187 {
188         if (type == DataType::AUDIO) {
189
190                 if (!(flags & Destructive)) {
191
192                         try {
193
194                                 boost::shared_ptr<Source> ret (new SndFileSource (s, path, embedded, chn, flags));
195
196                                 if (setup_peakfile (ret, defer_peaks)) {
197                                         return boost::shared_ptr<Source>();
198                                 }
199
200                                 ret->check_for_analysis_data_on_disk ();
201                                 if (announce) {
202                                         SourceCreated (ret);
203                                 }
204                                 return ret;
205                         }
206
207                         catch (failed_constructor& err) {
208 #ifdef USE_COREAUDIO_FOR_FILES
209
210                                 boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, embedded, chn, flags));
211                                 if (setup_peakfile (ret, defer_peaks)) {
212                                         return boost::shared_ptr<Source>();
213                                 }
214                                 ret->check_for_analysis_data_on_disk ();
215                                 if (announce) {
216                                         SourceCreated (ret);
217                                 }
218                                 return ret;
219
220 #else
221                                 throw; // rethrow
222 #endif
223                         }
224
225                 } else {
226                         // eh?
227                 }
228
229         } else if (type == DataType::MIDI) {
230
231                 boost::shared_ptr<Source> ret (new SMFSource (s, path, embedded, SMFSource::Flag(0)));
232
233                 if (announce) {
234                         SourceCreated (ret);
235                 }
236
237                 return ret;
238
239         }
240
241         return boost::shared_ptr<Source>();
242 }
243
244 boost::shared_ptr<Source>
245 SourceFactory::createWritable (DataType type, Session& s, const std::string& path, bool embedded,
246                 bool destructive, nframes_t rate, bool announce, bool defer_peaks)
247 {
248         /* this might throw failed_constructor(), which is OK */
249
250         if (type == DataType::AUDIO) {
251                 boost::shared_ptr<Source> ret (new SndFileSource (s, path, embedded,
252                                 s.config.get_native_file_data_format(),
253                                 s.config.get_native_file_header_format(),
254                                 rate,
255                                 (destructive
256                                         ? Source::Flag (SndFileSource::default_writable_flags | Source::Destructive)
257                                         : SndFileSource::default_writable_flags)));
258
259                 if (setup_peakfile (ret, defer_peaks)) {
260                         return boost::shared_ptr<Source>();
261                 }
262
263                 // no analysis data - this is a new file
264
265                 if (announce) {
266                         SourceCreated (ret);
267                 }
268                 return ret;
269
270         } else if (type == DataType::MIDI) {
271
272                 boost::shared_ptr<Source> ret (new SMFSource (s, path, embedded, Source::Flag(0)));
273
274                 // no analysis data - this is a new file
275
276                 if (announce) {
277                         SourceCreated (ret);
278                 }
279                 return ret;
280
281         }
282
283         return boost::shared_ptr<Source> ();
284 }
285