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