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