0c921dae8d0c12952168c3986f0b748a611b79fc
[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::construct_peak_filepath (const string& audio_path, bool oldformat) const
168 {
169         string base;
170         if (oldformat) {
171                 base = audio_path.substr (0, audio_path.find_last_of ('.'));
172         } else {
173                 base = audio_path;
174         }
175         base += '%';
176         base += (char) ('A' + _channel);
177         return _session.construct_peak_filepath (base, oldformat);
178 }
179
180 bool
181 AudioFileSource::get_soundfile_info (const string& path, SoundFileInfo& _info, string& error_msg)
182 {
183         /* try sndfile first because it gets timecode info from .wav (BWF) if it exists,
184            which at present, ExtAudioFile from Apple seems unable to do.
185         */
186
187         if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
188                 return true;
189         }
190
191 #ifdef HAVE_COREAUDIO
192         if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
193                 return true;
194         }
195 #endif // HAVE_COREAUDIO
196
197         return false;
198 }
199
200 XMLNode&
201 AudioFileSource::get_state ()
202 {
203         XMLNode& root (AudioSource::get_state());
204         char buf[32];
205         snprintf (buf, sizeof (buf), "%u", _channel);
206         root.add_property (X_("channel"), buf);
207         root.add_property (X_("origin"), _origin);
208         return root;
209 }
210
211 int
212 AudioFileSource::set_state (const XMLNode& node, int version)
213 {
214         if (Source::set_state (node, version)) {
215                 return -1;
216         }
217
218         if (AudioSource::set_state (node, version)) {
219                 return -1;
220         }
221
222         if (FileSource::set_state (node, version)) {
223                 return -1;
224         }
225
226         return 0;
227 }
228
229 void
230 AudioFileSource::mark_streaming_write_completed (const Lock& lock)
231 {
232         if (!writable()) {
233                 return;
234         }
235
236         AudioSource::mark_streaming_write_completed (lock);
237 }
238
239 int
240 AudioFileSource::move_dependents_to_trash()
241 {
242         return ::g_unlink (_peakpath.c_str());
243 }
244
245 void
246 AudioFileSource::set_header_position_offset (framecnt_t offset)
247 {
248         header_position_offset = offset;
249         HeaderPositionOffsetChanged ();
250 }
251
252 bool
253 AudioFileSource::is_empty (Session& /*s*/, string path)
254 {
255         SoundFileInfo info;
256         string err;
257
258         if (!get_soundfile_info (path, info, err)) {
259                 /* dangerous: we can't get info, so assume that its not empty */
260                 return false;
261         }
262
263         return info.length == 0;
264 }
265
266 int
267 AudioFileSource::setup_peakfile ()
268 {
269         if (_session.deletion_in_progress()) {
270                 return 0;
271         }
272         if (!(_flags & NoPeakFile)) {
273                 return initialize_peakfile (_path);
274         } else {
275                 return 0;
276         }
277 }
278
279 bool
280 AudioFileSource::safe_audio_file_extension(const string& file)
281 {
282         const char* suffixes[] = {
283                 ".aif", ".AIF",
284                 ".aifc", ".AIFC",
285                 ".aiff", ".AIFF",
286                 ".amb", ".AMB",
287                 ".au", ".AU",
288                 ".caf", ".CAF",
289                 ".cdr", ".CDR",
290                 ".flac", ".FLAC",
291                 ".htk", ".HTK",
292                 ".iff", ".IFF",
293                 ".mat", ".MAT",
294                 ".oga", ".OGA",
295                 ".ogg", ".OGG",
296                 ".paf", ".PAF",
297                 ".pvf", ".PVF",
298                 ".sf", ".SF",
299                 ".smp", ".SMP",
300                 ".snd", ".SND",
301                 ".maud", ".MAUD",
302                 ".voc", ".VOC"
303                 ".vwe", ".VWE",
304                 ".w64", ".W64",
305                 ".wav", ".WAV",
306 #ifdef HAVE_COREAUDIO
307                 ".aac", ".AAC",
308                 ".adts", ".ADTS",
309                 ".ac3", ".AC3",
310                 ".amr", ".AMR",
311                 ".mpa", ".MPA",
312                 ".mpeg", ".MPEG",
313                 ".mp1", ".MP1",
314                 ".mp2", ".MP2",
315                 ".mp3", ".MP3",
316                 ".mp4", ".MP4",
317                 ".m4a", ".M4A",
318                 ".sd2", ".SD2",         // libsndfile supports sd2 also, but the resource fork is required to open.
319 #endif // HAVE_COREAUDIO
320         };
321
322         for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
323                 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
324                         return true;
325                 }
326         }
327
328         return false;
329 }
330
331 Sample*
332 AudioFileSource::get_interleave_buffer (framecnt_t size)
333 {
334         SizedSampleBuffer* ssb;
335
336         if ((ssb = thread_interleave_buffer.get()) == 0) {
337                 ssb = new SizedSampleBuffer (size);
338                 thread_interleave_buffer.set (ssb);
339         }
340
341         if (ssb->size < size) {
342                 ssb = new SizedSampleBuffer (size);
343                 thread_interleave_buffer.set (ssb);
344         }
345
346         return ssb->buf;
347 }
348