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