Fix broken whitespace. I'd apologize for the compile times if it was my fault :D
[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/boost_debug.h"
26 #include "pbd/error.h"
27 #include "pbd/convert.h"
28 #include "pbd/pthread_utils.h"
29 #include "pbd/stacktrace.h"
30
31 #include "ardour/audioplaylist.h"
32 #include "ardour/audio_playlist_source.h"
33 #include "ardour/midi_playlist.h"
34 #include "ardour/midi_playlist_source.h"
35 #include "ardour/source_factory.h"
36 #include "ardour/sndfilesource.h"
37 #include "ardour/silentfilesource.h"
38 #include "ardour/rc_configuration.h"
39 #include "ardour/smf_source.h"
40 #include "ardour/session.h"
41
42 #ifdef  HAVE_COREAUDIO
43 #define USE_COREAUDIO_FOR_FILES
44 #endif
45
46 #ifdef USE_COREAUDIO_FOR_FILES
47 #include "ardour/coreaudiosource.h"
48 #endif
49
50
51 #include "i18n.h"
52
53 using namespace ARDOUR;
54 using namespace std;
55 using namespace PBD;
56
57 PBD::Signal1<void,boost::shared_ptr<Source> > SourceFactory::SourceCreated;
58 Glib::Cond* SourceFactory::PeaksToBuild;
59 Glib::StaticMutex SourceFactory::peak_building_lock = GLIBMM_STATIC_MUTEX_INIT;
60 std::list<boost::weak_ptr<AudioSource> > SourceFactory::files_with_peaks;
61
62 static void
63 peak_thread_work ()
64 {
65         SessionEvent::create_per_thread_pool (X_("PeakFile Builder "), 64);
66
67         while (true) {
68
69                 SourceFactory::peak_building_lock.lock ();
70
71           wait:
72                 if (SourceFactory::files_with_peaks.empty()) {
73                         SourceFactory::PeaksToBuild->wait (SourceFactory::peak_building_lock);
74                 }
75
76                 if (SourceFactory::files_with_peaks.empty()) {
77                         goto wait;
78                 }
79
80                 boost::shared_ptr<AudioSource> as (SourceFactory::files_with_peaks.front().lock());
81                 SourceFactory::files_with_peaks.pop_front ();
82                 SourceFactory::peak_building_lock.unlock ();
83
84                 if (!as) {
85                         continue;
86                 }
87
88                 as->setup_peakfile ();
89         }
90 }
91
92 void
93 SourceFactory::init ()
94 {
95         PeaksToBuild = new Glib::Cond();
96
97         for (int n = 0; n < 2; ++n) {
98                 Glib::Thread::create (sigc::ptr_fun (::peak_thread_work), false);
99         }
100 }
101
102 int
103 SourceFactory::setup_peakfile (boost::shared_ptr<Source> s, bool async)
104 {
105         boost::shared_ptr<AudioSource> as (boost::dynamic_pointer_cast<AudioSource> (s));
106
107         if (as) {
108
109                 if (async) {
110
111                         Glib::Mutex::Lock lm (peak_building_lock);
112                         files_with_peaks.push_back (boost::weak_ptr<AudioSource> (as));
113                         PeaksToBuild->broadcast ();
114
115                 } else {
116
117                         if (as->setup_peakfile ()) {
118                                 error << string_compose("SourceFactory: could not set up peakfile for %1", as->name()) << endmsg;
119                                 return -1;
120                         }
121                 }
122         }
123
124         return 0;
125 }
126
127 boost::shared_ptr<Source>
128 SourceFactory::createSilent (Session& s, const XMLNode& node, framecnt_t nframes, float sr)
129 {
130         Source* src = new SilentFileSource (s, node, nframes, sr);
131 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
132         // boost_debug_shared_ptr_mark_interesting (src, "Source");
133 #endif
134         boost::shared_ptr<Source> ret (src);
135         // no analysis data - the file is non-existent
136         SourceCreated (ret);
137         return ret;
138 }
139
140 boost::shared_ptr<Source>
141 SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
142 {
143         DataType type = DataType::AUDIO;
144         const XMLProperty* prop = node.property("type");
145
146         if (prop) {
147                 type = DataType (prop->value());
148         }
149
150         if (type == DataType::AUDIO) {
151
152                 /* it could be nested */
153
154                 if (node.property ("playlist") != 0) {
155
156                         try {
157                                 boost::shared_ptr<AudioPlaylistSource> ap (new AudioPlaylistSource (s, node));
158
159                                 if (setup_peakfile (ap, true)) {
160                                         return boost::shared_ptr<Source>();
161                                 }
162
163                                 ap->check_for_analysis_data_on_disk ();
164                                 SourceCreated (ap);
165                                 return ap;
166
167                         } catch (failed_constructor&) {
168                                 /* oh well, so much for that then ... */
169                         }
170
171                 } else {
172
173
174                         try {
175                                 Source* src = new SndFileSource (s, node);
176 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
177                                 // boost_debug_shared_ptr_mark_interesting (src, "Source");
178 #endif
179                                 boost::shared_ptr<Source> ret (src);
180                                 if (setup_peakfile (ret, defer_peaks)) {
181                                         return boost::shared_ptr<Source>();
182                                 }
183                                 ret->check_for_analysis_data_on_disk ();
184                                 SourceCreated (ret);
185                                 return ret;
186                         }
187
188                         catch (failed_constructor& err) {
189
190 #ifdef USE_COREAUDIO_FOR_FILES
191
192                                 /* this is allowed to throw */
193
194                                 Source *src = new CoreAudioSource (s, node);
195 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
196                                 // boost_debug_shared_ptr_mark_interesting (src, "Source");
197 #endif
198                                 boost::shared_ptr<Source> ret (src);
199
200                                 if (setup_peakfile (ret, defer_peaks)) {
201                                         return boost::shared_ptr<Source>();
202                                 }
203
204                                 ret->check_for_analysis_data_on_disk ();
205                                 SourceCreated (ret);
206                                 return ret;
207 #else
208                                 throw; // rethrow
209 #endif
210                         }
211                 }
212         } else if (type == DataType::MIDI) {
213                 boost::shared_ptr<SMFSource> src (new SMFSource (s, node));
214                 src->load_model (true, true);
215 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
216                 // boost_debug_shared_ptr_mark_interesting (src, "Source");
217 #endif
218                 src->check_for_analysis_data_on_disk ();
219                 SourceCreated (src);
220                 return src;
221         }
222
223         return boost::shared_ptr<Source>();
224 }
225
226 boost::shared_ptr<Source>
227 SourceFactory::createReadable (DataType type, Session& s, const string& path,
228                                int chn, Source::Flag flags, bool announce, bool defer_peaks)
229 {
230         if (type == DataType::AUDIO) {
231
232                 if (!(flags & Destructive)) {
233
234                         try {
235
236                                 Source* src = new SndFileSource (s, path, chn, flags);
237 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
238                                 // boost_debug_shared_ptr_mark_interesting (src, "Source");
239 #endif
240                                 boost::shared_ptr<Source> ret (src);
241
242                                 if (setup_peakfile (ret, defer_peaks)) {
243                                         return boost::shared_ptr<Source>();
244                                 }
245
246                                 ret->check_for_analysis_data_on_disk ();
247                                 if (announce) {
248                                         SourceCreated (ret);
249                                 }
250                                 return ret;
251                         }
252
253                         catch (failed_constructor& err) {
254 #ifdef USE_COREAUDIO_FOR_FILES
255
256                                 Source* src = new CoreAudioSource (s, path, chn, flags);
257 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
258                                 // boost_debug_shared_ptr_mark_interesting (src, "Source");
259 #endif
260                                 boost::shared_ptr<Source> ret (src);
261                                 if (setup_peakfile (ret, defer_peaks)) {
262                                         return boost::shared_ptr<Source>();
263                                 }
264                                 ret->check_for_analysis_data_on_disk ();
265                                 if (announce) {
266                                         SourceCreated (ret);
267                                 }
268                                 return ret;
269
270 #else
271                                 throw; // rethrow
272 #endif
273                         }
274
275                 } else {
276                         // eh?
277                 }
278
279         } else if (type == DataType::MIDI) {
280
281                 SMFSource* src = new SMFSource (s, path, SMFSource::Flag(0));
282                 src->load_model (true, true);
283 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
284                 // boost_debug_shared_ptr_mark_interesting (src, "Source");
285 #endif
286                 boost::shared_ptr<Source> ret (src);
287
288                 if (announce) {
289                         SourceCreated (ret);
290                 }
291
292                 return ret;
293
294         }
295
296         return boost::shared_ptr<Source>();
297 }
298
299 boost::shared_ptr<Source>
300 SourceFactory::createWritable (DataType type, Session& s, const std::string& path, const std::string& origin,
301                                bool destructive, framecnt_t rate, bool announce, bool defer_peaks)
302 {
303         /* this might throw failed_constructor(), which is OK */
304
305         if (type == DataType::AUDIO) {
306                 Source* src = new SndFileSource (s, path, origin,
307                                 s.config.get_native_file_data_format(),
308                                 s.config.get_native_file_header_format(),
309                                 rate,
310                                 (destructive
311                                         ? Source::Flag (SndFileSource::default_writable_flags | Source::Destructive)
312                                  : SndFileSource::default_writable_flags));
313 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
314                 // boost_debug_shared_ptr_mark_interesting (src, "Source");
315 #endif
316                 boost::shared_ptr<Source> ret (src);
317
318                 if (setup_peakfile (ret, defer_peaks)) {
319                         return boost::shared_ptr<Source>();
320                 }
321
322                 // no analysis data - this is a new file
323
324                 if (announce) {
325                         SourceCreated (ret);
326                 }
327                 return ret;
328
329         } else if (type == DataType::MIDI) {
330                 // XXX writable flags should belong to MidiSource too
331                 boost::shared_ptr<SMFSource> src (new SMFSource (s, path, SndFileSource::default_writable_flags));
332                 assert (src->writable ());
333
334                 src->load_model (true, true);
335 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
336                 // boost_debug_shared_ptr_mark_interesting (src, "Source");
337 #endif
338
339                 // no analysis data - this is a new file
340
341                 if (announce) {
342                         SourceCreated (src);
343                 }
344                 return src;
345
346         }
347
348         return boost::shared_ptr<Source> ();
349 }
350
351 boost::shared_ptr<Source>
352 SourceFactory::createFromPlaylist (DataType type, Session& s, boost::shared_ptr<Playlist> p, const ID& orig, const std::string& name,
353                                    uint32_t chn, frameoffset_t start, framecnt_t len, bool copy, bool defer_peaks)
354 {
355         if (type == DataType::AUDIO) {
356                 try {
357
358                         boost::shared_ptr<AudioPlaylist> ap = boost::dynamic_pointer_cast<AudioPlaylist>(p);
359
360                         if (ap) {
361
362                                 if (copy) {
363                                         ap.reset (new AudioPlaylist (ap, start, len, name, true));
364                                         start = 0;
365                                 }
366
367                                 Source* src = new AudioPlaylistSource (s, orig, name, ap, chn, start, len, Source::Flag (0));
368                                 boost::shared_ptr<Source> ret (src);
369
370                                 if (setup_peakfile (ret, defer_peaks)) {
371                                         return boost::shared_ptr<Source>();
372                                 }
373
374                                 ret->check_for_analysis_data_on_disk ();
375                                 SourceCreated (ret);
376                                 return ret;
377                         }
378                 }
379
380                 catch (failed_constructor& err) {
381                         /* relax - return at function scope */
382                 }
383
384         } else if (type == DataType::MIDI) {
385
386                 try {
387
388                         boost::shared_ptr<MidiPlaylist> ap = boost::dynamic_pointer_cast<MidiPlaylist>(p);
389
390                         if (ap) {
391
392                                 if (copy) {
393                                         ap.reset (new MidiPlaylist (ap, start, len, name, true));
394                                         start = 0;
395                                 }
396
397                                 Source* src = new MidiPlaylistSource (s, orig, name, ap, chn, start, len, Source::Flag (0));
398                                 boost::shared_ptr<Source> ret (src);
399
400                                 SourceCreated (ret);
401                                 return ret;
402                         }
403                 }
404
405                 catch (failed_constructor& err) {
406                         /* relax - return at function scope */
407                 }
408
409         }
410
411         return boost::shared_ptr<Source>();
412 }
413