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