summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2014-07-08 00:53:06 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2014-07-08 00:53:13 -0400
commitfcabd5d8ee172e9d27423864448902ad99634ac5 (patch)
tree5c20f5dd6cc3c285bd4eb5f849796b95665f0243 /libs
parentd3e3f5f0058f45825b46abf731ece39fc416efa0 (diff)
initial implementation of "bring all media into session folder". Incomplete but basically functional for audio files
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/file_source.h2
-rw-r--r--libs/ardour/ardour/session.h6
-rw-r--r--libs/ardour/ardour/sndfilesource.h2
-rw-r--r--libs/ardour/audiofilesource.cc2
-rw-r--r--libs/ardour/file_source.cc8
-rw-r--r--libs/ardour/session.cc238
-rw-r--r--libs/ardour/session_state.cc89
-rw-r--r--libs/ardour/smf_source.cc4
-rw-r--r--libs/ardour/sndfilesource.cc9
9 files changed, 291 insertions, 69 deletions
diff --git a/libs/ardour/ardour/file_source.h b/libs/ardour/ardour/file_source.h
index 8b8adfeb66..8cbbfed0d9 100644
--- a/libs/ardour/ardour/file_source.h
+++ b/libs/ardour/ardour/file_source.h
@@ -89,6 +89,8 @@ public:
*/
int rename (const std::string& name);
+ virtual void release_descriptor () {}
+
protected:
FileSource (Session& session, DataType type,
const std::string& path,
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 430c0d7a8c..53215af2b6 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -196,11 +196,16 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
std::string peak_path (std::string) const;
std::string peak_path_from_audio_path (std::string) const;
+ bool audio_source_name_is_unique (const std::string& name, uint32_t chan);
+ std::string format_audio_source_name (const std::string& legalized_base, uint32_t nchan, uint32_t chan, bool destructive, bool take_required, uint32_t cnt, bool related_exists);
+ std::string new_audio_source_path_for_embedded (const std::string& existing_path);
std::string new_audio_source_path (const std::string&, uint32_t nchans, uint32_t chan, bool destructive, bool take_required);
std::string new_midi_source_path (const std::string&);
RouteList new_route_from_template (uint32_t how_many, const std::string& template_path, const std::string& name);
std::vector<std::string> get_paths_for_new_sources (bool allow_replacing, const std::string& import_file_path, uint32_t channels);
+ int bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,std::string)> callback);
+
void process (pframes_t nframes);
BufferSet& get_silent_buffers (ChanCount count = ChanCount::ZERO);
@@ -863,6 +868,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
std::vector<std::string> source_search_path(DataType) const;
void ensure_search_path_includes (const std::string& path, DataType type);
+ void remove_dir_from_search_path (const std::string& path, DataType type);
std::list<std::string> unknown_processors () const;
diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h
index 831f8db5f7..99fb9f4d09 100644
--- a/libs/ardour/ardour/sndfilesource.h
+++ b/libs/ardour/ardour/sndfilesource.h
@@ -75,6 +75,8 @@ class LIBARDOUR_API SndFileSource : public AudioFileSource {
static int get_soundfile_info (const std::string& path, SoundFileInfo& _info, std::string& error_msg);
+ void release_descriptor ();
+
protected:
void set_path (const std::string& p);
void set_header_timeline_position ();
diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc
index 7d34b9d9a5..9c1b969190 100644
--- a/libs/ardour/audiofilesource.cc
+++ b/libs/ardour/audiofilesource.cc
@@ -32,6 +32,7 @@
#include "pbd/convert.h"
#include "pbd/basename.h"
+#include "pbd/file_utils.h"
#include "pbd/mountpoint.h"
#include "pbd/stl_delete.h"
#include "pbd/strsplit.h"
@@ -413,3 +414,4 @@ AudioFileSource::get_interleave_buffer (framecnt_t size)
return ssb->buf;
}
+
diff --git a/libs/ardour/file_source.cc b/libs/ardour/file_source.cc
index 8c41f981b9..bb6d3562fa 100644
--- a/libs/ardour/file_source.cc
+++ b/libs/ardour/file_source.cc
@@ -546,6 +546,12 @@ void
FileSource::set_path (const std::string& newpath)
{
_path = newpath;
+ set_within_session_from_path (newpath);
+ if (_within_session) {
+ _origin = Glib::path_get_basename (newpath);
+ } else {
+ _origin = newpath;
+ }
}
void
@@ -597,3 +603,5 @@ FileSource::rename (const string& newpath)
return 0;
}
+
+
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 989b916065..19a081e17b 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -44,6 +44,7 @@
#include "pbd/stacktrace.h"
#include "pbd/file_utils.h"
#include "pbd/convert.h"
+#include "pbd/md5.h"
#include "pbd/unwind.h"
#include "pbd/search_path.h"
@@ -3442,94 +3443,168 @@ Session::peak_path (string base) const
return Glib::build_filename (_session_dir->peak_path(), base + peakfile_suffix);
}
-/** Return a unique name based on \a base for a new internal audio source */
string
-Session::new_audio_source_path (const string& base, uint32_t nchan, uint32_t chan, bool destructive, bool take_required)
+Session::new_audio_source_path_for_embedded (const std::string& path)
{
- uint32_t cnt;
- string possible_name;
- const uint32_t limit = 9999; // arbitrary limit on number of files with the same basic name
- string legalized;
- string ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
- bool some_related_source_name_exists = false;
+ /* embedded source:
+ *
+ * we know that the filename is already unique because it exists
+ * out in the filesystem.
+ *
+ * However, when we bring it into the session, we could get a
+ * collision.
+ *
+ * Eg. two embedded files:
+ *
+ * /foo/bar/baz.wav
+ * /frob/nic/baz.wav
+ *
+ * When merged into session, these collide.
+ *
+ * There will not be a conflict with in-memory sources
+ * because when the source was created we already picked
+ * a unique name for it.
+ *
+ * This collision is not likely to be common, but we have to guard
+ * against it. So, if there is a collision, take the md5 hash of the
+ * the path, and use that as the filename instead.
+ */
- possible_name[0] = '\0';
- legalized = legalize_for_path (base);
+ SessionDirectory sdir (get_best_session_directory_for_new_audio());
+ string base = Glib::path_get_basename (path);
+ string newpath = Glib::build_filename (sdir.sound_path(), base);
+
+ if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
- std::vector<string> sdirs = source_search_path(DataType::AUDIO);
+ MD5 md5;
- // Find a "version" of the base name that doesn't exist in any of the possible directories.
+ md5.digestString (path.c_str());
+ md5.writeToString ();
+ base = md5.digestChars;
- for (cnt = (destructive ? ++destructive_index : 1); cnt <= limit; ++cnt) {
+ /* XXX base needs suffix from path */
+
+ newpath = Glib::build_filename (sdir.sound_path(), base);
- vector<space_and_path>::iterator i;
- uint32_t existing = 0;
+ /* if this collides, we're screwed */
- for (vector<string>::const_iterator i = sdirs.begin(); i != sdirs.end(); ++i) {
+ if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
+ error << string_compose (_("Merging embedded file %1: name collision AND md5 hash collision!"), path) << endmsg;
+ return string();
+ }
- ostringstream sstr;
+ }
- if (destructive) {
- sstr << 'T';
- sstr << setfill ('0') << setw (4) << cnt;
- sstr << legalized;
- } else {
- sstr << legalized;
-
- if (take_required || some_related_source_name_exists) {
- sstr << '-';
- sstr << cnt;
- }
- }
-
- if (nchan == 2) {
- if (chan == 0) {
- sstr << "%L";
- } else {
- sstr << "%R";
- }
- } else if (nchan > 2 && nchan < 26) {
- sstr << '%';
- sstr << 'a' + chan;
- }
+ return newpath;
+}
- sstr << ext;
+bool
+Session::audio_source_name_is_unique (const string& name, uint32_t chan)
+{
+ std::vector<string> sdirs = source_search_path (DataType::AUDIO);
+ vector<space_and_path>::iterator i;
+ uint32_t existing = 0;
+ string basename = PBD::basename_nosuffix (name);
- possible_name = sstr.str();
- const string spath = (*i);
+ for (vector<string>::const_iterator i = sdirs.begin(); i != sdirs.end(); ++i) {
+
+ /* note that we search *without* the extension so that
+ we don't end up both "Audio 1-1.wav" and "Audio 1-1.caf"
+ in the event that this new name is required for
+ a file format change.
+ */
- /* note that we search *without* the extension so that
- we don't end up both "Audio 1-1.wav" and "Audio 1-1.caf"
- in the event that this new name is required for
- a file format change.
- */
+ const string spath = *i;
+
+ if (matching_unsuffixed_filename_exists_in (spath, basename)) {
+ existing++;
+ break;
+ }
+
+ /* it is possible that we have the path already
+ * assigned to a source that has not yet been written
+ * (ie. the write source for a diskstream). we have to
+ * check this in order to make sure that our candidate
+ * path isn't used again, because that can lead to
+ * two Sources point to the same file with different
+ * notions of their removability.
+ */
+
+
+ string possible_path = Glib::build_filename (spath, name);
- if (matching_unsuffixed_filename_exists_in (spath, possible_name)) {
- existing++;
- break;
- }
+ if (audio_source_by_path_and_channel (possible_path, chan)) {
+ existing++;
+ break;
+ }
+ }
+
+ return (existing == 0);
+}
- /* it is possible that we have the path already
- * assigned to a source that has not yet been written
- * (ie. the write source for a diskstream). we have to
- * check this in order to make sure that our candidate
- * path isn't used again, because that can lead to
- * two Sources point to the same file with different
- * notions of their removability.
- */
+string
+Session::format_audio_source_name (const string& legalized_base, uint32_t nchan, uint32_t chan, bool destructive, bool take_required, uint32_t cnt, bool related_exists)
+{
+ ostringstream sstr;
+ const string ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
+
+ if (destructive) {
+ sstr << 'T';
+ sstr << setfill ('0') << setw (4) << cnt;
+ sstr << legalized_base;
+ } else {
+ sstr << legalized_base;
+
+ if (take_required || related_exists) {
+ sstr << '-';
+ sstr << cnt;
+ }
+ }
+
+ if (nchan == 2) {
+ if (chan == 0) {
+ sstr << "%L";
+ } else {
+ sstr << "%R";
+ }
+ } else if (nchan > 2) {
+ if (nchan < 26) {
+ sstr << '%';
+ sstr << 'a' + chan;
+ } else {
+ /* XXX what? more than 26 channels! */
+ sstr << '%';
+ sstr << chan+1;
+ }
+ }
+
+ sstr << ext;
- string possible_path = Glib::build_filename (spath, possible_name);
+ return sstr.str();
+}
- if (audio_source_by_path_and_channel (possible_path, chan)) {
- existing++;
- break;
- }
- }
+/** Return a unique name based on \a base for a new internal audio source */
+string
+Session::new_audio_source_path (const string& base, uint32_t nchan, uint32_t chan, bool destructive, bool take_required)
+{
+ uint32_t cnt;
+ string possible_name;
+ const uint32_t limit = 9999; // arbitrary limit on number of files with the same basic name
+ string legalized;
+ bool some_related_source_name_exists = false;
- if (existing == 0) {
+ legalized = legalize_for_path (base);
+
+ // Find a "version" of the base name that doesn't exist in any of the possible directories.
+
+ for (cnt = (destructive ? ++destructive_index : 1); cnt <= limit; ++cnt) {
+
+ possible_name = format_audio_source_name (legalized, nchan, chan, destructive, take_required, cnt, some_related_source_name_exists);
+
+ if (audio_source_name_is_unique (possible_name, chan)) {
break;
}
-
+
some_related_source_name_exists = true;
if (cnt > limit) {
@@ -4776,6 +4851,33 @@ Session::ensure_search_path_includes (const string& path, DataType type)
}
}
+void
+Session::remove_dir_from_search_path (const string& dir, DataType type)
+{
+ Searchpath sp;
+
+ switch (type) {
+ case DataType::AUDIO:
+ sp = Searchpath(config.get_audio_search_path ());
+ break;
+ case DataType::MIDI:
+ sp = Searchpath (config.get_midi_search_path ());
+ break;
+ }
+
+ sp -= dir;
+
+ switch (type) {
+ case DataType::AUDIO:
+ config.set_audio_search_path (sp.to_string());
+ break;
+ case DataType::MIDI:
+ config.set_midi_search_path (sp.to_string());
+ break;
+ }
+
+}
+
boost::shared_ptr<Speakers>
Session::get_speakers()
{
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index 9321973f7e..21088227d5 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -3773,3 +3773,92 @@ Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFo
return !(found_sr && found_data_format); // zero if they are both found
}
+
+typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
+typedef std::map<std::string,SeveralFileSources> SourcePathMap;
+
+int
+Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
+{
+ uint32_t total = 0;
+ uint32_t n = 0;
+ SourcePathMap source_path_map;
+ string new_path;
+ boost::shared_ptr<AudioFileSource> afs;
+ int ret = 0;
+
+ {
+
+ Glib::Threads::Mutex::Lock lm (source_lock);
+
+ cerr << " total sources = " << sources.size();
+
+ for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
+ boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
+
+ if (!fs) {
+ continue;
+ }
+
+ if (fs->within_session()) {
+ cerr << "skip " << fs->name() << endl;
+ continue;
+ }
+
+ if (source_path_map.find (fs->path()) != source_path_map.end()) {
+ source_path_map[fs->path()].push_back (fs);
+ } else {
+ SeveralFileSources v;
+ v.push_back (fs);
+ source_path_map.insert (make_pair (fs->path(), v));
+ }
+
+ total++;
+ }
+
+ cerr << " fsources = " << total << endl;
+
+ for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
+
+ /* tell caller where we are */
+
+ string old_path = i->first;
+
+ callback (n, total, old_path);
+
+ cerr << old_path << endl;
+
+ new_path.clear ();
+
+ switch (i->second.front()->type()) {
+ case DataType::AUDIO:
+ new_path = new_audio_source_path_for_embedded (old_path);
+ break;
+
+ case DataType::MIDI:
+ break;
+ }
+
+ cerr << "Move " << old_path << " => " << new_path << endl;
+
+ if (!copy_file (old_path, new_path)) {
+ cerr << "failed !\n";
+ ret = -1;
+ }
+
+ /* make sure we stop looking in the external
+ dir/folder. Remember, this is an all-or-nothing
+ operations, it doesn't merge just some files.
+ */
+ remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
+
+ for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
+ (*f)->set_path (new_path);
+ }
+ }
+ }
+
+ save_state ("", false, false);
+
+ return ret;
+}
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index e39ef3f548..6ec7c5a78c 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -26,6 +26,7 @@
#include <errno.h>
#include <regex.h>
+#include "pbd/file_utils.h"
#include "pbd/stl_delete.h"
#include "pbd/strsplit.h"
@@ -717,4 +718,5 @@ SMFSource::prevent_deletion ()
_flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));
}
-
+
+
diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc
index af25b3e76f..58fbab233b 100644
--- a/libs/ardour/sndfilesource.cc
+++ b/libs/ardour/sndfilesource.cc
@@ -1016,3 +1016,12 @@ SndFileSource::set_path (const string& p)
_descriptor->set_path (_path);
}
}
+
+void
+SndFileSource::release_descriptor ()
+{
+ if (_descriptor) {
+ _descriptor->release ();
+ _descriptor = 0;
+ }
+}