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