Replaced broken code in recent_sessions.cc
[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) const
168 {
169         return _session.construct_peak_filepath (audio_path);
170 }
171
172 string
173 AudioFileSource::find_broken_peakfile (const string& peak_path, const string& audio_path)
174 {
175         string str;
176
177         /* check for the broken location in use by 2.0 for several months */
178
179         str = broken_peak_path (audio_path);
180
181         if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
182
183                 if (!within_session()) {
184
185                         /* it would be nice to rename it but the nature of
186                            the bug means that we can't reliably use it.
187                         */
188
189                         return str;
190
191                 } else {
192                         /* all native files are mono, so we can just rename
193                            it.
194                         */
195                         ::rename (str.c_str(), peak_path.c_str());
196                 }
197
198         } else {
199                 /* Nasty band-aid for older sessions that were created before we
200                    used libsndfile for all audio files.
201                 */
202 #ifndef PLATFORM_WINDOWS // there's no old_peak_path() for windows
203                 str = old_peak_path (audio_path);
204                 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
205                         return str;
206                 }
207 #endif
208         }
209
210         return peak_path;
211 }
212
213 string
214 AudioFileSource::broken_peak_path (const string& audio_path)
215 {
216         return _session.construct_peak_filepath (basename_nosuffix (audio_path));
217 }
218
219 string
220 AudioFileSource::old_peak_path (const string& audio_path)
221 {
222         /* XXX hardly bombproof! fix me */
223
224         struct stat stat_file;
225         struct stat stat_mount;
226
227         string mp = mountpoint (audio_path);
228
229         stat (audio_path.c_str(), &stat_file);
230         stat (mp.c_str(), &stat_mount);
231
232         char buf[32];
233 #ifdef __APPLE__
234         snprintf (buf, sizeof (buf), "%llu-%llu-%d.peak",
235                         (unsigned long long)stat_mount.st_ino,
236                         (unsigned long long)stat_file.st_ino,
237                         _channel);
238 #else
239         snprintf (buf, sizeof (buf), "%" PRId64 "-%" PRId64 "-%d.peak", (int64_t) stat_mount.st_ino, (int64_t) stat_file.st_ino, _channel);
240 #endif
241
242         string res = peak_dir;
243         res += buf;
244         res += peakfile_suffix;
245
246         return res;
247 }
248
249 bool
250 AudioFileSource::get_soundfile_info (const string& path, SoundFileInfo& _info, string& error_msg)
251 {
252         /* try sndfile first because it gets timecode info from .wav (BWF) if it exists,
253            which at present, ExtAudioFile from Apple seems unable to do.
254         */
255
256         if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
257                 return true;
258         }
259
260 #ifdef HAVE_COREAUDIO
261         if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
262                 return true;
263         }
264 #endif // HAVE_COREAUDIO
265
266         return false;
267 }
268
269 XMLNode&
270 AudioFileSource::get_state ()
271 {
272         XMLNode& root (AudioSource::get_state());
273         char buf[32];
274         snprintf (buf, sizeof (buf), "%u", _channel);
275         root.add_property (X_("channel"), buf);
276         root.add_property (X_("origin"), _origin);
277         return root;
278 }
279
280 int
281 AudioFileSource::set_state (const XMLNode& node, int version)
282 {
283         if (Source::set_state (node, version)) {
284                 return -1;
285         }
286
287         if (AudioSource::set_state (node, version)) {
288                 return -1;
289         }
290
291         if (FileSource::set_state (node, version)) {
292                 return -1;
293         }
294
295         return 0;
296 }
297
298 void
299 AudioFileSource::mark_streaming_write_completed (const Lock& lock)
300 {
301         if (!writable()) {
302                 return;
303         }
304
305         AudioSource::mark_streaming_write_completed (lock);
306 }
307
308 int
309 AudioFileSource::move_dependents_to_trash()
310 {
311         return ::g_unlink (_peakpath.c_str());
312 }
313
314 void
315 AudioFileSource::set_header_position_offset (framecnt_t offset)
316 {
317         header_position_offset = offset;
318         HeaderPositionOffsetChanged ();
319 }
320
321 bool
322 AudioFileSource::is_empty (Session& /*s*/, string path)
323 {
324         SoundFileInfo info;
325         string err;
326
327         if (!get_soundfile_info (path, info, err)) {
328                 /* dangerous: we can't get info, so assume that its not empty */
329                 return false;
330         }
331
332         return info.length == 0;
333 }
334
335 int
336 AudioFileSource::setup_peakfile ()
337 {
338         if (_session.deletion_in_progress()) {
339                 return 0;
340         }
341         if (!(_flags & NoPeakFile)) {
342                 return initialize_peakfile (_path);
343         } else {
344                 return 0;
345         }
346 }
347
348 bool
349 AudioFileSource::safe_audio_file_extension(const string& file)
350 {
351         const char* suffixes[] = {
352                 ".aif", ".AIF",
353                 ".aifc", ".AIFC",
354                 ".aiff", ".AIFF",
355                 ".amb", ".AMB",
356                 ".au", ".AU",
357                 ".caf", ".CAF",
358                 ".cdr", ".CDR",
359                 ".flac", ".FLAC",
360                 ".htk", ".HTK",
361                 ".iff", ".IFF",
362                 ".mat", ".MAT",
363                 ".oga", ".OGA",
364                 ".ogg", ".OGG",
365                 ".paf", ".PAF",
366                 ".pvf", ".PVF",
367                 ".sf", ".SF",
368                 ".smp", ".SMP",
369                 ".snd", ".SND",
370                 ".maud", ".MAUD",
371                 ".voc", ".VOC"
372                 ".vwe", ".VWE",
373                 ".w64", ".W64",
374                 ".wav", ".WAV",
375 #ifdef HAVE_COREAUDIO
376                 ".aac", ".AAC",
377                 ".adts", ".ADTS",
378                 ".ac3", ".AC3",
379                 ".amr", ".AMR",
380                 ".mpa", ".MPA",
381                 ".mpeg", ".MPEG",
382                 ".mp1", ".MP1",
383                 ".mp2", ".MP2",
384                 ".mp3", ".MP3",
385                 ".mp4", ".MP4",
386                 ".m4a", ".M4A",
387                 ".sd2", ".SD2",         // libsndfile supports sd2 also, but the resource fork is required to open.
388 #endif // HAVE_COREAUDIO
389         };
390
391         for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
392                 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
393                         return true;
394                 }
395         }
396
397         return false;
398 }
399
400 Sample*
401 AudioFileSource::get_interleave_buffer (framecnt_t size)
402 {
403         SizedSampleBuffer* ssb;
404
405         if ((ssb = thread_interleave_buffer.get()) == 0) {
406                 ssb = new SizedSampleBuffer (size);
407                 thread_interleave_buffer.set (ssb);
408         }
409
410         if (ssb->size < size) {
411                 ssb = new SizedSampleBuffer (size);
412                 thread_interleave_buffer.set (ssb);
413         }
414
415         return ssb->buf;
416 }
417