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