X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=libs%2Fardour%2Fsession_state.cc;h=db7cbf2c0a594ac2ddf47306b2f04a77e8f3af1b;hb=94ebad385414e983ab7afc6915cea47484d2ed5f;hp=b54a01c8105814e7fc29cc8a1c1ba9ca72ccbe5b;hpb=dc36b063bfdfd4a680d6e17b0f8d18b812ba5226;p=ardour.git diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index b54a01c810..db7cbf2c0a 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -48,7 +48,7 @@ #endif #include -#include +#include "pbd/gstdio_compat.h" #include #include @@ -73,6 +73,7 @@ #include "pbd/stacktrace.h" #include "pbd/convert.h" #include "pbd/localtime_r.h" +#include "pbd/unwind.h" #include "ardour/amp.h" #include "ardour/async_midi_port.h" @@ -121,6 +122,8 @@ #include "control_protocol/control_protocol.h" +#include "LuaBridge/LuaBridge.h" + #include "i18n.h" #include @@ -217,11 +220,11 @@ Session::post_engine_init () MIDISceneChanger* msc; _scene_changer = msc = new MIDISceneChanger (*this); - msc->set_input_port (scene_input_port()); - msc->set_output_port (scene_out()); + msc->set_input_port (boost::dynamic_pointer_cast(scene_input_port())); + msc->set_output_port (boost::dynamic_pointer_cast(scene_output_port())); boost::function timer_func (boost::bind (&Session::audible_frame, this)); - boost::dynamic_pointer_cast(scene_in())->set_timer (timer_func); + boost::dynamic_pointer_cast(scene_input_port())->set_timer (timer_func); setup_midi_machine_control (); @@ -343,7 +346,7 @@ Session::post_engine_init () send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset)); send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ())); - MIDI::Name::MidiPatchManager::instance().set_session (this); + MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() ); ltc_tx_initialize(); /* initial program change will be delivered later; see ::config_changed() */ @@ -779,6 +782,10 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot return 1; } +#ifndef NDEBUG + const int64_t save_start_time = g_get_monotonic_time(); +#endif + /* tell sources we're saving first, in case they write out to a new file * which should be saved with the state rather than the old one */ for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) { @@ -791,7 +798,14 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot SessionSaveUnderway (); /* EMIT SIGNAL */ + bool mark_as_clean = true; + + if (!snapshot_name.empty() && !switch_to_snapshot) { + mark_as_clean = false; + } + if (template_only) { + mark_as_clean = false; tree.set_root (&get_template()); } else { tree.set_root (&get_state()); @@ -800,8 +814,10 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot if (snapshot_name.empty()) { snapshot_name = _current_snapshot_name; } else if (switch_to_snapshot) { - _current_snapshot_name = snapshot_name; - } + set_snapshot_name (snapshot_name); + } + + assert (!snapshot_name.empty()); if (!pending) { @@ -854,17 +870,23 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot save_history (snapshot_name); - bool was_dirty = dirty(); + if (mark_as_clean) { + bool was_dirty = dirty(); - _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty); + _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty); - if (was_dirty) { - DirtyChanged (); /* EMIT SIGNAL */ + if (was_dirty) { + DirtyChanged (); /* EMIT SIGNAL */ + } } StateSaved (snapshot_name); /* EMIT SIGNAL */ } +#ifndef NDEBUG + const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time; + cerr << "saved state in " << setprecision (1) << elapsed_time_us / 1000. << " ms\n"; +#endif return 0; } @@ -971,6 +993,8 @@ Session::load_state (string snapshot_name) } } + save_snapshot_name (snapshot_name); + return 0; } @@ -1235,6 +1259,26 @@ Session::state (bool full_state) node->add_child_copy (*_extra_xml); } + { + Glib::Threads::Mutex::Lock lm (lua_lock); + std::string saved; + { + luabridge::LuaRef savedstate ((*_lua_save)()); + saved = savedstate.cast(); + } + lua.collect_garbage (); + lm.release (); + + gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ()); + std::string b64s (b64); + g_free (b64); + + XMLNode* script_node = new XMLNode (X_("Script")); + script_node->add_property (X_("lua"), LUA_VERSION); + script_node->add_content (b64s); + node->add_child_nocopy (*script_node); + } + return *node; } @@ -1445,9 +1489,25 @@ Session::set_state (const XMLNode& node, int version) ControlProtocolManager::instance().set_state (*child, version); } + if ((child = find_named_node (node, "Script"))) { + for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) { + if (!(*n)->is_content ()) { continue; } + gsize size; + guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size); + try { + Glib::Threads::Mutex::Lock lm (lua_lock); + (*_lua_load)(std::string ((const char*)buf, size)); + } catch (luabridge::LuaException const& e) { + cerr << "LuaException:" << e.what () << endl; + } + g_free (buf); + } + } + update_route_record_state (); /* here beginneth the second phase ... */ + set_snapshot_name (_current_snapshot_name); StateReady (); /* EMIT SIGNAL */ @@ -2091,7 +2151,7 @@ Session::XMLSourceFactory (const XMLNode& node) } int -Session::save_template (string template_name) +Session::save_template (string template_name, bool replace_existing) { if ((_state_of_the_state & CannotSave) || template_name.empty ()) { return -1; @@ -2117,10 +2177,10 @@ Session::save_template (string template_name) } if (!ARDOUR::Profile->get_trx()) { - if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) { + if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) { warning << string_compose(_("Template \"%1\" already exists - new version not created"), template_dir_path) << endmsg; - return -1; + return -2; } if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) { @@ -2147,25 +2207,16 @@ Session::save_template (string template_name) XMLTree tree; - tree.set_root (&get_template()); + { + PBD::Unwinder uw (_template_state_dir, template_dir_path); + tree.set_root (&get_template()); + } + if (!tree.write (template_file_path)) { error << _("template not saved") << endmsg; return -1; } - if (!ARDOUR::Profile->get_trx()) { - /* copy plugin state directory */ - - std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins"))); - - if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) { - error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"), - template_plugin_state_path, g_strerror (errno)) << endmsg; - return -1; - } - copy_files (plugins_dir(), template_plugin_state_path); - } - store_recent_templates (template_file_path); return 0; @@ -3333,6 +3384,10 @@ Session::controllable_by_descriptor (const ControllableDescriptor& desc) case ControllableDescriptor::RemoteControlID: r = route_by_remote_id (desc.rid()); break; + + case ControllableDescriptor::SelectionCount: + r = route_by_selected_count (desc.selection_id()); + break; } if (!r) { @@ -3367,22 +3422,16 @@ Session::controllable_by_descriptor (const ControllableDescriptor& desc) } case ControllableDescriptor::PanDirection: - { - c = r->pannable()->pan_azimuth_control; + c = r->pan_azimuth_control(); break; - } case ControllableDescriptor::PanWidth: - { - c = r->pannable()->pan_width_control; + c = r->pan_width_control(); break; - } case ControllableDescriptor::PanElevation: - { - c = r->pannable()->pan_elevation_control; + c = r->pan_elevation_control(); break; - } case ControllableDescriptor::Balance: /* XXX simple pan control */ @@ -3412,26 +3461,12 @@ Session::controllable_by_descriptor (const ControllableDescriptor& desc) break; } - case ControllableDescriptor::SendGain: - { + case ControllableDescriptor::SendGain: { uint32_t send = desc.target (0); - - /* revert to zero-based counting */ - if (send > 0) { --send; } - - boost::shared_ptr p = r->nth_send (send); - - if (p) { - boost::shared_ptr s = boost::dynamic_pointer_cast(p); - boost::shared_ptr a = s->amp(); - - if (a) { - c = s->amp()->gain_control(); - } - } + c = r->send_level_controllable (send); break; } @@ -3734,7 +3769,7 @@ Session::config_changed (std::string p, bool ours) } else if (p == "click-gain") { if (_click_gain) { - _click_gain->set_gain (Config->get_click_gain(), this); + _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup); } } else if (p == "send-mtc") { @@ -3861,7 +3896,20 @@ void Session::setup_midi_machine_control () { _mmc = new MIDI::MachineControl; - _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port()); + + boost::shared_ptr async_in = boost::dynamic_pointer_cast (_midi_ports->mmc_input_port()); + boost::shared_ptr async_out = boost::dynamic_pointer_cast (_midi_ports->mmc_output_port()); + + if (!async_out || !async_out) { + return; + } + + /* XXXX argh, passing raw pointers back into libmidi++ */ + + MIDI::Port* mmc_in = async_in.get(); + MIDI::Port* mmc_out = async_out.get(); + + _mmc->set_ports (mmc_in, mmc_out); _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); @@ -3899,6 +3947,27 @@ Session::solo_cut_control() const return _solo_cut_control; } +void +Session::save_snapshot_name (const std::string & n) +{ + /* assure Stateful::_instant_xml is loaded + * add_instant_xml() only adds to existing data and defaults + * to use an empty Tree otherwise + */ + instant_xml ("LastUsedSnapshot"); + + XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot"); + last_used_snapshot->add_property ("name", string(n)); + add_instant_xml (*last_used_snapshot, false); +} + +void +Session::set_snapshot_name (const std::string & n) +{ + _current_snapshot_name = n; + save_snapshot_name (n); +} + int Session::rename (const std::string& new_name) { @@ -4100,7 +4169,7 @@ Session::rename (const std::string& new_name) } } - _current_snapshot_name = new_name; + set_snapshot_name (new_name); _name = new_name; set_dirty (); @@ -4181,6 +4250,29 @@ Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFo return !(found_sr && found_data_format); // zero if they are both found } +std::string +Session::get_snapshot_from_instant (const std::string& session_dir) +{ + std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml"); + + if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) { + return ""; + } + + XMLTree tree; + if (!tree.read (instant_xml_path)) { + return ""; + } + + const XMLProperty* prop; + XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot"); + if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) { + return prop->value(); + } + + return ""; +} + typedef std::vector > SeveralFileSources; typedef std::map SourcePathMap; @@ -4596,7 +4688,7 @@ Session::save_as (SaveAs& saveas) _path = to_dir; - _current_snapshot_name = saveas.new_name; + set_snapshot_name (saveas.new_name); _name = saveas.new_name; if (saveas.include_media && !saveas.copy_media) { @@ -4639,7 +4731,7 @@ Session::save_as (SaveAs& saveas) _path = old_path; _name = old_name; - _current_snapshot_name = old_snapshot; + set_snapshot_name (old_snapshot); (*_session_dir) = old_sd;