another round of compiler warning fixes
[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), "%llu-%llu-%d.peak",
241                         (unsigned long long)stat_mount.st_ino,
242                         (unsigned long long)stat_file.st_ino,
243                         _channel);
244 #else
245         snprintf (buf, sizeof (buf), "%" PRId64 "-%" PRId64 "-%d.peak", (int64_t) stat_mount.st_ino, (int64_t) stat_file.st_ino, _channel);
246 #endif
247
248         string res = peak_dir;
249         res += buf;
250         res += peakfile_suffix;
251
252         return res;
253 }
254
255 bool
256 AudioFileSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg)
257 {
258         /* try sndfile first because it gets timecode info from .wav (BWF) if it exists,
259            which at present, ExtAudioFile from Apple seems unable to do.
260         */
261
262         if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
263                 return true;
264         }
265
266 #ifdef HAVE_COREAUDIO
267         if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
268                 return true;
269         }
270 #endif // HAVE_COREAUDIO
271
272         return false;
273 }
274
275 XMLNode&
276 AudioFileSource::get_state ()
277 {
278         XMLNode& root (AudioSource::get_state());
279         char buf[32];
280         snprintf (buf, sizeof (buf), "%u", _channel);
281         root.add_property (X_("channel"), buf);
282         root.add_property (X_("origin"), _origin);
283         return root;
284 }
285
286 int
287 AudioFileSource::set_state (const XMLNode& node, int version)
288 {
289         if (Source::set_state (node, version)) {
290                 return -1;
291         }
292
293         if (AudioSource::set_state (node, version)) {
294                 return -1;
295         }
296
297         if (FileSource::set_state (node, version)) {
298                 return -1;
299         }
300
301         return 0;
302 }
303
304 void
305 AudioFileSource::mark_streaming_write_completed ()
306 {
307         if (!writable()) {
308                 return;
309         }
310
311         AudioSource::mark_streaming_write_completed ();
312 }
313
314 int
315 AudioFileSource::move_dependents_to_trash()
316 {
317         return ::g_unlink (peakpath.c_str());
318 }
319
320 void
321 AudioFileSource::set_header_position_offset (framecnt_t offset)
322 {
323         header_position_offset = offset;
324         HeaderPositionOffsetChanged ();
325 }
326
327 bool
328 AudioFileSource::is_empty (Session& /*s*/, string path)
329 {
330         SoundFileInfo info;
331         string err;
332
333         if (!get_soundfile_info (path, info, err)) {
334                 /* dangerous: we can't get info, so assume that its not empty */
335                 return false;
336         }
337
338         return info.length == 0;
339 }
340
341 int
342 AudioFileSource::setup_peakfile ()
343 {
344         if (!(_flags & NoPeakFile)) {
345                 return initialize_peakfile (_path);
346         } else {
347                 return 0;
348         }
349 }
350
351 bool
352 AudioFileSource::safe_audio_file_extension(const string& file)
353 {
354         const char* suffixes[] = {
355                 ".aif", ".AIF",
356                 ".aifc", ".AIFC",
357                 ".aiff", ".AIFF",
358                 ".amb", ".AMB",
359                 ".au", ".AU",
360                 ".caf", ".CAF",
361                 ".cdr", ".CDR",
362                 ".flac", ".FLAC",
363                 ".htk", ".HTK",
364                 ".iff", ".IFF",
365                 ".mat", ".MAT",
366                 ".oga", ".OGA",
367                 ".ogg", ".OGG",
368                 ".paf", ".PAF",
369                 ".pvf", ".PVF",
370                 ".sf", ".SF",
371                 ".smp", ".SMP",
372                 ".snd", ".SND",
373                 ".maud", ".MAUD",
374                 ".voc", ".VOC"
375                 ".vwe", ".VWE",
376                 ".w64", ".W64",
377                 ".wav", ".WAV",
378 #ifdef HAVE_COREAUDIO
379                 ".aac", ".AAC",
380                 ".adts", ".ADTS",
381                 ".ac3", ".AC3",
382                 ".amr", ".AMR",
383                 ".mpa", ".MPA",
384                 ".mpeg", ".MPEG",
385                 ".mp1", ".MP1",
386                 ".mp2", ".MP2",
387                 ".mp3", ".MP3",
388                 ".mp4", ".MP4",
389                 ".m4a", ".M4A",
390                 ".sd2", ".SD2",         // libsndfile supports sd2 also, but the resource fork is required to open.
391 #endif // HAVE_COREAUDIO
392         };
393
394         for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
395                 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
396                         return true;
397                 }
398         }
399
400         return false;
401 }
402
403 Sample*
404 AudioFileSource::get_interleave_buffer (framecnt_t size)
405 {
406         SizedSampleBuffer* ssb;
407
408         if ((ssb = thread_interleave_buffer.get()) == 0) {
409                 ssb = new SizedSampleBuffer (size);
410                 thread_interleave_buffer.set (ssb);
411         }
412
413         if (ssb->size < size) {
414                 ssb = new SizedSampleBuffer (size);
415                 thread_interleave_buffer.set (ssb);
416         }
417
418         return ssb->buf;
419 }
420