Fix ff->stop->play not at speed 1.0 on Mackie Control and some key bindings.
[ardour.git] / libs / ardour / session_state.cc
index a0651ecbdae3a58bea16557138ff57c6f47ae171..c440b77895bf68ae4e61e9913d4629a8e5181be7 100644 (file)
@@ -25,7 +25,6 @@
 #include <stdint.h>
 
 #include <algorithm>
-#include <fstream>
 #include <string>
 #include <cerrno>
 #include <cstdio> /* snprintf(3) ... grrr */
@@ -49,7 +48,7 @@
 #endif
 
 #include <glib.h>
-#include <pbd/gstdio_compat.h>
+#include "pbd/gstdio_compat.h"
 
 #include <glibmm.h>
 #include <glibmm/threads.h>
@@ -218,11 +217,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<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 ();
 
@@ -344,7 +343,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() */
@@ -792,7 +791,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());
@@ -801,8 +807,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) {
 
@@ -855,12 +863,14 @@ 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 */
@@ -972,6 +982,8 @@ Session::load_state (string snapshot_name)
                }
        }
 
+       save_snapshot_name (snapshot_name);
+
        return 0;
 }
 
@@ -1449,6 +1461,7 @@ Session::set_state (const XMLNode& node, int version)
        update_route_record_state ();
 
        /* here beginneth the second phase ... */
+       set_snapshot_name (_current_snapshot_name);
 
        StateReady (); /* EMIT SIGNAL */
 
@@ -2092,7 +2105,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;
@@ -2118,10 +2131,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) {
@@ -2935,6 +2948,17 @@ Session::cleanup_sources (CleanupReport& rep)
 
        _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))) {
@@ -3008,6 +3032,15 @@ Session::cleanup_sources (CleanupReport& rep)
 
                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) {
@@ -3842,7 +3875,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<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));
@@ -3880,6 +3926,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)
 {
@@ -4081,7 +4148,7 @@ Session::rename (const std::string& new_name)
                }
        }
 
-       _current_snapshot_name = new_name;
+       set_snapshot_name (new_name);
        _name = new_name;
 
        set_dirty ();
@@ -4162,6 +4229,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<boost::shared_ptr<FileSource> > SeveralFileSources;
 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
 
@@ -4577,7 +4667,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) {
@@ -4620,7 +4710,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;