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