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