fix clicking when processors become active/inactive; reduce crazy 2.5sec delay for...
[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                 return boost::shared_ptr<Source>();
139         }
140
141         type = DataType (prop->value());
142
143         if (type == DataType::AUDIO) {
144
145                 try {
146                         
147                         boost::shared_ptr<Source> ret (new SndFileSource (s, node));
148                         if (setup_peakfile (ret, defer_peaks)) {
149                                 return boost::shared_ptr<Source>();
150                         }
151                         ret->check_for_analysis_data_on_disk ();
152                         SourceCreated (ret);
153                         return ret;
154                 } 
155                 
156                 catch (failed_constructor& err) {
157
158 #ifdef USE_COREAUDIO_FOR_FILES
159                 
160                         /* this is allowed to throw */
161                         
162                         boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
163                         
164                         if (setup_peakfile (ret, defer_peaks)) {
165                                 return boost::shared_ptr<Source>();
166                         }
167                         
168                         ret->check_for_analysis_data_on_disk ();
169                         SourceCreated (ret);
170                         return ret;
171 #else
172                         throw; // rethrow 
173 #endif
174                 }
175
176         } else if (type == DataType::MIDI) {
177                 boost::shared_ptr<Source> ret (new SMFSource (s, node));
178                 ret->check_for_analysis_data_on_disk ();
179                 SourceCreated (ret);
180                 return ret;
181         }
182
183         return boost::shared_ptr<Source>();
184 }
185
186 boost::shared_ptr<Source>
187 SourceFactory::createReadable (DataType type, Session& s, const string& path, bool embedded,
188                 int chn, Source::Flag flags, bool announce, bool defer_peaks)
189 {
190         if (type == DataType::AUDIO) {
191
192                 if (!(flags & Destructive)) {
193                         
194                         try {
195                                 
196                                 boost::shared_ptr<Source> ret (new SndFileSource (s, path, embedded, chn, flags));
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                                 if (announce) {
204                                         SourceCreated (ret);
205                                 }
206                                 return ret;
207                         }
208                         
209                         catch (failed_constructor& err) {
210 #ifdef USE_COREAUDIO_FOR_FILES
211                                 
212                                 boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, embedded, chn, flags));
213                                 if (setup_peakfile (ret, defer_peaks)) {
214                                         return boost::shared_ptr<Source>();
215                                 }
216                                 ret->check_for_analysis_data_on_disk ();
217                                 if (announce) {
218                                         SourceCreated (ret);
219                                 }
220                                 return ret;
221                                 
222 #else
223                                 throw; // rethrow
224 #endif
225                         }
226
227                 } else {
228                         // eh?
229                 }
230         
231         } else if (type == DataType::MIDI) {
232                 
233                 boost::shared_ptr<Source> ret (new SMFSource (s, path, embedded, SMFSource::Flag(0)));
234                 
235                 if (announce) {
236                         SourceCreated (ret);
237                 }
238
239                 return ret;
240
241         }
242
243         return boost::shared_ptr<Source>();
244 }
245
246 boost::shared_ptr<Source>
247 SourceFactory::createWritable (DataType type, Session& s, const std::string& path, bool embedded,
248                 bool destructive, nframes_t rate, bool announce, bool defer_peaks)
249 {
250         /* this might throw failed_constructor(), which is OK */
251         
252         if (type == DataType::AUDIO) {
253                 boost::shared_ptr<Source> ret (new SndFileSource (s, path, embedded,
254                                 s.config.get_native_file_data_format(),
255                                 s.config.get_native_file_header_format(),
256                                 rate,
257                                 (destructive
258                                         ? Source::Flag (SndFileSource::default_writable_flags | Source::Destructive)
259                                         : SndFileSource::default_writable_flags)));     
260
261                 if (setup_peakfile (ret, defer_peaks)) {
262                         return boost::shared_ptr<Source>();
263                 }
264                 
265                 // no analysis data - this is a new file
266
267                 if (announce) {
268                         SourceCreated (ret);
269                 }
270                 return ret;
271
272         } else if (type == DataType::MIDI) {
273
274                 boost::shared_ptr<Source> ret (new SMFSource (s, path, embedded, Source::Flag(0)));
275         
276                 // no analysis data - this is a new file
277                 
278                 if (announce) {
279                         SourceCreated (ret);
280                 }
281                 return ret;
282
283         }
284
285         return boost::shared_ptr<Source> ();
286 }
287