Sort various things to reduce merge hell. No functional changes.
[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 #include <pbd/error.h>
22 #include <pbd/convert.h>
23 #include <pbd/pthread_utils.h>
24
25 #include <ardour/source_factory.h>
26 #include <ardour/sndfilesource.h>
27 #include <ardour/silentfilesource.h>
28 #include <ardour/configuration.h>
29 #include <ardour/smf_source.h>
30
31 #ifdef HAVE_COREAUDIO
32 #include <ardour/coreaudiosource.h>
33 #endif
34
35 #include "i18n.h"
36
37 using namespace ARDOUR;
38 using namespace std;
39 using namespace PBD;
40
41 sigc::signal<void,boost::shared_ptr<Source> > SourceFactory::SourceCreated;
42 Glib::Cond* SourceFactory::PeaksToBuild;
43 Glib::StaticMutex SourceFactory::peak_building_lock = GLIBMM_STATIC_MUTEX_INIT;
44 std::list<boost::weak_ptr<AudioSource> > SourceFactory::files_with_peaks;
45
46 static void 
47 peak_thread_work ()
48 {
49         PBD::ThreadCreated (pthread_self(), string ("peakbuilder-") + to_string (pthread_self(), std::dec));
50
51         while (true) {
52
53                 SourceFactory::peak_building_lock.lock ();
54                 
55           wait:
56                 if (SourceFactory::files_with_peaks.empty()) {
57                         SourceFactory::PeaksToBuild->wait (SourceFactory::peak_building_lock);
58                 }
59
60                 if (SourceFactory::files_with_peaks.empty()) {
61                         goto wait;
62                 }
63
64                 boost::shared_ptr<AudioSource> as (SourceFactory::files_with_peaks.front().lock());
65                 SourceFactory::files_with_peaks.pop_front ();
66                 SourceFactory::peak_building_lock.unlock ();
67                 
68                 if (!as) {
69                         continue;
70                 }
71                 as->setup_peakfile ();
72         }
73 }
74
75 void
76 SourceFactory::init ()
77 {
78         PeaksToBuild = new Glib::Cond();
79
80         for (int n = 0; n < 2; ++n) {
81                 Glib::Thread::create (sigc::ptr_fun (::peak_thread_work), false);
82         }
83 }
84
85 int
86 SourceFactory::setup_peakfile (boost::shared_ptr<Source> s, bool async)
87 {
88         boost::shared_ptr<AudioSource> as (boost::dynamic_pointer_cast<AudioSource> (s));
89
90         if (as) {
91
92                 if (async) {
93
94                         Glib::Mutex::Lock lm (peak_building_lock);
95                         files_with_peaks.push_back (boost::weak_ptr<AudioSource> (as));
96                         PeaksToBuild->broadcast ();
97
98                 } else {
99
100                         if (as->setup_peakfile ()) {
101                                 error << string_compose("SourceFactory: could not set up peakfile for %1", as->name()) << endmsg;
102                                 return -1;
103                         }
104                 }
105         }
106
107         return 0;
108 }
109
110 boost::shared_ptr<Source>
111 SourceFactory::createSilent (Session& s, const XMLNode& node, nframes_t nframes, float sr)
112 {
113         boost::shared_ptr<Source> ret (new SilentFileSource (s, node, nframes, sr));
114         // no analysis data - the file is non-existent
115         SourceCreated (ret);
116         return ret;
117 }
118
119 boost::shared_ptr<Source>
120 SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
121 {
122         DataType type = DataType::AUDIO;
123         const XMLProperty* prop = node.property("type");
124
125         if (prop) {
126                 type = DataType(prop->value());
127         }
128
129         if (type == DataType::AUDIO) {
130
131 #ifdef HAVE_COREAUDIO
132
133                 try {
134                         boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
135
136                         if (setup_peakfile (ret, defer_peaks)) {
137                                 return boost::shared_ptr<Source>();
138                         }
139
140                         ret->check_for_analysis_data_on_disk ();
141                         SourceCreated (ret);
142                         return ret;
143                 } 
144
145
146                 catch (failed_constructor& err) {
147
148                         /* this is allowed to throw */
149
150                         boost::shared_ptr<Source> ret (new SndFileSource (s, node));
151
152                         if (setup_peakfile (ret, defer_peaks)) {
153                                 return boost::shared_ptr<Source>();
154                         }
155
156                         ret->check_for_analysis_data_on_disk ();
157                         SourceCreated (ret);
158                         return ret;
159                 }
160 #else
161                 /* this is allowed to throw */
162
163                 boost::shared_ptr<Source> ret (new SndFileSource (s, node));
164
165                 if (setup_peakfile (ret, defer_peaks)) {
166                         return boost::shared_ptr<Source>();
167                 }
168
169                 ret->check_for_analysis_data_on_disk ();
170                 SourceCreated (ret);
171                 return ret;
172 #endif
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, string path, int chn, AudioFileSource::Flag flags, bool announce, bool defer_peaks)
186 {
187         if (type == DataType::AUDIO) {
188         
189 #ifdef HAVE_COREAUDIO
190                 try {
191                         boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, chn, flags));
192
193                         if (setup_peakfile (ret, defer_peaks)) {
194                                 return boost::shared_ptr<Source>();
195                         }
196
197                         ret->check_for_analysis_data_on_disk ();
198                         if (announce) {
199                                 SourceCreated (ret);
200                         }
201                         return ret;
202                 }
203                 
204                 catch (failed_constructor& err) {
205                         boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
206                         if (setup_peakfile (ret, defer_peaks)) {
207                                 return boost::shared_ptr<Source>();
208                         }
209                         ret->check_for_analysis_data_on_disk ();
210                         if (announce) {
211                                 SourceCreated (ret);
212                         }
213                         return ret;
214                 }
215 #else
216                 boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
217
218                 if (setup_peakfile (ret, defer_peaks)) {
219                         return boost::shared_ptr<Source>();
220                 }
221
222                 ret->check_for_analysis_data_on_disk ();
223                 if (announce) {
224                         SourceCreated (ret);
225                 }
226
227                 return ret;
228 #endif
229                 
230         } else if (type == DataType::MIDI) {
231
232                 // FIXME: flags?
233                 boost::shared_ptr<Source> ret (new SMFSource (s, path, SMFSource::Flag(0)));
234
235                 ret->check_for_analysis_data_on_disk ();
236                 if (announce) {
237                         SourceCreated (ret);
238                 }
239
240                 return ret;
241         }
242
243         return boost::shared_ptr<Source>();
244 }
245
246 boost::shared_ptr<Source>
247 SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, nframes_t rate, bool announce, bool defer_peaks)
248 {
249         /* this might throw failed_constructor(), which is OK */
250         
251         if (type == DataType::AUDIO) {
252                 boost::shared_ptr<Source> ret (new SndFileSource 
253                                                (s, path, 
254                                                 Config->get_native_file_data_format(),
255                                                 Config->get_native_file_header_format(),
256                                                 rate,
257                                                 (destructive ? AudioFileSource::Flag (SndFileSource::default_writable_flags | AudioFileSource::Destructive) :
258                                                  SndFileSource::default_writable_flags)));      
259
260                 if (setup_peakfile (ret, defer_peaks)) {
261                         return boost::shared_ptr<Source>();
262                 }
263                 
264                 // no analysis data - this is a new file
265
266                 if (announce) {
267                         SourceCreated (ret);
268                 }
269                 return ret;
270
271         } else if (type == DataType::MIDI) {
272
273                 boost::shared_ptr<Source> ret (new SMFSource (s, path));
274         
275                 // no analysis data - this is a new file
276                 
277                 if (announce) {
278                         SourceCreated (ret);
279                 }
280                 return ret;
281
282         }
283
284         return boost::shared_ptr<Source> ();
285 }