Merge branch 'selection_fixes' of https://github.com/nmains/ardour into cairocanvas
[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         base = PBD::basename_nosuffix (audio_path);
172         base += '%';
173         base += (char) ('A' + _channel);
174
175         return _session.peak_path (base);
176 }
177
178 string
179 AudioFileSource::find_broken_peakfile (string peak_path, string audio_path)
180 {
181         string str;
182
183         /* check for the broken location in use by 2.0 for several months */
184
185         str = broken_peak_path (audio_path);
186
187         if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
188
189                 if (!within_session()) {
190
191                         /* it would be nice to rename it but the nature of
192                            the bug means that we can't reliably use it.
193                         */
194
195                         peak_path = str;
196
197                 } else {
198                         /* all native files are mono, so we can just rename
199                            it.
200                         */
201                         ::rename (str.c_str(), peak_path.c_str());
202                 }
203
204         } else {
205                 /* Nasty band-aid for older sessions that were created before we
206                    used libsndfile for all audio files.
207                 */
208
209
210                 str = old_peak_path (audio_path);
211                 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
212                         peak_path = str;
213                 }
214         }
215
216         return peak_path;
217 }
218
219 string
220 AudioFileSource::broken_peak_path (string audio_path)
221 {
222         return _session.peak_path (basename_nosuffix (audio_path));
223 }
224
225 string
226 AudioFileSource::old_peak_path (string audio_path)
227 {
228         /* XXX hardly bombproof! fix me */
229
230         struct stat stat_file;
231         struct stat stat_mount;
232
233         string mp = mountpoint (audio_path);
234
235         stat (audio_path.c_str(), &stat_file);
236         stat (mp.c_str(), &stat_mount);
237
238         char buf[32];
239 #ifdef __APPLE__
240         snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
241 #else
242         snprintf (buf, sizeof (buf), "%" PRId64 "-%" PRId64 "-%d.peak", (int64_t) stat_mount.st_ino, (int64_t) stat_file.st_ino, _channel);
243 #endif
244
245         string res = peak_dir;
246         res += buf;
247         res += peakfile_suffix;
248
249         return res;
250 }
251
252 bool
253 AudioFileSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg)
254 {
255         /* try sndfile first because it gets timecode info from .wav (BWF) if it exists,
256            which at present, ExtAudioFile from Apple seems unable to do.
257         */
258
259         if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
260                 return true;
261         }
262
263 #ifdef HAVE_COREAUDIO
264         if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
265                 return true;
266         }
267 #endif // HAVE_COREAUDIO
268
269         return false;
270 }
271
272 XMLNode&
273 AudioFileSource::get_state ()
274 {
275         XMLNode& root (AudioSource::get_state());
276         char buf[32];
277         snprintf (buf, sizeof (buf), "%u", _channel);
278         root.add_property (X_("channel"), buf);
279         root.add_property (X_("origin"), _origin);
280         return root;
281 }
282
283 int
284 AudioFileSource::set_state (const XMLNode& node, int version)
285 {
286         if (Source::set_state (node, version)) {
287                 return -1;
288         }
289
290         if (AudioSource::set_state (node, version)) {
291                 return -1;
292         }
293
294         if (FileSource::set_state (node, version)) {
295                 return -1;
296         }
297
298         return 0;
299 }
300
301 void
302 AudioFileSource::mark_streaming_write_completed ()
303 {
304         if (!writable()) {
305                 return;
306         }
307
308         AudioSource::mark_streaming_write_completed ();
309 }
310
311 int
312 AudioFileSource::move_dependents_to_trash()
313 {
314         return ::g_unlink (peakpath.c_str());
315 }
316
317 void
318 AudioFileSource::set_header_position_offset (framecnt_t offset)
319 {
320         header_position_offset = offset;
321         HeaderPositionOffsetChanged ();
322 }
323
324 bool
325 AudioFileSource::is_empty (Session& /*s*/, string path)
326 {
327         SoundFileInfo info;
328         string err;
329
330         if (!get_soundfile_info (path, info, err)) {
331                 /* dangerous: we can't get info, so assume that its not empty */
332                 return false;
333         }
334
335         return info.length == 0;
336 }
337
338 int
339 AudioFileSource::setup_peakfile ()
340 {
341         if (!(_flags & NoPeakFile)) {
342                 return initialize_peakfile (_path);
343         } else {
344                 return 0;
345         }
346 }
347
348 bool
349 AudioFileSource::safe_audio_file_extension(const string& file)
350 {
351         const char* suffixes[] = {
352                 ".aif", ".AIF",
353                 ".aifc", ".AIFC",
354                 ".aiff", ".AIFF",
355                 ".amb", ".AMB",
356                 ".au", ".AU",
357                 ".caf", ".CAF",
358                 ".cdr", ".CDR",
359                 ".flac", ".FLAC",
360                 ".htk", ".HTK",
361                 ".iff", ".IFF",
362                 ".mat", ".MAT",
363                 ".oga", ".OGA",
364                 ".ogg", ".OGG",
365                 ".paf", ".PAF",
366                 ".pvf", ".PVF",
367                 ".sf", ".SF",
368                 ".smp", ".SMP",
369                 ".snd", ".SND",
370                 ".maud", ".MAUD",
371                 ".voc", ".VOC"
372                 ".vwe", ".VWE",
373                 ".w64", ".W64",
374                 ".wav", ".WAV",
375 #ifdef HAVE_COREAUDIO
376                 ".aac", ".AAC",
377                 ".adts", ".ADTS",
378                 ".ac3", ".AC3",
379                 ".amr", ".AMR",
380                 ".mpa", ".MPA",
381                 ".mpeg", ".MPEG",
382                 ".mp1", ".MP1",
383                 ".mp2", ".MP2",
384                 ".mp3", ".MP3",
385                 ".mp4", ".MP4",
386                 ".m4a", ".M4A",
387                 ".sd2", ".SD2",         // libsndfile supports sd2 also, but the resource fork is required to open.
388 #endif // HAVE_COREAUDIO
389         };
390
391         for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
392                 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
393                         return true;
394                 }
395         }
396
397         return false;
398 }
399
400 Sample*
401 AudioFileSource::get_interleave_buffer (framecnt_t size)
402 {
403         SizedSampleBuffer* ssb;
404
405         if ((ssb = thread_interleave_buffer.get()) == 0) {
406                 ssb = new SizedSampleBuffer (size);
407                 thread_interleave_buffer.set (ssb);
408         }
409
410         if (ssb->size < size) {
411                 ssb = new SizedSampleBuffer (size);
412                 thread_interleave_buffer.set (ssb);
413         }
414
415         return ssb->buf;
416 }
417