X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession_state.cc;h=c228f3c47b92ae1d27dbc9c9f4a9ee3d0705ecee;hb=44fd104ada0fbd8b76d34150e941d85d6de6f81b;hp=bdaaa9e15304ef970ec4b5232066aec29b0ee47d;hpb=f9c202dba050d3975f977bb08ceaf0b1b39fa499;p=ardour.git diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index bdaaa9e153..c228f3c47b 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -47,23 +47,23 @@ #endif #include +#include #include #include -#include -#include +#include #include #include #include #include -#include #include #include #include #include #include +#include #include #include #include @@ -138,10 +138,17 @@ Session::first_stage_init (string fullpath, string snapshot_name) _name = _current_snapshot_name = snapshot_name; + set_history_depth (Config->get_history_depth()); + _current_frame_rate = _engine.frame_rate (); + _nominal_frame_rate = _current_frame_rate; + _base_frame_rate = _current_frame_rate; + _tempo_map = new TempoMap (_current_frame_rate); _tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed)); + + g_atomic_int_set (&processing_prohibited, 0); insert_cnt = 0; _transport_speed = 0; @@ -161,7 +168,8 @@ Session::first_stage_init (string fullpath, string snapshot_name) pending_locate_frame = 0; pending_locate_roll = false; pending_locate_flush = false; - dstream_buffer_size = 0; + audio_dstream_buffer_size = 0; + midi_dstream_buffer_size = 0; state_tree = 0; state_was_pending = false; set_next_event (); @@ -174,7 +182,8 @@ Session::first_stage_init (string fullpath, string snapshot_name) _worst_output_latency = 0; _worst_input_latency = 0; _worst_track_latency = 0; - _state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading|Deletion); + _state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading); + _slave = 0; butler_mixdown_buffer = 0; butler_gain_buffer = 0; @@ -231,9 +240,6 @@ Session::first_stage_init (string fullpath, string snapshot_name) waiting_for_sync_offset = false; } - _current_frame_rate = 48000; - _base_frame_rate = 48000; - last_smpte_when = 0; _smpte_offset = 0; _smpte_offset_negative = true; @@ -266,7 +272,7 @@ Session::first_stage_init (string fullpath, string snapshot_name) Controllable::Destroyed.connect (mem_fun (*this, &Session::remove_controllable)); - IO::MoreChannels.connect (mem_fun (*this, &Session::ensure_buffers)); + IO::PortCountChanged.connect (mem_fun (*this, &Session::ensure_buffers)); /* stop IO objects from doing stuff until we're ready for them */ @@ -291,12 +297,13 @@ Session::second_stage_init (bool new_session) return -1; } - /*if (start_midi_thread ()) { + if (start_midi_thread ()) { return -1; - }*/ + } // set_state() will call setup_raid_path(), but if it's a new session we need // to call setup_raid_path() here. + if (state_tree) { if (set_state (*state_tree->root())) { return -1; @@ -317,7 +324,7 @@ Session::second_stage_init (bool new_session) _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave|Loading); - // set_auto_input (true); + _locations.changed.connect (mem_fun (this, &Session::locations_changed)); _locations.added.connect (mem_fun (this, &Session::locations_added)); setup_click_sounds (0); @@ -344,11 +351,15 @@ Session::second_stage_init (bool new_session) return -1; } - //send_full_time_code (); + BootMessage (_("Reset Remote Controls")); + + send_full_time_code (0); _engine.transport_locate (0); deliver_mmc (MIDI::MachineControl::cmdMmcReset, 0); deliver_mmc (MIDI::MachineControl::cmdLocate, 0); + BootMessage (_("Reset Control Protocols")); + ControlProtocolManager::instance().set_session (*this); if (new_session) { @@ -356,7 +367,19 @@ Session::second_stage_init (bool new_session) } else { _end_location_is_free = false; } + + _state_of_the_state = Clean; + + DirtyChanged (); /* EMIT SIGNAL */ + + if (state_was_pending) { + save_state (_current_snapshot_name); + remove_pending_capture_state (); + state_was_pending = false; + } + BootMessage (_("Session loading complete")); + return 0; } @@ -414,43 +437,122 @@ Session::setup_raid_path (string path) last_rr_session_dir = session_dirs.begin(); } -void -Session::initialize_start_and_end_locations (nframes_t start, nframes_t end) +int +Session::ensure_subdirs () { - start_location->set_end (start); - _locations.add (start_location); + string dir; - end_location->set_end (end); - _locations.add (end_location); -} + dir = session_directory().peak_path().to_string(); -bool -Session::create_session_file () -{ - _state_of_the_state = Clean; + if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) { + error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg; + return -1; + } + + dir = session_directory().sound_path().to_string(); + + if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) { + error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg; + return -1; + } + + dir = session_directory().midi_path().to_string(); - if (save_state (_current_snapshot_name)) { - error << "Could not create new session file" << endmsg; - return false; + if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) { + error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg; + return -1; + } + + dir = session_directory().dead_sound_path().to_string(); + + if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) { + error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg; + return -1; } - return true; + + dir = session_directory().export_path().to_string(); + + if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) { + error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg; + return -1; + } + + dir = analysis_dir (); + + if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) { + error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg; + return -1; + } + + return 0; } -bool -Session::create_session_file_from_template (const string& template_path) +int +Session::create (bool& new_session, const string& mix_template, nframes_t initial_length) { - sys::path session_file_path(_session_dir->root_path()); - session_file_path /= _name + statefile_suffix; + if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) { + error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg; + return -1; + } + + if (ensure_subdirs ()) { + return -1; + } + + /* check new_session so we don't overwrite an existing one */ + + if (!mix_template.empty()) { + std::string in_path = mix_template; + + ifstream in(in_path.c_str()); + + if (in){ + string out_path = _path; + out_path += _name; + out_path += statefile_suffix; + + ofstream out(out_path.c_str()); + + if (out){ + out << in.rdbuf(); + + // okay, session is set up. Treat like normal saved + // session from now on. + + new_session = false; + return 0; + + } else { + error << string_compose (_("Could not open %1 for writing mix template"), out_path) + << endmsg; + return -1; + } + + } else { + error << string_compose (_("Could not open mix template %1 for reading"), in_path) + << endmsg; + return -1; + } - if(!copy_file (template_path, session_file_path.to_string())) { - error << string_compose (_("Could not use session template %1 to create new session."), template_path) - << endmsg; - return false; } - return true; + + /* set initial start + end point */ + + start_location->set_end (0); + _locations.add (start_location); + + end_location->set_end (initial_length); + _locations.add (end_location); + + _state_of_the_state = Clean; + + save_state (""); + + return 0; } + int Session::load_diskstreams (const XMLNode& node) { @@ -494,11 +596,19 @@ Session::maybe_write_autosave() void Session::remove_pending_capture_state () { - sys::path xml_path(_session_dir->root_path()); - - xml_path /= _current_snapshot_name + pending_suffix; + sys::path pending_state_file_path(_session_dir->root_path()); + + pending_state_file_path /= _current_snapshot_name + pending_suffix; - unlink (xml_path.to_string().c_str()); + try + { + sys::remove (pending_state_file_path); + } + catch(sys::filesystem_error& ex) + { + error << string_compose(_("Could remove pending capture state at path \"%1\" (%2)"), + pending_state_file_path.to_string(), ex.what()) << endmsg; + } } /** Rename a state file. @@ -511,12 +621,21 @@ Session::rename_state (string old_name, string new_name) /* refuse to rename the current snapshot or the "main" one */ return; } - - const string old_xml_path = _path + old_name + statefile_suffix; - const string new_xml_path = _path + new_name + statefile_suffix; - if (rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) { - error << string_compose(_("could not rename snapshot %1 to %2"), old_name, new_name) << endmsg; + const string old_xml_filename = old_name + statefile_suffix; + const string new_xml_filename = new_name + statefile_suffix; + + const sys::path old_xml_path = _session_dir->root_path() / old_xml_filename; + const sys::path new_xml_path = _session_dir->root_path() / new_xml_filename; + + try + { + sys::rename (old_xml_path, new_xml_path); + } + catch (const sys::filesystem_error& err) + { + error << string_compose(_("could not rename snapshot %1 to %2 (%3)"), + old_name, new_name, err.what()) << endmsg; } } @@ -527,28 +646,29 @@ void Session::remove_state (string snapshot_name) { if (snapshot_name == _current_snapshot_name || snapshot_name == _name) { - /* refuse to remove the current snapshot or the "main" one */ + // refuse to remove the current snapshot or the "main" one return; } - - const string xml_path = _path + snapshot_name + statefile_suffix; - /* make a backup copy of the state file */ - const string bak_path = xml_path + ".bak"; - if (g_file_test (xml_path.c_str(), G_FILE_TEST_EXISTS)) { - copy_file (xml_path, bak_path); + sys::path xml_path(_session_dir->root_path()); + + xml_path /= snapshot_name + statefile_suffix; + + if (!create_backup_file (xml_path)) { + // don't remove it if a backup can't be made + // create_backup_file will log the error. + return; } - /* and delete it */ - unlink (xml_path.c_str()); + // and delete it + sys::remove (xml_path); } int Session::save_state (string snapshot_name, bool pending) { XMLTree tree; - string xml_path; - string bak_path; + sys::path xml_path(_session_dir->root_path()); if (_state_of_the_state & CannotSave) { return 1; @@ -574,45 +694,39 @@ Session::save_state (string snapshot_name, bool pending) if (!pending) { /* proper save: use statefile_suffix (.ardour in English) */ - xml_path = _path; - xml_path += snapshot_name; - xml_path += statefile_suffix; + + xml_path /= snapshot_name + statefile_suffix; /* make a backup copy of the old file */ - bak_path = xml_path; - bak_path += ".bak"; - - if (g_file_test (xml_path.c_str(), G_FILE_TEST_EXISTS)) { - copy_file (xml_path, bak_path); + + if (sys::exists(xml_path) && !create_backup_file (xml_path)) { + // create_backup_file will log the error + return -1; } } else { /* pending save: use pending_suffix (.pending in English) */ - xml_path = _path; - xml_path += snapshot_name; - xml_path += pending_suffix; - + xml_path /= snapshot_name + pending_suffix; } - string tmp_path; + sys::path tmp_path(_session_dir->root_path()); - tmp_path = _path; - tmp_path += snapshot_name; - tmp_path += ".tmp"; + tmp_path /= snapshot_name + temp_suffix; - // cerr << "actually writing state to " << xml_path << endl; + // cerr << "actually writing state to " << xml_path.to_string() << endl; - if (!tree.write (tmp_path)) { - error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg; - unlink (tmp_path.c_str()); + if (!tree.write (tmp_path.to_string())) { + error << string_compose (_("state could not be saved to %1"), tmp_path.to_string()) << endmsg; + sys::remove (tmp_path); return -1; } else { - if (rename (tmp_path.c_str(), xml_path.c_str()) != 0) { - error << string_compose (_("could not rename temporary session file %1 to %2"), tmp_path, xml_path) << endmsg; - unlink (tmp_path.c_str()); + if (rename (tmp_path.to_string().c_str(), xml_path.to_string().c_str()) != 0) { + error << string_compose (_("could not rename temporary session file %1 to %2"), + tmp_path.to_string(), xml_path.to_string()) << endmsg; + sys::remove (tmp_path); return -1; } } @@ -624,7 +738,7 @@ Session::save_state (string snapshot_name, bool pending) bool was_dirty = dirty(); _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty); - + if (was_dirty) { DirtyChanged (); /* EMIT SIGNAL */ } @@ -719,13 +833,26 @@ Session::load_state (string snapshot_name) backup_path /= snapshot_name + "-1" + statefile_suffix; + // only create a backup once + if (sys::exists (backup_path)) { + return 0; + } + info << string_compose (_("Copying old session file %1 to %2\nUse %2 with Ardour versions before 2.0 from now on"), xmlpath.to_string(), backup_path.to_string()) << endmsg; - copy_file (xmlpath.to_string(), backup_path.to_string()); - - /* if it fails, don't worry. right? */ + try + { + sys::copy_file (xmlpath, backup_path); + } + catch(sys::filesystem_error& ex) + { + error << string_compose (_("Unable to make backup of state file %1 (%2)"), + xmlpath.to_string(), ex.what()) + << endmsg; + return -1; + } } return 0; @@ -799,16 +926,16 @@ Session::state(bool full_state) // store libardour version, just in case char buf[16]; - snprintf(buf, sizeof(buf)-1, "%d.%d.%d", - libardour_major_version, libardour_minor_version, libardour_micro_version); + snprintf(buf, sizeof(buf), "%d.%d.%d", libardour3_major_version, libardour3_minor_version, libardour3_micro_version); node->add_property("version", string(buf)); /* store configuration settings */ if (full_state) { - /* store the name */ node->add_property ("name", _name); + snprintf (buf, sizeof (buf), "%" PRId32, _nominal_frame_rate); + node->add_property ("sample-rate", buf); if (session_dirs.size() > 1) { @@ -918,12 +1045,13 @@ Session::state(bool full_state) node->add_child_nocopy (loc.get_state()); } - child = node->add_child ("Connections"); + child = node->add_child ("Bundles"); { Glib::Mutex::Lock lm (bundle_lock); for (BundleList::iterator i = _bundles.begin(); i != _bundles.end(); ++i) { - if (!(*i)->dynamic()) { - child->add_child_nocopy ((*i)->get_state()); + boost::shared_ptr b = boost::dynamic_pointer_cast (*i); + if (b) { + child->add_child_nocopy (b->get_state()); } } } @@ -1036,7 +1164,18 @@ Session::set_state (const XMLNode& node) _name = prop->value (); } - setup_raid_path(_path); + if ((prop = node.property (X_("sample-rate"))) != 0) { + + _nominal_frame_rate = atoi (prop->value()); + + if (_nominal_frame_rate != _current_frame_rate) { + if (AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate)) { + return -1; + } + } + } + + setup_raid_path(_session_dir->root_path().to_string()); if ((prop = node.property (X_("id-counter"))) != 0) { uint64_t x; @@ -1162,13 +1301,16 @@ Session::set_state (const XMLNode& node) goto out; } - if ((child = find_named_node (node, "Connections")) == 0) { - error << _("Session: XML state has no connections section") << endmsg; - goto out; - } else if (load_bundles (*child)) { - goto out; + if ((child = find_named_node (node, "Bundles")) == 0) { + warning << _("Session: XML state has no bundles section (2.0 session?)") << endmsg; + //goto out; + } else { + /* We can't load Bundles yet as they need to be able + to convert from port names to Port objects, which can't happen until + later */ + _bundle_xml_node = new XMLNode (*child); } - + if ((child = find_named_node (node, "EditGroups")) == 0) { error << _("Session: XML state has no edit groups section") << endmsg; goto out; @@ -1202,7 +1344,7 @@ Session::set_state (const XMLNode& node) } else if (_click_io) { _click_io->set_state (*child); } - + if ((child = find_named_node (node, "ControlProtocols")) != 0) { ControlProtocolManager::instance().set_protocol_states (*child); } @@ -1211,14 +1353,6 @@ Session::set_state (const XMLNode& node) StateReady (); /* EMIT SIGNAL */ - _state_of_the_state = Clean; - - if (state_was_pending) { - save_state (_current_snapshot_name); - remove_pending_capture_state (); - state_was_pending = false; - } - return 0; out: @@ -1245,10 +1379,12 @@ Session::load_routes (const XMLNode& node) return -1; } + BootMessage (string_compose (_("Loaded track/bus %1"), route->name())); + new_routes.push_back (route); } - add_routes (new_routes); + add_routes (new_routes, false); return 0; } @@ -1296,7 +1432,14 @@ Session::load_regions (const XMLNode& node) for (niter = nlist.begin(); niter != nlist.end(); ++niter) { if ((region = XMLRegionFactory (**niter, false)) == 0) { - error << _("Session: cannot create Region from XML description.") << endmsg; + error << _("Session: cannot create Region from XML description."); + const XMLProperty *name = (**niter).property("name"); + + if (name) { + error << " " << string_compose (_("Can not load state for region '%1'"), name->value()); + } + + error << endmsg; } } @@ -1334,6 +1477,7 @@ Session::XMLAudioRegionFactory (const XMLNode& node, bool full) boost::shared_ptr source; boost::shared_ptr as; SourceList sources; + SourceList master_sources; uint32_t nchans = 1; char buf[128]; @@ -1393,7 +1537,27 @@ Session::XMLAudioRegionFactory (const XMLNode& node, bool full) sources.push_back (as); } } - + + for (uint32_t n=1; n < nchans; ++n) { + snprintf (buf, sizeof(buf), X_("master-source-%d"), n); + if ((prop = node.property (buf)) != 0) { + + PBD::ID id2 (prop->value()); + + if ((source = source_by_id (id2)) == 0) { + error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg; + return boost::shared_ptr(); + } + + as = boost::dynamic_pointer_cast(source); + if (!as) { + error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg; + return boost::shared_ptr(); + } + master_sources.push_back (as); + } + } + try { boost::shared_ptr region (boost::dynamic_pointer_cast (RegionFactory::create (sources, node))); @@ -1408,6 +1572,14 @@ Session::XMLAudioRegionFactory (const XMLNode& node, bool full) } } + if (!master_sources.empty()) { + if (master_sources.size() == nchans) { + error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg; + } else { + region->set_master_sources (master_sources); + } + } + return region; } @@ -1505,23 +1677,24 @@ Session::path_from_region_name (DataType type, string name, string identifier) char buf[PATH_MAX+1]; uint32_t n; SessionDirectory sdir(get_best_session_directory_for_new_source()); - string sound_dir = ((type == DataType::AUDIO) - ? sdir.sound_path().to_string() - : sdir.midi_path().to_string()); + sys::path source_dir = ((type == DataType::AUDIO) + ? sdir.sound_path() : sdir.midi_path()); string ext = ((type == DataType::AUDIO) ? ".wav" : ".mid"); for (n = 0; n < 999999; ++n) { if (identifier.length()) { - snprintf (buf, sizeof(buf), "%s/%s%s%" PRIu32 "%s", sound_dir.c_str(), name.c_str(), + snprintf (buf, sizeof(buf), "%s%s%" PRIu32 "%s", name.c_str(), identifier.c_str(), n, ext.c_str()); } else { - snprintf (buf, sizeof(buf), "%s/%s-%" PRIu32 "%s", sound_dir.c_str(), name.c_str(), + snprintf (buf, sizeof(buf), "%s-%" PRIu32 "%s", name.c_str(), n, ext.c_str()); } - if (!Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) { - return buf; + sys::path source_path = source_dir / buf; + + if (!sys::exists (source_path)) { + return source_path.to_string(); } } @@ -1569,7 +1742,8 @@ Session::XMLSourceFactory (const XMLNode& node) } try { - return SourceFactory::create (*this, node); + /* note: do peak building in another thread when loading session state */ + return SourceFactory::create (*this, node, true); } catch (failed_constructor& err) { @@ -1582,7 +1756,6 @@ int Session::save_template (string template_name) { XMLTree tree; - string xml_path, bak_path, template_path; if (_state_of_the_state & CannotSave) { return -1; @@ -1841,24 +2014,32 @@ Session::automation_dir () const return res; } +string +Session::analysis_dir () const +{ + string res = _path; + res += "analysis/"; + return res; +} + int -Session::load_bundles (const XMLNode& node) +Session::load_bundles (XMLNode const & node) { - XMLNodeList nlist = node.children(); - XMLNodeConstIterator niter; + XMLNodeList nlist = node.children(); + XMLNodeConstIterator niter; - set_dirty(); + set_dirty(); - for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - if ((*niter)->name() == "InputConnection") { - add_bundle (new ARDOUR::InputBundle (**niter)); - } else if ((*niter)->name() == "OutputConnection") { - add_bundle (new ARDOUR::OutputBundle (**niter)); - } else { - error << string_compose(_("Unknown node \"%1\" found in Connections list from state file"), (*niter)->name()) << endmsg; - return -1; - } - } + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { + if ((*niter)->name() == "InputBundle") { + add_bundle (boost::shared_ptr (new UserBundle (**niter, true))); + } else if ((*niter)->name() == "OutputBundle") { + add_bundle (boost::shared_ptr (new UserBundle (**niter, false))); + } else { + error << string_compose(_("Unknown node \"%1\" found in Bundles list from state file"), (*niter)->name()) << endmsg; + return -1; + } + } return 0; } @@ -1899,6 +2080,12 @@ Session::load_route_groups (const XMLNode& node, bool edit) return 0; } +void +Session::auto_save() +{ + save_state (_current_snapshot_name); +} + static bool state_file_filter (const string &str, void *arg) { @@ -1949,12 +2136,6 @@ Session::possible_states () const return possible_states(_path); } -void -Session::auto_save() -{ - save_state (_current_snapshot_name); -} - RouteGroup * Session::add_edit_group (string name) { @@ -2045,6 +2226,10 @@ Session::commit_reversible_command (Command *cmd) current_trans->add_command (cmd); } + if (current_trans->empty()) { + return; + } + gettimeofday (&now, 0); current_trans->set_timestamp (now); @@ -2288,6 +2473,7 @@ Session::cleanup_sources (Session::cleanup_report& rep) int ret = -1; _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup); + /* step 1: consider deleting all unused playlists */ @@ -2451,7 +2637,7 @@ Session::cleanup_sources (Session::cleanup_report& rep) newpath += dead_sound_dir_name; if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) { - error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), newpath, strerror (errno)) << endmsg; + error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg; return -1; } @@ -2527,6 +2713,7 @@ Session::cleanup_sources (Session::cleanup_report& rep) out: _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup); + return ret; } @@ -2600,6 +2787,7 @@ Session::set_dirty () _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty); + if (!was_dirty) { DirtyChanged(); /* EMIT SIGNAL */ } @@ -2613,6 +2801,7 @@ Session::set_clean () _state_of_the_state = Clean; + if (was_dirty) { DirtyChanged(); /* EMIT SIGNAL */ } @@ -2622,6 +2811,7 @@ void Session::set_deletion_in_progress () { _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion); + } void @@ -2686,76 +2876,85 @@ Session::instant_xml (const string& node_name) int Session::save_history (string snapshot_name) { - XMLTree tree; - string xml_path; - string bak_path; - - tree.set_root (&_history.get_state (Config->get_saved_history_depth())); - - if (snapshot_name.empty()) { - snapshot_name = _current_snapshot_name; - } + XMLTree tree; + + if (snapshot_name.empty()) { + snapshot_name = _current_snapshot_name; + } + + const string history_filename = snapshot_name + history_suffix; + const string backup_filename = history_filename + backup_suffix; + const sys::path xml_path = _session_dir->root_path() / history_filename; + const sys::path backup_path = _session_dir->root_path() / backup_filename; - xml_path = _path + snapshot_name + ".history"; + if (sys::exists (xml_path)) { + try + { + sys::rename (xml_path, backup_path); + } + catch (const sys::filesystem_error& err) + { + error << _("could not backup old history file, current history not saved") << endmsg; + return -1; + } + } - bak_path = xml_path + ".bak"; - if ((access (xml_path.c_str(), F_OK) == 0) && - (rename (xml_path.c_str(), bak_path.c_str()))) - { - error << _("could not backup old history file, current history not saved.") << endmsg; - return -1; - } + if (!Config->get_save_history() || Config->get_saved_history_depth() < 0) { + return 0; + } - if (!tree.write (xml_path)) - { - error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg; + tree.set_root (&_history.get_state (Config->get_saved_history_depth())); - /* don't leave a corrupt file lying around if it is - * possible to fix. - */ + if (!tree.write (xml_path.to_string())) + { + error << string_compose (_("history could not be saved to %1"), xml_path.to_string()) << endmsg; - if (unlink (xml_path.c_str())) { - error << string_compose (_("could not remove corrupt history file %1"), xml_path) << endmsg; - } else { - if (rename (bak_path.c_str(), xml_path.c_str())) + try { - error << string_compose (_("could not restore history file from backup %1"), bak_path) << endmsg; + sys::remove (xml_path); + sys::rename (backup_path, xml_path); + } + catch (const sys::filesystem_error& err) + { + error << string_compose (_("could not restore history file from backup %1 (%2)"), + backup_path.to_string(), err.what()) << endmsg; } - } - return -1; - } + return -1; + } - return 0; + return 0; } int Session::restore_history (string snapshot_name) { - XMLTree tree; - string xmlpath; + XMLTree tree; - if (snapshot_name.empty()) { - snapshot_name = _current_snapshot_name; - } + if (snapshot_name.empty()) { + snapshot_name = _current_snapshot_name; + } - /* read xml */ - xmlpath = _path + snapshot_name + ".history"; - cerr << string_compose(_("Loading history from '%1'."), xmlpath) << endmsg; + const string xml_filename = snapshot_name + history_suffix; + const sys::path xml_path = _session_dir->root_path() / xml_filename; - if (access (xmlpath.c_str(), F_OK)) { - info << string_compose (_("%1: no history file \"%2\" for this session."), _name, xmlpath) << endmsg; - return 1; - } + cerr << "Loading history from " << xml_path.to_string() << endmsg; - if (!tree.read (xmlpath)) { - error << string_compose (_("Could not understand session history file \"%1\""), xmlpath) << endmsg; - return -1; - } + if (!sys::exists (xml_path)) { + info << string_compose (_("%1: no history file \"%2\" for this session."), + _name, xml_path.to_string()) << endmsg; + return 1; + } - /* replace history */ - _history.clear(); + if (!tree.read (xml_path.to_string())) { + error << string_compose (_("Could not understand session history file \"%1\""), + xml_path.to_string()) << endmsg; + return -1; + } + + // replace history + _history.clear(); for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) { @@ -2791,8 +2990,16 @@ Session::restore_history (string snapshot_name) ut->add_command (c); } + } else if (n->name() == "DeltaCommand") { + PBD::ID id(n->property("midi_source")->value()); + boost::shared_ptr midi_source = + boost::dynamic_pointer_cast(source_by_id(id)); + if(midi_source) { + ut->add_command(new MidiModel::DeltaCommand(midi_source->model(), *n)); + } else { + error << "FIXME: Failed to downcast MidiSource for DeltaCommand" << endmsg; + } } else { - error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg; } } @@ -2993,6 +3200,10 @@ Session::config_changed (const char* parameter_name) set_remote_control_ids (); } else if (PARAM_IS ("denormal-model")) { setup_fpu (); + } else if (PARAM_IS ("history-depth")) { + set_history_depth (Config->get_history_depth()); + } else if (PARAM_IS ("sync-all-route-ordering")) { + sync_order_keys (); } set_dirty (); @@ -3000,3 +3211,9 @@ Session::config_changed (const char* parameter_name) #undef PARAM_IS } + +void +Session::set_history_depth (uint32_t d) +{ + _history.set_depth (d); +}