2edd06282b1129b80927b5e9129c88ade9ee0660
[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/gstdio_compat.h"
34 #include "pbd/convert.h"
35 #include "pbd/basename.h"
36 #include "pbd/file_utils.h"
37 #include "pbd/mountpoint.h"
38 #include "pbd/stl_delete.h"
39 #include "pbd/strsplit.h"
40 #include "pbd/shortpath.h"
41 #include "pbd/stacktrace.h"
42 #include "pbd/enumwriter.h"
43
44 #include <sndfile.h>
45
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 "pbd/i18n.h"
65
66 using namespace std;
67 using namespace ARDOUR;
68 using namespace PBD;
69 using namespace Glib;
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 sources listed in session-files (XML)
135  * and missing sources (SilentFileSource).
136  *
137  * If _origin is an absolute path after ::set_state(), then the
138  * file is external to the session.
139  */
140 AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
141         : Source (s, node)
142         , AudioSource (s, node)
143         , FileSource (s, node, must_exist)
144 {
145         if (set_state (node, Stateful::loading_state_version)) {
146                 throw failed_constructor ();
147         }
148
149         if (Glib::path_is_absolute (_origin)) {
150                 _path = _origin;
151         }
152
153         if (init (_path, must_exist)) {
154                 throw failed_constructor ();
155         }
156 }
157
158 AudioFileSource::~AudioFileSource ()
159 {
160         DEBUG_TRACE (DEBUG::Destruction, string_compose ("AudioFileSource destructor %1, removable? %2\n", _path, removable()));
161         if (removable()) {
162                 ::g_unlink (_path.c_str());
163                 ::g_unlink (_peakpath.c_str());
164         }
165 }
166
167 int
168 AudioFileSource::init (const string& pathstr, bool must_exist)
169 {
170         return FileSource::init (pathstr, must_exist);
171 }
172
173 string
174 AudioFileSource::construct_peak_filepath (const string& audio_path, const bool in_session, const bool old_peak_name) const
175 {
176         string base;
177         if (old_peak_name) {
178                 base = audio_path.substr (0, audio_path.find_last_of ('.'));
179         } else {
180                 base = audio_path;
181         }
182         base += '%';
183         base += (char) ('A' + _channel);
184         return _session.construct_peak_filepath (base, in_session, old_peak_name);
185 }
186
187 bool
188 AudioFileSource::get_soundfile_info (const string& path, SoundFileInfo& _info, string& error_msg)
189 {
190         /* try sndfile first because it gets timecode info from .wav (BWF) if it exists,
191            which at present, ExtAudioFile from Apple seems unable to do.
192         */
193
194         if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
195                 return true;
196         }
197
198 #ifdef HAVE_COREAUDIO
199         if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
200                 return true;
201         }
202 #endif // HAVE_COREAUDIO
203
204         return false;
205 }
206
207 XMLNode&
208 AudioFileSource::get_state ()
209 {
210         LocaleGuard lg;
211         XMLNode& root (AudioSource::get_state());
212         char buf[32];
213         snprintf (buf, sizeof (buf), "%u", _channel);
214         root.add_property (X_("channel"), buf);
215         root.add_property (X_("origin"), _origin);
216         snprintf (buf, sizeof (buf), "%f", _gain);
217         root.add_property (X_("gain"), buf);
218         return root;
219 }
220
221 int
222 AudioFileSource::set_state (const XMLNode& node, int version)
223 {
224         if (Source::set_state (node, version)) {
225                 return -1;
226         }
227
228         if (AudioSource::set_state (node, version)) {
229                 return -1;
230         }
231
232         if (FileSource::set_state (node, version)) {
233                 return -1;
234         }
235
236         return 0;
237 }
238
239 void
240 AudioFileSource::mark_streaming_write_completed (const Lock& lock)
241 {
242         if (!writable()) {
243                 return;
244         }
245
246         AudioSource::mark_streaming_write_completed (lock);
247 }
248
249 int
250 AudioFileSource::move_dependents_to_trash()
251 {
252         return ::g_unlink (_peakpath.c_str());
253 }
254
255 void
256 AudioFileSource::set_header_position_offset (framecnt_t offset)
257 {
258         header_position_offset = offset;
259         HeaderPositionOffsetChanged ();
260 }
261
262 bool
263 AudioFileSource::is_empty (Session& /*s*/, string path)
264 {
265         SoundFileInfo info;
266         string err;
267
268         if (!get_soundfile_info (path, info, err)) {
269                 /* dangerous: we can't get info, so assume that its not empty */
270                 return false;
271         }
272
273         return info.length == 0;
274 }
275
276 int
277 AudioFileSource::setup_peakfile ()
278 {
279         if (_session.deletion_in_progress()) {
280                 return 0;
281         }
282         if (!(_flags & NoPeakFile)) {
283                 return initialize_peakfile (_path, within_session());
284         } else {
285                 return 0;
286         }
287 }
288
289 void
290 AudioFileSource::set_gain (float g, bool temporarily)
291 {
292         if (_gain == g) {
293                 return;
294         }
295         _gain = g;
296         if (temporarily) {
297                 return;
298         }
299         close_peakfile();
300         setup_peakfile ();
301 }
302
303 bool
304 AudioFileSource::safe_audio_file_extension(const string& file)
305 {
306         const char* suffixes[] = {
307                 ".aif", ".AIF",
308                 ".aifc", ".AIFC",
309                 ".aiff", ".AIFF",
310                 ".amb", ".AMB",
311                 ".au", ".AU",
312                 ".caf", ".CAF",
313                 ".cdr", ".CDR",
314                 ".flac", ".FLAC",
315                 ".htk", ".HTK",
316                 ".iff", ".IFF",
317                 ".mat", ".MAT",
318                 ".oga", ".OGA",
319                 ".ogg", ".OGG",
320                 ".paf", ".PAF",
321                 ".pvf", ".PVF",
322                 ".sf", ".SF",
323                 ".smp", ".SMP",
324                 ".snd", ".SND",
325                 ".maud", ".MAUD",
326                 ".voc", ".VOC"
327                 ".vwe", ".VWE",
328                 ".w64", ".W64",
329                 ".wav", ".WAV",
330 #ifdef HAVE_COREAUDIO
331                 ".aac", ".AAC",
332                 ".adts", ".ADTS",
333                 ".ac3", ".AC3",
334                 ".amr", ".AMR",
335                 ".mpa", ".MPA",
336                 ".mpeg", ".MPEG",
337                 ".mp1", ".MP1",
338                 ".mp2", ".MP2",
339                 ".mp3", ".MP3",
340                 ".mp4", ".MP4",
341                 ".m4a", ".M4A",
342                 ".sd2", ".SD2",         // libsndfile supports sd2 also, but the resource fork is required to open.
343 #endif // HAVE_COREAUDIO
344         };
345
346         for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
347                 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
348                         return true;
349                 }
350         }
351
352         return false;
353 }
354
355 Sample*
356 AudioFileSource::get_interleave_buffer (framecnt_t size)
357 {
358         SizedSampleBuffer* ssb;
359
360         if ((ssb = thread_interleave_buffer.get()) == 0) {
361                 ssb = new SizedSampleBuffer (size);
362                 thread_interleave_buffer.set (ssb);
363         }
364
365         if (ssb->size < size) {
366                 ssb = new SizedSampleBuffer (size);
367                 thread_interleave_buffer.set (ssb);
368         }
369
370         return ssb->buf;
371 }
372