summaryrefslogtreecommitdiff
path: root/libs/ardour/session.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/session.cc')
-rw-r--r--libs/ardour/session.cc238
1 files changed, 170 insertions, 68 deletions
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()
{