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.
24 #include <stdio.h> // for rename(), sigh
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>
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)
53 #include <ardour/coreaudiosource.h>
54 #include <AudioToolbox/ExtendedAudioFile.h>
55 #include <AudioToolbox/AudioFormat.h>
56 #endif // HAVE_COREAUDIO
60 using namespace ARDOUR
;
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
{
77 SizedSampleBuffer (nframes_t sz
) : size (sz
) {
78 buf
= new Sample
[size
];
81 ~SizedSampleBuffer() {
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
),
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
),
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 ();
128 if (init (foo
, must_exist
)) {
129 throw failed_constructor ();
132 fix_writable_flags ();
135 AudioFileSource::~AudioFileSource ()
138 unlink (_path
.c_str());
139 unlink (peakpath
.c_str());
144 AudioFileSource::fix_writable_flags ()
146 if (!_session
.writable()) {
147 _flags
= Flag (_flags
& ~(Writable
|Removable
|RemovableIfEmpty
|RemoveAtDestroy
|CanRename
));
152 AudioFileSource::determine_embeddedness (ustring path
)
154 return (path
.find("/") == 0);
158 AudioFileSource::removable () const
160 return (_flags
& Removable
) && ((_flags
& RemoveAtDestroy
) || ((_flags
& RemovableIfEmpty
) && length() == 0));
164 AudioFileSource::writable() const
166 return (_flags
& Writable
);
170 AudioFileSource::init (ustring pathstr
, bool must_exist
)
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
) {
193 AudioFileSource::peak_path (ustring audio_path
)
197 base
= PBD::basename_nosuffix (audio_path
);
199 base
+= (char) ('A' + _channel
);
201 return _session
.peak_path (base
);
205 AudioFileSource::find_broken_peakfile (ustring peak_path
, ustring audio_path
)
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
)) {
217 /* it would be nice to rename it but the nature of
218 the bug means that we can't reliably use it.
224 /* all native files are mono, so we can just rename
227 ::rename (str
.c_str(), peak_path
.c_str());
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
)) {
246 AudioFileSource::broken_peak_path (ustring audio_path
)
248 return Glib::build_filename(_session
.peak_dir (), PBD::basename_nosuffix (audio_path
) + ".peak");
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
);
266 snprintf (buf
, sizeof (buf
), "%u-%u-%d.peak", stat_mount
.st_ino
, stat_file
.st_ino
, _channel
);
268 snprintf (buf
, sizeof (buf
), "%ld-%ld-%d.peak", stat_mount
.st_ino
, stat_file
.st_ino
, _channel
);
271 ustring res
= peak_dir
;
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) {
288 #ifdef HAVE_COREAUDIO
289 if (CoreAudioSource::get_soundfile_info (path
, _info
, error_msg
) == 0) {
292 #endif // HAVE_COREAUDIO
298 AudioFileSource::get_state ()
300 XMLNode
& root (AudioSource::get_state());
302 root
.add_property (X_("flags"), enum_2_string (_flags
));
303 snprintf (buf
, sizeof (buf
), "%u", _channel
);
304 root
.add_property (X_("channel"), buf
);
309 AudioFileSource::set_state (const XMLNode
& node
)
311 const XMLProperty
* prop
;
313 if (AudioSource::set_state (node
)) {
317 if ((prop
= node
.property (X_("flags"))) != 0) {
318 _flags
= Flag (string_2_enum (prop
->value(), _flags
));
324 fix_writable_flags ();
326 if ((prop
= node
.property (X_("channel"))) != 0) {
327 _channel
= atoi (prop
->value());
332 if ((prop
= node
.property (X_("name"))) != 0) {
333 _is_embedded
= AudioFileSource::determine_embeddedness (prop
->value());
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
);
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
)) {
356 _flags
= Flag (_flags
| Removable
| RemoveAtDestroy
);
360 AudioFileSource::mark_streaming_write_completed ()
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
);
373 PeaksReady (); /* EMIT SIGNAL */
378 AudioFileSource::mark_take (ustring id
)
386 AudioFileSource::move_to_trash (const ustring
& trash_dir_name
)
389 cerr
<< "tried to move an embedded region to trash" << endl
;
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
;
410 p
.push_back (newpath
);
411 p
.push_back (trash_dir_name
);
412 p
.push_back (Glib::path_get_basename (_path
));
414 newpath
= Glib::build_filename (p
);
416 if (Glib::file_test (newpath
, Glib::FILE_TEST_EXISTS
)) {
418 /* the new path already exists, try versioning */
420 char buf
[PATH_MAX
+1];
424 snprintf (buf
, sizeof (buf
), "%s.%d", newpath
.c_str(), version
);
427 while (Glib::file_test (newpath_v
, Glib::FILE_TEST_EXISTS
) && version
< 999) {
428 snprintf (buf
, sizeof (buf
), "%s.%d", newpath
.c_str(), ++version
);
432 if (version
== 999) {
433 error
<< string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
442 /* it doesn't exist, or we can't read it or something */
446 if (::rename (_path
.c_str(), newpath
.c_str()) != 0) {
447 error
<< string_compose (_("cannot 1 rename audio file source from %1 to %2 (%3)"),
448 _path
, newpath
, strerror (errno
))
453 if (::unlink (peakpath
.c_str()) != 0) {
454 error
<< string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
455 peakpath
, _path
, strerror (errno
))
457 /* try to back out */
458 rename (newpath
.c_str(), _path
.c_str());
465 /* file can not be removed twice, since the operation is not idempotent */
467 _flags
= Flag (_flags
& ~(RemoveAtDestroy
|Removable
|RemovableIfEmpty
));
473 AudioFileSource::find (ustring pathstr
, bool must_exist
, bool embedded
,
474 bool& isnew
, uint16_t& chan
,
475 ustring
& path
, std::string
& name
)
477 ustring::size_type pos
;
482 if (!Glib::path_is_absolute (pathstr
)) {
484 /* non-absolute pathname: find pathstr in search path */
486 vector
<ustring
> dirs
;
491 if (search_path
.length() == 0) {
492 error
<< _("FileSource: search path not set") << endmsg
;
496 split (search_path
, dirs
, ':');
500 for (vector
<ustring
>::iterator i
= dirs
.begin(); i
!= dirs
.end(); ++i
) {
502 fullpath
= Glib::build_filename (*i
, pathstr
);
504 /* i (paul) made a nasty design error by using ':' as a special character in
505 Ardour 0.99 .. this hack tries to make things sort of work.
508 if ((pos
= pathstr
.find_last_of (':')) != ustring::npos
) {
510 if (Glib::file_test (fullpath
, Glib::FILE_TEST_EXISTS
|Glib::FILE_TEST_IS_REGULAR
)) {
512 /* its a real file, no problem */
521 /* might be an older session using file:channel syntax. see if the version
522 without the :suffix exists
525 ustring shorter
= pathstr
.substr (0, pos
);
526 fullpath
= Glib::build_filename (*i
, shorter
);
528 if (Glib::file_test (pathstr
, Glib::FILE_TEST_EXISTS
|Glib::FILE_TEST_IS_REGULAR
)) {
529 chan
= atoi (pathstr
.substr (pos
+1));
537 /* new derived file (e.g. for timefx) being created in a newer session */
544 if (Glib::file_test (fullpath
, Glib::FILE_TEST_EXISTS
|Glib::FILE_TEST_IS_REGULAR
)) {
553 error
<< string_compose (_("FileSource: \"%1\" is ambigous when searching %2\n\t"), pathstr
, search_path
) << endmsg
;
556 } else if (cnt
== 0) {
559 error
<< string_compose(_("Filesource: cannot find required file (%1): while searching %2"), pathstr
, search_path
) << endmsg
;
572 /* external files and/or very very old style sessions include full paths */
574 /* ugh, handle ':' situation */
576 if ((pos
= pathstr
.find_last_of (':')) != ustring::npos
) {
578 ustring shorter
= pathstr
.substr (0, pos
);
580 if (Glib::file_test (shorter
, Glib::FILE_TEST_EXISTS
|Glib::FILE_TEST_IS_REGULAR
)) {
581 chan
= atoi (pathstr
.substr (pos
+1));
591 name
= Glib::path_get_basename (pathstr
);
594 if (!Glib::file_test (pathstr
, Glib::FILE_TEST_EXISTS
|Glib::FILE_TEST_IS_REGULAR
)) {
596 /* file does not exist or we cannot read it */
599 error
<< string_compose(_("Filesource: cannot find required file (%1): %2"), pathstr
, strerror (errno
)) << endmsg
;
603 if (errno
!= ENOENT
) {
604 error
<< string_compose(_("Filesource: cannot check for existing file (%1): %2"), pathstr
, strerror (errno
)) << endmsg
;
627 AudioFileSource::set_search_path (ustring p
)
633 AudioFileSource::set_header_position_offset (nframes_t offset
)
635 header_position_offset
= offset
;
636 HeaderPositionOffsetChanged ();
640 AudioFileSource::set_timeline_position (int64_t pos
)
642 timeline_position
= pos
;
646 AudioFileSource::set_allow_remove_if_empty (bool yn
)
653 _flags
= Flag (_flags
| RemovableIfEmpty
);
655 _flags
= Flag (_flags
& ~RemovableIfEmpty
);
658 fix_writable_flags ();
662 AudioFileSource::set_name (ustring newname
, bool destructive
)
664 Glib::Mutex::Lock
lm (_lock
);
665 ustring oldpath
= _path
;
666 ustring newpath
= Session::change_audio_path_by_name (oldpath
, _name
, newname
, destructive
);
668 if (newpath
.empty()) {
669 error
<< string_compose (_("programming error: %1"), "cannot generate a changed audio path") << endmsg
;
673 // Test whether newpath exists, if yes notify the user but continue.
674 if (access(newpath
.c_str(),F_OK
) == 0) {
675 error
<< _("Programming error! Tried to rename a file over another file! It's safe to continue working, but please report this to the developers.") << endmsg
;
679 if (rename (oldpath
.c_str(), newpath
.c_str()) != 0) {
680 error
<< string_compose (_("cannot 2 rename audio file %1 to %2"), _name
, newpath
) << endmsg
;
684 _name
= Glib::path_get_basename (newpath
);
687 return rename_peakfile (peak_path (_path
));
691 AudioFileSource::is_empty (Session
& s
, ustring path
)
696 if (!get_soundfile_info (path
, info
, err
)) {
697 /* dangerous: we can't get info, so assume that its not empty */
701 return info
.length
== 0;
705 AudioFileSource::setup_peakfile ()
707 if (!(_flags
& NoPeakFile
)) {
708 return initialize_peakfile (file_is_new
, _path
);
715 AudioFileSource::safe_file_extension(ustring file
)
717 const char* suffixes
[] = {
741 #ifdef HAVE_COREAUDIO
753 ".sd2", ".SD2", // libsndfile supports sd2 also, but the resource fork is required to open.
754 #endif // HAVE_COREAUDIO
757 for (size_t n
= 0; n
< sizeof(suffixes
)/sizeof(suffixes
[0]); ++n
) {
758 if (file
.rfind (suffixes
[n
]) == file
.length() - strlen (suffixes
[n
])) {
767 AudioFileSource::mark_immutable ()
769 /* destructive sources stay writable, and their other flags don't
773 if (!(_flags
& Destructive
)) {
774 _flags
= Flag (_flags
& ~(Writable
|Removable
|RemovableIfEmpty
|RemoveAtDestroy
|CanRename
));
780 AudioFileSource::get_interleave_buffer (nframes_t size
)
782 SizedSampleBuffer
* ssb
;
784 if ((ssb
= thread_interleave_buffer
.get()) == 0) {
785 ssb
= new SizedSampleBuffer (size
);
786 thread_interleave_buffer
.set (ssb
);
789 if (ssb
->size
< size
) {
790 ssb
= new SizedSampleBuffer (size
);
791 thread_interleave_buffer
.set (ssb
);