#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"
#include "control_protocol/control_protocol.h"
+#include "LuaBridge/LuaBridge.h"
+
#include "i18n.h"
#include <locale.h>
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<MidiPort>(scene_input_port()));
+ msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
- boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
+ boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
setup_midi_machine_control ();
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() */
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) {
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());
StateSaved (snapshot_name); /* EMIT SIGNAL */
}
+#ifndef NDEBUG
+ const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
+ cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
+#endif
return 0;
}
}
}
+ save_snapshot_name (snapshot_name);
+
return 0;
}
if (full_state) {
node->add_property ("name", _name);
- snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
+ snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
node->add_property ("sample-rate", buf);
if (session_dirs.size() > 1) {
snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
node->add_property ("id-counter", buf);
+ snprintf (buf, sizeof (buf), "%u", name_id_counter ());
+ node->add_property ("name-counter", buf);
+
/* save the event ID counter */
snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
node->add_child_copy (*_extra_xml);
}
+ {
+ Glib::Threads::Mutex::Lock lm (lua_lock);
+ std::string saved;
+ {
+ luabridge::LuaRef savedstate ((*_lua_save)());
+ saved = savedstate.cast<std::string>();
+ }
+ 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;
}
if ((prop = node.property (X_("sample-rate"))) != 0) {
- _nominal_frame_rate = atoi (prop->value());
+ _base_frame_rate = atoi (prop->value());
+ _nominal_frame_rate = _base_frame_rate;
- if (_nominal_frame_rate != _current_frame_rate) {
- boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
+ assert (AudioEngine::instance()->running ());
+ if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
+ boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
if (r.get_value_or (0)) {
goto out;
}
ID::init_counter (now);
}
- if ((prop = node.property (X_("event-counter"))) != 0) {
- Evoral::init_event_id_counter (atoi (prop->value()));
- }
+ if ((prop = node.property (X_("name-counter"))) != 0) {
+ init_name_id_counter (atoi (prop->value()));
+ }
+ if ((prop = node.property (X_("event-counter"))) != 0) {
+ Evoral::init_event_id_counter (atoi (prop->value()));
+ }
if ((child = find_named_node (node, "MIDIPorts")) != 0) {
_midi_ports->set_midi_port_states (child->children());
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 */
XMLTree tree;
- tree.set_root (&get_template());
+ {
+ PBD::Unwinder<std::string> 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;
cmd->name ()));
_current_trans->add_command (cmd);
}
+
+PBD::StatefulDiffCommand*
+Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
+{
+ PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
+ add_command (cmd);
+ return cmd;
+}
+
void
Session::begin_reversible_command (const string& name)
{
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) {
}
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 */
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<Processor> p = r->nth_send (send);
-
- if (p) {
- boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
- boost::shared_ptr<Amp> a = s->amp();
-
- if (a) {
- c = s->amp()->gain_control();
- }
- }
+ c = r->send_level_controllable (send);
break;
}
} 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") {
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<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
+ boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_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));
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)
{
}
}
- _current_snapshot_name = new_name;
+ set_snapshot_name (new_name);
_name = new_name;
set_dirty ();
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<boost::shared_ptr<FileSource> > SeveralFileSources;
typedef std::map<std::string,SeveralFileSources> SourcePathMap;
_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) {
_path = old_path;
_name = old_name;
- _current_snapshot_name = old_snapshot;
+ set_snapshot_name (old_snapshot);
(*_session_dir) = old_sd;