Merge with trunk R2978.
[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         SourceCreated (ret);
115         return ret;
116 }
117
118 boost::shared_ptr<Source>
119 SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
120 {
121        DataType type = DataType::AUDIO;
122        const XMLProperty* prop = node.property("type");
123
124        if (prop) {
125                type = DataType(prop->value());
126        }
127
128        if (type == DataType::AUDIO) {
129
130 #ifdef HAVE_COREAUDIO
131
132                try {
133                        boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
134                        
135                        if (setup_peakfile (ret, defer_peaks)) {
136                                return boost::shared_ptr<Source>();
137                        }
138                        
139                        SourceCreated (ret);
140                        return ret;
141                } 
142                
143                
144                catch (failed_constructor& err) {        
145                        
146                        /* this is allowed to throw */
147                        
148                        boost::shared_ptr<Source> ret (new SndFileSource (s, node));
149                        
150                        if (setup_peakfile (ret, defer_peaks)) {
151                                return boost::shared_ptr<Source>();
152                        }
153                        
154                        SourceCreated (ret);
155                        return ret;
156                }
157 #else
158                /* this is allowed to throw */
159
160                boost::shared_ptr<Source> ret (new SndFileSource (s, node));
161                
162                if (setup_peakfile (ret, defer_peaks)) {
163                        return boost::shared_ptr<Source>();
164                }
165                
166                SourceCreated (ret);
167                return ret;
168 #endif
169         
170        } else if (type == DataType::MIDI) {
171                    boost::shared_ptr<Source> ret (new SMFSource (s, node));
172                        
173                    SourceCreated (ret);
174                    return ret;
175        }
176
177         return boost::shared_ptr<Source>();
178 }
179
180 boost::shared_ptr<Source>
181 SourceFactory::createReadable (DataType type, Session& s, string path, int chn, AudioFileSource::Flag flags, bool announce, bool defer_peaks)
182 {
183         if (type == DataType::AUDIO) {
184         
185 #ifdef HAVE_COREAUDIO
186                 try {
187                         boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, chn, flags));
188
189                         if (setup_peakfile (ret, defer_peaks)) {
190                                 return boost::shared_ptr<Source>();
191                         }
192
193                         if (announce) {
194                                 SourceCreated (ret);
195                         }
196                         return ret;
197                 }
198                 
199                 catch (failed_constructor& err) {
200                         boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
201                         if (setup_peakfile (ret, defer_peaks)) {
202                                 return boost::shared_ptr<Source>();
203                         }
204                         if (announce) {
205                                 SourceCreated (ret);
206                         }
207                         return ret;
208                 }
209 #else
210                 boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
211
212                 if (setup_peakfile (ret, defer_peaks)) {
213                         return boost::shared_ptr<Source>();
214                 }
215
216                 if (announce) {
217                         SourceCreated (ret);
218                 }
219
220                 return ret;
221 #endif
222                 
223         } else if (type == DataType::MIDI) {
224
225                 // FIXME: flags?
226                 boost::shared_ptr<Source> ret (new SMFSource (s, path, SMFSource::Flag(0)));
227
228                 if (announce) {
229                         SourceCreated (ret);
230                 }
231
232                 return ret;
233         }
234
235         return boost::shared_ptr<Source>();
236 }
237
238 boost::shared_ptr<Source>
239 SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, nframes_t rate, bool announce, bool defer_peaks)
240 {
241         /* this might throw failed_constructor(), which is OK */
242         
243         if (type == DataType::AUDIO) {
244                 boost::shared_ptr<Source> ret (new SndFileSource 
245                                                (s, path, 
246                                                 Config->get_native_file_data_format(),
247                                                 Config->get_native_file_header_format(),
248                                                 rate,
249                                                 (destructive ? AudioFileSource::Flag (SndFileSource::default_writable_flags | AudioFileSource::Destructive) :
250                                                  SndFileSource::default_writable_flags)));      
251
252                 if (setup_peakfile (ret, defer_peaks)) {
253                         return boost::shared_ptr<Source>();
254                 }
255
256                 if (announce) {
257                         SourceCreated (ret);
258                 }
259                 return ret;
260
261         } else if (type == DataType::MIDI) {
262
263                 boost::shared_ptr<Source> ret (new SMFSource (s, path));
264                 
265                 if (announce) {
266                         SourceCreated (ret);
267                 }
268                 return ret;
269
270         }
271
272         return boost::shared_ptr<Source> ();
273 }