summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2015-01-14 17:53:23 -0500
committerPaul Davis <paul@linuxaudiosystems.com>2015-01-14 17:53:23 -0500
commit140778641cfa6ad208bdc2e5beca72b00c2501c9 (patch)
treefd77c0105d712aced5f3fd48cb307e92fad2712d
parent08d56360d683c83727d3d5c04ddc372cb703aa68 (diff)
get Session::save_as() working much more correctly, and cleaner
-rw-r--r--libs/ardour/ardour/session.h30
-rw-r--r--libs/ardour/file_source.cc1
-rw-r--r--libs/ardour/session_directory.cc1
-rw-r--r--libs/ardour/session_state.cc270
4 files changed, 171 insertions, 131 deletions
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 83af5c2da6..d769db25e6 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -393,17 +393,29 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
framecnt_t worst_track_latency () const { return _worst_track_latency; }
framecnt_t worst_playback_latency () const { return _worst_output_latency + _worst_track_latency; }
- int consolidate_all_media ();
-
struct SaveAs {
- std::string new_parent_folder;
- std::string new_name;
- bool switch_to;
- bool copy_media;
- bool copy_external;
+ std::string new_parent_folder; /* parent folder where new session folder will be created */
+ std::string new_name; /* name of newly saved session */
+ bool switch_to; /* true if we should be working on newly saved session after save-as; false otherwise */
+ bool copy_media; /* true if media files (audio, media, etc) should be copied into newly saved session; false otherwise */
+ bool copy_external; /* true if external media should be consolidated into the newly saved session; false otherwise */
- /* emitted as we make progress */
+ /* emitted as we make progress. 3 arguments passed to signal
+ * handler:
+ *
+ * 1: percentage complete measured as a fraction (0-1.0) of
+ * total data copying done.
+ * 2: number of files copied so far
+ * 3: total number of files to copy
+ *
+ * Handler should return true for save-as to continue, or false
+ * to stop (and remove all evidence of partial save-as).
+ */
PBD::Signal3<bool,float,int64_t,int64_t> Progress;
+
+ /* if save_as() returns non-zero, this string will indicate the reason why.
+ */
+ std::string failure_message;
};
int save_as (SaveAs&);
@@ -1693,6 +1705,8 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void setup_click_state (const XMLNode*);
void setup_bundles ();
+ void save_as_bring_callback (uint32_t, uint32_t, std::string);
+
static int get_session_info_from_path (XMLTree& state_tree, const std::string& xmlpath);
};
diff --git a/libs/ardour/file_source.cc b/libs/ardour/file_source.cc
index 0aec49e6bd..b4ecb157c5 100644
--- a/libs/ardour/file_source.cc
+++ b/libs/ardour/file_source.cc
@@ -337,7 +337,6 @@ FileSource::find (Session& s, DataType type, const string& path, bool must_exist
}
found_path = keeppath;
-
ret = true;
out:
diff --git a/libs/ardour/session_directory.cc b/libs/ardour/session_directory.cc
index 9d0be414da..b6536ebec9 100644
--- a/libs/ardour/session_directory.cc
+++ b/libs/ardour/session_directory.cc
@@ -176,6 +176,7 @@ SessionDirectory::sub_directories () const
tmp_paths.push_back (sound_path ());
tmp_paths.push_back (midi_path ());
+ tmp_paths.push_back (video_path ());
tmp_paths.push_back (peak_path ());
tmp_paths.push_back (dead_path ());
tmp_paths.push_back (export_path ());
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index be4a7cb1cf..45693960c2 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -3935,6 +3935,13 @@ bool accept_all_files (string const &, void *)
return true;
}
+void
+Session::save_as_bring_callback (uint32_t,uint32_t,string)
+{
+ /* It would be good if this did something useful vis-a-vis save-as, but the arguments doesn't provide the correct information right now to do this.
+ */
+}
+
int
Session::save_as (SaveAs& saveas)
{
@@ -3946,6 +3953,14 @@ Session::save_as (SaveAs& saveas)
int64_t copied = 0;
int64_t cnt = 0;
int64_t all = 0;
+ int32_t internal_file_cnt = 0;
+
+ vector<string> do_not_copy_extensions;
+ do_not_copy_extensions.push_back (statefile_suffix);
+ do_not_copy_extensions.push_back (pending_suffix);
+ do_not_copy_extensions.push_back (backup_suffix);
+ do_not_copy_extensions.push_back (temp_suffix);
+ do_not_copy_extensions.push_back (history_suffix);
/* get total size */
@@ -3961,165 +3976,173 @@ Session::save_as (SaveAs& saveas)
all += files.size();
- cerr << (*sd).path << " Contained " << files.size() << " total now " << all << endl;
-
for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
GStatBuf gsb;
-
- if ((*i).find (X_("interchange")) == string::npos || saveas.copy_media) {
- g_stat ((*i).c_str(), &gsb);
- total_bytes += gsb.st_size;
- }
+ g_stat ((*i).c_str(), &gsb);
+ total_bytes += gsb.st_size;
}
- cerr << "\ttotal size now " << total_bytes << endl;
}
- /* Create the new session directory */
+ /* save old values so we can switch back if we are not switching to the new session */
string old_path = _path;
string old_name = _name;
string old_snapshot = _current_snapshot_name;
string old_sd = _session_dir->root_path();
+ vector<string> old_search_path[DataType::num_types];
+ string old_config_search_path[DataType::num_types];
+
+ old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
+ old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
+ old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
+ old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
+
+ /* switch session directory */
(*_session_dir) = to_dir;
+ /* create new tree */
+
if (!_session_dir->create()) {
return -1;
}
- cerr << "Created new session dir " << _session_dir->root_path() << endl;
-
try {
- if (saveas.copy_media) {
-
- /* copy all media files. Find each location in
- * session_dirs, and copy files from there to
- * target.
+ /* copy all media files. Find each location in
+ * session_dirs, and copy files from there to
+ * target.
+ */
+
+ for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
+
+ /* need to clear this because
+ * find_files_matching_filter() is cumulative
*/
- for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
-
- /* need to clear this because
- * find_files_matching_filter() is cumulative
- */
-
- files.clear ();
-
- find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
-
- const size_t prefix_len = (*sd).path.size();
+ files.clear ();
+
+ const size_t prefix_len = (*sd).path.size();
+
+ /* Work just on the files within this session dir */
+
+ find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
+
+ /* copy all the files. Handling is different for media files
+ than others because of the *silly* subtree we have below the interchange
+ folder. That really was a bad idea, but I'm not fixing it as part of
+ implementing ::save_as().
+ */
+
+ for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
- /* copy all media files (everything below
- * interchange/)
- */
+ std::string from = *i;
- for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
- std::string from = *i;
-
-
- if ((*i).find (X_("interchange")) != string::npos) {
+ if ((*i).find (interchange_dir_name) != string::npos) {
+
+ /* media file */
- /* media file */
-
- GStatBuf gsb;
- g_stat ((*i).c_str(), &gsb);
+ if (saveas.copy_media) {
- /* strip the session dir prefix from
- * each full path, then prepend new
- * to_dir to give complete path.
+ /* typedir is the "midifiles" or "audiofiles" etc. part of the path.
*/
+ string typedir = Glib::path_get_basename (Glib::path_get_dirname (*i));
+ vector<string> v;
+ v.push_back (to_dir);
+ v.push_back (interchange_dir_name);
+ v.push_back (new_folder);
+ v.push_back (typedir);
+ v.push_back (Glib::path_get_basename (*i));
- std::string to = Glib::build_filename (to_dir, (*i).substr (prefix_len));
-
- cerr << "Copy " << from << " to " << to << endl;
+ std::string to = Glib::build_filename (v);
if (!copy_file (from, to)) {
throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
}
+ }
+
+ /* we found media files inside the session folder */
+
+ internal_file_cnt++;
+
+ } else {
+
+ /* normal non-media file. Don't copy state, history, etc.
+ */
+
+ bool do_copy = true;
+
+ for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
+ if (((*i).length() > (*v).length()) && ((*i).find (*v) == (*i).length() - (*v).length())) {
+ /* end of filename matches extension, do not copy file */
+ do_copy = false;
+ break;
+ }
+ }
+
+ if (do_copy) {
+ string to = Glib::build_filename (to_dir, (*i).substr (prefix_len));
- copied += gsb.st_size;
- double fraction = (double) copied / total_bytes;
-
- /* tell someone "X percent, file M of
- * N"; M is one-based
- */
-
- cnt++;
-
- cerr << "PROGRESS " << fraction << "%, " << cnt << " of " << all << endl;
-
-#if 0
- if (!saveas.Progress (fraction, cnt, all)) {
- throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
+ if (!copy_file (from, to)) {
+ throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
}
-#endif
}
}
+
+ /* measure file size even if we're not going to copy so that our Progress
+ signals are correct, since we included these do-not-copy files
+ in the computation of the total size and file count.
+ */
+
+ GStatBuf gsb;
+ g_stat ((*i).c_str(), &gsb);
+ copied += gsb.st_size;
+ cnt++;
+
+ double fraction = (double) copied / total_bytes;
+
+ /* tell someone "X percent, file M of N"; M is one-based */
+
+ boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
+ bool keep_going = true;
+
+ if (res) {
+ keep_going = *res;
+ }
+
+ if (!keep_going) {
+ throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
+ }
}
}
_path = to_dir;
_current_snapshot_name = saveas.new_name;
_name = saveas.new_name;
-
- cerr << "New path = " << _path << endl;
-
- if (!saveas.copy_media && saveas.switch_to) {
- /* need to make all internal file sources point to old session */
-
- for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
- boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
+ if (!saveas.copy_media) {
- if (fs && fs->within_session()) {
+ /* reset search paths of the new session (which we're pretending to be right now) to
+ include the original session search path, so we can still find all audio.
+ */
- cerr << "fs " << fs->name() << " is inside session " << fs->path() << endl;
-
- /* give it an absolute path referencing
- * the original session. Should be
- * easy, but in general, we don't
- * actually know where it lives - it
- * could be in any session dir. So we
- * have to look for it.
- *
- * Note that the session_dirs list
- */
+ if (internal_file_cnt) {
+ for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
+ ensure_search_path_includes (*s, DataType::AUDIO);
+ }
- for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
- SessionDirectory sdir ((*sd).path);
- string file_dir;
- switch (fs->type()) {
- case DataType::AUDIO:
- file_dir = sdir.sound_path();
- break;
- case DataType::MIDI:
- file_dir = sdir.midi_path();
- break;
- default:
- continue;
- }
- string possible_path = Glib::build_filename (file_dir, fs->path());
- if (Glib::file_test (possible_path, Glib::FILE_TEST_EXISTS)) {
- /* Found it */
- cerr << "Reset path for " << fs->name() << " @ " << fs->path() << " to " << possible_path << endl;
- fs->set_path (possible_path);
- break;
- }
- }
-
+ for (vector<string>::iterator s = old_search_path[DataType::MIDI].begin(); s != old_search_path[DataType::MIDI].end(); ++s) {
+ ensure_search_path_includes (*s, DataType::MIDI);
}
}
}
bool was_dirty = dirty ();
- cerr << "Saving state\n";
-
save_state ("", false, false);
save_default_options ();
if (saveas.copy_media && saveas.copy_external) {
- if (consolidate_all_media()) {
+ if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
}
}
@@ -4138,9 +4161,15 @@ Session::save_as (SaveAs& saveas)
set_dirty ();
}
+ if (internal_file_cnt) {
+ /* reset these to their original values */
+ config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
+ config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
+ }
+
} else {
- /* prune session dirs
+ /* prune session dirs, and update disk space statistics
*/
space_and_path sp;
@@ -4148,14 +4177,23 @@ Session::save_as (SaveAs& saveas)
session_dirs.clear ();
session_dirs.push_back (sp);
refresh_disk_space ();
-
- cerr << "pruned session dirs, sd = " << _session_dir->root_path()
- << " path = " << _path << endl;
}
+ } catch (Glib::FileError& e) {
+
+ saveas.failure_message = e.what();
+
+ /* recursively remove all the directories */
+
+ remove_directory (to_dir);
+
+ /* return error */
+
+ return -1;
+
} catch (...) {
- cerr << "copying/saveas failed\n";
+ saveas.failure_message = _("unknown reason");
/* recursively remove all the directories */
@@ -4165,18 +4203,6 @@ Session::save_as (SaveAs& saveas)
return -1;
}
- cerr << "saveas completed successfully\n";
return 0;
}
-
-
-/** Check all sources used by the current snapshot
- * and make a copy of any external media within
- * the session.
- */
-int
-Session::consolidate_all_media ()
-{
- return 0;
-}