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