use libsndfile in preference to ExtAudioFile when getting info on a source file,...
[ardour2.git] / libs / ardour / audiofilesource.cc
blob53f3247f4ae1574ea46b13891fde5a6f2dd31e59
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 #include <vector>
22 #include <sys/time.h>
23 #include <sys/stat.h>
24 #include <stdio.h> // for rename(), sigh
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <errno.h>
29 #include <pbd/convert.h>
30 #include <pbd/basename.h>
31 #include <pbd/mountpoint.h>
32 #include <pbd/pathscanner.h>
33 #include <pbd/stl_delete.h>
34 #include <pbd/strsplit.h>
35 #include <pbd/shortpath.h>
36 #include <pbd/enumwriter.h>
38 #include <sndfile.h>
40 #include <glibmm/miscutils.h>
41 #include <glibmm/fileutils.h>
42 #include <glibmm/thread.h>
44 #include <ardour/audiofilesource.h>
45 #include <ardour/sndfile_helpers.h>
46 #include <ardour/sndfilesource.h>
47 #include <ardour/session.h>
48 #include <ardour/source_factory.h>
50 // if these headers come before sigc++ is included
51 // the parser throws ObjC++ errors. (nil is a keyword)
52 #ifdef HAVE_COREAUDIO
53 #include <ardour/coreaudiosource.h>
54 #include <AudioToolbox/ExtendedAudioFile.h>
55 #include <AudioToolbox/AudioFormat.h>
56 #endif // HAVE_COREAUDIO
58 #include "i18n.h"
60 using namespace ARDOUR;
61 using namespace PBD;
62 using namespace Glib;
64 ustring AudioFileSource::peak_dir = "";
65 ustring AudioFileSource::search_path;
67 sigc::signal<void> AudioFileSource::HeaderPositionOffsetChanged;
68 uint64_t AudioFileSource::header_position_offset = 0;
70 /* XXX maybe this too */
71 char AudioFileSource::bwf_serial_number[13] = "000000000000";
73 struct SizedSampleBuffer {
74 nframes_t size;
75 Sample* buf;
77 SizedSampleBuffer (nframes_t sz) : size (sz) {
78 buf = new Sample[size];
81 ~SizedSampleBuffer() {
82 delete [] buf;
86 Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
88 AudioFileSource::AudioFileSource (Session& s, ustring path, Flag flags)
89 : AudioSource (s, path), _flags (flags),
90 _channel (0)
92 /* constructor used for existing external to session files. file must exist already */
93 _is_embedded = AudioFileSource::determine_embeddedness (path);
95 if (init (path, true)) {
96 throw failed_constructor ();
99 fix_writable_flags ();
102 AudioFileSource::AudioFileSource (Session& s, ustring path, Flag flags, SampleFormat samp_format, HeaderFormat hdr_format)
103 : AudioSource (s, path), _flags (flags),
104 _channel (0)
106 /* constructor used for new internal-to-session files. file cannot exist */
107 _is_embedded = false;
109 if (init (path, false)) {
110 throw failed_constructor ();
113 fix_writable_flags ();
116 AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
117 : AudioSource (s, node), _flags (Flag (Writable|CanRename))
118 /* _channel is set in set_state() or init() */
120 /* constructor used for existing internal-to-session files. file must exist */
122 if (set_state (node)) {
123 throw failed_constructor ();
126 string foo = _name;
128 if (init (foo, must_exist)) {
129 throw failed_constructor ();
132 fix_writable_flags ();
135 AudioFileSource::~AudioFileSource ()
137 if (removable()) {
138 unlink (_path.c_str());
139 unlink (peakpath.c_str());
143 void
144 AudioFileSource::fix_writable_flags ()
146 if (!_session.writable()) {
147 _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
151 bool
152 AudioFileSource::determine_embeddedness (ustring path)
154 return (path.find("/") == 0);
157 bool
158 AudioFileSource::removable () const
160 return (_flags & Removable) && ((_flags & RemoveAtDestroy) || ((_flags & RemovableIfEmpty) && length() == 0));
163 bool
164 AudioFileSource::writable() const
166 return (_flags & Writable);
170 AudioFileSource::init (ustring pathstr, bool must_exist)
172 _length = 0;
173 timeline_position = 0;
174 _peaks_built = false;
176 /* is_embedded() can't work yet, because our _path is not set */
178 bool embedded = determine_embeddedness (pathstr);
180 if (!find (pathstr, must_exist, embedded, file_is_new, _channel, _path, _name)) {
181 throw non_existent_source ();
184 if (file_is_new && must_exist) {
185 return -1;
188 return 0;
192 ustring
193 AudioFileSource::peak_path (ustring audio_path)
195 ustring base;
197 base = PBD::basename_nosuffix (audio_path);
198 base += '%';
199 base += (char) ('A' + _channel);
201 return _session.peak_path (base);
204 ustring
205 AudioFileSource::find_broken_peakfile (ustring peak_path, ustring audio_path)
207 ustring str;
209 /* check for the broken location in use by 2.0 for several months */
211 str = broken_peak_path (audio_path);
213 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
215 if (is_embedded()) {
217 /* it would be nice to rename it but the nature of
218 the bug means that we can't reliably use it.
221 peak_path = str;
223 } else {
224 /* all native files are mono, so we can just rename
227 ::rename (str.c_str(), peak_path.c_str());
230 } else {
231 /* Nasty band-aid for older sessions that were created before we
232 used libsndfile for all audio files.
236 str = old_peak_path (audio_path);
237 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
238 peak_path = str;
242 return peak_path;
245 ustring
246 AudioFileSource::broken_peak_path (ustring audio_path)
248 return Glib::build_filename(_session.peak_dir (), PBD::basename_nosuffix (audio_path) + ".peak");
251 ustring
252 AudioFileSource::old_peak_path (ustring audio_path)
254 /* XXX hardly bombproof! fix me */
256 struct stat stat_file;
257 struct stat stat_mount;
259 ustring mp = mountpoint (audio_path);
261 stat (audio_path.c_str(), &stat_file);
262 stat (mp.c_str(), &stat_mount);
264 char buf[32];
265 #ifdef __APPLE__
266 snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
267 #else
268 snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
269 #endif
271 ustring res = peak_dir;
272 res += buf;
274 return res;
277 bool
278 AudioFileSource::get_soundfile_info (ustring path, SoundFileInfo& _info, string& error_msg)
280 /* try sndfile first because it gets timecode info from .wav (BWF) if it exists,
281 which at present, ExtAudioFile from Apple seems unable to do.
284 if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
285 return true;
288 #ifdef HAVE_COREAUDIO
289 if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
290 return true;
292 #endif // HAVE_COREAUDIO
294 return false;
297 XMLNode&
298 AudioFileSource::get_state ()
300 XMLNode& root (AudioSource::get_state());
301 char buf[32];
302 root.add_property (X_("flags"), enum_2_string (_flags));
303 snprintf (buf, sizeof (buf), "%u", _channel);
304 root.add_property (X_("channel"), buf);
305 return root;
309 AudioFileSource::set_state (const XMLNode& node)
311 const XMLProperty* prop;
313 if (AudioSource::set_state (node)) {
314 return -1;
317 if ((prop = node.property (X_("flags"))) != 0) {
318 _flags = Flag (string_2_enum (prop->value(), _flags));
319 } else {
320 _flags = Flag (0);
324 fix_writable_flags ();
326 if ((prop = node.property (X_("channel"))) != 0) {
327 _channel = atoi (prop->value());
328 } else {
329 _channel = 0;
332 if ((prop = node.property (X_("name"))) != 0) {
333 _is_embedded = AudioFileSource::determine_embeddedness (prop->value());
334 } else {
335 _is_embedded = false;
338 if ((prop = node.property (X_("destructive"))) != 0) {
339 /* old style, from the period when we had DestructiveFileSource */
340 _flags = Flag (_flags | Destructive);
343 return 0;
346 void
347 AudioFileSource::mark_for_remove ()
349 // This operation is not allowed for sources for destructive tracks or embedded files.
350 // Fortunately mark_for_remove() is never called for embedded files. This function
351 // must be fixed if that ever happens.
352 if (!_session.writable() || (_flags & Destructive)) {
353 return;
356 _flags = Flag (_flags | Removable | RemoveAtDestroy);
359 void
360 AudioFileSource::mark_streaming_write_completed ()
362 if (!writable()) {
363 return;
366 /* XXX notice that we're readers of _peaks_built
367 but we must hold a solid lock on PeaksReady.
370 Glib::Mutex::Lock lm (_lock);
372 if (_peaks_built) {
373 PeaksReady (); /* EMIT SIGNAL */
377 void
378 AudioFileSource::mark_take (ustring id)
380 if (writable()) {
381 _take_id = id;
386 AudioFileSource::move_to_trash (const ustring& trash_dir_name)
388 if (is_embedded()) {
389 cerr << "tried to move an embedded region to trash" << endl;
390 return -1;
393 ustring newpath;
395 if (!writable()) {
396 return -1;
399 /* don't move the file across filesystems, just
400 stick it in the `trash_dir_name' directory
401 on whichever filesystem it was already on.
404 newpath = Glib::path_get_dirname (_path);
405 newpath = Glib::path_get_dirname (newpath);
407 cerr << "from " << _path << " dead dir looks like " << newpath << endl;
409 newpath += '/';
410 newpath += trash_dir_name;
411 newpath += '/';
412 newpath += Glib::path_get_basename (_path);
414 if (access (newpath.c_str(), F_OK) == 0) {
416 /* the new path already exists, try versioning */
418 char buf[PATH_MAX+1];
419 int version = 1;
420 ustring newpath_v;
422 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
423 newpath_v = buf;
425 while (access (newpath_v.c_str(), F_OK) == 0 && version < 999) {
426 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
427 newpath_v = buf;
430 if (version == 999) {
431 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
432 newpath)
433 << endmsg;
434 } else {
435 newpath = newpath_v;
438 } else {
440 /* it doesn't exist, or we can't read it or something */
444 if (::rename (_path.c_str(), newpath.c_str()) != 0) {
445 error << string_compose (_("cannot rename audio file source from %1 to %2 (%3)"),
446 _path, newpath, strerror (errno))
447 << endmsg;
448 return -1;
451 if (::unlink (peakpath.c_str()) != 0) {
452 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
453 peakpath, _path, strerror (errno))
454 << endmsg;
455 /* try to back out */
456 rename (newpath.c_str(), _path.c_str());
457 return -1;
460 _path = newpath;
461 peakpath = "";
463 /* file can not be removed twice, since the operation is not idempotent */
465 _flags = Flag (_flags & ~(RemoveAtDestroy|Removable|RemovableIfEmpty));
467 return 0;
470 bool
471 AudioFileSource::find (ustring pathstr, bool must_exist, bool embedded,
472 bool& isnew, uint16_t& chan,
473 ustring& path, std::string& name)
475 ustring::size_type pos;
476 bool ret = false;
478 isnew = false;
480 if (pathstr[0] != '/') {
482 /* non-absolute pathname: find pathstr in search path */
484 vector<ustring> dirs;
485 int cnt;
486 ustring fullpath;
487 ustring keeppath;
489 if (search_path.length() == 0) {
490 error << _("FileSource: search path not set") << endmsg;
491 goto out;
494 split (search_path, dirs, ':');
496 cnt = 0;
498 for (vector<ustring>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
500 fullpath = *i;
501 if (fullpath[fullpath.length()-1] != '/') {
502 fullpath += '/';
505 fullpath += pathstr;
507 /* i (paul) made a nasty design error by using ':' as a special character in
508 Ardour 0.99 .. this hack tries to make things sort of work.
511 if ((pos = pathstr.find_last_of (':')) != ustring::npos) {
513 if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
515 /* its a real file, no problem */
517 keeppath = fullpath;
518 ++cnt;
520 } else {
522 if (must_exist) {
524 /* might be an older session using file:channel syntax. see if the version
525 without the :suffix exists
528 ustring shorter = pathstr.substr (0, pos);
529 fullpath = *i;
531 if (fullpath[fullpath.length()-1] != '/') {
532 fullpath += '/';
535 fullpath += shorter;
537 if (Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
538 chan = atoi (pathstr.substr (pos+1));
539 pathstr = shorter;
540 keeppath = fullpath;
541 ++cnt;
544 } else {
546 /* new derived file (e.g. for timefx) being created in a newer session */
551 } else {
553 if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
554 keeppath = fullpath;
555 ++cnt;
560 if (cnt > 1) {
562 error << string_compose (_("FileSource: \"%1\" is ambigous when searching %2\n\t"), pathstr, search_path) << endmsg;
563 goto out;
565 } else if (cnt == 0) {
567 if (must_exist) {
568 error << string_compose(_("Filesource: cannot find required file (%1): while searching %2"), pathstr, search_path) << endmsg;
569 goto out;
570 } else {
571 isnew = true;
575 name = pathstr;
576 path = keeppath;
577 ret = true;
579 } else {
581 /* external files and/or very very old style sessions include full paths */
583 /* ugh, handle ':' situation */
585 if ((pos = pathstr.find_last_of (':')) != ustring::npos) {
587 ustring shorter = pathstr.substr (0, pos);
589 if (Glib::file_test (shorter, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
590 chan = atoi (pathstr.substr (pos+1));
591 pathstr = shorter;
595 path = pathstr;
597 if (embedded) {
598 name = pathstr;
599 } else {
600 name = Glib::path_get_basename (pathstr);
603 if (!Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
605 /* file does not exist or we cannot read it */
607 if (must_exist) {
608 error << string_compose(_("Filesource: cannot find required file (%1): %2"), pathstr, strerror (errno)) << endmsg;
609 goto out;
612 if (errno != ENOENT) {
613 error << string_compose(_("Filesource: cannot check for existing file (%1): %2"), pathstr, strerror (errno)) << endmsg;
614 goto out;
617 /* a new file */
619 isnew = true;
620 ret = true;
622 } else {
624 /* already exists */
626 ret = true;
631 out:
632 return ret;
635 void
636 AudioFileSource::set_search_path (ustring p)
638 search_path = p;
641 void
642 AudioFileSource::set_header_position_offset (nframes_t offset)
644 header_position_offset = offset;
645 HeaderPositionOffsetChanged ();
648 void
649 AudioFileSource::set_timeline_position (int64_t pos)
651 timeline_position = pos;
654 void
655 AudioFileSource::set_allow_remove_if_empty (bool yn)
657 if (!writable()) {
658 return;
661 if (yn) {
662 _flags = Flag (_flags | RemovableIfEmpty);
663 } else {
664 _flags = Flag (_flags & ~RemovableIfEmpty);
667 fix_writable_flags ();
671 AudioFileSource::set_name (ustring newname, bool destructive)
673 Glib::Mutex::Lock lm (_lock);
674 ustring oldpath = _path;
675 ustring newpath = Session::change_audio_path_by_name (oldpath, _name, newname, destructive);
677 if (newpath.empty()) {
678 error << string_compose (_("programming error: %1"), "cannot generate a changed audio path") << endmsg;
679 return -1;
682 // Test whether newpath exists, if yes notify the user but continue.
683 if (access(newpath.c_str(),F_OK) == 0) {
684 error << _("Programming error! Ardour tried to rename a file over another file! It's safe to continue working, but please report this to the developers.") << endmsg;
685 return -1;
688 if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
689 error << string_compose (_("cannot rename audio file %1 to %2"), _name, newpath) << endmsg;
690 return -1;
693 _name = Glib::path_get_basename (newpath);
694 _path = newpath;
696 return rename_peakfile (peak_path (_path));
699 bool
700 AudioFileSource::is_empty (Session& s, ustring path)
702 SoundFileInfo info;
703 string err;
705 if (!get_soundfile_info (path, info, err)) {
706 /* dangerous: we can't get info, so assume that its not empty */
707 return false;
710 return info.length == 0;
714 AudioFileSource::setup_peakfile ()
716 if (!(_flags & NoPeakFile)) {
717 return initialize_peakfile (file_is_new, _path);
718 } else {
719 return 0;
723 bool
724 AudioFileSource::safe_file_extension(ustring file)
726 const char* suffixes[] = {
727 ".aif", ".AIF",
728 ".aifc", ".AIFC",
729 ".aiff", ".AIFF",
730 ".amb", ".AMB",
731 ".au", ".AU",
732 ".caf", ".CAF",
733 ".cdr", ".CDR",
734 ".flac", ".FLAC",
735 ".htk", ".HTK",
736 ".iff", ".IFF",
737 ".mat", ".MAT",
738 ".oga", ".OGA",
739 ".ogg", ".OGG",
740 ".paf", ".PAF",
741 ".pvf", ".PVF",
742 ".sf", ".SF",
743 ".smp", ".SMP",
744 ".snd", ".SND",
745 ".maud", ".MAUD",
746 ".voc", ".VOC"
747 ".vwe", ".VWE",
748 ".w64", ".W64",
749 ".wav", ".WAV",
750 #ifdef HAVE_COREAUDIO
751 ".aac", ".AAC",
752 ".adts", ".ADTS",
753 ".ac3", ".AC3",
754 ".amr", ".AMR",
755 ".mpa", ".MPA",
756 ".mpeg", ".MPEG",
757 ".mp1", ".MP1",
758 ".mp2", ".MP2",
759 ".mp3", ".MP3",
760 ".mp4", ".MP4",
761 ".m4a", ".M4A",
762 ".sd2", ".SD2", // libsndfile supports sd2 also, but the resource fork is required to open.
763 #endif // HAVE_COREAUDIO
766 for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
767 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
768 return true;
772 return false;
775 void
776 AudioFileSource::mark_immutable ()
778 /* destructive sources stay writable, and their other flags don't
779 change.
782 if (!(_flags & Destructive)) {
783 _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
788 Sample*
789 AudioFileSource::get_interleave_buffer (nframes_t size)
791 SizedSampleBuffer* ssb;
793 if ((ssb = thread_interleave_buffer.get()) == 0) {
794 ssb = new SizedSampleBuffer (size);
795 thread_interleave_buffer.set (ssb);
798 if (ssb->size < size) {
799 ssb = new SizedSampleBuffer (size);
800 thread_interleave_buffer.set (ssb);
803 return ssb->buf;