various fixes to MidiRegionView selection handling, key handling, drawing of ghost...
[ardour2.git] / libs / ardour / audiofilesource.cc
blobd3d3a4f4a77e85a02afc9f9d27ad2f5562450e1b
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/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"
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
64 #include "i18n.h"
66 using namespace std;
67 using namespace ARDOUR;
68 using namespace PBD;
69 using namespace Glib;
71 string AudioFileSource::peak_dir = "";
73 PBD::Signal0<void> AudioFileSource::HeaderPositionOffsetChanged;
74 uint64_t AudioFileSource::header_position_offset = 0;
76 /* XXX maybe this too */
77 char AudioFileSource::bwf_serial_number[13] = "000000000000";
79 struct SizedSampleBuffer {
80 framecnt_t size;
81 Sample* buf;
83 SizedSampleBuffer (framecnt_t sz) : size (sz) {
84 buf = new Sample[size];
87 ~SizedSampleBuffer() {
88 delete [] buf;
92 Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
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)
101 /* note that origin remains empty */
103 if (init (_path, true)) {
104 throw failed_constructor ();
106 cerr << "audiofile source created with path " << path << endl;
109 /** Constructor used for new internal-to-session files. */
110 AudioFileSource::AudioFileSource (Session& s, const string& path, const string& origin, Source::Flag flags,
111 SampleFormat /*samp_format*/, HeaderFormat /*hdr_format*/)
112 : Source (s, DataType::AUDIO, path, flags)
113 , AudioSource (s, path)
114 , FileSource (s, DataType::AUDIO, path, origin, flags)
116 /* note that origin remains empty */
118 if (init (_path, false)) {
119 throw failed_constructor ();
123 /** Constructor used for existing internal-to-session files via XML. File must exist. */
124 AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
125 : Source (s, node)
126 , AudioSource (s, node)
127 , FileSource (s, node, must_exist)
129 if (set_state (node, Stateful::loading_state_version)) {
130 throw failed_constructor ();
133 if (init (_path, must_exist)) {
134 throw failed_constructor ();
138 AudioFileSource::~AudioFileSource ()
140 DEBUG_TRACE (DEBUG::Destruction, string_compose ("AudioFileSource destructor %1, removable? %2\n", _path, removable()));
141 if (removable()) {
142 unlink (_path.c_str());
143 unlink (peakpath.c_str());
148 AudioFileSource::init (const string& pathstr, bool must_exist)
150 return FileSource::init (pathstr, must_exist);
153 string
154 AudioFileSource::peak_path (string audio_path)
156 string base;
158 base = PBD::basename_nosuffix (audio_path);
159 base += '%';
160 base += (char) ('A' + _channel);
162 return _session.peak_path (base);
165 string
166 AudioFileSource::find_broken_peakfile (string peak_path, string audio_path)
168 string str;
170 /* check for the broken location in use by 2.0 for several months */
172 str = broken_peak_path (audio_path);
174 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
176 if (!within_session()) {
178 /* it would be nice to rename it but the nature of
179 the bug means that we can't reliably use it.
182 peak_path = str;
184 } else {
185 /* all native files are mono, so we can just rename
188 ::rename (str.c_str(), peak_path.c_str());
191 } else {
192 /* Nasty band-aid for older sessions that were created before we
193 used libsndfile for all audio files.
197 str = old_peak_path (audio_path);
198 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
199 peak_path = str;
203 return peak_path;
206 string
207 AudioFileSource::broken_peak_path (string audio_path)
209 return _session.peak_path (basename_nosuffix (audio_path));
212 string
213 AudioFileSource::old_peak_path (string audio_path)
215 /* XXX hardly bombproof! fix me */
217 struct stat stat_file;
218 struct stat stat_mount;
220 string mp = mountpoint (audio_path);
222 stat (audio_path.c_str(), &stat_file);
223 stat (mp.c_str(), &stat_mount);
225 char buf[32];
226 #ifdef __APPLE__
227 snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
228 #else
229 snprintf (buf, sizeof (buf), "%" PRId64 "-%" PRId64 "-%d.peak", (int64_t) stat_mount.st_ino, (int64_t) stat_file.st_ino, _channel);
230 #endif
232 string res = peak_dir;
233 res += buf;
234 res += peakfile_suffix;
236 return res;
239 bool
240 AudioFileSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg)
242 /* try sndfile first because it gets timecode info from .wav (BWF) if it exists,
243 which at present, ExtAudioFile from Apple seems unable to do.
246 if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
247 return true;
250 #ifdef HAVE_COREAUDIO
251 if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
252 return true;
254 #endif // HAVE_COREAUDIO
256 return false;
259 XMLNode&
260 AudioFileSource::get_state ()
262 XMLNode& root (AudioSource::get_state());
263 char buf[32];
264 snprintf (buf, sizeof (buf), "%u", _channel);
265 root.add_property (X_("channel"), buf);
266 root.add_property (X_("origin"), _origin);
267 return root;
271 AudioFileSource::set_state (const XMLNode& node, int version)
273 if (Source::set_state (node, version)) {
274 return -1;
277 if (AudioSource::set_state (node, version)) {
278 return -1;
281 if (FileSource::set_state (node, version)) {
282 return -1;
285 return 0;
288 void
289 AudioFileSource::mark_streaming_write_completed ()
291 if (!writable()) {
292 return;
295 AudioSource::mark_streaming_write_completed ();
299 AudioFileSource::move_dependents_to_trash()
301 return ::unlink (peakpath.c_str());
304 void
305 AudioFileSource::set_header_position_offset (framecnt_t offset)
307 header_position_offset = offset;
308 HeaderPositionOffsetChanged ();
311 bool
312 AudioFileSource::is_empty (Session& /*s*/, string path)
314 SoundFileInfo info;
315 string err;
317 if (!get_soundfile_info (path, info, err)) {
318 /* dangerous: we can't get info, so assume that its not empty */
319 return false;
322 return info.length == 0;
326 AudioFileSource::setup_peakfile ()
328 if (!(_flags & NoPeakFile)) {
329 return initialize_peakfile (_file_is_new, _path);
330 } else {
331 return 0;
335 bool
336 AudioFileSource::safe_audio_file_extension(const string& file)
338 const char* suffixes[] = {
339 ".aif", ".AIF",
340 ".aifc", ".AIFC",
341 ".aiff", ".AIFF",
342 ".amb", ".AMB",
343 ".au", ".AU",
344 ".caf", ".CAF",
345 ".cdr", ".CDR",
346 ".flac", ".FLAC",
347 ".htk", ".HTK",
348 ".iff", ".IFF",
349 ".mat", ".MAT",
350 ".oga", ".OGA",
351 ".ogg", ".OGG",
352 ".paf", ".PAF",
353 ".pvf", ".PVF",
354 ".sf", ".SF",
355 ".smp", ".SMP",
356 ".snd", ".SND",
357 ".maud", ".MAUD",
358 ".voc", ".VOC"
359 ".vwe", ".VWE",
360 ".w64", ".W64",
361 ".wav", ".WAV",
362 #ifdef HAVE_COREAUDIO
363 ".aac", ".AAC",
364 ".adts", ".ADTS",
365 ".ac3", ".AC3",
366 ".amr", ".AMR",
367 ".mpa", ".MPA",
368 ".mpeg", ".MPEG",
369 ".mp1", ".MP1",
370 ".mp2", ".MP2",
371 ".mp3", ".MP3",
372 ".mp4", ".MP4",
373 ".m4a", ".M4A",
374 ".sd2", ".SD2", // libsndfile supports sd2 also, but the resource fork is required to open.
375 #endif // HAVE_COREAUDIO
378 for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
379 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
380 return true;
384 return false;
387 Sample*
388 AudioFileSource::get_interleave_buffer (framecnt_t size)
390 SizedSampleBuffer* ssb;
392 if ((ssb = thread_interleave_buffer.get()) == 0) {
393 ssb = new SizedSampleBuffer (size);
394 thread_interleave_buffer.set (ssb);
397 if (ssb->size < size) {
398 ssb = new SizedSampleBuffer (size);
399 thread_interleave_buffer.set (ssb);
402 return ssb->buf;