X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession_state.cc;h=ebb2b99cc1406eb8bebe068e6b041feef0eea170;hb=9bf40bde3aed831791108bfccc4b1e10b071afdc;hp=326a4be546f727adedb8caec0f8b397903430d0a;hpb=e31f5d999837b0d0d63dc824c50e9da4acca7244;p=ardour.git diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 326a4be546..ebb2b99cc1 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -755,7 +755,7 @@ Session::remove_state (string snapshot_name) /** @param snapshot_name Name to save under, without .ardour / .pending prefix */ int -Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only) +Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only, bool for_archive, bool only_used_assets) { DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL))); @@ -765,6 +765,10 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot /* prevent concurrent saves from different threads */ Glib::Threads::Mutex::Lock lm (save_state_lock); + Glib::Threads::Mutex::Lock lx (save_source_lock, Glib::Threads::NOT_LOCK); + if (!for_archive) { + lx.acquire (); + } if (!_writable || (_state_of_the_state & CannotSave)) { return 1; @@ -777,7 +781,7 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot _save_queued = false; snapshot_t fork_state = NormalSave; - if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending) { + if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending && !for_archive) { /* snapshot, close midi */ fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep; } @@ -796,10 +800,11 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot } } + PBD::Unwinder uw (LV2Plugin::force_state_save, for_archive); + SessionSaveUnderway (); /* EMIT SIGNAL */ bool mark_as_clean = true; - if (!snapshot_name.empty() && !switch_to_snapshot) { mark_as_clean = false; } @@ -808,7 +813,7 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot mark_as_clean = false; tree.set_root (&get_template()); } else { - tree.set_root (&state (false, fork_state)); + tree.set_root (&state (false, fork_state, only_used_assets)); } if (snapshot_name.empty()) { @@ -870,7 +875,7 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot } } - if (!pending) { + if (!pending && !for_archive) { save_history (snapshot_name); @@ -1107,6 +1112,12 @@ Session::export_track_state (boost::shared_ptr rl, const string& path return tree.write (sn.c_str()); } +static void +merge_all_sources (boost::shared_ptr pl, std::set >* all_sources) +{ + pl->deep_sources (*all_sources); +} + namespace { struct route_id_compare { @@ -1119,7 +1130,7 @@ struct route_id_compare { } // anon namespace XMLNode& -Session::state (bool save_template, snapshot_t snapshot_type) +Session::state (bool save_template, snapshot_t snapshot_type, bool only_used_assets) { LocaleGuard lg; XMLNode* node = new XMLNode("Session"); @@ -1214,6 +1225,13 @@ Session::state (bool save_template, snapshot_t snapshot_type) if (!save_template) { Glib::Threads::Mutex::Lock sl (source_lock); + set > sources_used_by_this_snapshot; + + if (only_used_assets) { + playlists->sync_all_regions_with_regions (); + playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false); + } + for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) { /* Don't save information about non-file Sources, or @@ -1232,6 +1250,17 @@ Session::state (bool save_template, snapshot_t snapshot_type) } } + if (only_used_assets) { + /* skip only unused audio files */ + boost::shared_ptr afs = boost::dynamic_pointer_cast (fs); + if (afs && !afs->used()) { + continue; + } + if (afs && sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) { + continue; + } + } + if (snapshot_type != NormalSave && fs->within_session ()) { /* copy MIDI sources to new file * @@ -1301,15 +1330,18 @@ Session::state (bool save_template, snapshot_t snapshot_type) if (!save_template) { Glib::Threads::Mutex::Lock rl (region_lock); - const RegionFactory::RegionMap& region_map (RegionFactory::all_regions()); - for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) { - boost::shared_ptr r = i->second; - /* only store regions not attached to playlists */ - if (r->playlist() == 0) { - if (boost::dynamic_pointer_cast(r)) { - child->add_child_nocopy ((boost::dynamic_pointer_cast(r))->get_basic_state ()); - } else { - child->add_child_nocopy (r->get_state ()); + + if (!only_used_assets) { + const RegionFactory::RegionMap& region_map (RegionFactory::all_regions()); + for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) { + boost::shared_ptr r = i->second; + /* only store regions not attached to playlists */ + if (r->playlist() == 0) { + if (boost::dynamic_pointer_cast(r)) { + child->add_child_nocopy ((boost::dynamic_pointer_cast(r))->get_basic_state ()); + } else { + child->add_child_nocopy (r->get_state ()); + } } } } @@ -1320,10 +1352,21 @@ Session::state (bool save_template, snapshot_t snapshot_type) XMLNode* ca = node->add_child (X_("CompoundAssociations")); for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) { + if (i->first->playlist () == 0 && only_used_assets) { + continue; + } XMLNode* can = new XMLNode (X_("CompoundAssociation")); can->set_property (X_("copy"), i->first->id()); can->set_property (X_("original"), i->second->id()); ca->add_child_nocopy (*can); + /* see above, child is still "Regions" here */ + if (i->second->playlist() == 0 && only_used_assets) { + if (boost::shared_ptr ar = boost::dynamic_pointer_cast( i->second)) { + child->add_child_nocopy (ar->get_basic_state ()); + } else { + child->add_child_nocopy (ar->get_state ()); + } + } } } } @@ -1397,7 +1440,7 @@ Session::state (bool save_template, snapshot_t snapshot_type) } } - playlists->add_state (node, save_template, /* include unused*/ true); + playlists->add_state (node, save_template, !only_used_assets); child = node->add_child ("RouteGroups"); for (list::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) { @@ -3267,12 +3310,6 @@ Session::cleanup_peakfiles () return 0; } -static void -merge_all_sources (boost::shared_ptr pl, std::set >* all_sources) -{ - pl->deep_sources (*all_sources); -} - int Session::cleanup_sources (CleanupReport& rep) { @@ -3937,7 +3974,6 @@ Session::restore_history (string snapshot_name) for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) { XMLNode *t = *it; - UndoTransaction* ut = new UndoTransaction (); std::string name; int64_t tv_sec; @@ -3948,6 +3984,7 @@ Session::restore_history (string snapshot_name) continue; } + UndoTransaction* ut = new UndoTransaction (); ut->set_name (name); struct timeval tv; @@ -4023,11 +4060,7 @@ Session::config_changed (std::string p, bool ours) set_dirty (); } - if (p == "seamless-loop") { - - } else if (p == "rf-speed") { - - } else if (p == "auto-loop") { + if (p == "auto-loop") { } else if (p == "session-monitoring") { @@ -4769,21 +4802,33 @@ Session::save_as_bring_callback (uint32_t,uint32_t,string) } static string -make_new_media_path (string old_path, string new_session_folder, string new_session_path) +make_new_media_path (string old_path, string new_session_folder, string new_session_name) { - /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */ - + // old_path must be in within_session () string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path)); vector v; v.push_back (new_session_folder); /* full path */ v.push_back (interchange_dir_name); - v.push_back (new_session_path); /* just one directory/folder */ + v.push_back (new_session_name); /* just one directory/folder */ v.push_back (typedir); v.push_back (Glib::path_get_basename (old_path)); return Glib::build_filename (v); } +static string +make_new_audio_path (string filename, string new_session_folder, string new_session_name) +{ + vector v; + v.push_back (new_session_folder); /* full path */ + v.push_back (interchange_dir_name); + v.push_back (new_session_name); + v.push_back (ARDOUR::sound_dir_name); + v.push_back (filename); + + return Glib::build_filename (v); +} + int Session::save_as (SaveAs& saveas) { @@ -5229,8 +5274,13 @@ Session::archive_session (const std::string& dest, return -1; } + /* We are going to temporarily change some source properties, + * don't allow any concurrent saves (periodic or otherwise */ + Glib::Threads::Mutex::Lock lm (save_source_lock); + + disable_record (false); + /* save current values */ - bool was_dirty = dirty (); string old_path = _path; string old_name = _name; string old_snapshot = _current_snapshot_name; @@ -5312,6 +5362,7 @@ Session::archive_session (const std::string& dest, blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR); std::map, std::string> orig_sources; + std::map, std::string> orig_origin; std::map, float> orig_gain; set > sources_used_by_this_snapshot; @@ -5320,11 +5371,31 @@ Session::archive_session (const std::string& dest, playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false); } - // collect audio sources for this session, calc total size for encoding - // add option to only include *used* sources (see Session::cleanup_sources) + /* collect audio sources for this session, calc total size for encoding + * add option to only include *used* sources (see Session::cleanup_sources) + */ size_t total_size = 0; { Glib::Threads::Mutex::Lock lm (source_lock); + + /* build a list of used names */ + std::set audio_file_names; + for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) { + boost::shared_ptr afs = boost::dynamic_pointer_cast (i->second); + if (!afs || afs->readable_length () == 0) { + continue; + } + if (only_used_sources) { + if (!afs->used()) { + continue; + } + if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) { + continue; + } + } + audio_file_names.insert (Glib::path_get_basename (afs->path())); + } + for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) { boost::shared_ptr afs = boost::dynamic_pointer_cast (i->second); if (!afs || afs->readable_length () == 0) { @@ -5345,11 +5416,34 @@ Session::archive_session (const std::string& dest, if (compress_audio != NO_ENCODE) { total_size += afs->readable_length (); } else { - if (afs->within_session()) { - filemap[from] = make_new_media_path (from, name, name); + /* copy files as-is */ + if (!afs->within_session()) { + string to = Glib::path_get_basename (from); + + /* avoid name collitions, see also new_audio_source_path_for_embedded () + * - avoid conflict with files existing in interchange + * - avoid conflict with other embedded sources + */ + if (audio_file_names.find (to) == audio_file_names.end ()) { + // we need a new name, add a '-' before the '.' + string bn = to.substr (0, to.find_last_of ('.')); + string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.')); + to = bn + "-1" + ext; + } + while (audio_file_names.find (to) == audio_file_names.end ()) { + to = bump_name_once (to, '-'); + } + + audio_file_names.insert (to); + filemap[from] = make_new_audio_path (to, name, name); + + remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO); + + orig_origin[afs] = afs->origin (); + afs->set_origin (""); + } else { filemap[from] = make_new_media_path (from, name, name); - remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO); } } } @@ -5391,6 +5485,13 @@ Session::archive_session (const std::string& dest, new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac"); g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755); + /* avoid name collisions of external files with same name */ + if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) { + new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac"); + } + while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) { + new_path = bump_name_once (new_path, '-'); + } if (progress) { progress->descend ((float)afs->readable_length () / total_size); @@ -5473,22 +5574,8 @@ Session::archive_session (const std::string& dest, /* write session file */ _path = to_dir; g_mkdir_with_parents (externals_dir ().c_str (), 0755); -#ifdef LV2_SUPPORT - PBD::Unwinder uw (LV2Plugin::force_state_save, true); -#endif - save_state (name, /*pending, don't fork MIDI, don't mark clean */ true); -#ifndef NDEBUG - cerr << "archiving state from " - << Glib::build_filename (to_dir, legalize_for_path (name) + pending_suffix) - << " to " - << Glib::build_filename (to_dir, legalize_for_path (name) + statefile_suffix) - << endl; -#endif - - ::g_rename ( - Glib::build_filename (to_dir, legalize_for_path (name) + pending_suffix).c_str(), - Glib::build_filename (to_dir, legalize_for_path (name) + statefile_suffix).c_str()); + save_state (name, false, false, false, true, only_used_sources); save_default_options (); @@ -5531,12 +5618,12 @@ Session::archive_session (const std::string& dest, _name = old_name; set_snapshot_name (old_snapshot); (*_session_dir) = old_sd; - if (was_dirty) { - set_dirty (); - } config.set_audio_search_path (old_config_search_path[DataType::AUDIO]); config.set_midi_search_path (old_config_search_path[DataType::MIDI]); + for (std::map, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) { + i->first->set_origin (i->second); + } for (std::map, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) { i->first->replace_file (i->second); }