48aaeb8d08ee6cc82a5c3c5ed65d44126b057234
[ardour.git] / libs / ardour / audiofilesource.cc
1 /*
2     Copyright (C) 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 */
19
20 #include <vector>
21
22 #include <sys/time.h>
23 #include <sys/stat.h>
24 #include <stdio.h> // for rename(), sigh
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <errno.h>
28
29 #include "pbd/convert.h"
30 #include "pbd/basename.h"
31 #include "pbd/mountpoint.h"
32 #include "pbd/stl_delete.h"
33 #include "pbd/strsplit.h"
34 #include "pbd/shortpath.h"
35 #include "pbd/enumwriter.h"
36
37 #include <sndfile.h>
38
39 #include <glibmm/miscutils.h>
40 #include <glibmm/fileutils.h>
41 #include <glibmm/thread.h>
42
43 #include "ardour/audiofilesource.h"
44 #include "ardour/sndfile_helpers.h"
45 #include "ardour/sndfilesource.h"
46 #include "ardour/session.h"
47 #include "ardour/session_directory.h"
48 #include "ardour/source_factory.h"
49 #include "ardour/filename_extensions.h"
50
51 // if these headers come before sigc++ is included
52 // the parser throws ObjC++ errors. (nil is a keyword)
53 #ifdef HAVE_COREAUDIO 
54 #include "ardour/coreaudiosource.h"
55 #include <AudioToolbox/ExtendedAudioFile.h>
56 #include <AudioToolbox/AudioFormat.h>
57 #endif // HAVE_COREAUDIO
58
59 #include "i18n.h"
60
61 using namespace ARDOUR;
62 using namespace PBD;
63 using namespace Glib;
64
65 ustring AudioFileSource::peak_dir = "";
66
67 sigc::signal<void> AudioFileSource::HeaderPositionOffsetChanged;
68 uint64_t           AudioFileSource::header_position_offset = 0;
69
70 /* XXX maybe this too */
71 char AudioFileSource::bwf_serial_number[13] = "000000000000";
72
73 struct SizedSampleBuffer {
74     nframes_t size;
75     Sample* buf;
76
77     SizedSampleBuffer (nframes_t sz) : size (sz) { 
78             buf = new Sample[size];
79     }
80
81     ~SizedSampleBuffer() {
82             delete [] buf;
83     }
84 };
85
86 Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
87
88 /** Constructor used for existing internal-to-session files. */
89 AudioFileSource::AudioFileSource (Session& s, const ustring& path, bool embedded, Source::Flag flags)
90         : Source (s, DataType::AUDIO, path, flags)
91         , AudioSource (s, path)
92         , FileSource (s, DataType::AUDIO, path, embedded, flags)
93 {
94         if (init (path, true)) {
95                 throw failed_constructor ();
96         }
97 }
98
99 /** Constructor used for new internal-to-session files. */
100 AudioFileSource::AudioFileSource (Session& s, const ustring& path, bool embedded, Source::Flag flags,
101                 SampleFormat samp_format, HeaderFormat hdr_format)
102         : Source (s, DataType::AUDIO, path, flags)
103         , AudioSource (s, path)
104         , FileSource (s, DataType::AUDIO, path, embedded, flags)
105 {
106         _is_embedded = false;
107
108         if (init (path, false)) {
109                 throw failed_constructor ();
110         }
111 }
112
113 /** Constructor used for existing internal-to-session files.  File must exist. */
114 AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
115         : Source (s, node)
116         , AudioSource (s, node)
117         , FileSource (s, node, must_exist)
118 {
119         if (set_state (node)) {
120                 throw failed_constructor ();
121         }
122
123         if (init (_name, must_exist)) {
124                 throw failed_constructor ();
125         }
126 }
127
128 AudioFileSource::~AudioFileSource ()
129 {
130         if (removable()) {
131                 unlink (_path.c_str());
132                 unlink (peakpath.c_str());
133         }
134 }
135
136 int
137 AudioFileSource::init (const ustring& pathstr, bool must_exist)
138 {
139         _peaks_built = false;
140         return FileSource::init (pathstr, must_exist);
141 }
142
143 ustring
144 AudioFileSource::peak_path (ustring audio_path)
145 {
146         ustring base;
147
148         base = PBD::basename_nosuffix (audio_path);
149         base += '%';
150         base += (char) ('A' + _channel);
151
152         return _session.peak_path (base);
153 }
154
155 ustring
156 AudioFileSource::find_broken_peakfile (ustring peak_path, ustring audio_path)
157 {
158         ustring str;
159
160         /* check for the broken location in use by 2.0 for several months */
161         
162         str = broken_peak_path (audio_path);
163         
164         if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
165                 
166                 if (is_embedded()) {
167                         
168                         /* it would be nice to rename it but the nature of 
169                            the bug means that we can't reliably use it.
170                         */
171                         
172                         peak_path = str;
173                         
174                 } else {
175                         /* all native files are mono, so we can just rename
176                            it.
177                         */
178                         ::rename (str.c_str(), peak_path.c_str());
179                 }
180                 
181         } else {
182                 /* Nasty band-aid for older sessions that were created before we
183                    used libsndfile for all audio files.
184                 */
185                 
186                 
187                 str = old_peak_path (audio_path);       
188                 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
189                         peak_path = str;
190                 }
191         }
192
193         return peak_path;
194 }
195
196 ustring
197 AudioFileSource::broken_peak_path (ustring audio_path)
198 {
199         return _session.peak_path (audio_path);
200 }
201
202 ustring
203 AudioFileSource::old_peak_path (ustring audio_path)
204 {
205         /* XXX hardly bombproof! fix me */
206
207         struct stat stat_file;
208         struct stat stat_mount;
209
210         ustring mp = mountpoint (audio_path);
211
212         stat (audio_path.c_str(), &stat_file);
213         stat (mp.c_str(), &stat_mount);
214
215         char buf[32];
216 #ifdef __APPLE__
217         snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
218 #else
219         snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
220 #endif
221
222         ustring res = peak_dir;
223         res += buf;
224         res += peakfile_suffix;
225
226         return res;
227 }
228
229 bool
230 AudioFileSource::get_soundfile_info (ustring path, SoundFileInfo& _info, string& error_msg)
231 {
232 #ifdef HAVE_COREAUDIO
233         if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
234                 return true;
235         }
236 #endif // HAVE_COREAUDIO
237
238         if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
239                 return true;
240         }
241
242         return false;
243 }
244
245 XMLNode&
246 AudioFileSource::get_state ()
247 {
248         XMLNode& root (AudioSource::get_state());
249         char buf[32];
250         snprintf (buf, sizeof (buf), "%u", _channel);
251         root.add_property (X_("channel"), buf);
252         return root;
253 }
254
255 int
256 AudioFileSource::set_state (const XMLNode& node)
257 {
258         if (Source::set_state (node)) {
259                 return -1;
260         }
261
262         if (AudioSource::set_state (node)) {
263                 return -1;
264         }
265         
266         if (FileSource::set_state (node)) {
267                 return -1;
268         }
269
270         return 0;
271 }
272
273 void
274 AudioFileSource::mark_streaming_write_completed ()
275 {
276         if (!writable()) {
277                 return;
278         }
279         
280         /* XXX notice that we're readers of _peaks_built
281            but we must hold a solid lock on PeaksReady.
282         */
283
284         Glib::Mutex::Lock lm (_lock);
285
286         if (_peaks_built) {
287                 PeaksReady (); /* EMIT SIGNAL */
288         }
289 }
290
291 int
292 AudioFileSource::move_dependents_to_trash()
293 {
294         return ::unlink (peakpath.c_str());
295 }
296
297 void
298 AudioFileSource::set_header_position_offset (nframes_t offset)
299 {
300         header_position_offset = offset;
301         HeaderPositionOffsetChanged ();
302 }
303
304 bool
305 AudioFileSource::is_empty (Session& s, ustring path)
306 {
307         SoundFileInfo info;
308         string err;
309         
310         if (!get_soundfile_info (path, info, err)) {
311                 /* dangerous: we can't get info, so assume that its not empty */
312                 return false; 
313         }
314
315         return info.length == 0;
316 }
317
318 int
319 AudioFileSource::setup_peakfile ()
320 {
321         if (!(_flags & NoPeakFile)) {
322                 return initialize_peakfile (_file_is_new, _path);
323         } else {
324                 return 0;
325         }
326 }
327
328 bool
329 AudioFileSource::safe_audio_file_extension(const ustring& file)
330 {
331         const char* suffixes[] = {
332                 ".wav", ".WAV",
333                 ".aiff", ".AIFF",
334                 ".caf", ".CAF",
335                 ".aif", ".AIF",
336                 ".amb", ".AMB",
337                 ".snd", ".SND",
338                 ".au", ".AU",
339                 ".raw", ".RAW",
340                 ".sf", ".SF",
341                 ".cdr", ".CDR",
342                 ".smp", ".SMP",
343                 ".maud", ".MAUD",
344                 ".vwe", ".VWE",
345                 ".paf", ".PAF",
346                 ".voc", ".VOC",
347 #ifdef HAVE_FLAC
348                 ".flac", ".FLAC",
349 #endif // HAVE_FLAC
350 #ifdef HAVE_COREAUDIO
351                 ".mp3", ".MP3",
352                 ".aac", ".AAC",
353                 ".mp4", ".MP4",
354 #endif // HAVE_COREAUDIO
355         };
356
357         for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
358                 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
359                         return true;
360                 }
361         }
362
363         return false;
364 }
365
366 Sample*
367 AudioFileSource::get_interleave_buffer (nframes_t size)
368 {
369         SizedSampleBuffer* ssb;
370
371         if ((ssb = thread_interleave_buffer.get()) == 0) {
372                 ssb = new SizedSampleBuffer (size);
373                 thread_interleave_buffer.set (ssb);
374         }
375
376         if (ssb->size < size) {
377                 ssb = new SizedSampleBuffer (size);
378                 thread_interleave_buffer.set (ssb);
379         }
380
381         return ssb->buf;
382 }