Fix displaying of notes in auto-created MIDI region when it's the first region in...
[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;
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
72                 as->setup_peakfile ();
73         }
74 }
75
76 void
77 SourceFactory::init ()
78 {
79         PeaksToBuild = new Glib::Cond();
80
81         for (int n = 0; n < 2; ++n) {
82                 Glib::Thread::create (sigc::ptr_fun (::peak_thread_work), false);
83         }
84 }
85
86 int
87 SourceFactory::setup_peakfile (boost::shared_ptr<Source> s, bool async)
88 {
89         boost::shared_ptr<AudioSource> as (boost::dynamic_pointer_cast<AudioSource> (s));
90
91         if (as) {
92
93                 if (async) {
94
95                         Glib::Mutex::Lock lm (peak_building_lock);
96                         files_with_peaks.push_back (boost::weak_ptr<AudioSource> (as));
97                         PeaksToBuild->broadcast ();
98
99                 } else {
100
101                         if (as->setup_peakfile ()) {
102                                 error << string_compose("SourceFactory: could not set up peakfile for %1", as->name()) << endmsg;
103                                 return -1;
104                         }
105                 }
106         }
107
108         return 0;
109 }
110
111 boost::shared_ptr<Source>
112 SourceFactory::createSilent (Session& s, const XMLNode& node, nframes_t nframes, float sr)
113 {
114         boost::shared_ptr<Source> ret (new SilentFileSource (s, node, nframes, sr));
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                        SourceCreated (ret);
141                        return ret;
142                } 
143                
144                
145                catch (failed_constructor& err) {        
146                        
147                        /* this is allowed to throw */
148                        
149                        boost::shared_ptr<Source> ret (new SndFileSource (s, node));
150                        
151                        if (setup_peakfile (ret, defer_peaks)) {
152                                return boost::shared_ptr<Source>();
153                        }
154                        
155                        SourceCreated (ret);
156                        return ret;
157                }
158 #else
159                /* this is allowed to throw */
160
161                boost::shared_ptr<Source> ret (new SndFileSource (s, node));
162                
163                if (setup_peakfile (ret, defer_peaks)) {
164                        return boost::shared_ptr<Source>();
165                }
166                
167                SourceCreated (ret);
168                return ret;
169 #endif
170         
171        } else if (type == DataType::MIDI) {
172                    boost::shared_ptr<Source> ret (new SMFSource (s, node));
173                        
174                    SourceCreated (ret);
175                    return ret;
176        }
177
178         return boost::shared_ptr<Source>();
179 }
180
181 boost::shared_ptr<Source>
182 SourceFactory::createReadable (DataType type, Session& s, string path, int chn, AudioFileSource::Flag flags, bool announce, bool defer_peaks)
183 {
184         if (type == DataType::AUDIO) {
185         
186 #ifdef HAVE_COREAUDIO
187                 try {
188                         boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, chn, flags));
189
190                         if (setup_peakfile (ret, defer_peaks)) {
191                                 return boost::shared_ptr<Source>();
192                         }
193
194                         if (announce) {
195                                 SourceCreated (ret);
196                         }
197                         return ret;
198                 }
199                 
200                 catch (failed_constructor& err) {
201                         boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
202                         if (setup_peakfile (ret, defer_peaks)) {
203                                 return boost::shared_ptr<Source>();
204                         }
205                         if (announce) {
206                                 SourceCreated (ret);
207                         }
208                         return ret;
209                 }
210 #else
211                 boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
212
213                 if (setup_peakfile (ret, defer_peaks)) {
214                         return boost::shared_ptr<Source>();
215                 }
216
217                 if (announce) {
218                         SourceCreated (ret);
219                 }
220
221                 return ret;
222 #endif
223                 
224         } else if (type == DataType::MIDI) {
225
226                 // FIXME: flags?
227                 boost::shared_ptr<Source> ret (new SMFSource (s, path, SMFSource::Flag(0)));
228
229                 if (announce) {
230                         SourceCreated (ret);
231                 }
232
233                 return ret;
234         }
235
236         return boost::shared_ptr<Source>();
237 }
238
239 boost::shared_ptr<Source>
240 SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, nframes_t rate, bool announce, bool defer_peaks)
241 {
242         /* this might throw failed_constructor(), which is OK */
243         
244         if (type == DataType::AUDIO) {
245                 boost::shared_ptr<Source> ret (new SndFileSource 
246                                                (s, path, 
247                                                 Config->get_native_file_data_format(),
248                                                 Config->get_native_file_header_format(),
249                                                 rate,
250                                                 (destructive ? AudioFileSource::Flag (SndFileSource::default_writable_flags | AudioFileSource::Destructive) :
251                                                  SndFileSource::default_writable_flags)));      
252
253                 if (setup_peakfile (ret, false)) {
254                         return boost::shared_ptr<Source>();
255                 }
256
257                 if (announce) {
258                         SourceCreated (ret);
259                 }
260                 return ret;
261
262         } else if (type == DataType::MIDI) {
263
264                 boost::shared_ptr<Source> ret (new SMFSource (s, path));
265                 
266                 if (announce) {
267                         SourceCreated (ret);
268                 }
269                 return ret;
270
271         }
272
273         return boost::shared_ptr<Source> ();
274 }