Move is_embedded calculation to a single place.
[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/mountpoint.h"
36 #include "pbd/stl_delete.h"
37 #include "pbd/strsplit.h"
38 #include "pbd/shortpath.h"
39 #include "pbd/enumwriter.h"
40
41 #include <sndfile.h>
42
43 #include <glibmm/miscutils.h>
44 #include <glibmm/fileutils.h>
45 #include <glibmm/thread.h>
46
47 #include "ardour/audiofilesource.h"
48 #include "ardour/debug.h"
49 #include "ardour/sndfile_helpers.h"
50 #include "ardour/sndfilesource.h"
51 #include "ardour/session.h"
52 #include "ardour/session_directory.h"
53 #include "ardour/source_factory.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 ustring AudioFileSource::peak_dir = "";
72
73 sigc::signal<void> AudioFileSource::HeaderPositionOffsetChanged;
74 uint64_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     nframes_t size;
81     Sample* buf;
82
83     SizedSampleBuffer (nframes_t sz) : size (sz) {
84             buf = new Sample[size];
85     }
86
87     ~SizedSampleBuffer() {
88             delete [] buf;
89     }
90 };
91
92 Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
93
94 /** Constructor used for existing internal-to-session files. */
95 AudioFileSource::AudioFileSource (Session& s, const ustring& path, bool embedded, Source::Flag flags)
96         : Source (s, DataType::AUDIO, path, flags)
97         , AudioSource (s, path)
98         , FileSource (s, DataType::AUDIO, path, embedded, flags)
99 {
100         if (init (path, true)) {
101                 throw failed_constructor ();
102         }
103 }
104
105 /** Constructor used for new internal-to-session files. */
106 AudioFileSource::AudioFileSource (Session& s, const ustring& path, bool embedded, Source::Flag flags,
107                                   SampleFormat /*samp_format*/, HeaderFormat /*hdr_format*/)
108         : Source (s, DataType::AUDIO, path, flags)
109         , AudioSource (s, path)
110         , FileSource (s, DataType::AUDIO, path, embedded, flags)
111 {
112         _is_embedded = false;
113
114         if (init (path, false)) {
115                 throw failed_constructor ();
116         }
117 }
118
119 /** Constructor used for existing internal-to-session files.  File must exist. */
120 AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
121         : Source (s, node)
122         , AudioSource (s, node)
123         , FileSource (s, node, must_exist)
124 {
125         if (set_state (node, Stateful::loading_state_version)) {
126                 throw failed_constructor ();
127         }
128
129         if (init (_name, must_exist)) {
130                 throw failed_constructor ();
131         }
132 }
133
134 AudioFileSource::~AudioFileSource ()
135 {
136         DEBUG_TRACE (DEBUG::Destruction, string_compose ("AudioFileSource destructor %1, removable? %2\n", _path, removable()));
137         if (removable()) {
138                 unlink (_path.c_str());
139                 unlink (peakpath.c_str());
140         }
141 }
142
143 int
144 AudioFileSource::init (const ustring& pathstr, bool must_exist)
145 {
146         _peaks_built = false;
147         return FileSource::init (pathstr, must_exist);
148 }
149
150 ustring
151 AudioFileSource::peak_path (ustring audio_path)
152 {
153         ustring base;
154
155         base = PBD::basename_nosuffix (audio_path);
156         base += '%';
157         base += (char) ('A' + _channel);
158
159         return _session.peak_path (base);
160 }
161
162 ustring
163 AudioFileSource::find_broken_peakfile (ustring peak_path, ustring audio_path)
164 {
165         ustring str;
166
167         /* check for the broken location in use by 2.0 for several months */
168
169         str = broken_peak_path (audio_path);
170
171         if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
172
173                 if (is_embedded()) {
174
175                         /* it would be nice to rename it but the nature of
176                            the bug means that we can't reliably use it.
177                         */
178
179                         peak_path = str;
180
181                 } else {
182                         /* all native files are mono, so we can just rename
183                            it.
184                         */
185                         ::rename (str.c_str(), peak_path.c_str());
186                 }
187
188         } else {
189                 /* Nasty band-aid for older sessions that were created before we
190                    used libsndfile for all audio files.
191                 */
192
193
194                 str = old_peak_path (audio_path);
195                 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
196                         peak_path = str;
197                 }
198         }
199
200         return peak_path;
201 }
202
203 ustring
204 AudioFileSource::broken_peak_path (ustring audio_path)
205 {
206         return _session.peak_path (audio_path);
207 }
208
209 ustring
210 AudioFileSource::old_peak_path (ustring audio_path)
211 {
212         /* XXX hardly bombproof! fix me */
213
214         struct stat stat_file;
215         struct stat stat_mount;
216
217         ustring mp = mountpoint (audio_path);
218
219         stat (audio_path.c_str(), &stat_file);
220         stat (mp.c_str(), &stat_mount);
221
222         char buf[32];
223 #ifdef __APPLE__
224         snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
225 #else
226         snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
227 #endif
228
229         ustring res = peak_dir;
230         res += buf;
231         res += peakfile_suffix;
232
233         return res;
234 }
235
236 bool
237 AudioFileSource::get_soundfile_info (ustring path, SoundFileInfo& _info, string& error_msg)
238 {
239 #ifdef HAVE_COREAUDIO
240         if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
241                 return true;
242         }
243 #endif // HAVE_COREAUDIO
244
245         if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
246                 return true;
247         }
248
249         return false;
250 }
251
252 XMLNode&
253 AudioFileSource::get_state ()
254 {
255         XMLNode& root (AudioSource::get_state());
256         char buf[32];
257         snprintf (buf, sizeof (buf), "%u", _channel);
258         root.add_property (X_("channel"), buf);
259         return root;
260 }
261
262 int
263 AudioFileSource::set_state (const XMLNode& node, int version)
264 {
265         if (Source::set_state (node, version)) {
266                 return -1;
267         }
268
269         if (AudioSource::set_state (node, version)) {
270                 return -1;
271         }
272
273         if (FileSource::set_state (node, version)) {
274                 return -1;
275         }
276
277         return 0;
278 }
279
280 void
281 AudioFileSource::mark_streaming_write_completed ()
282 {
283         if (!writable()) {
284                 return;
285         }
286
287         /* XXX notice that we're readers of _peaks_built
288            but we must hold a solid lock on PeaksReady.
289         */
290
291         Glib::Mutex::Lock lm (_lock);
292
293         if (_peaks_built) {
294                 PeaksReady (); /* EMIT SIGNAL */
295         }
296 }
297
298 int
299 AudioFileSource::move_dependents_to_trash()
300 {
301         return ::unlink (peakpath.c_str());
302 }
303
304 void
305 AudioFileSource::set_header_position_offset (nframes_t offset)
306 {
307         header_position_offset = offset;
308         HeaderPositionOffsetChanged ();
309 }
310
311 bool
312 AudioFileSource::is_empty (Session& /*s*/, ustring path)
313 {
314         SoundFileInfo info;
315         string err;
316
317         if (!get_soundfile_info (path, info, err)) {
318                 /* dangerous: we can't get info, so assume that its not empty */
319                 return false;
320         }
321
322         return info.length == 0;
323 }
324
325 int
326 AudioFileSource::setup_peakfile ()
327 {
328         if (!(_flags & NoPeakFile)) {
329                 return initialize_peakfile (_file_is_new, _path);
330         } else {
331                 return 0;
332         }
333 }
334
335 bool
336 AudioFileSource::safe_audio_file_extension(const ustring& file)
337 {
338         const char* suffixes[] = {
339                 ".wav", ".WAV",
340                 ".aiff", ".AIFF",
341                 ".caf", ".CAF",
342                 ".aif", ".AIF",
343                 ".amb", ".AMB",
344                 ".snd", ".SND",
345                 ".au", ".AU",
346                 ".raw", ".RAW",
347                 ".sf", ".SF",
348                 ".cdr", ".CDR",
349                 ".smp", ".SMP",
350                 ".maud", ".MAUD",
351                 ".vwe", ".VWE",
352                 ".paf", ".PAF",
353                 ".voc", ".VOC",
354                 ".ogg", ".OGG",
355                 ".flac", ".FLAC",
356 #ifdef HAVE_COREAUDIO
357                 ".mp3", ".MP3",
358                 ".aac", ".AAC",
359                 ".mp4", ".MP4",
360 #endif // HAVE_COREAUDIO
361         };
362
363         for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
364                 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
365                         return true;
366                 }
367         }
368
369         return false;
370 }
371
372 Sample*
373 AudioFileSource::get_interleave_buffer (nframes_t size)
374 {
375         SizedSampleBuffer* ssb;
376
377         if ((ssb = thread_interleave_buffer.get()) == 0) {
378                 ssb = new SizedSampleBuffer (size);
379                 thread_interleave_buffer.set (ssb);
380         }
381
382         if (ssb->size < size) {
383                 ssb = new SizedSampleBuffer (size);
384                 thread_interleave_buffer.set (ssb);
385         }
386
387         return ssb->buf;
388 }