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