Fix angle bracket project-local include paths.
[ardour2.git] / libs / ardour / audiofilesource.cc
blob8de786eb0e0901f94c64cf3d516a328651e0772d
1 /*
2 Copyright (C) 2006 Paul Davis
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.
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.
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.
20 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
24 #include <vector>
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>
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"
41 #include <sndfile.h>
43 #include <glibmm/miscutils.h>
44 #include <glibmm/fileutils.h>
45 #include <glibmm/thread.h>
47 #include "ardour/audiofilesource.h"
48 #include "ardour/sndfile_helpers.h"
49 #include "ardour/sndfilesource.h"
50 #include "ardour/session.h"
51 #include "ardour/session_directory.h"
52 #include "ardour/source_factory.h"
53 #include "ardour/filename_extensions.h"
55 // if these headers come before sigc++ is included
56 // the parser throws ObjC++ errors. (nil is a keyword)
57 #ifdef HAVE_COREAUDIO
58 #include "ardour/coreaudiosource.h"
59 #include <AudioToolbox/ExtendedAudioFile.h>
60 #include <AudioToolbox/AudioFormat.h>
61 #endif // HAVE_COREAUDIO
63 #include "i18n.h"
65 using namespace std;
66 using namespace ARDOUR;
67 using namespace PBD;
68 using namespace Glib;
70 ustring AudioFileSource::peak_dir = "";
72 sigc::signal<void> AudioFileSource::HeaderPositionOffsetChanged;
73 uint64_t AudioFileSource::header_position_offset = 0;
75 /* XXX maybe this too */
76 char AudioFileSource::bwf_serial_number[13] = "000000000000";
78 struct SizedSampleBuffer {
79 nframes_t size;
80 Sample* buf;
82 SizedSampleBuffer (nframes_t sz) : size (sz) {
83 buf = new Sample[size];
86 ~SizedSampleBuffer() {
87 delete [] buf;
91 Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
93 /** Constructor used for existing internal-to-session files. */
94 AudioFileSource::AudioFileSource (Session& s, const ustring& path, bool embedded, Source::Flag flags)
95 : Source (s, DataType::AUDIO, path, flags)
96 , AudioSource (s, path)
97 , FileSource (s, DataType::AUDIO, path, embedded, flags)
99 if (init (path, true)) {
100 throw failed_constructor ();
104 /** Constructor used for new internal-to-session files. */
105 AudioFileSource::AudioFileSource (Session& s, const ustring& path, bool embedded, 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, embedded, flags)
111 _is_embedded = false;
113 if (init (path, false)) {
114 throw failed_constructor ();
118 /** Constructor used for existing internal-to-session files. 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)
124 if (set_state (node, Stateful::loading_state_version)) {
125 throw failed_constructor ();
128 if (init (_name, must_exist)) {
129 throw failed_constructor ();
133 AudioFileSource::~AudioFileSource ()
135 if (removable()) {
136 unlink (_path.c_str());
137 unlink (peakpath.c_str());
142 AudioFileSource::init (const ustring& pathstr, bool must_exist)
144 _peaks_built = false;
145 return FileSource::init (pathstr, must_exist);
148 ustring
149 AudioFileSource::peak_path (ustring audio_path)
151 ustring base;
153 base = PBD::basename_nosuffix (audio_path);
154 base += '%';
155 base += (char) ('A' + _channel);
157 return _session.peak_path (base);
160 ustring
161 AudioFileSource::find_broken_peakfile (ustring peak_path, ustring audio_path)
163 ustring str;
165 /* check for the broken location in use by 2.0 for several months */
167 str = broken_peak_path (audio_path);
169 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
171 if (is_embedded()) {
173 /* it would be nice to rename it but the nature of
174 the bug means that we can't reliably use it.
177 peak_path = str;
179 } else {
180 /* all native files are mono, so we can just rename
183 ::rename (str.c_str(), peak_path.c_str());
186 } else {
187 /* Nasty band-aid for older sessions that were created before we
188 used libsndfile for all audio files.
192 str = old_peak_path (audio_path);
193 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
194 peak_path = str;
198 return peak_path;
201 ustring
202 AudioFileSource::broken_peak_path (ustring audio_path)
204 return _session.peak_path (audio_path);
207 ustring
208 AudioFileSource::old_peak_path (ustring audio_path)
210 /* XXX hardly bombproof! fix me */
212 struct stat stat_file;
213 struct stat stat_mount;
215 ustring mp = mountpoint (audio_path);
217 stat (audio_path.c_str(), &stat_file);
218 stat (mp.c_str(), &stat_mount);
220 char buf[32];
221 #ifdef __APPLE__
222 snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
223 #else
224 snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
225 #endif
227 ustring res = peak_dir;
228 res += buf;
229 res += peakfile_suffix;
231 return res;
234 bool
235 AudioFileSource::get_soundfile_info (ustring path, SoundFileInfo& _info, string& error_msg)
237 #ifdef HAVE_COREAUDIO
238 if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
239 return true;
241 #endif // HAVE_COREAUDIO
243 if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
244 return true;
247 return false;
250 XMLNode&
251 AudioFileSource::get_state ()
253 XMLNode& root (AudioSource::get_state());
254 char buf[32];
255 snprintf (buf, sizeof (buf), "%u", _channel);
256 root.add_property (X_("channel"), buf);
257 return root;
261 AudioFileSource::set_state (const XMLNode& node, int version)
263 if (Source::set_state (node, version)) {
264 return -1;
267 if (AudioSource::set_state (node, version)) {
268 return -1;
271 if (FileSource::set_state (node, version)) {
272 return -1;
275 return 0;
278 void
279 AudioFileSource::mark_streaming_write_completed ()
281 if (!writable()) {
282 return;
285 /* XXX notice that we're readers of _peaks_built
286 but we must hold a solid lock on PeaksReady.
289 Glib::Mutex::Lock lm (_lock);
291 if (_peaks_built) {
292 PeaksReady (); /* EMIT SIGNAL */
297 AudioFileSource::move_dependents_to_trash()
299 return ::unlink (peakpath.c_str());
302 void
303 AudioFileSource::set_header_position_offset (nframes_t offset)
305 header_position_offset = offset;
306 HeaderPositionOffsetChanged ();
309 bool
310 AudioFileSource::is_empty (Session& /*s*/, ustring path)
312 SoundFileInfo info;
313 string err;
315 if (!get_soundfile_info (path, info, err)) {
316 /* dangerous: we can't get info, so assume that its not empty */
317 return false;
320 return info.length == 0;
324 AudioFileSource::setup_peakfile ()
326 if (!(_flags & NoPeakFile)) {
327 return initialize_peakfile (_file_is_new, _path);
328 } else {
329 return 0;
333 bool
334 AudioFileSource::safe_audio_file_extension(const ustring& file)
336 const char* suffixes[] = {
337 ".wav", ".WAV",
338 ".aiff", ".AIFF",
339 ".caf", ".CAF",
340 ".aif", ".AIF",
341 ".amb", ".AMB",
342 ".snd", ".SND",
343 ".au", ".AU",
344 ".raw", ".RAW",
345 ".sf", ".SF",
346 ".cdr", ".CDR",
347 ".smp", ".SMP",
348 ".maud", ".MAUD",
349 ".vwe", ".VWE",
350 ".paf", ".PAF",
351 ".voc", ".VOC",
352 ".ogg", ".OGG",
353 ".flac", ".FLAC",
354 #ifdef HAVE_COREAUDIO
355 ".mp3", ".MP3",
356 ".aac", ".AAC",
357 ".mp4", ".MP4",
358 #endif // HAVE_COREAUDIO
361 for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
362 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
363 return true;
367 return false;
370 Sample*
371 AudioFileSource::get_interleave_buffer (nframes_t size)
373 SizedSampleBuffer* ssb;
375 if ((ssb = thread_interleave_buffer.get()) == 0) {
376 ssb = new SizedSampleBuffer (size);
377 thread_interleave_buffer.set (ssb);
380 if (ssb->size < size) {
381 ssb = new SizedSampleBuffer (size);
382 thread_interleave_buffer.set (ssb);
385 return ssb->buf;