#include <stdint.h>
#include <algorithm>
-#include <fstream>
#include <string>
#include <cerrno>
#include <cstdio> /* snprintf(3) ... grrr */
#endif
#include <glib.h>
-#include <pbd/gstdio_compat.h>
+#include "pbd/gstdio_compat.h"
#include <glibmm.h>
#include <glibmm/threads.h>
#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"
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() */
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());
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) {
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 */
}
}
+ save_snapshot_name (snapshot_name);
+
return 0;
}
update_route_record_state ();
/* here beginneth the second phase ... */
+ set_snapshot_name (_current_snapshot_name);
StateReady (); /* EMIT SIGNAL */
}
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;
}
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) {
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;
_state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
+ /* this is mostly for windows which doesn't allow file
+ * renaming if the file is in use. But we don't special
+ * case it because we need to know if this causes
+ * problems, and the easiest way to notice that is to
+ * keep it in place for all platforms.
+ */
+
+ request_stop (false);
+ _butler->summon ();
+ _butler->wait_until_finished ();
+
/* consider deleting all unused playlists */
if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
+ /* this is mostly for windows which doesn't allow file
+ * renaming if the file is in use. But we don't special
+ * case it because we need to know if this causes
+ * problems, and the easiest way to notice that is to
+ * keep it in place for all platforms.
+ */
+
+ fs->close ();
+
if (!fs->is_stub()) {
if (playlists->source_use_count (fs) != 0) {
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;