#include <sys/time.h>
#include <sys/stat.h>
+#include <stdio.h> // for rename(), sigh
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
+#include <pbd/convert.h>
+#include <pbd/basename.h>
#include <pbd/mountpoint.h>
-#include <pbd/pathscanner.h>
#include <pbd/stl_delete.h>
#include <pbd/strsplit.h>
#include <pbd/shortpath.h>
#include <glibmm/miscutils.h>
#include <glibmm/fileutils.h>
+#include <glibmm/thread.h>
#include <ardour/audiofilesource.h>
#include <ardour/sndfile_helpers.h>
#include <ardour/sndfilesource.h>
#include <ardour/session.h>
+#include <ardour/session_directory.h>
#include <ardour/source_factory.h>
+#include <ardour/filename_extensions.h>
// if these headers come before sigc++ is included
// the parser throws ObjC++ errors. (nil is a keyword)
/* XXX maybe this too */
char AudioFileSource::bwf_serial_number[13] = "000000000000";
+struct SizedSampleBuffer {
+ nframes_t size;
+ Sample* buf;
+
+ SizedSampleBuffer (nframes_t sz) : size (sz) {
+ buf = new Sample[size];
+ }
+
+ ~SizedSampleBuffer() {
+ delete [] buf;
+ }
+};
+
+Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
+
+/** Constructor used for existing internal-to-session files. File must exist. */
AudioFileSource::AudioFileSource (Session& s, ustring path, Flag flags)
: AudioSource (s, path), _flags (flags),
_channel (0)
{
- /* constructor used for existing external to session files. file must exist already */
_is_embedded = AudioFileSource::determine_embeddedness (path);
if (init (path, true)) {
}
+/** Constructor used for new internal-to-session files. File cannot exist. */
AudioFileSource::AudioFileSource (Session& s, ustring path, Flag flags, SampleFormat samp_format, HeaderFormat hdr_format)
: AudioSource (s, path), _flags (flags),
_channel (0)
{
- /* constructor used for new internal-to-session files. file cannot exist */
_is_embedded = false;
if (init (path, false)) {
}
}
+/** Constructor used for existing internal-to-session files. File must exist. */
AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
: AudioSource (s, node), _flags (Flag (Writable|CanRename))
- /* _channel is set in set_state() or init() */
+ /* _channel is set in set_state() or init() */
{
- /* constructor used for existing internal-to-session files. file must exist */
-
if (set_state (node)) {
throw failed_constructor ();
}
int
AudioFileSource::init (ustring pathstr, bool must_exist)
{
- bool is_new = false;
-
_length = 0;
timeline_position = 0;
_peaks_built = false;
- file_is_new = false;
- if (!find (pathstr, must_exist, is_new, _channel)) {
+ if (!find (pathstr, must_exist, file_is_new, _channel)) {
throw non_existent_source ();
}
- if (is_new && must_exist) {
+ if (file_is_new && must_exist) {
return -1;
}
ustring
AudioFileSource::peak_path (ustring audio_path)
{
- return _session.peak_path_from_audio_path (audio_path);
+ ustring base;
+
+ base = PBD::basename_nosuffix (audio_path);
+ base += '%';
+ base += (char) ('A' + _channel);
+
+ return _session.peak_path (base);
+}
+
+ustring
+AudioFileSource::find_broken_peakfile (ustring peak_path, ustring audio_path)
+{
+ ustring str;
+
+ /* check for the broken location in use by 2.0 for several months */
+
+ str = broken_peak_path (audio_path);
+
+ if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
+
+ if (is_embedded()) {
+
+ /* it would be nice to rename it but the nature of
+ the bug means that we can't reliably use it.
+ */
+
+ peak_path = str;
+
+ } else {
+ /* all native files are mono, so we can just rename
+ it.
+ */
+ ::rename (str.c_str(), peak_path.c_str());
+ }
+
+ } else {
+ /* Nasty band-aid for older sessions that were created before we
+ used libsndfile for all audio files.
+ */
+
+
+ str = old_peak_path (audio_path);
+ if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
+ peak_path = str;
+ }
+ }
+
+ return peak_path;
+}
+
+ustring
+AudioFileSource::broken_peak_path (ustring audio_path)
+{
+ return _session.peak_path (audio_path);
}
ustring
ustring res = peak_dir;
res += buf;
+ res += peakfile_suffix;
return res;
}
if (!writable()) {
return;
}
+
+ /* XXX notice that we're readers of _peaks_built
+ but we must hold a solid lock on PeaksReady.
+ */
Glib::Mutex::Lock lm (_lock);
return -1;
}
- ustring newpath;
-
if (!writable()) {
return -1;
}
- /* don't move the file across filesystems, just
- stick it in the `trash_dir_name' directory
- on whichever filesystem it was already on.
+ /* don't move the file across filesystems, just stick it in the
+ trash_dir_name directory on whichever filesystem it was already on
*/
+ ustring newpath;
newpath = Glib::path_get_dirname (_path);
newpath = Glib::path_get_dirname (newpath);
- cerr << "from " << _path << " dead dir looks like " << newpath << endl;
-
- newpath += '/';
- newpath += trash_dir_name;
- newpath += '/';
+ newpath += string("/") + trash_dir_name + "/";
newpath += Glib::path_get_basename (_path);
+ /* the new path already exists, try versioning */
if (access (newpath.c_str(), F_OK) == 0) {
-
- /* the new path already exists, try versioning */
-
char buf[PATH_MAX+1];
int version = 1;
ustring newpath_v;
}
if (version == 999) {
- error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
- newpath)
- << endmsg;
+ PBD::error << string_compose (
+ _("there are already 1000 files with names like %1; versioning discontinued"),
+ newpath)
+ << endmsg;
} else {
newpath = newpath_v;
}
-
- } else {
-
- /* it doesn't exist, or we can't read it or something */
-
}
if (::rename (_path.c_str(), newpath.c_str()) != 0) {
- error << string_compose (_("cannot rename audio file source from %1 to %2 (%3)"),
- _path, newpath, strerror (errno))
- << endmsg;
+ PBD::error << string_compose (
+ _("cannot rename audio file source from %1 to %2 (%3)"),
+ _path, newpath, strerror (errno)) << endmsg;
return -1;
}
peakpath = "";
/* file can not be removed twice, since the operation is not idempotent */
-
_flags = Flag (_flags & ~(RemoveAtDestroy|Removable|RemovableIfEmpty));
return 0;
cnt = 0;
for (vector<ustring>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
-
fullpath = *i;
if (fullpath[fullpath.length()-1] != '/') {
fullpath += '/';
}
}
+ /* Current find() is unable to parse relative path names to yet non-existant
+ sources. QuickFix(tm) */
+ if (keeppath == "") {
+ if (must_exist) {
+ error << "AudioFileSource::find(), keeppath = \"\", but the file must exist" << endl;
+ } else {
+ keeppath = pathstr;
+ }
+ }
+
_name = pathstr;
_path = keeppath;
ret = true;
HeaderPositionOffsetChanged ();
}
-void
-AudioFileSource::handle_header_position_change ()
-{
- if (writable()) {
- set_header_timeline_position ();
- flush_header ();
- }
-}
-
void
AudioFileSource::set_timeline_position (int64_t pos)
{
}
int
-AudioFileSource::set_name (ustring newname, bool destructive)
+AudioFileSource::set_source_name (ustring newname, bool destructive)
{
Glib::Mutex::Lock lm (_lock);
ustring oldpath = _path;
bool
AudioFileSource::is_empty (Session& s, ustring path)
{
- bool ret = false;
+ SoundFileInfo info;
+ string err;
- boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, s, path, 0, NoPeakFile, false));
-
- if (afs) {
- ret = (afs->length() == 0);
+ if (!get_soundfile_info (path, info, err)) {
+ /* dangerous: we can't get info, so assume that its not empty */
+ return false;
}
- return ret;
+ return info.length == 0;
}
int
bool
AudioFileSource::safe_file_extension(ustring file)
{
- return !(file.rfind(".wav") == ustring::npos &&
- file.rfind(".aiff")== ustring::npos &&
- file.rfind(".aif") == ustring::npos &&
- file.rfind(".snd") == ustring::npos &&
- file.rfind(".au") == ustring::npos &&
- file.rfind(".raw") == ustring::npos &&
- file.rfind(".sf") == ustring::npos &&
- file.rfind(".cdr") == ustring::npos &&
- file.rfind(".smp") == ustring::npos &&
- file.rfind(".maud")== ustring::npos &&
- file.rfind(".vwe") == ustring::npos &&
- file.rfind(".paf") == ustring::npos &&
- /* protools convention */
- file.rfind(".L") == ustring::npos &&
- file.rfind(".R") == ustring::npos &&
+ const char* suffixes[] = {
+ ".wav", ".WAV",
+ ".aiff", ".AIFF",
+ ".caf", ".CAF",
+ ".aif", ".AIF",
+ ".amb", ".AMB",
+ ".snd", ".SND",
+ ".au", ".AU",
+ ".raw", ".RAW",
+ ".sf", ".SF",
+ ".cdr", ".CDR",
+ ".smp", ".SMP",
+ ".maud", ".MAUD",
+ ".vwe", ".VWE",
+ ".paf", ".PAF",
+ ".voc", ".VOC",
#ifdef HAVE_FLAC
- file.rfind(".flac")== ustring::npos &&
+ ".flac", ".FLAC",
#endif // HAVE_FLAC
#ifdef HAVE_COREAUDIO
- file.rfind(".mp3") == ustring::npos &&
- file.rfind(".aac") == ustring::npos &&
- file.rfind(".mp4") == ustring::npos &&
+ ".mp3", ".MP3",
+ ".aac", ".AAC",
+ ".mp4", ".MP4",
#endif // HAVE_COREAUDIO
- file.rfind(".voc") == ustring::npos);
+ };
+
+ for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
+ if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
+ return true;
+ }
+ }
+
+ return false;
}
void
_flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
}
}
+
+
+Sample*
+AudioFileSource::get_interleave_buffer (nframes_t size)
+{
+ SizedSampleBuffer* ssb;
+
+ if ((ssb = thread_interleave_buffer.get()) == 0) {
+ ssb = new SizedSampleBuffer (size);
+ thread_interleave_buffer.set (ssb);
+ }
+
+ if (ssb->size < size) {
+ ssb = new SizedSampleBuffer (size);
+ thread_interleave_buffer.set (ssb);
+ }
+
+ return ssb->buf;
+}