fix crash when copy'ing latent plugins
[ardour.git] / libs / ardour / session.cc
index 17fb4e533940d174f861eefde08e8e8a8190a618..61bfce14b6bfc995f0203b44e42bdf17652e60d8 100644 (file)
@@ -23,7 +23,6 @@
 #include <string>
 #include <vector>
 #include <sstream>
 #include <string>
 #include <vector>
 #include <sstream>
-#include <fstream>
 #include <cstdio> /* sprintf(3) ... grrr */
 #include <cmath>
 #include <cerrno>
 #include <cstdio> /* sprintf(3) ... grrr */
 #include <cmath>
 #include <cerrno>
 #include <boost/algorithm/string/erase.hpp>
 
 #include "pbd/basename.h"
 #include <boost/algorithm/string/erase.hpp>
 
 #include "pbd/basename.h"
-#include "pbd/boost_debug.h"
 #include "pbd/convert.h"
 #include "pbd/convert.h"
 #include "pbd/error.h"
 #include "pbd/file_utils.h"
 #include "pbd/md5.h"
 #include "pbd/convert.h"
 #include "pbd/convert.h"
 #include "pbd/error.h"
 #include "pbd/file_utils.h"
 #include "pbd/md5.h"
+#include "pbd/pthread_utils.h"
 #include "pbd/search_path.h"
 #include "pbd/stacktrace.h"
 #include "pbd/stl_delete.h"
 #include "pbd/search_path.h"
 #include "pbd/stacktrace.h"
 #include "pbd/stl_delete.h"
@@ -59,6 +58,7 @@
 #include "ardour/audioengine.h"
 #include "ardour/audiofilesource.h"
 #include "ardour/auditioner.h"
 #include "ardour/audioengine.h"
 #include "ardour/audiofilesource.h"
 #include "ardour/auditioner.h"
+#include "ardour/boost_debug.h"
 #include "ardour/buffer_manager.h"
 #include "ardour/buffer_set.h"
 #include "ardour/bundle.h"
 #include "ardour/buffer_manager.h"
 #include "ardour/buffer_set.h"
 #include "ardour/bundle.h"
 #include "ardour/engine_state_controller.h"
 #endif
 #include "ardour/filename_extensions.h"
 #include "ardour/engine_state_controller.h"
 #endif
 #include "ardour/filename_extensions.h"
+#include "ardour/gain_control.h"
 #include "ardour/graph.h"
 #include "ardour/graph.h"
+#include "ardour/luabindings.h"
 #include "ardour/midiport_manager.h"
 #include "ardour/scene_changer.h"
 #include "ardour/midiport_manager.h"
 #include "ardour/scene_changer.h"
+#include "ardour/midi_patch_manager.h"
 #include "ardour/midi_track.h"
 #include "ardour/midi_ui.h"
 #include "ardour/operations.h"
 #include "ardour/midi_track.h"
 #include "ardour/midi_ui.h"
 #include "ardour/operations.h"
 #include "ardour/recent_sessions.h"
 #include "ardour/region.h"
 #include "ardour/region_factory.h"
 #include "ardour/recent_sessions.h"
 #include "ardour/region.h"
 #include "ardour/region_factory.h"
+#include "ardour/revision.h"
 #include "ardour/route_graph.h"
 #include "ardour/route_group.h"
 #include "ardour/route_graph.h"
 #include "ardour/route_group.h"
-#include "ardour/route_sorters.h"
 #include "ardour/send.h"
 #include "ardour/session.h"
 #include "ardour/session_directory.h"
 #include "ardour/session_playlists.h"
 #include "ardour/smf_source.h"
 #include "ardour/send.h"
 #include "ardour/session.h"
 #include "ardour/session_directory.h"
 #include "ardour/session_playlists.h"
 #include "ardour/smf_source.h"
+#include "ardour/solo_isolate_control.h"
 #include "ardour/source_factory.h"
 #include "ardour/speakers.h"
 #include "ardour/tempo.h"
 #include "ardour/source_factory.h"
 #include "ardour/speakers.h"
 #include "ardour/tempo.h"
+#include "ardour/ticker.h"
 #include "ardour/track.h"
 #include "ardour/user_bundle.h"
 #include "ardour/utils.h"
 #include "ardour/track.h"
 #include "ardour/user_bundle.h"
 #include "ardour/utils.h"
+#include "ardour/vca_manager.h"
+#include "ardour/vca.h"
 
 #include "midi++/port.h"
 #include "midi++/mmc.h"
 
 
 #include "midi++/port.h"
 #include "midi++/mmc.h"
 
-#include "i18n.h"
+#include "LuaBridge/LuaBridge.h"
+
+#include "pbd/i18n.h"
+
+#include <glibmm/checksum.h>
 
 namespace ARDOUR {
 class MidiSource;
 
 namespace ARDOUR {
 class MidiSource;
@@ -118,11 +129,14 @@ using namespace ARDOUR;
 using namespace PBD;
 
 bool Session::_disable_all_loaded_plugins = false;
 using namespace PBD;
 
 bool Session::_disable_all_loaded_plugins = false;
+bool Session::_bypass_all_loaded_plugins = false;
+guint Session::_name_id_counter = 0;
 
 PBD::Signal1<int,uint32_t> Session::AudioEngineSetupRequired;
 PBD::Signal1<void,std::string> Session::Dialog;
 PBD::Signal0<int> Session::AskAboutPendingState;
 PBD::Signal2<int, framecnt_t, framecnt_t> Session::AskAboutSampleRateMismatch;
 
 PBD::Signal1<int,uint32_t> Session::AudioEngineSetupRequired;
 PBD::Signal1<void,std::string> Session::Dialog;
 PBD::Signal0<int> Session::AskAboutPendingState;
 PBD::Signal2<int, framecnt_t, framecnt_t> Session::AskAboutSampleRateMismatch;
+PBD::Signal2<void, framecnt_t, framecnt_t> Session::NotifyAboutSampleRateMismatch;
 PBD::Signal0<void> Session::SendFeedback;
 PBD::Signal3<int,Session*,std::string,DataType> Session::MissingFile;
 
 PBD::Signal0<void> Session::SendFeedback;
 PBD::Signal3<int,Session*,std::string,DataType> Session::MissingFile;
 
@@ -135,10 +149,17 @@ PBD::Signal0<void> Session::FeedbackDetected;
 PBD::Signal0<void> Session::SuccessfulGraphSort;
 PBD::Signal2<void,std::string,std::string> Session::VersionMismatch;
 
 PBD::Signal0<void> Session::SuccessfulGraphSort;
 PBD::Signal2<void,std::string,std::string> Session::VersionMismatch;
 
-const framecnt_t Session::bounce_chunk_size = 65536;
+const framecnt_t Session::bounce_chunk_size = 8192;
 static void clean_up_session_event (SessionEvent* ev) { delete ev; }
 const SessionEvent::RTeventCallback Session::rt_cleanup (clean_up_session_event);
 
 static void clean_up_session_event (SessionEvent* ev) { delete ev; }
 const SessionEvent::RTeventCallback Session::rt_cleanup (clean_up_session_event);
 
+// seconds should be added after the region exceeds end marker
+#ifdef USE_TRACKS_CODE_FEATURES
+const uint32_t Session::session_end_shift = 5;
+#else
+const uint32_t Session::session_end_shift = 0;
+#endif
+
 /** @param snapshot_name Snapshot name, without .ardour suffix */
 Session::Session (AudioEngine &eng,
                   const string& fullpath,
 /** @param snapshot_name Snapshot name, without .ardour suffix */
 Session::Session (AudioEngine &eng,
                   const string& fullpath,
@@ -151,12 +172,13 @@ Session::Session (AudioEngine &eng,
        , _bounce_processing_active (false)
        , waiting_for_sync_offset (false)
        , _base_frame_rate (0)
        , _bounce_processing_active (false)
        , waiting_for_sync_offset (false)
        , _base_frame_rate (0)
-       , _current_frame_rate (0)
        , _nominal_frame_rate (0)
        , _nominal_frame_rate (0)
+       , _current_frame_rate (0)
        , transport_sub_state (0)
        , _record_status (Disabled)
        , _transport_frame (0)
        , _session_range_location (0)
        , transport_sub_state (0)
        , _record_status (Disabled)
        , _transport_frame (0)
        , _session_range_location (0)
+       , _session_range_end_is_free (true)
        , _slave (0)
        , _silent (false)
        , _transport_speed (0)
        , _slave (0)
        , _silent (false)
        , _transport_speed (0)
@@ -170,9 +192,10 @@ Session::Session (AudioEngine &eng,
        , current_block_size (0)
        , _worst_output_latency (0)
        , _worst_input_latency (0)
        , current_block_size (0)
        , _worst_output_latency (0)
        , _worst_input_latency (0)
-       , _worst_track_latency (0)
+       , _worst_track_latency (0)
        , _have_captured (false)
        , _non_soloed_outs_muted (false)
        , _have_captured (false)
        , _non_soloed_outs_muted (false)
+       , _listening (false)
        , _listen_cnt (0)
        , _solo_isolated_cnt (0)
        , _writable (false)
        , _listen_cnt (0)
        , _solo_isolated_cnt (0)
        , _writable (false)
@@ -184,11 +207,15 @@ Session::Session (AudioEngine &eng,
        , average_dir (0)
        , have_first_delta_accumulator (false)
        , _slave_state (Stopped)
        , average_dir (0)
        , have_first_delta_accumulator (false)
        , _slave_state (Stopped)
+       , _mtc_active (false)
+       , _ltc_active (false)
        , post_export_sync (false)
        , post_export_position (0)
        , _exporting (false)
        , post_export_sync (false)
        , post_export_position (0)
        , _exporting (false)
-       , _export_started (false)
        , _export_rolling (false)
        , _export_rolling (false)
+       , _realtime_export (false)
+       , _export_preroll (0)
+       , _export_latency (0)
        , _pre_export_mmc_enabled (false)
        , _name (snapshot_name)
        , _is_new (true)
        , _pre_export_mmc_enabled (false)
        , _name (snapshot_name)
        , _is_new (true)
@@ -199,7 +226,7 @@ Session::Session (AudioEngine &eng,
        , loop_changing (false)
        , last_loopend (0)
        , _session_dir (new SessionDirectory (fullpath))
        , loop_changing (false)
        , last_loopend (0)
        , _session_dir (new SessionDirectory (fullpath))
-       , _current_snapshot_name (snapshot_name)          
+       , _current_snapshot_name (snapshot_name)
        , state_tree (0)
        , state_was_pending (false)
        , _state_of_the_state (StateOfTheState(CannotSave|InitialConnecting|Loading))
        , state_tree (0)
        , state_was_pending (false)
        , _state_of_the_state (StateOfTheState(CannotSave|InitialConnecting|Loading))
@@ -213,6 +240,9 @@ Session::Session (AudioEngine &eng,
        , pending_locate_flush (false)
        , pending_abort (false)
        , pending_auto_loop (false)
        , pending_locate_flush (false)
        , pending_abort (false)
        , pending_auto_loop (false)
+       , _mempool ("Session", 2097152)
+       , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool))
+       , _n_lua_scripts (0)
        , _butler (new Butler (*this))
        , _post_transport_work (0)
        ,  cumulative_rf_motion (0)
        , _butler (new Butler (*this))
        , _post_transport_work (0)
        ,  cumulative_rf_motion (0)
@@ -221,6 +251,8 @@ Session::Session (AudioEngine &eng,
        , _ignore_skips_updates (false)
        , _rt_thread_active (false)
        , _rt_emit_pending (false)
        , _ignore_skips_updates (false)
        , _rt_thread_active (false)
        , _rt_emit_pending (false)
+       , _ac_thread_active (false)
+       , _latency_recompute_pending (0)
        , step_speed (0)
        , outbound_mtc_timecode_frame (0)
        , next_quarter_frame_to_send (-1)
        , step_speed (0)
        , outbound_mtc_timecode_frame (0)
        , next_quarter_frame_to_send (-1)
@@ -252,7 +284,6 @@ Session::Session (AudioEngine &eng,
        , _route_deletion_in_progress (false)
        , destructive_index (0)
        , _track_number_decimals(1)
        , _route_deletion_in_progress (false)
        , destructive_index (0)
        , _track_number_decimals(1)
-       , solo_update_disabled (false)
        , default_fade_steepness (0)
        , default_fade_msecs (0)
        , _total_free_4k_blocks (0)
        , default_fade_steepness (0)
        , default_fade_msecs (0)
        , _total_free_4k_blocks (0)
@@ -270,41 +301,61 @@ Session::Session (AudioEngine &eng,
        , click_emphasis_length (0)
        , _clicks_cleared (0)
        , _play_range (false)
        , click_emphasis_length (0)
        , _clicks_cleared (0)
        , _play_range (false)
+       , _range_selection (-1,-1)
+       , _object_selection (-1,-1)
        , main_outs (0)
        , first_file_data_format_reset (true)
        , first_file_header_format_reset (true)
        , have_looped (false)
        , _have_rec_enabled_track (false)
        , main_outs (0)
        , first_file_data_format_reset (true)
        , first_file_header_format_reset (true)
        , have_looped (false)
        , _have_rec_enabled_track (false)
-    , _have_rec_disabled_track (true)
+       , _have_rec_disabled_track (true)
        , _step_editors (0)
        , _suspend_timecode_transmission (0)
        ,  _speakers (new Speakers)
        , _step_editors (0)
        , _suspend_timecode_transmission (0)
        ,  _speakers (new Speakers)
-       , _order_hint (-1)
        , ignore_route_processor_changes (false)
        , ignore_route_processor_changes (false)
+       , midi_clock (0)
        , _scene_changer (0)
        , _midi_ports (0)
        , _mmc (0)
        , _scene_changer (0)
        , _midi_ports (0)
        , _mmc (0)
+       , _vca_manager (new VCAManager (*this))
 {
        uint32_t sr = 0;
 
 {
        uint32_t sr = 0;
 
+       created_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
+
        pthread_mutex_init (&_rt_emit_mutex, 0);
        pthread_cond_init (&_rt_emit_cond, 0);
 
        pthread_mutex_init (&_rt_emit_mutex, 0);
        pthread_cond_init (&_rt_emit_cond, 0);
 
+       pthread_mutex_init (&_auto_connect_mutex, 0);
+       pthread_cond_init (&_auto_connect_cond, 0);
+
+       init_name_id_counter (1); // reset for new sessions, start at 1
+       VCA::set_next_vca_number (1); // reset for new sessions, start at 1
+
        pre_engine_init (fullpath);
        pre_engine_init (fullpath);
-       
+
+       setup_lua ();
+
        if (_is_new) {
 
        if (_is_new) {
 
-#ifdef USE_TRACKS_CODE_FEATURES                
+               Stateful::loading_state_version = CURRENT_SESSION_FILE_VERSION;
+
+#ifdef USE_TRACKS_CODE_FEATURES
                sr = EngineStateController::instance()->get_current_sample_rate();
 #endif
                sr = EngineStateController::instance()->get_current_sample_rate();
 #endif
-               if (ensure_engine (sr)) {
+               if (ensure_engine (sr, true)) {
                        destroy ();
                        destroy ();
-                       throw failed_constructor ();
+                       throw SessionException (_("Cannot connect to audio/midi engine"));
                }
 
                }
 
+               // set samplerate for plugins added early
+               // e.g from templates or MB channelstrip
+               set_block_size (_engine.samples_per_cycle());
+               set_frame_rate (_engine.sample_rate());
+
                if (create (mix_template, bus_profile)) {
                        destroy ();
                if (create (mix_template, bus_profile)) {
                        destroy ();
-                       throw failed_constructor ();
+                       throw SessionException (_("Session initialization failed"));
                }
 
                /* if a mix template was provided, then ::create() will
                }
 
                /* if a mix template was provided, then ::create() will
@@ -318,9 +369,9 @@ Session::Session (AudioEngine &eng,
                 * of a template.
                 */
 
                 * of a template.
                 */
 
-               if (!mix_template.empty()) { 
+               if (!mix_template.empty()) {
                        if (load_state (_current_snapshot_name)) {
                        if (load_state (_current_snapshot_name)) {
-                               throw failed_constructor ();
+                               throw SessionException (_("Failed to load template/snapshot state"));
                        }
                        store_recent_templates (mix_template);
                }
                        }
                        store_recent_templates (mix_template);
                }
@@ -331,30 +382,31 @@ Session::Session (AudioEngine &eng,
        } else {
 
                if (load_state (_current_snapshot_name)) {
        } else {
 
                if (load_state (_current_snapshot_name)) {
-                       throw failed_constructor ();
+                       throw SessionException (_("Failed to load state"));
                }
                }
-       
+
                /* try to get sample rate from XML state so that we
                 * can influence the SR if we set up the audio
                 * engine.
                 */
 
                if (state_tree) {
                /* try to get sample rate from XML state so that we
                 * can influence the SR if we set up the audio
                 * engine.
                 */
 
                if (state_tree) {
-                       const XMLProperty* prop;
-                       if ((prop = state_tree->root()->property (X_("sample-rate"))) != 0) {           
+                       XMLProperty const * prop;
+                       XMLNode const * root (state_tree->root());
+                       if ((prop = root->property (X_("sample-rate"))) != 0) {
                                sr = atoi (prop->value());
                        }
                }
 
                                sr = atoi (prop->value());
                        }
                }
 
-               if (ensure_engine (sr)) {
+               if (ensure_engine (sr, false)) {
                        destroy ();
                        destroy ();
-                       throw failed_constructor ();
+                       throw SessionException (_("Cannot connect to audio/midi engine"));
                }
        }
 
        if (post_engine_init ()) {
                destroy ();
                }
        }
 
        if (post_engine_init ()) {
                destroy ();
-               throw failed_constructor ();
+               throw SessionException (_("Cannot configure audio/midi engine with session parameters"));
        }
 
        store_recent_sessions (_name, _path);
        }
 
        store_recent_sessions (_name, _path);
@@ -373,9 +425,8 @@ Session::Session (AudioEngine &eng,
        StartTimeChanged.connect_same_thread (*this, boost::bind (&Session::start_time_changed, this, _1));
        EndTimeChanged.connect_same_thread (*this, boost::bind (&Session::end_time_changed, this, _1));
 
        StartTimeChanged.connect_same_thread (*this, boost::bind (&Session::start_time_changed, this, _1));
        EndTimeChanged.connect_same_thread (*this, boost::bind (&Session::end_time_changed, this, _1));
 
-       _is_new = false;
-
        emit_thread_start ();
        emit_thread_start ();
+       auto_connect_thread_start ();
 
        /* hook us up to the engine since we are now completely constructed */
 
 
        /* hook us up to the engine since we are now completely constructed */
 
@@ -385,40 +436,40 @@ Session::Session (AudioEngine &eng,
        _engine.reset_timebase ();
 
 #ifdef USE_TRACKS_CODE_FEATURES
        _engine.reset_timebase ();
 
 #ifdef USE_TRACKS_CODE_FEATURES
-       
+
        EngineStateController::instance()->set_session(this);
        EngineStateController::instance()->set_session(this);
-       
+
        if (_is_new ) {
                if ( ARDOUR::Profile->get_trx () ) {
 
                        /* Waves Tracks: fill session with tracks basing on the amount of inputs.
                         * each available input must have corresponding track when session starts.
                         */
        if (_is_new ) {
                if ( ARDOUR::Profile->get_trx () ) {
 
                        /* Waves Tracks: fill session with tracks basing on the amount of inputs.
                         * each available input must have corresponding track when session starts.
                         */
-                       
+
                        uint32_t how_many (0);
                        uint32_t how_many (0);
-                       
+
                        std::vector<std::string> inputs;
                        EngineStateController::instance()->get_physical_audio_inputs(inputs);
                        std::vector<std::string> inputs;
                        EngineStateController::instance()->get_physical_audio_inputs(inputs);
-                       
+
                        how_many = inputs.size();
                        how_many = inputs.size();
-                       
+
                        list<boost::shared_ptr<AudioTrack> > tracks;
                        list<boost::shared_ptr<AudioTrack> > tracks;
-                       
-                       // Track names after driver 
+
+                       // Track names after driver
                        if (Config->get_tracks_auto_naming() == NameAfterDriver) {
                                string track_name = "";
                                for (std::vector<string>::size_type i = 0; i < inputs.size(); ++i) {
                                        string track_name;
                                        track_name = inputs[i];
                                        replace_all (track_name, "system:capture", "");
                        if (Config->get_tracks_auto_naming() == NameAfterDriver) {
                                string track_name = "";
                                for (std::vector<string>::size_type i = 0; i < inputs.size(); ++i) {
                                        string track_name;
                                        track_name = inputs[i];
                                        replace_all (track_name, "system:capture", "");
-                                       
+
                                        list<boost::shared_ptr<AudioTrack> > single_track = new_audio_track (1, 1, Normal, 0, 1, track_name);
                                        tracks.insert(tracks.begin(), single_track.front());
                                        list<boost::shared_ptr<AudioTrack> > single_track = new_audio_track (1, 1, Normal, 0, 1, track_name);
                                        tracks.insert(tracks.begin(), single_track.front());
-                               }   
+                               }
                        } else { // Default track names
                                tracks = new_audio_track (1, 1, Normal, 0, how_many, string());
                        }
                        } else { // Default track names
                                tracks = new_audio_track (1, 1, Normal, 0, how_many, string());
                        }
-                       
+
                        if (tracks.size() != how_many) {
                                destroy ();
                                throw failed_constructor ();
                        if (tracks.size() != how_many) {
                                destroy ();
                                throw failed_constructor ();
@@ -426,22 +477,41 @@ Session::Session (AudioEngine &eng,
                }
        }
 #endif
                }
        }
 #endif
-       
+
        _is_new = false;
        session_loaded ();
        _is_new = false;
        session_loaded ();
+
        BootMessage (_("Session loading complete"));
 }
 
 Session::~Session ()
 {
        BootMessage (_("Session loading complete"));
 }
 
 Session::~Session ()
 {
-#ifdef PT_TIMING       
+#ifdef PT_TIMING
        ST.dump ("ST.dump");
        ST.dump ("ST.dump");
-#endif 
+#endif
        destroy ();
 }
 
        destroy ();
 }
 
+unsigned int
+Session::next_name_id ()
+{
+       return g_atomic_int_add (&_name_id_counter, 1);
+}
+
+unsigned int
+Session::name_id_counter ()
+{
+       return g_atomic_int_get (&_name_id_counter);
+}
+
+void
+Session::init_name_id_counter (guint n)
+{
+       g_atomic_int_set (&_name_id_counter, n);
+}
+
 int
 int
-Session::ensure_engine (uint32_t desired_sample_rate)
+Session::ensure_engine (uint32_t desired_sample_rate, bool isnew)
 {
        if (_engine.current_backend() == 0) {
                /* backend is unknown ... */
 {
        if (_engine.current_backend() == 0) {
                /* backend is unknown ... */
@@ -449,6 +519,8 @@ Session::ensure_engine (uint32_t desired_sample_rate)
                if (r.get_value_or (-1) != 0) {
                        return -1;
                }
                if (r.get_value_or (-1) != 0) {
                        return -1;
                }
+       } else if (!isnew && _engine.running() && _engine.sample_rate () == desired_sample_rate) {
+               /* keep engine */
        } else if (_engine.setup_required()) {
                /* backend is known, but setup is needed */
                boost::optional<int> r = AudioEngineSetupRequired (desired_sample_rate);
        } else if (_engine.setup_required()) {
                /* backend is known, but setup is needed */
                boost::optional<int> r = AudioEngineSetupRequired (desired_sample_rate);
@@ -461,8 +533,7 @@ Session::ensure_engine (uint32_t desired_sample_rate)
                }
        }
 
                }
        }
 
-       /* at this point the engine should be running
-       */
+       /* at this point the engine should be running */
 
        if (!_engine.running()) {
                return -1;
 
        if (!_engine.running()) {
                return -1;
@@ -479,7 +550,7 @@ Session::immediately_post_engine ()
         * know that the engine is running, but before we either create a
         * session or set state for an existing one.
         */
         * know that the engine is running, but before we either create a
         * session or set state for an existing one.
         */
-        
+
        if (how_many_dsp_threads () > 1) {
                /* For now, only create the graph if we are using >1 DSP threads, as
                   it is a bit slower than the old code with 1 thread.
        if (how_many_dsp_threads () > 1) {
                /* For now, only create the graph if we are using >1 DSP threads, as
                   it is a bit slower than the old code with 1 thread.
@@ -500,6 +571,7 @@ Session::immediately_post_engine ()
        }
 
        try {
        }
 
        try {
+               LocaleGuard lg;
                BootMessage (_("Set up LTC"));
                setup_ltc ();
                BootMessage (_("Set up Click"));
                BootMessage (_("Set up LTC"));
                setup_ltc ();
                BootMessage (_("Set up Click"));
@@ -530,12 +602,26 @@ Session::destroy ()
 
        remove_pending_capture_state ();
 
 
        remove_pending_capture_state ();
 
+       Analyser::flush ();
+
        _state_of_the_state = StateOfTheState (CannotSave|Deletion);
 
        _state_of_the_state = StateOfTheState (CannotSave|Deletion);
 
+       /* stop autoconnecting */
+       auto_connect_thread_terminate ();
+
        /* disconnect from any and all signals that we are connected to */
 
        /* disconnect from any and all signals that we are connected to */
 
+       Port::PortSignalDrop (); /* EMIT SIGNAL */
        drop_connections ();
 
        drop_connections ();
 
+       /* shutdown control surface protocols while we still have ports
+          and the engine to move data to any devices.
+       */
+
+       ControlProtocolManager::instance().drop_protocols ();
+
+       MIDI::Name::MidiPatchManager::instance().remove_search_path(session_directory().midi_patch_path());
+
        _engine.remove_session ();
 
 #ifdef USE_TRACKS_CODE_FEATURES
        _engine.remove_session ();
 
 #ifdef USE_TRACKS_CODE_FEATURES
@@ -559,14 +645,25 @@ Session::destroy ()
        delete state_tree;
        state_tree = 0;
 
        delete state_tree;
        state_tree = 0;
 
-       /* reset dynamic state version back to default */
+       // unregister all lua functions, drop held references (if any)
+       (*_lua_cleanup)();
+       lua.do_command ("Session = nil");
+       delete _lua_run;
+       delete _lua_add;
+       delete _lua_del;
+       delete _lua_list;
+       delete _lua_save;
+       delete _lua_load;
+       delete _lua_cleanup;
+       lua.collect_garbage ();
 
 
+       /* reset dynamic state version back to default */
        Stateful::loading_state_version = 0;
 
        _butler->drop_references ();
        delete _butler;
        _butler = 0;
        Stateful::loading_state_version = 0;
 
        _butler->drop_references ();
        delete _butler;
        _butler = 0;
-       
+
        delete _all_route_group;
 
        DEBUG_TRACE (DEBUG::Destruction, "delete route groups\n");
        delete _all_route_group;
 
        DEBUG_TRACE (DEBUG::Destruction, "delete route groups\n");
@@ -607,6 +704,11 @@ Session::destroy ()
        DEBUG_TRACE (DEBUG::Destruction, "delete regions\n");
        RegionFactory::delete_all_regions ();
 
        DEBUG_TRACE (DEBUG::Destruction, "delete regions\n");
        RegionFactory::delete_all_regions ();
 
+       /* Do this early so that VCAs no longer hold references to routes */
+
+       DEBUG_TRACE (DEBUG::Destruction, "delete vcas\n");
+       delete _vca_manager;
+
        DEBUG_TRACE (DEBUG::Destruction, "delete routes\n");
 
        /* reset these three references to special routes before we do the usual route delete thing */
        DEBUG_TRACE (DEBUG::Destruction, "delete routes\n");
 
        /* reset these three references to special routes before we do the usual route delete thing */
@@ -647,6 +749,9 @@ Session::destroy ()
        pthread_cond_destroy (&_rt_emit_cond);
        pthread_mutex_destroy (&_rt_emit_mutex);
 
        pthread_cond_destroy (&_rt_emit_cond);
        pthread_mutex_destroy (&_rt_emit_mutex);
 
+       pthread_cond_destroy (&_auto_connect_cond);
+       pthread_mutex_destroy (&_auto_connect_mutex);
+
        delete _scene_changer; _scene_changer = 0;
        delete midi_control_ui; midi_control_ui = 0;
 
        delete _scene_changer; _scene_changer = 0;
        delete midi_control_ui; midi_control_ui = 0;
 
@@ -654,23 +759,58 @@ Session::destroy ()
        delete _midi_ports; _midi_ports = 0;
        delete _locations; _locations = 0;
 
        delete _midi_ports; _midi_ports = 0;
        delete _locations; _locations = 0;
 
+       delete midi_clock;
        delete _tempo_map;
        delete _tempo_map;
-       
+
+       /* clear event queue, the session is gone, nobody is interested in
+        * those anymore, but they do leak memory if not removed
+        */
+       while (!immediate_events.empty ()) {
+               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+               SessionEvent *ev = immediate_events.front ();
+               DEBUG_TRACE (DEBUG::SessionEvents, string_compose ("Drop event: %1\n", enum_2_string (ev->type)));
+               immediate_events.pop_front ();
+               bool remove = true;
+               bool del = true;
+               switch (ev->type) {
+                       case SessionEvent::AutoLoop:
+                       case SessionEvent::AutoLoopDeclick:
+                       case SessionEvent::Skip:
+                       case SessionEvent::PunchIn:
+                       case SessionEvent::PunchOut:
+                       case SessionEvent::StopOnce:
+                       case SessionEvent::RangeStop:
+                       case SessionEvent::RangeLocate:
+                               remove = false;
+                               del = false;
+                               break;
+                       case SessionEvent::RealTimeOperation:
+                               process_rtop (ev);
+                               del = false;
+                       default:
+                               break;
+               }
+               if (remove) {
+                       del = del && !_remove_event (ev);
+               }
+               if (del) {
+                       delete ev;
+               }
+       }
+
        DEBUG_TRACE (DEBUG::Destruction, "Session::destroy() done\n");
 
        DEBUG_TRACE (DEBUG::Destruction, "Session::destroy() done\n");
 
-#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
-       boost_debug_list_ptrs ();
-#endif
+       BOOST_SHOW_POINTERS ();
 }
 
 void
 Session::setup_ltc ()
 {
        XMLNode* child = 0;
 }
 
 void
 Session::setup_ltc ()
 {
        XMLNode* child = 0;
-       
+
        _ltc_input.reset (new IO (*this, X_("LTC In"), IO::Input));
        _ltc_output.reset (new IO (*this, X_("LTC Out"), IO::Output));
        _ltc_input.reset (new IO (*this, X_("LTC In"), IO::Input));
        _ltc_output.reset (new IO (*this, X_("LTC Out"), IO::Output));
-       
+
        if (state_tree && (child = find_named_node (*state_tree->root(), X_("LTC In"))) != 0) {
                _ltc_input->set_state (*(child->children().front()), Stateful::loading_state_version);
        } else {
        if (state_tree && (child = find_named_node (*state_tree->root(), X_("LTC In"))) != 0) {
                _ltc_input->set_state (*(child->children().front()), Stateful::loading_state_version);
        } else {
@@ -680,7 +820,7 @@ Session::setup_ltc ()
                }
                reconnect_ltc_input ();
        }
                }
                reconnect_ltc_input ();
        }
-       
+
        if (state_tree && (child = find_named_node (*state_tree->root(), X_("LTC Out"))) != 0) {
                _ltc_output->set_state (*(child->children().front()), Stateful::loading_state_version);
        } else {
        if (state_tree && (child = find_named_node (*state_tree->root(), X_("LTC Out"))) != 0) {
                _ltc_output->set_state (*(child->children().front()), Stateful::loading_state_version);
        } else {
@@ -690,11 +830,11 @@ Session::setup_ltc ()
                }
                reconnect_ltc_output ();
        }
                }
                reconnect_ltc_output ();
        }
-       
+
        /* fix up names of LTC ports because we don't want the normal
         * IO style of NAME/TYPE-{in,out}N
         */
        /* fix up names of LTC ports because we don't want the normal
         * IO style of NAME/TYPE-{in,out}N
         */
-       
+
        _ltc_input->nth (0)->set_name (X_("LTC-in"));
        _ltc_output->nth (0)->set_name (X_("LTC-out"));
 }
        _ltc_input->nth (0)->set_name (X_("LTC-in"));
        _ltc_output->nth (0)->set_name (X_("LTC-out"));
 }
@@ -703,8 +843,12 @@ void
 Session::setup_click ()
 {
        _clicking = false;
 Session::setup_click ()
 {
        _clicking = false;
+
+       boost::shared_ptr<AutomationList> gl (new AutomationList (Evoral::Parameter (GainAutomation)));
+       boost::shared_ptr<GainControl> gain_control = boost::shared_ptr<GainControl> (new GainControl (*this, Evoral::Parameter(GainAutomation), gl));
+
        _click_io.reset (new ClickIO (*this, X_("Click")));
        _click_io.reset (new ClickIO (*this, X_("Click")));
-       _click_gain.reset (new Amp (*this));
+       _click_gain.reset (new Amp (*this, _("Fader"), gain_control, true));
        _click_gain->activate ();
        if (state_tree) {
                setup_click_state (state_tree->root());
        _click_gain->activate ();
        if (state_tree) {
                setup_click_state (state_tree->root());
@@ -715,11 +859,11 @@ Session::setup_click ()
 
 void
 Session::setup_click_state (const XMLNode* node)
 
 void
 Session::setup_click_state (const XMLNode* node)
-{      
+{
        const XMLNode* child = 0;
        const XMLNode* child = 0;
-       
+
        if (node && (child = find_named_node (*node, "Click")) != 0) {
        if (node && (child = find_named_node (*node, "Click")) != 0) {
-               
+
                /* existing state for Click */
                int c = 0;
 
                /* existing state for Click */
                int c = 0;
 
@@ -735,7 +879,7 @@ Session::setup_click_state (const XMLNode* node)
                                }
                        }
                }
                                }
                        }
                }
-                       
+
                if (c == 0) {
                        _clicking = Config->get_clicking ();
 
                if (c == 0) {
                        _clicking = Config->get_clicking ();
 
@@ -801,10 +945,10 @@ Session::setup_bundles ()
        /* mono output bundles */
 
        for (uint32_t np = 0; np < outputs[DataType::AUDIO].size(); ++np) {
        /* mono output bundles */
 
        for (uint32_t np = 0; np < outputs[DataType::AUDIO].size(); ++np) {
-               char buf[32];
+               char buf[64];
                std::string pn = _engine.get_pretty_name_by_name (outputs[DataType::AUDIO][np]);
                if (!pn.empty()) {
                std::string pn = _engine.get_pretty_name_by_name (outputs[DataType::AUDIO][np]);
                if (!pn.empty()) {
-                       snprintf (buf, sizeof (buf), _("out %s"), pn.substr(0,12).c_str());
+                       snprintf (buf, sizeof (buf), _("out %s"), pn.c_str());
                } else {
                        snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
                }
                } else {
                        snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
                }
@@ -835,10 +979,10 @@ Session::setup_bundles ()
        /* mono input bundles */
 
        for (uint32_t np = 0; np < inputs[DataType::AUDIO].size(); ++np) {
        /* mono input bundles */
 
        for (uint32_t np = 0; np < inputs[DataType::AUDIO].size(); ++np) {
-               char buf[32];
+               char buf[64];
                std::string pn = _engine.get_pretty_name_by_name (inputs[DataType::AUDIO][np]);
                if (!pn.empty()) {
                std::string pn = _engine.get_pretty_name_by_name (inputs[DataType::AUDIO][np]);
                if (!pn.empty()) {
-                       snprintf (buf, sizeof (buf), _("in %s"), pn.substr(0,12).c_str());
+                       snprintf (buf, sizeof (buf), _("in %s"), pn.c_str());
                } else {
                        snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
                }
                } else {
                        snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
                }
@@ -909,7 +1053,7 @@ Session::auto_connect_master_bus ()
        if (!_master_out || !Config->get_auto_connect_standard_busses() || _monitor_out) {
                return;
        }
        if (!_master_out || !Config->get_auto_connect_standard_busses() || _monitor_out) {
                return;
        }
-       
+
        // Waves Tracks: Do not connect master bas for Tracks if AutoConnectMaster option is not set
        // In this case it means "Multi Out" output mode
        if (ARDOUR::Profile->get_trx() && !(Config->get_output_auto_connect() & AutoConnectMaster) ) {
        // Waves Tracks: Do not connect master bas for Tracks if AutoConnectMaster option is not set
        // In this case it means "Multi Out" output mode
        if (ARDOUR::Profile->get_trx() && !(Config->get_output_auto_connect() & AutoConnectMaster) ) {
@@ -918,21 +1062,21 @@ Session::auto_connect_master_bus ()
 
        /* if requested auto-connect the outputs to the first N physical ports.
         */
 
        /* if requested auto-connect the outputs to the first N physical ports.
         */
-       
+
        uint32_t limit = _master_out->n_outputs().n_total();
        vector<string> outputs[DataType::num_types];
        uint32_t limit = _master_out->n_outputs().n_total();
        vector<string> outputs[DataType::num_types];
-       
+
        for (uint32_t i = 0; i < DataType::num_types; ++i) {
                _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
        }
        for (uint32_t i = 0; i < DataType::num_types; ++i) {
                _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
        }
-       
+
        for (uint32_t n = 0; n < limit; ++n) {
                boost::shared_ptr<Port> p = _master_out->output()->nth (n);
                string connect_to;
                if (outputs[p->type()].size() > n) {
                        connect_to = outputs[p->type()][n];
                }
        for (uint32_t n = 0; n < limit; ++n) {
                boost::shared_ptr<Port> p = _master_out->output()->nth (n);
                string connect_to;
                if (outputs[p->type()].size() > n) {
                        connect_to = outputs[p->type()][n];
                }
-               
+
                if (!connect_to.empty() && p->connected_to (connect_to) == false) {
                        if (_master_out->output()->connect (p, connect_to, this)) {
                                error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to)
                if (!connect_to.empty() && p->connected_to (connect_to) == false) {
                        if (_master_out->output()->connect (p, connect_to, this)) {
                                error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to)
@@ -963,20 +1107,20 @@ Session::remove_monitor_section ()
                /* Hold process lock while doing this so that we don't hear bits and
                 * pieces of audio as we work on each route.
                 */
                /* Hold process lock while doing this so that we don't hear bits and
                 * pieces of audio as we work on each route.
                 */
-               
+
                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-               
+
                /* Connect tracks to monitor section. Note that in an
                   existing session, the internal sends will already exist, but we want the
                   routes to notice that they connect to the control out specifically.
                */
                /* Connect tracks to monitor section. Note that in an
                   existing session, the internal sends will already exist, but we want the
                   routes to notice that they connect to the control out specifically.
                */
-               
-               
+
+
                boost::shared_ptr<RouteList> r = routes.reader ();
                PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
                boost::shared_ptr<RouteList> r = routes.reader ();
                PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
-               
+
                for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
                for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
-                       
+
                        if ((*x)->is_monitor()) {
                                /* relax */
                        } else if ((*x)->is_master()) {
                        if ((*x)->is_monitor()) {
                                /* relax */
                        } else if ((*x)->is_master()) {
@@ -988,11 +1132,17 @@ Session::remove_monitor_section ()
        }
 
        remove_route (_monitor_out);
        }
 
        remove_route (_monitor_out);
+       if (_state_of_the_state & Deletion) {
+               return;
+       }
+
        auto_connect_master_bus ();
 
        if (auditioner) {
                auditioner->connect ();
        }
        auto_connect_master_bus ();
 
        if (auditioner) {
                auditioner->connect ();
        }
+
+       Config->ParameterChanged ("use-monitor-bus");
 }
 
 void
 }
 
 void
@@ -1004,34 +1154,36 @@ Session::add_monitor_section ()
                return;
        }
 
                return;
        }
 
-       boost::shared_ptr<Route> r (new Route (*this, _("Monitor"), Route::MonitorOut, DataType::AUDIO));
+       boost::shared_ptr<Route> r (new Route (*this, _("Monitor"), PresentationInfo::MonitorOut, DataType::AUDIO));
 
        if (r->init ()) {
                return;
        }
 
 
        if (r->init ()) {
                return;
        }
 
-#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
-       // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
-#endif
-       {
+       BOOST_MARK_ROUTE(r);
+
+       try {
                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                r->input()->ensure_io (_master_out->output()->n_ports(), false, this);
                r->output()->ensure_io (_master_out->output()->n_ports(), false, this);
                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                r->input()->ensure_io (_master_out->output()->n_ports(), false, this);
                r->output()->ensure_io (_master_out->output()->n_ports(), false, this);
+       } catch (...) {
+               error << _("Cannot create monitor section. 'Monitor' Port name is not unique.") << endmsg;
+               return;
        }
 
        rl.push_back (r);
        }
 
        rl.push_back (r);
-       add_routes (rl, false, false, false);
-       
+       add_routes (rl, false, false, false, 0);
+
        assert (_monitor_out);
 
        /* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else
           are undefined, at best.
        */
        assert (_monitor_out);
 
        /* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else
           are undefined, at best.
        */
-       
+
        uint32_t limit = _monitor_out->n_inputs().n_audio();
        uint32_t limit = _monitor_out->n_inputs().n_audio();
-       
+
        if (_master_out) {
        if (_master_out) {
-               
+
                /* connect the inputs to the master bus outputs. this
                 * represents a separate data feed from the internal sends from
                 * each route. as of jan 2011, it allows the monitor section to
                /* connect the inputs to the master bus outputs. this
                 * represents a separate data feed from the internal sends from
                 * each route. as of jan 2011, it allows the monitor section to
@@ -1045,7 +1197,7 @@ Session::add_monitor_section ()
                for (uint32_t n = 0; n < limit; ++n) {
                        boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n);
                        boost::shared_ptr<AudioPort> o = _master_out->output()->ports().nth_audio_port (n);
                for (uint32_t n = 0; n < limit; ++n) {
                        boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n);
                        boost::shared_ptr<AudioPort> o = _master_out->output()->ports().nth_audio_port (n);
-                       
+
                        if (o) {
                                string connect_to = o->name();
                                if (_monitor_out->input()->connect (p, connect_to, this)) {
                        if (o) {
                                string connect_to = o->name();
                                if (_monitor_out->input()->connect (p, connect_to, this)) {
@@ -1056,16 +1208,16 @@ Session::add_monitor_section ()
                        }
                }
        }
                        }
                }
        }
-       
+
        /* if monitor section is not connected, connect it to physical outs
         */
        /* if monitor section is not connected, connect it to physical outs
         */
-       
-       if (Config->get_auto_connect_standard_busses() && !_monitor_out->output()->connected ()) {
-               
+
+       if ((Config->get_auto_connect_standard_busses () || Profile->get_mixbus ()) && !_monitor_out->output()->connected ()) {
+
                if (!Config->get_monitor_bus_preferred_bundle().empty()) {
                if (!Config->get_monitor_bus_preferred_bundle().empty()) {
-                       
+
                        boost::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle());
                        boost::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle());
-                       
+
                        if (b) {
                                _monitor_out->output()->connect_ports_to_bundle (b, true, this);
                        } else {
                        if (b) {
                                _monitor_out->output()->connect_ports_to_bundle (b, true, this);
                        } else {
@@ -1073,9 +1225,9 @@ Session::add_monitor_section ()
                                                           Config->get_monitor_bus_preferred_bundle())
                                        << endmsg;
                        }
                                                           Config->get_monitor_bus_preferred_bundle())
                                        << endmsg;
                        }
-                       
+
                } else {
                } else {
-                       
+
                        /* Monitor bus is audio only */
 
                        vector<string> outputs[DataType::num_types];
                        /* Monitor bus is audio only */
 
                        vector<string> outputs[DataType::num_types];
@@ -1086,17 +1238,17 @@ Session::add_monitor_section ()
 
                        uint32_t mod = outputs[DataType::AUDIO].size();
                        uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
 
                        uint32_t mod = outputs[DataType::AUDIO].size();
                        uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
-                       
+
                        if (mod != 0) {
                        if (mod != 0) {
-                               
+
                                for (uint32_t n = 0; n < limit; ++n) {
                                for (uint32_t n = 0; n < limit; ++n) {
-                                       
+
                                        boost::shared_ptr<Port> p = _monitor_out->output()->ports().port(DataType::AUDIO, n);
                                        string connect_to;
                                        if (outputs[DataType::AUDIO].size() > (n % mod)) {
                                                connect_to = outputs[DataType::AUDIO][n % mod];
                                        }
                                        boost::shared_ptr<Port> p = _monitor_out->output()->ports().port(DataType::AUDIO, n);
                                        string connect_to;
                                        if (outputs[DataType::AUDIO].size() > (n % mod)) {
                                                connect_to = outputs[DataType::AUDIO][n % mod];
                                        }
-                                       
+
                                        if (!connect_to.empty()) {
                                                if (_monitor_out->output()->connect (p, connect_to, this)) {
                                                        error << string_compose (
                                        if (!connect_to.empty()) {
                                                if (_monitor_out->output()->connect (p, connect_to, this)) {
                                                        error << string_compose (
@@ -1114,7 +1266,7 @@ Session::add_monitor_section ()
        /* Hold process lock while doing this so that we don't hear bits and
         * pieces of audio as we work on each route.
         */
        /* Hold process lock while doing this so that we don't hear bits and
         * pieces of audio as we work on each route.
         */
-        
+
        Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
        /* Connect tracks to monitor section. Note that in an
        Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
        /* Connect tracks to monitor section. Note that in an
@@ -1128,7 +1280,7 @@ Session::add_monitor_section ()
        PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
 
        for (RouteList::iterator x = rls->begin(); x != rls->end(); ++x) {
        PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
 
        for (RouteList::iterator x = rls->begin(); x != rls->end(); ++x) {
-               
+
                if ((*x)->is_monitor()) {
                        /* relax */
                } else if ((*x)->is_master()) {
                if ((*x)->is_monitor()) {
                        /* relax */
                } else if ((*x)->is_master()) {
@@ -1141,6 +1293,7 @@ Session::add_monitor_section ()
        if (auditioner) {
                auditioner->connect ();
        }
        if (auditioner) {
                auditioner->connect ();
        }
+       Config->ParameterChanged ("use-monitor-bus");
 }
 
 void
 }
 
 void
@@ -1165,8 +1318,12 @@ Session::reset_monitor_section ()
        _master_out->output()->disconnect (this);
        _monitor_out->output()->disconnect (this);
 
        _master_out->output()->disconnect (this);
        _monitor_out->output()->disconnect (this);
 
-       _monitor_out->input()->ensure_io (_master_out->output()->n_ports(), false, this);
-       _monitor_out->output()->ensure_io (_master_out->output()->n_ports(), false, this);
+       // monitor section follow master bus - except midi
+       ChanCount mon_chn (_master_out->output()->n_ports());
+       mon_chn.set_midi (0);
+
+       _monitor_out->input()->ensure_io (mon_chn, false, this);
+       _monitor_out->output()->ensure_io (mon_chn, false, this);
 
        for (uint32_t n = 0; n < limit; ++n) {
                boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n);
 
        for (uint32_t n = 0; n < limit; ++n) {
                boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n);
@@ -1361,7 +1518,7 @@ Session::set_track_monitor_input_status (bool yn)
        boost::shared_ptr<RouteList> rl = routes.reader ();
        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                boost::shared_ptr<AudioTrack> tr = boost::dynamic_pointer_cast<AudioTrack> (*i);
        boost::shared_ptr<RouteList> rl = routes.reader ();
        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                boost::shared_ptr<AudioTrack> tr = boost::dynamic_pointer_cast<AudioTrack> (*i);
-               if (tr && tr->record_enabled ()) {
+               if (tr && tr->rec_enable_control()->get_value()) {
                        //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl;
                        tr->request_input_monitoring (yn);
                }
                        //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl;
                        tr->request_input_monitoring (yn);
                }
@@ -1447,6 +1604,19 @@ Session::auto_loop_changed (Location* location)
                clear_events (SessionEvent::AutoLoop);
        }
 
                clear_events (SessionEvent::AutoLoop);
        }
 
+       /* possibly move playhead if not rolling; if we are rolling we'll move
+          to the loop start on stop if that is appropriate.
+        */
+
+       framepos_t pos;
+
+       if (!transport_rolling() && select_playhead_priority_target (pos)) {
+               if (pos == location->start()) {
+                       request_locate (pos);
+               }
+       }
+
+
        last_loopend = location->end();
        set_dirty ();
 }
        last_loopend = location->end();
        set_dirty ();
 }
@@ -1496,14 +1666,14 @@ Session::set_session_extents (framepos_t start, framepos_t end)
                //if there is no existing session, we need to make a new session location  (should never happen)
                existing = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
        }
                //if there is no existing session, we need to make a new session location  (should never happen)
                existing = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
        }
-       
+
        if (end <= start) {
                error << _("Session: you can't use that location for session start/end)") << endmsg;
                return;
        }
 
        existing->set( start, end );
        if (end <= start) {
                error << _("Session: you can't use that location for session start/end)") << endmsg;
                return;
        }
 
        existing->set( start, end );
-       
+
        set_dirty();
 }
 
        set_dirty();
 }
 
@@ -1555,7 +1725,7 @@ Session::set_auto_loop_location (Location* location)
                        }
                }
        }
                        }
                }
        }
-    
+
        /* take care of our stuff first */
 
        auto_loop_changed (location);
        /* take care of our stuff first */
 
        auto_loop_changed (location);
@@ -1577,7 +1747,7 @@ Session::update_skips (Location* loc, bool consolidate)
        if (_ignore_skips_updates) {
                return;
        }
        if (_ignore_skips_updates) {
                return;
        }
-       
+
        Locations::LocationList skips;
 
         if (consolidate) {
        Locations::LocationList skips;
 
         if (consolidate) {
@@ -1586,7 +1756,7 @@ Session::update_skips (Location* loc, bool consolidate)
         }
 
        sync_locations_to_skips ();
         }
 
        sync_locations_to_skips ();
-        
+
        set_dirty ();
 }
 
        set_dirty ();
 }
 
@@ -1608,7 +1778,7 @@ Session::consolidate_skips (Location* loc)
                         ++l;
                         continue;
                 }
                         ++l;
                         continue;
                 }
-                        
+
                 switch (Evoral::coverage ((*l)->start(), (*l)->end(), loc->start(), loc->end())) {
                 case Evoral::OverlapInternal:
                 case Evoral::OverlapExternal:
                 switch (Evoral::coverage ((*l)->start(), (*l)->end(), loc->start(), loc->end())) {
                 case Evoral::OverlapInternal:
                 case Evoral::OverlapExternal:
@@ -1647,9 +1817,9 @@ Session::_sync_locations_to_skips ()
        Locations::LocationList const & locs (_locations->list());
 
        for (Locations::LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
        Locations::LocationList const & locs (_locations->list());
 
        for (Locations::LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
-               
+
                Location* location = *i;
                Location* location = *i;
-               
+
                if (location->is_skip() && location->is_skipping()) {
                        SessionEvent* ev = new SessionEvent (SessionEvent::Skip, SessionEvent::Add, location->start(), location->end(), 1.0);
                        queue_event (ev);
                if (location->is_skip() && location->is_skipping()) {
                        SessionEvent* ev = new SessionEvent (SessionEvent::Skip, SessionEvent::Add, location->start(), location->end(), 1.0);
                        queue_event (ev);
@@ -1668,7 +1838,7 @@ Session::location_added (Location *location)
         if (location->is_auto_loop()) {
                 set_auto_loop_location (location);
         }
         if (location->is_auto_loop()) {
                 set_auto_loop_location (location);
         }
-        
+
         if (location->is_session_range()) {
                 /* no need for any signal handling or event setting with the session range,
                    because we keep a direct reference to it and use its start/end directly.
         if (location->is_session_range()) {
                 /* no need for any signal handling or event setting with the session range,
                    because we keep a direct reference to it and use its start/end directly.
@@ -1695,7 +1865,7 @@ Session::location_added (Location *location)
 
                 update_skips (location, true);
         }
 
                 update_skips (location, true);
         }
-        
+
        set_dirty ();
 }
 
        set_dirty ();
 }
 
@@ -1706,7 +1876,7 @@ Session::location_removed (Location *location)
                set_auto_loop_location (0);
                set_track_loop (false);
         }
                set_auto_loop_location (0);
                set_track_loop (false);
         }
-        
+
         if (location->is_auto_punch()) {
                 set_auto_punch_location (0);
         }
         if (location->is_auto_punch()) {
                 set_auto_punch_location (0);
         }
@@ -1717,7 +1887,7 @@ Session::location_removed (Location *location)
         }
 
         if (location->is_skip()) {
         }
 
         if (location->is_skip()) {
-                
+
                 update_skips (location, false);
         }
 
                 update_skips (location, false);
         }
 
@@ -1733,19 +1903,19 @@ Session::locations_changed ()
 void
 Session::_locations_changed (const Locations::LocationList& locations)
 {
 void
 Session::_locations_changed (const Locations::LocationList& locations)
 {
-        /* There was some mass-change in the Locations object. 
+        /* There was some mass-change in the Locations object.
 
            We might be re-adding a location here but it doesn't actually matter
            for all the locations that the Session takes an interest in.
         */
 
            We might be re-adding a location here but it doesn't actually matter
            for all the locations that the Session takes an interest in.
         */
-       
+
        {
                PBD::Unwinder<bool> protect_ignore_skip_updates (_ignore_skips_updates, true);
                for (Locations::LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
                        location_added (*i);
                }
        }
        {
                PBD::Unwinder<bool> protect_ignore_skip_updates (_ignore_skips_updates, true);
                for (Locations::LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
                        location_added (*i);
                }
        }
-       
+
        update_skips (NULL, false);
 }
 
        update_skips (NULL, false);
 }
 
@@ -1763,7 +1933,7 @@ Session::enable_record ()
                if (rs == Recording) {
                        break;
                }
                if (rs == Recording) {
                        break;
                }
-               
+
                if (g_atomic_int_compare_and_exchange (&_record_status, rs, Recording)) {
 
                        _last_record_location = _transport_frame;
                if (g_atomic_int_compare_and_exchange (&_record_status, rs, Recording)) {
 
                        _last_record_location = _transport_frame;
@@ -1779,6 +1949,13 @@ Session::enable_record ()
        }
 }
 
        }
 }
 
+void
+Session::set_all_tracks_record_enabled (bool enable )
+{
+       boost::shared_ptr<RouteList> rl = routes.reader();
+       set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), enable, Controllable::NoGroup);
+}
+
 void
 Session::disable_record (bool rt_context, bool force)
 {
 void
 Session::disable_record (bool rt_context, bool force)
 {
@@ -1786,7 +1963,7 @@ Session::disable_record (bool rt_context, bool force)
 
        if ((rs = (RecordState) g_atomic_int_get (&_record_status)) != Disabled) {
 
 
        if ((rs = (RecordState) g_atomic_int_get (&_record_status)) != Disabled) {
 
-               if ((!Config->get_latched_record_enable () && !play_loop) || force) {
+               if (!Config->get_latched_record_enable () || force) {
                        g_atomic_int_set (&_record_status, Disabled);
                        send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordExit));
                } else {
                        g_atomic_int_set (&_record_status, Disabled);
                        send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordExit));
                } else {
@@ -1853,59 +2030,55 @@ framepos_t
 Session::audible_frame () const
 {
        framepos_t ret;
 Session::audible_frame () const
 {
        framepos_t ret;
-       framepos_t tf;
-       framecnt_t offset;
 
 
-       offset = worst_playback_latency ();
+       frameoffset_t offset = worst_playback_latency (); // - _engine.samples_since_cycle_start ();
+       offset *= transport_speed ();
 
        if (synced_to_engine()) {
                /* Note: this is basically just sync-to-JACK */
 
        if (synced_to_engine()) {
                /* Note: this is basically just sync-to-JACK */
-               tf = _engine.transport_frame();
+               ret = _engine.transport_frame();
        } else {
        } else {
-               tf = _transport_frame;
+               ret = _transport_frame;
        }
 
        }
 
-       ret = tf;
-
-       if (!non_realtime_work_pending()) {
-
-               /* MOVING */
+       if (transport_rolling()) {
+               ret -= offset;
 
                /* Check to see if we have passed the first guaranteed
 
                /* Check to see if we have passed the first guaranteed
-                  audible frame past our last start position. if not,
-                  return that last start point because in terms
-                  of audible frames, we have not moved yet.
-
-                  `Start position' in this context means the time we last
-                  either started, located, or changed transport direction.
-               */
+                * audible frame past our last start position. if not,
+                * return that last start point because in terms
+                * of audible frames, we have not moved yet.
+                *
+                * `Start position' in this context means the time we last
+                * either started, located, or changed transport direction.
+                */
 
                if (_transport_speed > 0.0f) {
 
                        if (!play_loop || !have_looped) {
 
                if (_transport_speed > 0.0f) {
 
                        if (!play_loop || !have_looped) {
-                               if (tf < _last_roll_or_reversal_location + offset) {
+                               if (ret < _last_roll_or_reversal_location) {
                                        return _last_roll_or_reversal_location;
                                }
                                        return _last_roll_or_reversal_location;
                                }
+                       } else {
+                               // latent loops
+                               Location *location = _locations->auto_loop_location();
+                               frameoffset_t lo = location->start() - ret;
+                               if (lo > 0) {
+                                       ret = location->end () - lo;
+                               }
                        }
 
                        }
 
-
-                       /* forwards */
-                       ret -= offset;
-
                } else if (_transport_speed < 0.0f) {
 
                        /* XXX wot? no backward looping? */
 
                } else if (_transport_speed < 0.0f) {
 
                        /* XXX wot? no backward looping? */
 
-                       if (tf > _last_roll_or_reversal_location - offset) {
+                       if (ret > _last_roll_or_reversal_location) {
                                return _last_roll_or_reversal_location;
                                return _last_roll_or_reversal_location;
-                       } else {
-                               /* backwards */
-                               ret += offset;
                        }
                }
        }
 
                        }
                }
        }
 
-       return ret;
+       return std::max ((framepos_t)0, ret);
 }
 
 void
 }
 
 void
@@ -1918,14 +2091,19 @@ Session::set_frame_rate (framecnt_t frames_per_second)
                here.
        */
 
                here.
        */
 
-       _base_frame_rate = frames_per_second;
+       if (_base_frame_rate == 0) {
+               _base_frame_rate = frames_per_second;
+       }
+       else if (_base_frame_rate != frames_per_second && frames_per_second != _nominal_frame_rate) {
+               NotifyAboutSampleRateMismatch (_base_frame_rate, frames_per_second);
+       }
        _nominal_frame_rate = frames_per_second;
 
        sync_time_vars();
 
        clear_clicks ();
        reset_write_sources (false);
        _nominal_frame_rate = frames_per_second;
 
        sync_time_vars();
 
        clear_clicks ();
        reset_write_sources (false);
-       
+
        // XXX we need some equivalent to this, somehow
        // SndFileSource::setup_standard_crossfades (frames_per_second);
 
        // XXX we need some equivalent to this, somehow
        // SndFileSource::setup_standard_crossfades (frames_per_second);
 
@@ -1942,7 +2120,7 @@ Session::set_block_size (pframes_t nframes)
           ::process(). It is therefore fine to do things that block
           here.
        */
           ::process(). It is therefore fine to do things that block
           here.
        */
-       
+
        {
                current_block_size = nframes;
 
        {
                current_block_size = nframes;
 
@@ -2029,6 +2207,10 @@ Session::resort_routes ()
                return;
        }
 
                return;
        }
 
+       if (_route_deletion_in_progress) {
+               return;
+       }
+
        {
                RCUWriter<RouteList> writer (routes);
                boost::shared_ptr<RouteList> r = writer.get_copy ();
        {
                RCUWriter<RouteList> writer (routes);
                boost::shared_ptr<RouteList> r = writer.get_copy ();
@@ -2037,16 +2219,18 @@ Session::resort_routes ()
        }
 
 #ifndef NDEBUG
        }
 
 #ifndef NDEBUG
-       boost::shared_ptr<RouteList> rl = routes.reader ();
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               DEBUG_TRACE (DEBUG::Graph, string_compose ("%1 fed by ...\n", (*i)->name()));
+       if (DEBUG_ENABLED(DEBUG::Graph)) {
+               boost::shared_ptr<RouteList> rl = routes.reader ();
+               for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                       DEBUG_TRACE (DEBUG::Graph, string_compose ("%1 fed by ...\n", (*i)->name()));
 
 
-               const Route::FedBy& fb ((*i)->fed_by());
+                       const Route::FedBy& fb ((*i)->fed_by());
 
 
-               for (Route::FedBy::const_iterator f = fb.begin(); f != fb.end(); ++f) {
-                       boost::shared_ptr<Route> sf = f->r.lock();
-                       if (sf) {
-                               DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 (sends only ? %2)\n", sf->name(), f->sends_only));
+                       for (Route::FedBy::const_iterator f = fb.begin(); f != fb.end(); ++f) {
+                               boost::shared_ptr<Route> sf = f->r.lock();
+                               if (sf) {
+                                       DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 (sends only ? %2)\n", sf->name(), f->sends_only));
+                               }
                        }
                }
        }
                        }
                }
        }
@@ -2065,7 +2249,7 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
        /* We are going to build a directed graph of our routes;
           this is where the edges of that graph are put.
        */
        /* We are going to build a directed graph of our routes;
           this is where the edges of that graph are put.
        */
-       
+
        GraphEdges edges;
 
        /* Go through all routes doing two things:
        GraphEdges edges;
 
        /* Go through all routes doing two things:
@@ -2078,7 +2262,7 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
         *    routes directly or indirectly feed them.  This information
         *    is used by the solo code.
         */
         *    routes directly or indirectly feed them.  This information
         *    is used by the solo code.
         */
-          
+
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
 
                /* Clear out the route's list of direct or indirect feeds */
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
 
                /* Clear out the route's list of direct or indirect feeds */
@@ -2102,7 +2286,7 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
 
        /* Attempt a topological sort of the route graph */
        boost::shared_ptr<RouteList> sorted_routes = topological_sort (r, edges);
 
        /* Attempt a topological sort of the route graph */
        boost::shared_ptr<RouteList> sorted_routes = topological_sort (r, edges);
-       
+
        if (sorted_routes) {
                /* We got a satisfactory topological sort, so there is no feedback;
                   use this new graph.
        if (sorted_routes) {
                /* We got a satisfactory topological sort, so there is no feedback;
                   use this new graph.
@@ -2113,7 +2297,7 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
                if (_process_graph) {
                        _process_graph->rechain (sorted_routes, edges);
                }
                if (_process_graph) {
                        _process_graph->rechain (sorted_routes, edges);
                }
-               
+
                _current_route_graph = edges;
 
                /* Complete the building of the routes' lists of what directly
                _current_route_graph = edges;
 
                /* Complete the building of the routes' lists of what directly
@@ -2128,8 +2312,7 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
 #ifndef NDEBUG
                DEBUG_TRACE (DEBUG::Graph, "Routes resorted, order follows:\n");
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
 #ifndef NDEBUG
                DEBUG_TRACE (DEBUG::Graph, "Routes resorted, order follows:\n");
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 signal order %2\n",
-                                                                  (*i)->name(), (*i)->order_key ()));
+                       DEBUG_TRACE (DEBUG::Graph, string_compose ("\t%1 presentation order %2\n", (*i)->name(), (*i)->presentation_info().order()));
                }
 #endif
 
                }
 #endif
 
@@ -2144,7 +2327,7 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
                   so the solo code will think that everything is still connected
                   as it was before.
                */
                   so the solo code will think that everything is still connected
                   as it was before.
                */
-               
+
                FeedbackDetected (); /* EMIT SIGNAL */
        }
 
                FeedbackDetected (); /* EMIT SIGNAL */
        }
 
@@ -2163,23 +2346,43 @@ Session::resort_routes_using (boost::shared_ptr<RouteList> r)
  *  and \a id do not reflect a free route name.
  */
 bool
  *  and \a id do not reflect a free route name.
  */
 bool
-Session::find_route_name (string const & base, uint32_t& id, char* name, size_t name_len, bool definitely_add_number)
+Session::find_route_name (string const & base, uint32_t& id, string& name, bool definitely_add_number)
 {
 {
+       /* the base may conflict with ports that do not belong to existing
+          routes, but hidden objects like the click track. So check port names
+          before anything else.
+       */
+
+       for (vector<string>::const_iterator reserved = reserved_io_names.begin(); reserved != reserved_io_names.end(); ++reserved) {
+               if (base == *reserved) {
+                       /* Check if this reserved name already exists, and if
+                          so, disallow it without a numeric suffix.
+                       */
+                       if (route_by_name (*reserved)) {
+                               definitely_add_number = true;
+                               if (id < 1) {
+                                       id = 1;
+                               }
+                       }
+                       break;
+               }
+       }
+
        if (!definitely_add_number && route_by_name (base) == 0) {
                /* juse use the base */
        if (!definitely_add_number && route_by_name (base) == 0) {
                /* juse use the base */
-               snprintf (name, name_len, "%s", base.c_str());
+               name = base;
                return true;
        }
 
        do {
                return true;
        }
 
        do {
-               snprintf (name, name_len, "%s %" PRIu32, base.c_str(), id);
+               name = string_compose ("%1 %2", base, id);
 
                if (route_by_name (name) == 0) {
                        return true;
                }
 
                ++id;
 
                if (route_by_name (name) == 0) {
                        return true;
                }
 
                ++id;
-               
+
        } while (id < (UINT_MAX-1));
 
        return false;
        } while (id < (UINT_MAX-1));
 
        return false;
@@ -2203,24 +2406,46 @@ Session::count_existing_track_channels (ChanCount& in, ChanCount& out)
        }
 }
 
        }
 }
 
+string
+Session::default_track_name_pattern (DataType t)
+{
+       switch (t) {
+       case DataType::AUDIO:
+               if (Profile->get_trx()) {
+                       return _("Track ");
+               } else {
+                       return _("Audio ");
+               }
+               break;
+
+       case DataType::MIDI:
+               return _("MIDI ");
+       }
+
+       return "";
+}
+
 /** Caller must not hold process lock
  *  @param name_template string to use for the start of the name, or "" to use "MIDI".
  *  @param instrument plugin info for the instrument to insert pre-fader, if any
  */
 list<boost::shared_ptr<MidiTrack> >
 /** Caller must not hold process lock
  *  @param name_template string to use for the start of the name, or "" to use "MIDI".
  *  @param instrument plugin info for the instrument to insert pre-fader, if any
  */
 list<boost::shared_ptr<MidiTrack> >
-Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost::shared_ptr<PluginInfo> instrument, 
-                        TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template)
+Session::new_midi_track (const ChanCount& input, const ChanCount& output,
+                         boost::shared_ptr<PluginInfo> instrument, Plugin::PresetRecord* pset,
+                         RouteGroup* route_group, uint32_t how_many, string name_template, PresentationInfo::order_t order,
+                         TrackMode mode)
 {
 {
-       char track_name[1024];
+       string track_name;
        uint32_t track_id = 0;
        string port;
        RouteList new_routes;
        list<boost::shared_ptr<MidiTrack> > ret;
 
        uint32_t track_id = 0;
        string port;
        RouteList new_routes;
        list<boost::shared_ptr<MidiTrack> > ret;
 
-       bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("MIDI");
+       const string name_pattern = default_track_name_pattern (DataType::MIDI);
+       bool const use_number = (how_many != 1) || name_template.empty () || (name_template == name_pattern);
 
        while (how_many) {
 
        while (how_many) {
-               if (!find_route_name (name_template.empty() ? _("MIDI") : name_template, ++track_id, track_name, sizeof(track_name), use_number)) {
+               if (!find_route_name (name_template.empty() ? _("MIDI") : name_template, ++track_id, track_name, use_number)) {
                        error << "cannot find name for new midi track" << endmsg;
                        goto failed;
                }
                        error << "cannot find name for new midi track" << endmsg;
                        goto failed;
                }
@@ -2228,21 +2453,24 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
                boost::shared_ptr<MidiTrack> track;
 
                try {
                boost::shared_ptr<MidiTrack> track;
 
                try {
-                       track.reset (new MidiTrack (*this, track_name, Route::Flag (0), mode));
+                       track.reset (new MidiTrack (*this, track_name, mode));
 
                        if (track->init ()) {
                                goto failed;
                        }
 
 
                        if (track->init ()) {
                                goto failed;
                        }
 
+                       if (Profile->get_mixbus ()) {
+                               track->set_strict_io (true);
+                       }
+
                        track->use_new_diskstream();
 
                        track->use_new_diskstream();
 
-#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
-                       // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
-#endif
+                       BOOST_MARK_TRACK (track);
+
                        {
                                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                                if (track->input()->ensure_io (input, false, this)) {
                        {
                                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                                if (track->input()->ensure_io (input, false, this)) {
-                                       error << "cannot configure " << input << " out configuration for new midi track" << endmsg;     
+                                       error << "cannot configure " << input << " out configuration for new midi track" << endmsg;
                                        goto failed;
                                }
 
                                        goto failed;
                                }
 
@@ -2260,14 +2488,8 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
 
                        track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
 
 
                        track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
 
-                       if (Config->get_remote_model() == UserOrdered) {
-                               track->set_remote_control_id (next_control_id());
-                       }
-
                        new_routes.push_back (track);
                        ret.push_back (track);
                        new_routes.push_back (track);
                        ret.push_back (track);
-
-                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
                }
 
                catch (failed_constructor &err) {
                }
 
                catch (failed_constructor &err) {
@@ -2288,17 +2510,20 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
        if (!new_routes.empty()) {
                StateProtector sp (this);
                if (Profile->get_trx()) {
        if (!new_routes.empty()) {
                StateProtector sp (this);
                if (Profile->get_trx()) {
-                       add_routes (new_routes, false, false, false);
+                       add_routes (new_routes, false, false, false, order);
                } else {
                } else {
-                       add_routes (new_routes, true, true, false);
+                       add_routes (new_routes, true, true, false, order);
                }
 
                if (instrument) {
                        for (RouteList::iterator r = new_routes.begin(); r != new_routes.end(); ++r) {
                                PluginPtr plugin = instrument->load (*this);
                }
 
                if (instrument) {
                        for (RouteList::iterator r = new_routes.begin(); r != new_routes.end(); ++r) {
                                PluginPtr plugin = instrument->load (*this);
+                               if (pset) {
+                                       plugin->load_preset (*pset);
+                               }
                                boost::shared_ptr<Processor> p (new PluginInsert (*this, plugin));
                                (*r)->add_processor (p, PreFader);
                                boost::shared_ptr<Processor> p (new PluginInsert (*this, plugin));
                                (*r)->add_processor (p, PreFader);
-                               
+
                        }
                }
        }
                        }
                }
        }
@@ -2306,158 +2531,122 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
        return ret;
 }
 
        return ret;
 }
 
-void
-Session::midi_output_change_handler (IOChange change, void * /*src*/, boost::weak_ptr<Route> wmt)
+RouteList
+Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name_template, boost::shared_ptr<PluginInfo> instrument, Plugin::PresetRecord* pset,
+                         PresentationInfo::Flag flag, PresentationInfo::order_t order)
 {
 {
-        boost::shared_ptr<Route> midi_track (wmt.lock());
+       string bus_name;
+       uint32_t bus_id = 0;
+       string port;
+       RouteList ret;
 
 
-        if (!midi_track) {
-                return;
-        }
+       bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Midi Bus");
 
 
-       if ((change.type & IOChange::ConfigurationChanged) && Config->get_output_auto_connect() != ManualConnect) {
+       while (how_many) {
+               if (!find_route_name (name_template.empty () ? _("Midi Bus") : name_template, ++bus_id, bus_name, use_number)) {
+                       error << "cannot find name for new midi bus" << endmsg;
+                       goto failure;
+               }
 
 
-                if (change.after.n_audio() <= change.before.n_audio()) {
-                        return;
-                }
+               try {
+                       boost::shared_ptr<Route> bus (new Route (*this, bus_name, flag, DataType::AUDIO)); // XXX Editor::add_routes is not ready for ARDOUR::DataType::MIDI
 
 
-                /* new audio ports: make sure the audio goes somewhere useful,
-                   unless the user has no-auto-connect selected.
+                       if (bus->init ()) {
+                               goto failure;
+                       }
 
 
-                   The existing ChanCounts don't matter for this call as they are only
-                   to do with matching input and output indices, and we are only changing
-                   outputs here.
-                */
+                       if (Profile->get_mixbus ()) {
+                               bus->set_strict_io (true);
+                       }
 
 
-                ChanCount dummy;
+                       BOOST_MARK_ROUTE(bus);
 
 
-                auto_connect_route (midi_track, dummy, dummy, false, false, ChanCount(), change.before);
-        }
-}
+                       {
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
 
-/** @param connect_inputs true to connect inputs as well as outputs, false to connect just outputs.
- *  @param input_start Where to start from when auto-connecting inputs; e.g. if this is 0, auto-connect starting from input 0.
- *  @param output_start As \a input_start, but for outputs.
- */
-void
-Session::auto_connect_route (boost::shared_ptr<Route> route, ChanCount& existing_inputs, ChanCount& existing_outputs,
-                             bool with_lock, bool connect_inputs, ChanCount input_start, ChanCount output_start)
-{
-       if (!IO::connecting_legal) {
-               return;
-       }
+                               if (bus->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
+                                       error << _("cannot configure new midi bus input") << endmsg;
+                                       goto failure;
+                               }
 
 
-       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
 
 
-       if (with_lock) {
-               lm.acquire ();
-       }
+                               if (bus->output()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
+                                       error << _("cannot configure new midi bus output") << endmsg;
+                                       goto failure;
+                               }
+                       }
 
 
-       /* If both inputs and outputs are auto-connected to physical ports,
-          use the max of input and output offsets to ensure auto-connected
-          port numbers always match up (e.g. the first audio input and the
-          first audio output of the route will have the same physical
-          port number).  Otherwise just use the lowest input or output
-          offset possible.
-       */
+                       if (route_group) {
+                               route_group->add (bus);
+                       }
 
 
-       DEBUG_TRACE (DEBUG::Graph,
-                    string_compose("Auto-connect: existing in = %1 out = %2\n",
-                                   existing_inputs, existing_outputs));
+                       bus->add_internal_return ();
+                       ret.push_back (bus);
+               }
 
 
-       const bool in_out_physical =
-               (Config->get_input_auto_connect() & AutoConnectPhysical)
-               && (Config->get_output_auto_connect() & AutoConnectPhysical)
-               && connect_inputs;
-
-       const ChanCount in_offset = in_out_physical
-               ? ChanCount::max(existing_inputs, existing_outputs)
-                : existing_inputs;
-
-       const ChanCount out_offset = in_out_physical
-               ? ChanCount::max(existing_inputs, existing_outputs)
-               : existing_outputs;
-
-       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-               vector<string> physinputs;
-               vector<string> physoutputs;
-
-               _engine.get_physical_outputs (*t, physoutputs);
-               _engine.get_physical_inputs (*t, physinputs);
-
-               if (!physinputs.empty() && connect_inputs) {
-                       uint32_t nphysical_in = physinputs.size();
+               catch (failed_constructor &err) {
+                       error << _("Session: could not create new audio route.") << endmsg;
+                       goto failure;
+               }
 
 
-                       DEBUG_TRACE (DEBUG::Graph,
-                                    string_compose("There are %1 physical inputs of type %2\n",
-                                                   nphysical_in, *t));
+               catch (AudioEngine::PortRegistrationFailure& pfe) {
+                       error << pfe.what() << endmsg;
+                       goto failure;
+               }
 
 
-                       for (uint32_t i = input_start.get(*t); i < route->n_inputs().get(*t) && i < nphysical_in; ++i) {
-                               string port;
 
 
-                               if (Config->get_input_auto_connect() & AutoConnectPhysical) {
-                                       DEBUG_TRACE (DEBUG::Graph,
-                                                    string_compose("Get index %1 + %2 % %3 = %4\n",
-                                                                   in_offset.get(*t), i, nphysical_in,
-                                                                   (in_offset.get(*t) + i) % nphysical_in));
-                                       port = physinputs[(in_offset.get(*t) + i) % nphysical_in];
-                               }
+               --how_many;
+       }
 
 
-                               DEBUG_TRACE (DEBUG::Graph,
-                                            string_compose("Connect route %1 IN to %2\n",
-                                                           route->name(), port));
+  failure:
+       if (!ret.empty()) {
+               StateProtector sp (this);
+               add_routes (ret, false, false, false, order);
 
 
-                               if (!port.empty() && route->input()->connect (route->input()->ports().port(*t, i), port, this)) {
-                                       break;
+               if (instrument) {
+                       for (RouteList::iterator r = ret.begin(); r != ret.end(); ++r) {
+                               PluginPtr plugin = instrument->load (*this);
+                               if (pset) {
+                                       plugin->load_preset (*pset);
                                }
                                }
-
-                                ChanCount one_added (*t, 1);
-                                existing_inputs += one_added;
+                               boost::shared_ptr<Processor> p (new PluginInsert (*this, plugin));
+                               (*r)->add_processor (p, PreFader);
                        }
                }
                        }
                }
+       }
 
 
-               if (!physoutputs.empty()) {
-                       uint32_t nphysical_out = physoutputs.size();
-                       for (uint32_t i = output_start.get(*t); i < route->n_outputs().get(*t); ++i) {
-                               string port;
+       return ret;
 
 
-                               /* Waves Tracks:
-                                * do not create new connections if we reached the limit of physical outputs
-                                * in Multi Out mode
-                                */
+}
 
 
-                               if (!(Config->get_output_auto_connect() & AutoConnectMaster) &&
-                                   ARDOUR::Profile->get_trx () &&
-                                   existing_outputs.get(*t) == nphysical_out ) {
-                                       break;
-                               }
 
 
-                               if ((*t) == DataType::MIDI && (Config->get_output_auto_connect() & AutoConnectPhysical)) {
-                                       port = physoutputs[(out_offset.get(*t) + i) % nphysical_out];
-                               } else if ((*t) == DataType::AUDIO && (Config->get_output_auto_connect() & AutoConnectMaster)) {
-                                        /* master bus is audio only */
-                                       if (_master_out && _master_out->n_inputs().get(*t) > 0) {
-                                               port = _master_out->input()->ports().port(*t,
-                                                               i % _master_out->input()->n_ports().get(*t))->name();
-                                       }
-                               }
+void
+Session::midi_output_change_handler (IOChange change, void * /*src*/, boost::weak_ptr<Route> wmt)
+{
+       boost::shared_ptr<Route> midi_track (wmt.lock());
 
 
-                               DEBUG_TRACE (DEBUG::Graph,
-                                            string_compose("Connect route %1 OUT to %2\n",
-                                                           route->name(), port));
+       if (!midi_track) {
+               return;
+       }
 
 
-                               if (!port.empty() && route->output()->connect (route->output()->ports().port(*t, i), port, this)) {
-                                       break;
-                               }
+       if ((change.type & IOChange::ConfigurationChanged) && Config->get_output_auto_connect() != ManualConnect) {
 
 
-                                ChanCount one_added (*t, 1);
-                                existing_outputs += one_added;
-                       }
+               if (change.after.n_audio() <= change.before.n_audio()) {
+                       return;
                }
                }
+
+               /* new audio ports: make sure the audio goes somewhere useful,
+                * unless the user has no-auto-connect selected.
+                *
+                * The existing ChanCounts don't matter for this call as they are only
+                * to do with matching input and output indices, and we are only changing
+                * outputs here.
+                */
+               auto_connect_route (midi_track, false, ChanCount(), change.before);
        }
 }
 
        }
 }
 
-#ifdef USE_TRACKS_CODE_FEATURES 
+#ifdef USE_TRACKS_CODE_FEATURES
 
 static bool
 compare_routes_by_remote_id (const boost::shared_ptr<Route>& route1, const boost::shared_ptr<Route>& route2)
 
 static bool
 compare_routes_by_remote_id (const boost::shared_ptr<Route>& route1, const boost::shared_ptr<Route>& route2)
@@ -2472,42 +2661,42 @@ Session::reconnect_existing_routes (bool withLock, bool reconnect_master, bool r
        if (!IO::connecting_legal) {
                return;
        }
        if (!IO::connecting_legal) {
                return;
        }
-    
+
        // if we are deleting routes we will call this once at the end
        if (_route_deletion_in_progress) {
                return;
        }
        // if we are deleting routes we will call this once at the end
        if (_route_deletion_in_progress) {
                return;
        }
-    
+
        Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
        Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
-    
+
        if (withLock) {
                lm.acquire ();
        }
        if (withLock) {
                lm.acquire ();
        }
-    
+
        // We need to disconnect the route's inputs and outputs first
        // basing on autoconnect configuration
        bool reconnectIputs = !(Config->get_input_auto_connect() & ManualConnect) && reconnect_inputs;
        bool reconnectOutputs = !(Config->get_output_auto_connect() & ManualConnect) && reconnect_outputs;
        // We need to disconnect the route's inputs and outputs first
        // basing on autoconnect configuration
        bool reconnectIputs = !(Config->get_input_auto_connect() & ManualConnect) && reconnect_inputs;
        bool reconnectOutputs = !(Config->get_output_auto_connect() & ManualConnect) && reconnect_outputs;
-    
+
        ChanCount existing_inputs;
        ChanCount existing_outputs;
        count_existing_track_channels (existing_inputs, existing_outputs);
        ChanCount existing_inputs;
        ChanCount existing_outputs;
        count_existing_track_channels (existing_inputs, existing_outputs);
-    
+
        //ChanCount inputs = ChanCount::ZERO;
        //ChanCount outputs = ChanCount::ZERO;
        //ChanCount inputs = ChanCount::ZERO;
        //ChanCount outputs = ChanCount::ZERO;
-    
+
        RouteList existing_routes = *routes.reader ();
        existing_routes.sort (compare_routes_by_remote_id);
        RouteList existing_routes = *routes.reader ();
        existing_routes.sort (compare_routes_by_remote_id);
-    
+
        {
                PBD::Unwinder<bool> protect_ignore_changes (_reconnecting_routes_in_progress, true);
 
                vector<string> physinputs;
                vector<string> physoutputs;
        {
                PBD::Unwinder<bool> protect_ignore_changes (_reconnecting_routes_in_progress, true);
 
                vector<string> physinputs;
                vector<string> physoutputs;
-        
+
                EngineStateController::instance()->get_physical_audio_outputs(physoutputs);
                EngineStateController::instance()->get_physical_audio_inputs(physinputs);
                EngineStateController::instance()->get_physical_audio_outputs(physoutputs);
                EngineStateController::instance()->get_physical_audio_inputs(physinputs);
-                
+
                uint32_t input_n = 0;
                uint32_t output_n = 0;
                RouteList::iterator rIter = existing_routes.begin();
                uint32_t input_n = 0;
                uint32_t output_n = 0;
                RouteList::iterator rIter = existing_routes.begin();
@@ -2523,52 +2712,52 @@ Session::reconnect_existing_routes (bool withLock, bool reconnect_master, bool r
                        } else if (current_output_auto_connection == AutoConnectMaster) {
                                (*rIter)->amp()->activate();
                        }
                        } else if (current_output_auto_connection == AutoConnectMaster) {
                                (*rIter)->amp()->activate();
                        }
-            
+
                        if (reconnectIputs) {
                                (*rIter)->input()->disconnect (this); //GZ: check this; could be heavy
                        if (reconnectIputs) {
                                (*rIter)->input()->disconnect (this); //GZ: check this; could be heavy
-                
+
                                for (uint32_t route_input_n = 0; route_input_n < (*rIter)->n_inputs().get(DataType::AUDIO); ++route_input_n) {
                                for (uint32_t route_input_n = 0; route_input_n < (*rIter)->n_inputs().get(DataType::AUDIO); ++route_input_n) {
-                    
+
                                        if (current_input_auto_connection & AutoConnectPhysical) {
                                        if (current_input_auto_connection & AutoConnectPhysical) {
-                        
+
                                                if ( input_n == physinputs.size() ) {
                                                        break;
                                                }
                                                if ( input_n == physinputs.size() ) {
                                                        break;
                                                }
-                        
+
                                                string port = physinputs[input_n];
                                                string port = physinputs[input_n];
-                    
+
                                                if (port.empty() ) {
                                                        error << "Physical Input number "<< input_n << " is unavailable and cannot be connected" << endmsg;
                                                }
                                                if (port.empty() ) {
                                                        error << "Physical Input number "<< input_n << " is unavailable and cannot be connected" << endmsg;
                                                }
-                        
+
                                                //GZ: check this; could be heavy
                                                (*rIter)->input()->connect ((*rIter)->input()->ports().port(DataType::AUDIO, route_input_n), port, this);
                                                ++input_n;
                                        }
                                }
                        }
                                                //GZ: check this; could be heavy
                                                (*rIter)->input()->connect ((*rIter)->input()->ports().port(DataType::AUDIO, route_input_n), port, this);
                                                ++input_n;
                                        }
                                }
                        }
-            
+
                        if (reconnectOutputs) {
                        if (reconnectOutputs) {
-                
+
                                //normalize route ouptuts: reduce the amount outputs to be equal to the amount of inputs
                                if (current_output_auto_connection & AutoConnectPhysical) {
                                //normalize route ouptuts: reduce the amount outputs to be equal to the amount of inputs
                                if (current_output_auto_connection & AutoConnectPhysical) {
-                
+
                                        //GZ: check this; could be heavy
                                        (*rIter)->output()->disconnect (this);
                                        size_t route_inputs_count = (*rIter)->n_inputs().get(DataType::AUDIO);
                                        //GZ: check this; could be heavy
                                        (*rIter)->output()->disconnect (this);
                                        size_t route_inputs_count = (*rIter)->n_inputs().get(DataType::AUDIO);
-                    
+
                                        //GZ: check this; could be heavy
                                        (*rIter)->output()->ensure_io(ChanCount(DataType::AUDIO, route_inputs_count), false, this );
                                        //GZ: check this; could be heavy
                                        (*rIter)->output()->ensure_io(ChanCount(DataType::AUDIO, route_inputs_count), false, this );
-               
+
                                } else if (current_output_auto_connection & AutoConnectMaster){
                                } else if (current_output_auto_connection & AutoConnectMaster){
-                    
+
                                        if (!reconnect_master) {
                                                continue;
                                        }
                                        if (!reconnect_master) {
                                                continue;
                                        }
-                    
+
                                        //GZ: check this; could be heavy
                                        (*rIter)->output()->disconnect (this);
                                        //GZ: check this; could be heavy
                                        (*rIter)->output()->disconnect (this);
-                    
+
                                        if (_master_out) {
                                                uint32_t master_inputs_count = _master_out->n_inputs().get(DataType::AUDIO);
                                                (*rIter)->output()->ensure_io(ChanCount(DataType::AUDIO, master_inputs_count), false, this );
                                        if (_master_out) {
                                                uint32_t master_inputs_count = _master_out->n_inputs().get(DataType::AUDIO);
                                                (*rIter)->output()->ensure_io(ChanCount(DataType::AUDIO, master_inputs_count), false, this );
@@ -2577,54 +2766,52 @@ Session::reconnect_existing_routes (bool withLock, bool reconnect_master, bool r
                                                break;
                                        }
                                }
                                                break;
                                        }
                                }
-                
+
                                for (uint32_t route_output_n = 0; route_output_n < (*rIter)->n_outputs().get(DataType::AUDIO); ++route_output_n) {
                                        if (current_output_auto_connection & AutoConnectPhysical) {
                                for (uint32_t route_output_n = 0; route_output_n < (*rIter)->n_outputs().get(DataType::AUDIO); ++route_output_n) {
                                        if (current_output_auto_connection & AutoConnectPhysical) {
-                        
+
                                                if ( output_n == physoutputs.size() ) {
                                                        break;
                                                }
                                                if ( output_n == physoutputs.size() ) {
                                                        break;
                                                }
-                        
+
                                                string port = physoutputs[output_n];
                                                string port = physoutputs[output_n];
-                        
+
                                                if (port.empty() ) {
                                                        error << "Physical Output number "<< output_n << " is unavailable and cannot be connected" << endmsg;
                                                }
                                                if (port.empty() ) {
                                                        error << "Physical Output number "<< output_n << " is unavailable and cannot be connected" << endmsg;
                                                }
-                    
+
                                                //GZ: check this; could be heavy
                                                (*rIter)->output()->connect ((*rIter)->output()->ports().port(DataType::AUDIO, route_output_n), port, this);
                                                ++output_n;
                                                //GZ: check this; could be heavy
                                                (*rIter)->output()->connect ((*rIter)->output()->ports().port(DataType::AUDIO, route_output_n), port, this);
                                                ++output_n;
-                        
+
                                        } else if (current_output_auto_connection & AutoConnectMaster) {
                                        } else if (current_output_auto_connection & AutoConnectMaster) {
-                  
+
                                                if ( route_output_n == _master_out->n_inputs().get(DataType::AUDIO) ) {
                                                        break;
                                                }
                                                if ( route_output_n == _master_out->n_inputs().get(DataType::AUDIO) ) {
                                                        break;
                                                }
-                        
+
                                                // connect to master bus
                                                string port = _master_out->input()->ports().port(DataType::AUDIO, route_output_n)->name();
                                                // connect to master bus
                                                string port = _master_out->input()->ports().port(DataType::AUDIO, route_output_n)->name();
-                    
+
                                                if (port.empty() ) {
                                                        error << "MasterBus Input number "<< route_output_n << " is unavailable and cannot be connected" << endmsg;
                                                }
                                                if (port.empty() ) {
                                                        error << "MasterBus Input number "<< route_output_n << " is unavailable and cannot be connected" << endmsg;
                                                }
-                        
-                            
+
+
                                                //GZ: check this; could be heavy
                                                (*rIter)->output()->connect ((*rIter)->output()->ports().port(DataType::AUDIO, route_output_n), port, this);
                                                //GZ: check this; could be heavy
                                                (*rIter)->output()->connect ((*rIter)->output()->ports().port(DataType::AUDIO, route_output_n), port, this);
-                            
+
                                        }
                                }
                        }
                                        }
                                }
                        }
-            
-                       //auto_connect_route (*rIter, inputs, outputs, false, reconnectIputs);
                }
                }
-        
+
                _master_out->output()->disconnect (this);
                auto_connect_master_bus ();
        }
                _master_out->output()->disconnect (this);
                auto_connect_master_bus ();
        }
-    
+
        graph_reordered ();
        graph_reordered ();
-    
+
        session_routes_reconnected (); /* EMIT SIGNAL */
 }
 
        session_routes_reconnected (); /* EMIT SIGNAL */
 }
 
@@ -2632,16 +2819,16 @@ void
 Session::reconnect_midi_scene_ports(bool inputs)
 {
     if (inputs ) {
 Session::reconnect_midi_scene_ports(bool inputs)
 {
     if (inputs ) {
-        
+
         boost::shared_ptr<MidiPort> scene_in_ptr = scene_in();
         if (scene_in_ptr) {
             scene_in_ptr->disconnect_all ();
         boost::shared_ptr<MidiPort> scene_in_ptr = scene_in();
         if (scene_in_ptr) {
             scene_in_ptr->disconnect_all ();
-            
+
             std::vector<EngineStateController::MidiPortState> midi_port_states;
             EngineStateController::instance()->get_physical_midi_input_states (midi_port_states);
             std::vector<EngineStateController::MidiPortState> midi_port_states;
             EngineStateController::instance()->get_physical_midi_input_states (midi_port_states);
-            
+
             std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
             std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
-            
+
             for (; state_iter != midi_port_states.end(); ++state_iter) {
                 if (state_iter->active && state_iter->available && state_iter->scene_connected) {
                     scene_in_ptr->connect (state_iter->name);
             for (; state_iter != midi_port_states.end(); ++state_iter) {
                 if (state_iter->active && state_iter->available && state_iter->scene_connected) {
                     scene_in_ptr->connect (state_iter->name);
@@ -2650,17 +2837,17 @@ Session::reconnect_midi_scene_ports(bool inputs)
         }
 
     } else {
         }
 
     } else {
-        
+
         boost::shared_ptr<MidiPort> scene_out_ptr = scene_out();
         boost::shared_ptr<MidiPort> scene_out_ptr = scene_out();
-        
+
         if (scene_out_ptr ) {
             scene_out_ptr->disconnect_all ();
 
             std::vector<EngineStateController::MidiPortState> midi_port_states;
             EngineStateController::instance()->get_physical_midi_output_states (midi_port_states);
         if (scene_out_ptr ) {
             scene_out_ptr->disconnect_all ();
 
             std::vector<EngineStateController::MidiPortState> midi_port_states;
             EngineStateController::instance()->get_physical_midi_output_states (midi_port_states);
-            
+
             std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
             std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
-            
+
             for (; state_iter != midi_port_states.end(); ++state_iter) {
                 if (state_iter->active && state_iter->available && state_iter->scene_connected) {
                     scene_out_ptr->connect (state_iter->name);
             for (; state_iter != midi_port_states.end(); ++state_iter) {
                 if (state_iter->active && state_iter->available && state_iter->scene_connected) {
                     scene_out_ptr->connect (state_iter->name);
@@ -2671,66 +2858,67 @@ Session::reconnect_midi_scene_ports(bool inputs)
 }
 
 void
 }
 
 void
-Session::reconnect_mtc_ports()
+Session::reconnect_mtc_ports ()
 {
 {
-#if 0
        boost::shared_ptr<MidiPort> mtc_in_ptr = _midi_ports->mtc_input_port();
 
        boost::shared_ptr<MidiPort> mtc_in_ptr = _midi_ports->mtc_input_port();
 
-       if (mtc_in_ptr) {
-               mtc_in_ptr->disconnect_all ();
-        
-               std::vector<EngineStateController::MidiPortState> midi_port_states;
-               EngineStateController::instance()->get_physical_midi_input_states (midi_port_states);
-        
-               std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
-        
-               for (; state_iter != midi_port_states.end(); ++state_iter) {
-                       if (state_iter->available && state_iter->mtc_in) {
-                               mtc_in_ptr->connect (state_iter->name);
-                       }
-               }
-        
-               if (!_midi_ports->mtc_input_port ()->connected () &&
-                   config.get_external_sync () &&
-                   (Config->get_sync_source () == MTC) ) {
-                       config.set_external_sync (false);
-               }
-               if ( ARDOUR::Profile->get_trx () ) {
-                       // Tracks need this signal to update timecode_source_dropdown
-                       MtcOrLtcInputPortChanged (); //emit signal
+       if (!mtc_in_ptr) {
+               return;
+       }
+
+       mtc_in_ptr->disconnect_all ();
+
+       std::vector<EngineStateController::MidiPortState> midi_port_states;
+       EngineStateController::instance()->get_physical_midi_input_states (midi_port_states);
+
+       std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
+
+       for (; state_iter != midi_port_states.end(); ++state_iter) {
+               if (state_iter->available && state_iter->mtc_in) {
+                       mtc_in_ptr->connect (state_iter->name);
                }
        }
                }
        }
-#endif
+
+       if (!_midi_ports->mtc_input_port ()->connected () &&
+           config.get_external_sync () &&
+           (Config->get_sync_source () == MTC) ) {
+               config.set_external_sync (false);
+       }
+
+       if ( ARDOUR::Profile->get_trx () ) {
+               // Tracks need this signal to update timecode_source_dropdown
+               MtcOrLtcInputPortChanged (); //emit signal
+       }
 }
 
 void
 Session::reconnect_mmc_ports(bool inputs)
 {
        if (inputs ) { // get all enabled midi input ports
 }
 
 void
 Session::reconnect_mmc_ports(bool inputs)
 {
        if (inputs ) { // get all enabled midi input ports
-        
+
                boost::shared_ptr<MidiPort> mmc_in_ptr = _midi_ports->mmc_in();
                if (mmc_in_ptr) {
                        mmc_in_ptr->disconnect_all ();
                        std::vector<std::string> enabled_midi_inputs;
                        EngineStateController::instance()->get_physical_midi_inputs (enabled_midi_inputs);
                boost::shared_ptr<MidiPort> mmc_in_ptr = _midi_ports->mmc_in();
                if (mmc_in_ptr) {
                        mmc_in_ptr->disconnect_all ();
                        std::vector<std::string> enabled_midi_inputs;
                        EngineStateController::instance()->get_physical_midi_inputs (enabled_midi_inputs);
-            
+
                        std::vector<std::string>::iterator port_iter = enabled_midi_inputs.begin();
                        std::vector<std::string>::iterator port_iter = enabled_midi_inputs.begin();
-            
+
                        for (; port_iter != enabled_midi_inputs.end(); ++port_iter) {
                                mmc_in_ptr->connect (*port_iter);
                        }
 
                }
        } else { // get all enabled midi output ports
                        for (; port_iter != enabled_midi_inputs.end(); ++port_iter) {
                                mmc_in_ptr->connect (*port_iter);
                        }
 
                }
        } else { // get all enabled midi output ports
-        
+
                boost::shared_ptr<MidiPort> mmc_out_ptr = _midi_ports->mmc_out();
                if (mmc_out_ptr ) {
                        mmc_out_ptr->disconnect_all ();
                        std::vector<std::string> enabled_midi_outputs;
                        EngineStateController::instance()->get_physical_midi_outputs (enabled_midi_outputs);
                boost::shared_ptr<MidiPort> mmc_out_ptr = _midi_ports->mmc_out();
                if (mmc_out_ptr ) {
                        mmc_out_ptr->disconnect_all ();
                        std::vector<std::string> enabled_midi_outputs;
                        EngineStateController::instance()->get_physical_midi_outputs (enabled_midi_outputs);
-            
+
                        std::vector<std::string>::iterator port_iter = enabled_midi_outputs.begin();
                        std::vector<std::string>::iterator port_iter = enabled_midi_outputs.begin();
-            
+
                        for (; port_iter != enabled_midi_outputs.end(); ++port_iter) {
                                mmc_out_ptr->connect (*port_iter);
                        }
                        for (; port_iter != enabled_midi_outputs.end(); ++port_iter) {
                                mmc_out_ptr->connect (*port_iter);
                        }
@@ -2740,32 +2928,53 @@ Session::reconnect_mmc_ports(bool inputs)
 
 #endif
 
 
 #endif
 
+void
+Session::ensure_route_presentation_info_gap (PresentationInfo::order_t first_new_order, uint32_t how_many)
+{
+       if (first_new_order == PresentationInfo::max_order) {
+               /* adding at end, no worries */
+               return;
+       }
+
+       /* create a gap in the presentation info to accomodate @param how_many
+        * new objects.
+        */
+       StripableList sl;
+       get_stripables (sl);
+
+       for (StripableList::iterator si = sl.begin(); si != sl.end(); ++si) {
+               boost::shared_ptr<Stripable> s (*si);
+
+               if (s->is_monitor() || s->is_auditioner()) {
+                       continue;
+               }
+
+               if (s->presentation_info().order () >= first_new_order) {
+                       s->set_presentation_order (s->presentation_info().order () + how_many);
+               }
+       }
+}
+
 /** Caller must not hold process lock
  *  @param name_template string to use for the start of the name, or "" to use "Audio".
  */
 list< boost::shared_ptr<AudioTrack> >
 /** Caller must not hold process lock
  *  @param name_template string to use for the start of the name, or "" to use "Audio".
  */
 list< boost::shared_ptr<AudioTrack> >
-Session::new_audio_track (int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group, 
-                         uint32_t how_many, string name_template)
+Session::new_audio_track (int input_channels, int output_channels, RouteGroup* route_group,
+                          uint32_t how_many, string name_template, PresentationInfo::order_t order,
+                          TrackMode mode)
 {
 {
-       char track_name[1024];
+       string track_name;
        uint32_t track_id = 0;
        string port;
        RouteList new_routes;
        list<boost::shared_ptr<AudioTrack> > ret;
 
        uint32_t track_id = 0;
        string port;
        RouteList new_routes;
        list<boost::shared_ptr<AudioTrack> > ret;
 
-       string name_pattern;
+       const string name_pattern = default_track_name_pattern (DataType::AUDIO);
+       bool const use_number = (how_many != 1) || name_template.empty () || (name_template == name_pattern);
 
 
-       if (Profile->get_trx() ) {
-               name_pattern = "Track ";
-       } else {
-               name_pattern = "Audio ";
-       }
-    
-       bool const use_number = (how_many != 1) || name_template.empty () || name_template == _(name_pattern.c_str() );
-       
        while (how_many) {
 
        while (how_many) {
 
-               if (!find_route_name (name_template.empty() ? _(name_pattern.c_str()) : name_template, ++track_id, track_name, sizeof(track_name), use_number)) {
+               if (!find_route_name (name_template.empty() ? _(name_pattern.c_str()) : name_template, ++track_id, track_name, use_number)) {
                        error << "cannot find name for new audio track" << endmsg;
                        goto failed;
                }
                        error << "cannot find name for new audio track" << endmsg;
                        goto failed;
                }
@@ -2773,12 +2982,16 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                boost::shared_ptr<AudioTrack> track;
 
                try {
                boost::shared_ptr<AudioTrack> track;
 
                try {
-                       track.reset (new AudioTrack (*this, track_name, Route::Flag (0), mode));
+                       track.reset (new AudioTrack (*this, track_name, mode));
 
                        if (track->init ()) {
                                goto failed;
                        }
 
 
                        if (track->init ()) {
                                goto failed;
                        }
 
+                       if (Profile->get_mixbus ()) {
+                               track->set_strict_io (true);
+                       }
+
                        if (ARDOUR::Profile->get_trx ()) {
                                // TRACKS considers it's not a USE CASE, it's
                                // a piece of behavior of the session model:
                        if (ARDOUR::Profile->get_trx ()) {
                                // TRACKS considers it's not a USE CASE, it's
                                // a piece of behavior of the session model:
@@ -2789,15 +3002,14 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                                //  0 for Stereo Out mode
                                //  0 Multi Out mode
                                if (Config->get_output_auto_connect() & AutoConnectMaster) {
                                //  0 for Stereo Out mode
                                //  0 Multi Out mode
                                if (Config->get_output_auto_connect() & AutoConnectMaster) {
-                                       track->set_gain (dB_to_coefficient (0), 0);
+                                       track->gain_control()->set_value (dB_to_coefficient (0), Controllable::NoGroup);
                                }
                        }
 
                        track->use_new_diskstream();
 
                                }
                        }
 
                        track->use_new_diskstream();
 
-#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
-                       // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
-#endif
+                       BOOST_MARK_TRACK (track);
+
                        {
                                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                        {
                                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
@@ -2825,14 +3037,9 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                        track->non_realtime_input_change();
 
                        track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
                        track->non_realtime_input_change();
 
                        track->DiskstreamChanged.connect_same_thread (*this, boost::bind (&Session::resort_routes, this));
-                       if (Config->get_remote_model() == UserOrdered) {
-                               track->set_remote_control_id (next_control_id());
-                       }
 
                        new_routes.push_back (track);
                        ret.push_back (track);
 
                        new_routes.push_back (track);
                        ret.push_back (track);
-
-                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
                }
 
                catch (failed_constructor &err) {
                }
 
                catch (failed_constructor &err) {
@@ -2853,9 +3060,9 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
        if (!new_routes.empty()) {
                StateProtector sp (this);
                if (Profile->get_trx()) {
        if (!new_routes.empty()) {
                StateProtector sp (this);
                if (Profile->get_trx()) {
-                       add_routes (new_routes, false, false, false);
+                       add_routes (new_routes, false, false, false, order);
                } else {
                } else {
-                       add_routes (new_routes, true, true, false);
+                       add_routes (new_routes, true, true, false, order);
                }
        }
 
                }
        }
 
@@ -2866,31 +3073,35 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
  *  @param name_template string to use for the start of the name, or "" to use "Bus".
  */
 RouteList
  *  @param name_template string to use for the start of the name, or "" to use "Bus".
  */
 RouteList
-Session::new_audio_route (int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many, string name_template)
+Session::new_audio_route (int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many, string name_template,
+                          PresentationInfo::Flag flags, PresentationInfo::order_t order)
 {
 {
-       char bus_name[32];
+       string bus_name;
        uint32_t bus_id = 0;
        string port;
        RouteList ret;
 
        bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Bus");
        uint32_t bus_id = 0;
        string port;
        RouteList ret;
 
        bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Bus");
-       
+
        while (how_many) {
        while (how_many) {
-               if (!find_route_name (name_template.empty () ? _("Bus") : name_template, ++bus_id, bus_name, sizeof(bus_name), use_number)) {
+               if (!find_route_name (name_template.empty () ? _("Bus") : name_template, ++bus_id, bus_name, use_number)) {
                        error << "cannot find name for new audio bus" << endmsg;
                        goto failure;
                }
 
                try {
                        error << "cannot find name for new audio bus" << endmsg;
                        goto failure;
                }
 
                try {
-                       boost::shared_ptr<Route> bus (new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO));
+                       boost::shared_ptr<Route> bus (new Route (*this, bus_name, flags, DataType::AUDIO));
 
                        if (bus->init ()) {
                                goto failure;
                        }
 
 
                        if (bus->init ()) {
                                goto failure;
                        }
 
-#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
-                       // boost_debug_shared_ptr_mark_interesting (bus.get(), "Route");
-#endif
+                       if (Profile->get_mixbus ()) {
+                               bus->set_strict_io (true);
+                       }
+
+                       BOOST_MARK_ROUTE(bus);
+
                        {
                                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                        {
                                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
@@ -2913,20 +3124,11 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
                        if (route_group) {
                                route_group->add (bus);
                        }
                        if (route_group) {
                                route_group->add (bus);
                        }
-                       if (Config->get_remote_model() == UserOrdered) {
-                               bus->set_remote_control_id (next_control_id());
-                       }
 
                        bus->add_internal_return ();
 
                        bus->add_internal_return ();
-
                        ret.push_back (bus);
                        ret.push_back (bus);
-                       
-                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
-
-                       ARDOUR::GUIIdle ();
                }
 
                }
 
-
                catch (failed_constructor &err) {
                        error << _("Session: could not create new audio route.") << endmsg;
                        goto failure;
                catch (failed_constructor &err) {
                        error << _("Session: could not create new audio route.") << endmsg;
                        goto failure;
@@ -2945,9 +3147,9 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
        if (!ret.empty()) {
                StateProtector sp (this);
                if (Profile->get_trx()) {
        if (!ret.empty()) {
                StateProtector sp (this);
                if (Profile->get_trx()) {
-                       add_routes (ret, false, false, false);
+                       add_routes (ret, false, false, false, order);
                } else {
                } else {
-                       add_routes (ret, false, true, true); // autoconnect // outputs only
+                       add_routes (ret, false, true, true, order); // autoconnect // outputs only
                }
        }
 
                }
        }
 
@@ -2956,33 +3158,39 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
 }
 
 RouteList
 }
 
 RouteList
-Session::new_route_from_template (uint32_t how_many, const std::string& template_path, const std::string& name_base)
+Session::new_route_from_template (uint32_t how_many, const std::string& template_path, const std::string& name_base, PlaylistDisposition pd)
 {
 {
-       RouteList ret;
-       uint32_t control_id;
        XMLTree tree;
        XMLTree tree;
-       uint32_t number = 0;
-       const uint32_t being_added = how_many;
 
        if (!tree.read (template_path.c_str())) {
 
        if (!tree.read (template_path.c_str())) {
-               return ret;
+               return RouteList();
        }
 
        }
 
-       XMLNode* node = tree.root();
+       return new_route_from_template (how_many, *tree.root(), name_base, pd);
+}
 
 
+RouteList
+Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::string& name_base, PlaylistDisposition pd)
+{
+       RouteList ret;
+       uint32_t number = 0;
+       const uint32_t being_added = how_many;
+       /* This will prevent the use of any existing XML-provided PBD::ID
+          values by Stateful.
+       */
+       Stateful::ForceIDRegeneration force_ids;
        IO::disable_connecting ();
 
        IO::disable_connecting ();
 
-       control_id = next_control_id ();
-
        while (how_many) {
 
        while (how_many) {
 
-               XMLNode node_copy (*node);
+               /* We're going to modify the node contents a bit so take a
+                * copy. The node may be re-used when duplicating more than once.
+                */
 
 
-               /* Remove IDs of everything so that new ones are used */
-               node_copy.remove_property_recursively (X_("id"));
+               XMLNode node_copy (node);
 
                try {
 
                try {
-                       char name[32];
+                       string name;
 
                        if (!name_base.empty()) {
 
 
                        if (!name_base.empty()) {
 
@@ -2991,7 +3199,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                                 * numbered, via the final parameter.
                                 */
 
                                 * numbered, via the final parameter.
                                 */
 
-                               if (!find_route_name (name_base.c_str(), ++number, name, sizeof(name), (being_added > 1))) {
+                               if (!find_route_name (name_base.c_str(), ++number, name, (being_added > 1))) {
                                        fatal << _("Session: UINT_MAX routes? impossible!") << endmsg;
                                        /*NOTREACHDE*/
                                }
                                        fatal << _("Session: UINT_MAX routes? impossible!") << endmsg;
                                        /*NOTREACHDE*/
                                }
@@ -2999,28 +3207,82 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                        } else {
 
                                string const route_name  = node_copy.property(X_("name"))->value ();
                        } else {
 
                                string const route_name  = node_copy.property(X_("name"))->value ();
-                       
+
                                /* generate a new name by adding a number to the end of the template name */
                                /* generate a new name by adding a number to the end of the template name */
-                               if (!find_route_name (route_name.c_str(), ++number, name, sizeof(name), true)) {
+                               if (!find_route_name (route_name.c_str(), ++number, name, true)) {
                                        fatal << _("Session: UINT_MAX routes? impossible!") << endmsg;
                                        abort(); /*NOTREACHED*/
                                }
                        }
 
                        /* set this name in the XML description that we are about to use */
                                        fatal << _("Session: UINT_MAX routes? impossible!") << endmsg;
                                        abort(); /*NOTREACHED*/
                                }
                        }
 
                        /* set this name in the XML description that we are about to use */
-                       Route::set_name_in_state (node_copy, name);
+
+                       bool rename_playlist;
+                       switch (pd) {
+                       case NewPlaylist:
+                               rename_playlist = true;
+                               break;
+                       default:
+                       case CopyPlaylist:
+                       case SharePlaylist:
+                               rename_playlist = false;
+                       }
+
+                       Route::set_name_in_state (node_copy, name, rename_playlist);
 
                        /* trim bitslots from listen sends so that new ones are used */
                        XMLNodeList children = node_copy.children ();
                        for (XMLNodeList::iterator i = children.begin(); i != children.end(); ++i) {
                                if ((*i)->name() == X_("Processor")) {
 
                        /* trim bitslots from listen sends so that new ones are used */
                        XMLNodeList children = node_copy.children ();
                        for (XMLNodeList::iterator i = children.begin(); i != children.end(); ++i) {
                                if ((*i)->name() == X_("Processor")) {
-                                       XMLProperty* role = (*i)->property (X_("role"));
+                                       /* ForceIDRegeneration does not catch the following */
+                                       XMLProperty const * role = (*i)->property (X_("role"));
+                                       XMLProperty const * type = (*i)->property (X_("type"));
+                                       if (role && role->value() == X_("Aux")) {
+                                               /* check if the target bus exists.
+                                                * we should not save aux-sends in templates.
+                                                */
+                                               XMLProperty const * target = (*i)->property (X_("target"));
+                                               if (!target) {
+                                                       (*i)->add_property ("type", "dangling-aux-send");
+                                                       continue;
+                                               }
+                                               boost::shared_ptr<Route> r = route_by_id (target->value());
+                                               if (!r || boost::dynamic_pointer_cast<Track>(r)) {
+                                                       (*i)->add_property ("type", "dangling-aux-send");
+                                                       continue;
+                                               }
+                                       }
                                        if (role && role->value() == X_("Listen")) {
                                                (*i)->remove_property (X_("bitslot"));
                                        }
                                        if (role && role->value() == X_("Listen")) {
                                                (*i)->remove_property (X_("bitslot"));
                                        }
+                                       else if (role && (role->value() == X_("Send") || role->value() == X_("Aux"))) {
+                                               char buf[32];
+                                               Delivery::Role xrole;
+                                               uint32_t bitslot = 0;
+                                               xrole = Delivery::Role (string_2_enum (role->value(), xrole));
+                                               std::string name = Send::name_and_id_new_send(*this, xrole, bitslot, false);
+                                               snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
+                                               (*i)->remove_property (X_("bitslot"));
+                                               (*i)->remove_property (X_("name"));
+                                               (*i)->add_property ("bitslot", buf);
+                                               (*i)->add_property ("name", name);
+                                       }
+                                       else if (type && type->value() == X_("intreturn")) {
+                                               (*i)->remove_property (X_("bitslot"));
+                                               (*i)->add_property ("ignore-bitslot", "1");
+                                       }
+                                       else if (type && type->value() == X_("return")) {
+                                               // Return::set_state() generates a new one
+                                               (*i)->remove_property (X_("bitslot"));
+                                       }
+                                       else if (type && type->value() == X_("port")) {
+                                               // PortInsert::set_state() handles the bitslot
+                                               (*i)->remove_property (X_("bitslot"));
+                                               (*i)->add_property ("ignore-name", "1");
+                                       }
                                }
                        }
                                }
                        }
-                       
+
                        boost::shared_ptr<Route> route (XMLRouteFactory (node_copy, 3000));
 
                        if (route == 0) {
                        boost::shared_ptr<Route> route (XMLRouteFactory (node_copy, 3000));
 
                        if (route == 0) {
@@ -3043,12 +3305,22 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                                route->output()->changed (change, this);
                        }
 
                                route->output()->changed (change, this);
                        }
 
-                       route->set_remote_control_id (control_id);
-                       ++control_id;
+                       boost::shared_ptr<Track> track;
 
 
-                       ret.push_back (route);
+                       if ((track = boost::dynamic_pointer_cast<Track> (route))) {
+                               switch (pd) {
+                               case NewPlaylist:
+                                       track->use_new_playlist ();
+                                       break;
+                               case CopyPlaylist:
+                                       track->use_copy_playlist ();
+                                       break;
+                               case SharePlaylist:
+                                       break;
+                               }
+                       };
 
 
-                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
+                       ret.push_back (route);
                }
 
                catch (failed_constructor &err) {
                }
 
                catch (failed_constructor &err) {
@@ -3068,9 +3340,9 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
        if (!ret.empty()) {
                StateProtector sp (this);
                if (Profile->get_trx()) {
        if (!ret.empty()) {
                StateProtector sp (this);
                if (Profile->get_trx()) {
-                       add_routes (ret, false, false, false);
+                       add_routes (ret, false, false, false, PresentationInfo::max_order);
                } else {
                } else {
-                       add_routes (ret, true, true, false);
+                       add_routes (ret, true, true, false, PresentationInfo::max_order);
                }
                IO::enable_connecting ();
        }
                }
                IO::enable_connecting ();
        }
@@ -3079,11 +3351,11 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
 }
 
 void
 }
 
 void
-Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, bool save)
+Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, bool save, PresentationInfo::order_t order)
 {
        try {
                PBD::Unwinder<bool> aip (_adding_routes_in_progress, true);
 {
        try {
                PBD::Unwinder<bool> aip (_adding_routes_in_progress, true);
-               add_routes_inner (new_routes, input_auto_connect, output_auto_connect);
+               add_routes_inner (new_routes, input_auto_connect, output_auto_connect, order);
 
        } catch (...) {
                error << _("Adding new tracks/busses failed") << endmsg;
 
        } catch (...) {
                error << _("Adding new tracks/busses failed") << endmsg;
@@ -3093,61 +3365,60 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
 
        update_latency (true);
        update_latency (false);
 
        update_latency (true);
        update_latency (false);
-               
+
        set_dirty();
        set_dirty();
-       
+
        if (save) {
                save_state (_current_snapshot_name);
        }
        if (save) {
                save_state (_current_snapshot_name);
        }
-       
-       reassign_track_numbers();
 
        update_route_record_state ();
 
        update_route_record_state ();
-    
+
        RouteAdded (new_routes); /* EMIT SIGNAL */
 }
 
 void
        RouteAdded (new_routes); /* EMIT SIGNAL */
 }
 
 void
-Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect)
+Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, PresentationInfo::order_t order)
 {
 {
-        ChanCount existing_inputs;
-        ChanCount existing_outputs;
-       uint32_t order = next_control_id();
-
-       if (_order_hint > -1) {
-               order = _order_hint;
-               _order_hint = -1;
-       }
+       ChanCount existing_inputs;
+       ChanCount existing_outputs;
+       uint32_t n_routes;
+       uint32_t added = 0;
 
 
-        count_existing_track_channels (existing_inputs, existing_outputs);
+       count_existing_track_channels (existing_inputs, existing_outputs);
 
        {
                RCUWriter<RouteList> writer (routes);
                boost::shared_ptr<RouteList> r = writer.get_copy ();
                r->insert (r->end(), new_routes.begin(), new_routes.end());
 
        {
                RCUWriter<RouteList> writer (routes);
                boost::shared_ptr<RouteList> r = writer.get_copy ();
                r->insert (r->end(), new_routes.begin(), new_routes.end());
+               n_routes = r->size();
 
                /* if there is no control out and we're not in the middle of loading,
 
                /* if there is no control out and we're not in the middle of loading,
-                  resort the graph here. if there is a control out, we will resort
-                  toward the end of this method. if we are in the middle of loading,
-                  we will resort when done.
-               */
+                * resort the graph here. if there is a control out, we will resort
+                * toward the end of this method. if we are in the middle of loading,
+                * we will resort when done.
+                */
 
                if (!_monitor_out && IO::connecting_legal) {
                        resort_routes_using (r);
                }
        }
 
 
                if (!_monitor_out && IO::connecting_legal) {
                        resort_routes_using (r);
                }
        }
 
-       for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
+       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("ensure order gap starting at %1 for %2\n", order, new_routes.size()));
+       ensure_route_presentation_info_gap (order, new_routes.size());
+
+       for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x, ++added) {
 
                boost::weak_ptr<Route> wpr (*x);
                boost::shared_ptr<Route> r (*x);
 
 
                boost::weak_ptr<Route> wpr (*x);
                boost::shared_ptr<Route> r (*x);
 
-               r->listen_changed.connect_same_thread (*this, boost::bind (&Session::route_listen_changed, this, _1, wpr));
-               r->solo_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_changed, this, _1, _2, wpr));
-               r->solo_isolated_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_isolated_changed, this, _1, wpr));
-               r->mute_changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this, _1));
+               r->solo_control()->Changed.connect_same_thread (*this, boost::bind (&Session::route_solo_changed, this, _1, _2,wpr));
+               r->solo_isolate_control()->Changed.connect_same_thread (*this, boost::bind (&Session::route_solo_isolated_changed, this, wpr));
+               r->mute_control()->Changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this));
+
                r->output()->changed.connect_same_thread (*this, boost::bind (&Session::set_worst_io_latencies_x, this, _1, _2));
                r->processors_changed.connect_same_thread (*this, boost::bind (&Session::route_processors_changed, this, _1));
                r->output()->changed.connect_same_thread (*this, boost::bind (&Session::set_worst_io_latencies_x, this, _1, _2));
                r->processors_changed.connect_same_thread (*this, boost::bind (&Session::route_processors_changed, this, _1));
+               r->processor_latency_changed.connect_same_thread (*this, boost::bind (&Session::queue_latency_recompute, this));
 
                if (r->is_master()) {
                        _master_out = r;
 
                if (r->is_master()) {
                        _master_out = r;
@@ -3161,52 +3432,72 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
                if (tr) {
                        tr->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::track_playlist_changed, this, boost::weak_ptr<Track> (tr)));
                        track_playlist_changed (boost::weak_ptr<Track> (tr));
                if (tr) {
                        tr->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::track_playlist_changed, this, boost::weak_ptr<Track> (tr)));
                        track_playlist_changed (boost::weak_ptr<Track> (tr));
-                       tr->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_route_record_state, this));
+                       tr->rec_enable_control()->Changed.connect_same_thread (*this, boost::bind (&Session::update_route_record_state, this));
 
                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (tr);
                        if (mt) {
                                mt->StepEditStatusChange.connect_same_thread (*this, boost::bind (&Session::step_edit_status_change, this, _1));
 
                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (tr);
                        if (mt) {
                                mt->StepEditStatusChange.connect_same_thread (*this, boost::bind (&Session::step_edit_status_change, this, _1));
-                                mt->output()->changed.connect_same_thread (*this, boost::bind (&Session::midi_output_change_handler, this, _1, _2, boost::weak_ptr<Route>(mt)));
+                               mt->output()->changed.connect_same_thread (*this, boost::bind (&Session::midi_output_change_handler, this, _1, _2, boost::weak_ptr<Route>(mt)));
                        }
                }
 
                        }
                }
 
+               if (!r->presentation_info().special()) {
 
 
-               if (input_auto_connect || output_auto_connect) {
-                       auto_connect_route (r, existing_inputs, existing_outputs, true, input_auto_connect);
-               }
+                       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("checking PI state for %1\n", r->name()));
 
 
-               /* order keys are a GUI responsibility but we need to set up
-                  reasonable defaults because they also affect the remote control
-                  ID in most situations.
-               */
+                       /* presentation info order may already have been set from XML */
+
+                       if (!r->presentation_info().order_set()) {
 
 
-               if (!r->has_order_key ()) {
-                       if (r->is_auditioner()) {
-                               /* use an arbitrarily high value */
-                               r->set_order_key (UINT_MAX);
+                               if (order == PresentationInfo::max_order) {
+                                       /* just add to the end */
+                                       r->set_presentation_order (n_routes + added, false);
+                                       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order not set, set to NR %1 + %2 = %3\n", n_routes, added, n_routes + added));
+                               } else {
+                                       r->set_presentation_order (order + added);
+                                       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order not set, set to %1 + %2 = %3\n", order, added, order + added));
+                               }
                        } else {
                        } else {
-                               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("while adding, set %1 to order key %2\n", r->name(), order));
-                               r->set_order_key (order);
-                               order++;
+                               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("group order already set to %1\n", r->presentation_info().order()));
                        }
                }
 
                        }
                }
 
+#if !defined(__APPLE__) && !defined(__FreeBSD__)
+               /* clang complains: 'operator<<' should be declared prior to the call site or in an associated namespace of one of its
+                * arguments std::ostream& operator<<(std::ostream& o, ARDOUR::PresentationInfo const& rid)"
+                */
+               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("added route %1, group order %2 type %3 (summary: %4)\n",
+                                                              r->name(),
+                                                              r->presentation_info().order(),
+                                                              enum_2_string (r->presentation_info().flags()),
+                                                              r->presentation_info()));
+#endif
+
+
+               if (input_auto_connect || output_auto_connect) {
+                       auto_connect_route (r, input_auto_connect, ChanCount (), ChanCount (), existing_inputs, existing_outputs);
+                       existing_inputs += r->n_inputs();
+                       existing_outputs += r->n_outputs();
+               }
+
                ARDOUR::GUIIdle ();
        }
 
        if (_monitor_out && IO::connecting_legal) {
                ARDOUR::GUIIdle ();
        }
 
        if (_monitor_out && IO::connecting_legal) {
-               Glib::Threads::Mutex::Lock lm (_engine.process_lock());         
-               
+               Glib::Threads::Mutex::Lock lm (_engine.process_lock());
+
                for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
                        if ((*x)->is_monitor()) {
                                /* relax */
                        } else if ((*x)->is_master()) {
                for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
                        if ((*x)->is_monitor()) {
                                /* relax */
                        } else if ((*x)->is_master()) {
-                                       /* relax */
+                               /* relax */
                        } else {
                                (*x)->enable_monitor_send ();
                        }
                }
        }
                        } else {
                                (*x)->enable_monitor_send ();
                        }
                }
        }
+
+       reassign_track_numbers ();
 }
 
 void
 }
 
 void
@@ -3217,7 +3508,7 @@ Session::globally_set_send_gains_to_zero (boost::shared_ptr<Route> dest)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
-                       s->amp()->gain_control()->set_value (GAIN_COEFF_ZERO);
+                       s->amp()->gain_control()->set_value (GAIN_COEFF_ZERO, Controllable::NoGroup);
                }
        }
 }
                }
        }
 }
@@ -3230,7 +3521,7 @@ Session::globally_set_send_gains_to_unity (boost::shared_ptr<Route> dest)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
-                       s->amp()->gain_control()->set_value (GAIN_COEFF_UNITY);
+                       s->amp()->gain_control()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup);
                }
        }
 }
                }
        }
 }
@@ -3243,7 +3534,7 @@ Session::globally_set_send_gains_from_track(boost::shared_ptr<Route> dest)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
-                       s->amp()->gain_control()->set_value ((*i)->gain_control()->get_value());
+                       s->amp()->gain_control()->set_value ((*i)->gain_control()->get_value(), Controllable::NoGroup);
                }
        }
 }
                }
        }
 }
@@ -3295,48 +3586,46 @@ Session::add_internal_send (boost::shared_ptr<Route> dest, boost::shared_ptr<Pro
        graph_reordered ();
 }
 
        graph_reordered ();
 }
 
-
 void
 Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
 {
        { // RCU Writer scope
 void
 Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
 {
        { // RCU Writer scope
+               PBD::Unwinder<bool> uw_flag (_route_deletion_in_progress, true);
                RCUWriter<RouteList> writer (routes);
                boost::shared_ptr<RouteList> rs = writer.get_copy ();
                RCUWriter<RouteList> writer (routes);
                boost::shared_ptr<RouteList> rs = writer.get_copy ();
-        
-        
+
+
                for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) {
                for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) {
-            
+
                        if (*iter == _master_out) {
                                continue;
                        }
                        if (*iter == _master_out) {
                                continue;
                        }
-            
-                       (*iter)->set_solo (false, this);
-            
+
+                       (*iter)->solo_control()->set_value (0.0, Controllable::NoGroup);
+
                        rs->remove (*iter);
                        rs->remove (*iter);
-            
+
                        /* deleting the master out seems like a dumb
                           idea, but its more of a UI policy issue
                           than our concern.
                        */
                        /* deleting the master out seems like a dumb
                           idea, but its more of a UI policy issue
                           than our concern.
                        */
-            
+
                        if (*iter == _master_out) {
                                _master_out = boost::shared_ptr<Route> ();
                        }
                        if (*iter == _master_out) {
                                _master_out = boost::shared_ptr<Route> ();
                        }
-            
+
                        if (*iter == _monitor_out) {
                                _monitor_out.reset ();
                        }
 
                        if (*iter == _monitor_out) {
                                _monitor_out.reset ();
                        }
 
-                       update_route_solo_state ();
-            
                        // We need to disconnect the route's inputs and outputs
                        // We need to disconnect the route's inputs and outputs
-            
+
                        (*iter)->input()->disconnect (0);
                        (*iter)->output()->disconnect (0);
                        (*iter)->input()->disconnect (0);
                        (*iter)->output()->disconnect (0);
-            
+
                        /* if the route had internal sends sending to it, remove them */
                        if ((*iter)->internal_return()) {
                        /* if the route had internal sends sending to it, remove them */
                        if ((*iter)->internal_return()) {
-                
+
                                boost::shared_ptr<RouteList> r = routes.reader ();
                                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                                        boost::shared_ptr<Send> s = (*i)->internal_send_for (*iter);
                                boost::shared_ptr<RouteList> r = routes.reader ();
                                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                                        boost::shared_ptr<Send> s = (*i)->internal_send_for (*iter);
@@ -3345,31 +3634,30 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
                                        }
                                }
                        }
                                        }
                                }
                        }
-            
+
                        /* if the monitoring section had a pointer to this route, remove it */
                        if (_monitor_out && !(*iter)->is_master() && !(*iter)->is_monitor()) {
                                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                                PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
                                (*iter)->remove_aux_or_listen (_monitor_out);
                        }
                        /* if the monitoring section had a pointer to this route, remove it */
                        if (_monitor_out && !(*iter)->is_master() && !(*iter)->is_monitor()) {
                                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                                PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
                                (*iter)->remove_aux_or_listen (_monitor_out);
                        }
-            
+
                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*iter);
                        if (mt && mt->step_editing()) {
                                if (_step_editors > 0) {
                                        _step_editors--;
                                }
                        }
                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*iter);
                        if (mt && mt->step_editing()) {
                                if (_step_editors > 0) {
                                        _step_editors--;
                                }
                        }
-
-                       RouteAddedOrRemoved (false); /* EMIT SIGNAL */
                }
                }
-    
+
                /* writer goes out of scope, forces route list update */
 
        } // end of RCU Writer scope
                /* writer goes out of scope, forces route list update */
 
        } // end of RCU Writer scope
-    
+
+       update_route_solo_state ();
        update_latency_compensation ();
        set_dirty();
        update_latency_compensation ();
        set_dirty();
-    
+
        /* Re-sort routes to remove the graph's current references to the one that is
         * going away, then flush old references out of the graph.
         * Wave Tracks: reconnect routes
        /* Re-sort routes to remove the graph's current references to the one that is
         * going away, then flush old references out of the graph.
         * Wave Tracks: reconnect routes
@@ -3378,36 +3666,39 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
 #ifdef USE_TRACKS_CODE_FEATURES
                reconnect_existing_routes(true, false);
 #else
 #ifdef USE_TRACKS_CODE_FEATURES
                reconnect_existing_routes(true, false);
 #else
+               routes.flush (); // maybe unsafe, see below.
                resort_routes ();
 #endif
                resort_routes ();
 #endif
-    
-       if (_process_graph) {
+
+       if (_process_graph && !(_state_of_the_state & Deletion)) {
                _process_graph->clear_other_chain ();
        }
                _process_graph->clear_other_chain ();
        }
-    
+
        /* get rid of it from the dead wood collection in the route list manager */
        /* XXX i think this is unsafe as it currently stands, but i am not sure. (pd, october 2nd, 2006) */
        /* get rid of it from the dead wood collection in the route list manager */
        /* XXX i think this is unsafe as it currently stands, but i am not sure. (pd, october 2nd, 2006) */
-    
+
        routes.flush ();
        routes.flush ();
-    
+
        /* try to cause everyone to drop their references
         * and unregister ports from the backend
         */
        /* try to cause everyone to drop their references
         * and unregister ports from the backend
         */
-       PBD::Unwinder<bool> uw_flag (_route_deletion_in_progress, true);
 
        for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) {
                (*iter)->drop_references ();
        }
 
        for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) {
                (*iter)->drop_references ();
        }
-    
-       Route::RemoteControlIDChange(); /* EMIT SIGNAL */
-    
+
+       if (_state_of_the_state & Deletion) {
+               return;
+       }
+
+       PresentationInfo::Change(); /* EMIT SIGNAL */
+
        /* save the new state of the world */
        /* save the new state of the world */
-    
+
        if (save_state (_current_snapshot_name)) {
                save_history (_current_snapshot_name);
        }
 
        if (save_state (_current_snapshot_name)) {
                save_history (_current_snapshot_name);
        }
 
-       reassign_track_numbers();
        update_route_record_state ();
 }
 
        update_route_record_state ();
 }
 
@@ -3420,30 +3711,51 @@ Session::remove_route (boost::shared_ptr<Route> route)
 }
 
 void
 }
 
 void
-Session::route_mute_changed (void* /*src*/)
+Session::route_mute_changed ()
 {
        set_dirty ();
 }
 
 void
 {
        set_dirty ();
 }
 
 void
-Session::route_listen_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
+Session::route_listen_changed (Controllable::GroupControlDisposition group_override, boost::weak_ptr<Route> wpr)
 {
 {
-       boost::shared_ptr<Route> route = wpr.lock();
+       boost::shared_ptr<Route> route (wpr.lock());
+
        if (!route) {
        if (!route) {
-               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_changed")) << endmsg;
                return;
        }
 
                return;
        }
 
-       if (route->listening_via_monitor ()) {
+       assert (Config->get_solo_control_is_listen_control());
+
+       if (route->solo_control()->soloed_by_self_or_masters()) {
 
                if (Config->get_exclusive_solo()) {
 
                if (Config->get_exclusive_solo()) {
-                       /* new listen: disable all other listen */
+
+                       RouteGroup* rg = route->route_group ();
+                       const bool group_already_accounted_for = (group_override == Controllable::ForGroup);
+
                        boost::shared_ptr<RouteList> r = routes.reader ();
                        boost::shared_ptr<RouteList> r = routes.reader ();
+
                        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                               if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                               if ((*i) == route) {
+                                       /* already changed */
                                        continue;
                                }
                                        continue;
                                }
-                               (*i)->set_listen (false, this);
+
+                               if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) {
+                                       /* route does not get solo propagated to it */
+                                       continue;
+                               }
+
+                               if ((group_already_accounted_for && (*i)->route_group() && (*i)->route_group() == rg)) {
+                                       /* this route is a part of the same solo group as the route
+                                        * that was changed. Changing that route did change or will
+                                        * change all group members appropriately, so we can ignore it
+                                        * here
+                                        */
+                                       continue;
+                               }
+                               (*i)->solo_control()->set_value (0.0, Controllable::NoGroup);
                        }
                }
 
                        }
                }
 
@@ -3456,20 +3768,19 @@ Session::route_listen_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
 
        update_route_solo_state ();
 }
 
        update_route_solo_state ();
 }
+
 void
 void
-Session::route_solo_isolated_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
+Session::route_solo_isolated_changed (boost::weak_ptr<Route> wpr)
 {
 {
-       boost::shared_ptr<Route> route = wpr.lock ();
+       boost::shared_ptr<Route> route (wpr.lock());
 
        if (!route) {
 
        if (!route) {
-               /* should not happen */
-               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_changed")) << endmsg;
                return;
        }
 
        bool send_changed = false;
 
                return;
        }
 
        bool send_changed = false;
 
-       if (route->solo_isolated()) {
+       if (route->solo_isolate_control()->solo_isolated()) {
                if (_solo_isolated_cnt == 0) {
                        send_changed = true;
                }
                if (_solo_isolated_cnt == 0) {
                        send_changed = true;
                }
@@ -3487,53 +3798,92 @@ Session::route_solo_isolated_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
 }
 
 void
 }
 
 void
-Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_ptr<Route> wpr)
+Session::route_solo_changed (bool self_solo_changed, Controllable::GroupControlDisposition group_override,  boost::weak_ptr<Route> wpr)
 {
 {
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("route solo change, self = %1\n", self_solo_change));
+       DEBUG_TRACE (DEBUG::Solo, string_compose ("route solo change, self = %1\n", self_solo_changed));
 
 
-       if (!self_solo_change) {
-               // session doesn't care about changes to soloed-by-others
+       boost::shared_ptr<Route> route (wpr.lock());
+
+       if (!route) {
                return;
        }
 
                return;
        }
 
-       if (solo_update_disabled) {
-               // We know already
-               DEBUG_TRACE (DEBUG::Solo, "solo update disabled - changed ignored\n");
+       if (Config->get_solo_control_is_listen_control()) {
+               route_listen_changed (group_override, wpr);
                return;
        }
 
                return;
        }
 
-       boost::shared_ptr<Route> route = wpr.lock ();
-       assert (route);
+       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: self %2 masters %3 transition %4\n", route->name(), route->self_soloed(), route->solo_control()->get_masters_value(), route->solo_control()->transitioned_into_solo()));
 
 
-       boost::shared_ptr<RouteList> r = routes.reader ();
-       int32_t delta;
+       if (route->solo_control()->transitioned_into_solo() == 0) {
+               /* route solo changed by upstream/downstream; not interesting
+                  to Session.
+               */
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 not self-soloed nor soloed by master (%2), ignoring\n", route->name(), route->solo_control()->get_masters_value()));
+               return;
+       }
 
 
-       if (route->self_soloed()) {
-               delta = 1;
-       } else {
-               delta = -1;
+       if (route->solo_control()->transitioned_into_solo() == 0) {
+               /* reason for being soloed changed (e.g. master went away, we
+                * took over the master state), but actual status did
+                * not. nothing to do.
+                */
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: solo change was change in reason, not status\n", route->name()));
        }
 
        }
 
+       boost::shared_ptr<RouteList> r = routes.reader ();
+       int32_t delta = route->solo_control()->transitioned_into_solo ();
+
+       /* the route may be a member of a group that has shared-solo
+        * semantics. If so, then all members of that group should follow the
+        * solo of the changed route. But ... this is optional, controlled by a
+        * Controllable::GroupControlDisposition.
+        *
+        * The first argument to the signal that this method is connected to is the
+        * GroupControlDisposition value that was used to change solo.
+        *
+        * If the solo change was done with group semantics (either InverseGroup
+        * (force the entire group to change even if the group shared solo is
+        * disabled) or UseGroup (use the group, which may or may not have the
+        * shared solo property enabled)) then as we propagate the change to
+        * the entire session we should IGNORE THE GROUP that the changed route
+        * belongs to.
+        */
+
        RouteGroup* rg = route->route_group ();
        RouteGroup* rg = route->route_group ();
-       bool leave_group_alone = (rg && rg->is_active() && rg->is_solo());
+       const bool group_already_accounted_for = (group_override == Controllable::ForGroup);
 
        if (delta == 1 && Config->get_exclusive_solo()) {
 
        if (delta == 1 && Config->get_exclusive_solo()) {
-               
+
                /* new solo: disable all other solos, but not the group if its solo-enabled */
 
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                /* new solo: disable all other solos, but not the group if its solo-enabled */
 
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner() ||
-                           (leave_group_alone && ((*i)->route_group() == rg))) {
+
+                       if ((*i) == route) {
+                               /* already changed */
+                               continue;
+                       }
+
+                       if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) {
+                               /* route does not get solo propagated to it */
+                               continue;
+                       }
+
+                       if ((group_already_accounted_for && (*i)->route_group() && (*i)->route_group() == rg)) {
+                               /* this route is a part of the same solo group as the route
+                                * that was changed. Changing that route did change or will
+                                * change all group members appropriately, so we can ignore it
+                                * here
+                                */
                                continue;
                        }
                                continue;
                        }
-                       (*i)->set_solo (false, this);
+
+                       (*i)->solo_control()->set_value (0.0, group_override);
                }
        }
 
        DEBUG_TRACE (DEBUG::Solo, string_compose ("propagate solo change, delta = %1\n", delta));
 
                }
        }
 
        DEBUG_TRACE (DEBUG::Solo, string_compose ("propagate solo change, delta = %1\n", delta));
 
-       solo_update_disabled = true;
-
        RouteList uninvolved;
 
        DEBUG_TRACE (DEBUG::Solo, string_compose ("%1\n", route->name()));
        RouteList uninvolved;
 
        DEBUG_TRACE (DEBUG::Solo, string_compose ("%1\n", route->name()));
@@ -3542,20 +3892,38 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
                bool via_sends_only;
                bool in_signal_flow;
 
                bool via_sends_only;
                bool in_signal_flow;
 
-               if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner() ||
-                   (leave_group_alone && ((*i)->route_group() == rg))) {
+               if ((*i) == route) {
+                       /* already changed */
+                       continue;
+               }
+
+               if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) {
+                       /* route does not get solo propagated to it */
+                       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 excluded from solo because iso = %2 can_solo = %3\n", (*i)->name(), (*i)->solo_isolate_control()->solo_isolated(),
+                                                                 (*i)->can_solo()));
+                       continue;
+               }
+
+               if ((group_already_accounted_for && (*i)->route_group() && (*i)->route_group() == rg)) {
+                       /* this route is a part of the same solo group as the route
+                        * that was changed. Changing that route did change or will
+                        * change all group members appropriately, so we can ignore it
+                        * here
+                        */
                        continue;
                }
 
                in_signal_flow = false;
 
                DEBUG_TRACE (DEBUG::Solo, string_compose ("check feed from %1\n", (*i)->name()));
                        continue;
                }
 
                in_signal_flow = false;
 
                DEBUG_TRACE (DEBUG::Solo, string_compose ("check feed from %1\n", (*i)->name()));
-               
+
                if ((*i)->feeds (route, &via_sends_only)) {
                        DEBUG_TRACE (DEBUG::Solo, string_compose ("\tthere is a feed from %1\n", (*i)->name()));
                        if (!via_sends_only) {
                                if (!route->soloed_by_others_upstream()) {
                if ((*i)->feeds (route, &via_sends_only)) {
                        DEBUG_TRACE (DEBUG::Solo, string_compose ("\tthere is a feed from %1\n", (*i)->name()));
                        if (!via_sends_only) {
                                if (!route->soloed_by_others_upstream()) {
-                                       (*i)->mod_solo_by_others_downstream (delta);
+                                       (*i)->solo_control()->mod_solo_by_others_downstream (delta);
+                               } else {
+                                       DEBUG_TRACE (DEBUG::Solo, "\talready soloed by others upstream\n");
                                }
                        } else {
                                DEBUG_TRACE (DEBUG::Solo, string_compose ("\tthere is a send-only feed from %1\n", (*i)->name()));
                                }
                        } else {
                                DEBUG_TRACE (DEBUG::Solo, string_compose ("\tthere is a send-only feed from %1\n", (*i)->name()));
@@ -3564,7 +3932,7 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
                } else {
                        DEBUG_TRACE (DEBUG::Solo, string_compose ("\tno feed from %1\n", (*i)->name()));
                }
                } else {
                        DEBUG_TRACE (DEBUG::Solo, string_compose ("\tno feed from %1\n", (*i)->name()));
                }
-               
+
                DEBUG_TRACE (DEBUG::Solo, string_compose ("check feed to %1\n", (*i)->name()));
 
                if (route->feeds (*i, &via_sends_only)) {
                DEBUG_TRACE (DEBUG::Solo, string_compose ("check feed to %1\n", (*i)->name()));
 
                if (route->feeds (*i, &via_sends_only)) {
@@ -3574,18 +3942,15 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
                           sends are involved.
                        */
                        DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 feeds %2 via sends only %3 sboD %4 sboU %5\n",
                           sends are involved.
                        */
                        DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 feeds %2 via sends only %3 sboD %4 sboU %5\n",
-                                                                 route->name(),
-                                                                 (*i)->name(),
-                                                                 via_sends_only,
-                                                                 route->soloed_by_others_downstream(),
-                                                                 route->soloed_by_others_upstream()));
+                                                                 route->name(),
+                                                                 (*i)->name(),
+                                                                 via_sends_only,
+                                                                 route->soloed_by_others_downstream(),
+                                                                 route->soloed_by_others_upstream()));
                        if (!via_sends_only) {
                        if (!via_sends_only) {
-                               if (!route->soloed_by_others_downstream()) {
-                                       DEBUG_TRACE (DEBUG::Solo, string_compose ("\tmod %1 by %2\n", (*i)->name(), delta));
-                                       (*i)->mod_solo_by_others_upstream (delta);
-                               } else {
-                                       DEBUG_TRACE (DEBUG::Solo, "\talready soloed by others downstream\n");
-                               }
+                               //NB. Triggers Invert Push, which handles soloed by downstream
+                               DEBUG_TRACE (DEBUG::Solo, string_compose ("\tmod %1 by %2\n", (*i)->name(), delta));
+                               (*i)->solo_control()->mod_solo_by_others_upstream (delta);
                        } else {
                                DEBUG_TRACE (DEBUG::Solo, string_compose ("\tfeed to %1 ignored, sends-only\n", (*i)->name()));
                        }
                        } else {
                                DEBUG_TRACE (DEBUG::Solo, string_compose ("\tfeed to %1 ignored, sends-only\n", (*i)->name()));
                        }
@@ -3599,7 +3964,6 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
                }
        }
 
                }
        }
 
-       solo_update_disabled = false;
        DEBUG_TRACE (DEBUG::Solo, "propagation complete\n");
 
        update_route_solo_state (r);
        DEBUG_TRACE (DEBUG::Solo, "propagation complete\n");
 
        update_route_solo_state (r);
@@ -3611,7 +3975,7 @@ Session::route_solo_changed (bool self_solo_change, void* /*src*/, boost::weak_p
        for (RouteList::iterator i = uninvolved.begin(); i != uninvolved.end(); ++i) {
                DEBUG_TRACE (DEBUG::Solo, string_compose ("mute change for %1, which neither feeds or is fed by %2\n", (*i)->name(), route->name()));
                (*i)->act_on_mute ();
        for (RouteList::iterator i = uninvolved.begin(); i != uninvolved.end(); ++i) {
                DEBUG_TRACE (DEBUG::Solo, string_compose ("mute change for %1, which neither feeds or is fed by %2\n", (*i)->name(), route->name()));
                (*i)->act_on_mute ();
-               (*i)->mute_changed (this);
+               (*i)->mute_control()->Changed (false, Controllable::NoGroup);
        }
 
        SoloChanged (); /* EMIT SIGNAL */
        }
 
        SoloChanged (); /* EMIT SIGNAL */
@@ -3624,6 +3988,7 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
        /* now figure out if anything that matters is soloed (or is "listening")*/
 
        bool something_soloed = false;
        /* now figure out if anything that matters is soloed (or is "listening")*/
 
        bool something_soloed = false;
+       bool something_listening = false;
        uint32_t listeners = 0;
        uint32_t isolated = 0;
 
        uint32_t listeners = 0;
        uint32_t isolated = 0;
 
@@ -3632,19 +3997,21 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
        }
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
        }
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (!(*i)->is_master() && !(*i)->is_monitor() && !(*i)->is_auditioner() && (*i)->self_soloed()) {
-                       something_soloed = true;
-               }
-
-               if (!(*i)->is_auditioner() && (*i)->listening_via_monitor()) {
+               if ((*i)->can_solo()) {
                        if (Config->get_solo_control_is_listen_control()) {
                        if (Config->get_solo_control_is_listen_control()) {
-                               listeners++;
+                               if ((*i)->self_soloed() || (*i)->solo_control()->get_masters_value()) {
+                                       listeners++;
+                                       something_listening = true;
+                               }
                        } else {
                        } else {
-                               (*i)->set_listen (false, this);
+                               (*i)->set_listen (false);
+                               if ((*i)->can_solo() && ((*i)->self_soloed() || (*i)->solo_control()->get_masters_value())) {
+                                       something_soloed = true;
+                               }
                        }
                }
 
                        }
                }
 
-               if ((*i)->solo_isolated()) {
+               if ((*i)->solo_isolate_control()->solo_isolated()) {
                        isolated++;
                }
        }
                        isolated++;
                }
        }
@@ -3654,6 +4021,11 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
                SoloActive (_non_soloed_outs_muted); /* EMIT SIGNAL */
        }
 
                SoloActive (_non_soloed_outs_muted); /* EMIT SIGNAL */
        }
 
+       if (something_listening != _listening) {
+               _listening = something_listening;
+               SoloActive (_listening);
+       }
+
        _listen_cnt = listeners;
 
        if (isolated != _solo_isolated_cnt) {
        _listen_cnt = listeners;
 
        if (isolated != _solo_isolated_cnt) {
@@ -3665,6 +4037,16 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
                                                  something_soloed, listeners, isolated));
 }
 
                                                  something_soloed, listeners, isolated));
 }
 
+void
+Session::get_stripables (StripableList& sl) const
+{
+       boost::shared_ptr<RouteList> r = routes.reader ();
+       sl.insert (sl.end(), r->begin(), r->end());
+
+       VCAList v = _vca_manager->vcas ();
+       sl.insert (sl.end(), v.begin(), v.end());
+}
+
 boost::shared_ptr<RouteList>
 Session::get_routes_with_internal_returns() const
 {
 boost::shared_ptr<RouteList>
 Session::get_routes_with_internal_returns() const
 {
@@ -3680,10 +4062,21 @@ Session::get_routes_with_internal_returns() const
 }
 
 bool
 }
 
 bool
-Session::io_name_is_legal (const std::string& name)
+Session::io_name_is_legal (const std::string& name) const
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
+       for (vector<string>::const_iterator reserved = reserved_io_names.begin(); reserved != reserved_io_names.end(); ++reserved) {
+               if (name == *reserved) {
+                       if (!route_by_name (*reserved)) {
+                               /* first instance of a reserved name is allowed */
+                               return true;
+                       }
+                       /* all other instances of a reserved name are not allowed */
+                       return false;
+               }
+       }
+
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((*i)->name() == name) {
                        return false;
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((*i)->name() == name) {
                        return false;
@@ -3718,19 +4111,19 @@ Session::set_exclusive_input_active (boost::shared_ptr<RouteList> rl, bool onoff
        for (RouteList::iterator rt = rl->begin(); rt != rl->end(); ++rt) {
 
                PortSet& ps ((*rt)->input()->ports());
        for (RouteList::iterator rt = rl->begin(); rt != rl->end(); ++rt) {
 
                PortSet& ps ((*rt)->input()->ports());
-               
+
                for (PortSet::iterator p = ps.begin(); p != ps.end(); ++p) {
                        p->get_connections (connections);
                }
                for (PortSet::iterator p = ps.begin(); p != ps.end(); ++p) {
                        p->get_connections (connections);
                }
-               
+
                for (vector<string>::iterator s = connections.begin(); s != connections.end(); ++s) {
                        routes_using_input_from (*s, rl2);
                }
                for (vector<string>::iterator s = connections.begin(); s != connections.end(); ++s) {
                        routes_using_input_from (*s, rl2);
                }
-               
+
                /* scan all relevant routes to see if others are on or off */
                /* scan all relevant routes to see if others are on or off */
-               
+
                bool others_are_already_on = false;
                bool others_are_already_on = false;
-               
+
                for (RouteList::iterator r = rl2.begin(); r != rl2.end(); ++r) {
 
                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*r);
                for (RouteList::iterator r = rl2.begin(); r != rl2.end(); ++r) {
 
                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*r);
@@ -3748,11 +4141,11 @@ Session::set_exclusive_input_active (boost::shared_ptr<RouteList> rl, bool onoff
                                mt->set_input_active (onoff);
                        }
                }
                                mt->set_input_active (onoff);
                        }
                }
-               
+
                if (flip_others) {
 
                        /* globally reverse other routes */
                if (flip_others) {
 
                        /* globally reverse other routes */
-                       
+
                        for (RouteList::iterator r = rl2.begin(); r != rl2.end(); ++r) {
                                if ((*r) != (*rt)) {
                                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*r);
                        for (RouteList::iterator r = rl2.begin(); r != rl2.end(); ++r) {
                                if ((*r) != (*rt)) {
                                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*r);
@@ -3778,7 +4171,7 @@ Session::routes_using_input_from (const string& str, RouteList& rl)
 }
 
 boost::shared_ptr<Route>
 }
 
 boost::shared_ptr<Route>
-Session::route_by_name (string name)
+Session::route_by_name (string name) const
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
@@ -3792,7 +4185,7 @@ Session::route_by_name (string name)
 }
 
 boost::shared_ptr<Route>
 }
 
 boost::shared_ptr<Route>
-Session::route_by_id (PBD::ID id)
+Session::route_by_id (PBD::ID id) const
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
@@ -3805,8 +4198,23 @@ Session::route_by_id (PBD::ID id)
        return boost::shared_ptr<Route> ((Route*) 0);
 }
 
        return boost::shared_ptr<Route> ((Route*) 0);
 }
 
+boost::shared_ptr<Processor>
+Session::processor_by_id (PBD::ID id) const
+{
+       boost::shared_ptr<RouteList> r = routes.reader ();
+
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               boost::shared_ptr<Processor> p = (*i)->Route::processor_by_id (id);
+               if (p) {
+                       return p;
+               }
+       }
+
+       return boost::shared_ptr<Processor> ();
+}
+
 boost::shared_ptr<Track>
 boost::shared_ptr<Track>
-Session::track_by_diskstream_id (PBD::ID id)
+Session::track_by_diskstream_id (PBD::ID id) const
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
@@ -3821,19 +4229,75 @@ Session::track_by_diskstream_id (PBD::ID id)
 }
 
 boost::shared_ptr<Route>
 }
 
 boost::shared_ptr<Route>
-Session::route_by_remote_id (uint32_t id)
+Session::get_remote_nth_route (PresentationInfo::order_t n) const
+{
+       return boost::dynamic_pointer_cast<Route> (get_remote_nth_stripable (n, PresentationInfo::Route));
+}
+
+boost::shared_ptr<Stripable>
+Session::get_remote_nth_stripable (PresentationInfo::order_t n, PresentationInfo::Flag flags) const
+{
+       StripableList sl;
+       PresentationInfo::order_t match_cnt = 0;
+
+       get_stripables (sl);
+       sl.sort (Stripable::PresentationOrderSorter());
+
+       for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
+
+               if ((*s)->presentation_info().hidden()) {
+                       /* if the caller didn't explicitly ask for hidden
+                          stripables, ignore hidden ones. This matches
+                          the semantics of the pre-PresentationOrder
+                          "get by RID" logic of Ardour 4.x and earlier.
+
+                          XXX at some point we should likely reverse
+                          the logic of the flags, because asking for "the
+                          hidden stripables" is not going to be common,
+                          whereas asking for visible ones is normal.
+                       */
+
+                       if (! (flags & PresentationInfo::Hidden)) {
+                               continue;
+                       }
+               }
+
+               if ((*s)->presentation_info().flag_match (flags)) {
+                       if (match_cnt++ == n) {
+                               return *s;
+                       }
+               }
+       }
+
+       /* there is no nth stripable that matches the given flags */
+       return boost::shared_ptr<Stripable>();
+}
+
+boost::shared_ptr<Route>
+Session::route_by_selected_count (uint32_t id) const
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if ((*i)->remote_control_id() == id) {
-                       return *i;
-               }
+               /* NOT IMPLEMENTED */
        }
 
        return boost::shared_ptr<Route> ((Route*) 0);
 }
 
        }
 
        return boost::shared_ptr<Route> ((Route*) 0);
 }
 
+struct PresentationOrderSorter {
+       bool operator() (boost::shared_ptr<Stripable> a, boost::shared_ptr<Stripable> b) {
+               if (a->presentation_info().special() && !b->presentation_info().special()) {
+                       /* a is not ordered, b is; b comes before a */
+                       return false;
+               } else if (!b->presentation_info().order_set() && a->presentation_info().order_set()) {
+                       /* b is not ordered, a is; a comes before b */
+                       return true;
+               } else {
+                       return a->presentation_info().order() < b->presentation_info().order();
+               }
+       }
+};
 
 void
 Session::reassign_track_numbers ()
 
 void
 Session::reassign_track_numbers ()
@@ -3841,7 +4305,7 @@ Session::reassign_track_numbers ()
        int64_t tn = 0;
        int64_t bn = 0;
        RouteList r (*(routes.reader ()));
        int64_t tn = 0;
        int64_t bn = 0;
        RouteList r (*(routes.reader ()));
-       SignalOrderRouteSorter sorter;
+       PresentationOrderSorter sorter;
        r.sort (sorter);
 
        StateProtector sp (this);
        r.sort (sorter);
 
        StateProtector sp (this);
@@ -3868,6 +4332,16 @@ Session::reassign_track_numbers ()
                // trigger GUI re-layout
                config.ParameterChanged("track-name-number");
        }
                // trigger GUI re-layout
                config.ParameterChanged("track-name-number");
        }
+
+#ifndef NDEBUG
+       if (DEBUG_ENABLED(DEBUG::OrderKeys)) {
+               boost::shared_ptr<RouteList> rl = routes.reader ();
+               for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 numbered %2\n", (*i)->name(), (*i)->track_number()));
+               }
+       }
+#endif /* NDEBUG */
+
 }
 
 void
 }
 
 void
@@ -3921,9 +4395,11 @@ Session::maybe_update_session_range (framepos_t a, framepos_t b)
                return;
        }
 
                return;
        }
 
+       framepos_t session_end_marker_shift_samples = session_end_shift * _nominal_frame_rate;
+
        if (_session_range_location == 0) {
 
        if (_session_range_location == 0) {
 
-               add_session_range_location (a, b);
+               set_session_range_location (a, b + session_end_marker_shift_samples);
 
        } else {
 
 
        } else {
 
@@ -3931,12 +4407,18 @@ Session::maybe_update_session_range (framepos_t a, framepos_t b)
                        _session_range_location->set_start (a);
                }
 
                        _session_range_location->set_start (a);
                }
 
-               if (b > _session_range_location->end()) {
+               if (_session_range_end_is_free && (b > _session_range_location->end())) {
                        _session_range_location->set_end (b);
                }
        }
 }
 
                        _session_range_location->set_end (b);
                }
        }
 }
 
+void
+Session::set_end_is_free (bool yn)
+{
+       _session_range_end_is_free = yn;
+}
+
 void
 Session::playlist_ranges_moved (list<Evoral::RangeMove<framepos_t> > const & ranges)
 {
 void
 Session::playlist_ranges_moved (list<Evoral::RangeMove<framepos_t> > const & ranges)
 {
@@ -4070,13 +4552,13 @@ Session::add_source (boost::shared_ptr<Source> source)
                /* yay, new source */
 
                boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (source);
                /* yay, new source */
 
                boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (source);
-               
+
                if (fs) {
                        if (!fs->within_session()) {
                                ensure_search_path_includes (Glib::path_get_dirname (fs->path()), fs->type());
                        }
                }
                if (fs) {
                        if (!fs->within_session()) {
                                ensure_search_path_includes (Glib::path_get_dirname (fs->path()), fs->type());
                        }
                }
-               
+
                set_dirty();
 
                boost::shared_ptr<AudioFileSource> afs;
                set_dirty();
 
                boost::shared_ptr<AudioFileSource> afs;
@@ -4172,7 +4654,7 @@ Session::midi_source_by_path (const std::string& path) const
                        = boost::dynamic_pointer_cast<MidiSource>(s->second);
                boost::shared_ptr<FileSource> fs
                        = boost::dynamic_pointer_cast<FileSource>(s->second);
                        = boost::dynamic_pointer_cast<MidiSource>(s->second);
                boost::shared_ptr<FileSource> fs
                        = boost::dynamic_pointer_cast<FileSource>(s->second);
-               
+
                if (ms && fs && fs->path() == path) {
                        return ms;
                }
                if (ms && fs && fs->path() == path) {
                        return ms;
                }
@@ -4199,20 +4681,31 @@ Session::count_sources_by_origin (const string& path)
        return cnt;
 }
 
        return cnt;
 }
 
+static string
+peak_file_helper (const string& peak_path, const string& file_path, const string& file_base, bool hash) {
+       if (hash) {
+               std::string checksum = Glib::Checksum::compute_checksum(Glib::Checksum::CHECKSUM_SHA1, file_path + G_DIR_SEPARATOR + file_base);
+               return Glib::build_filename (peak_path, checksum + peakfile_suffix);
+       } else {
+               return Glib::build_filename (peak_path, file_base + peakfile_suffix);
+       }
+}
+
 string
 string
-Session::peak_path (string base) const
+Session::construct_peak_filepath (const string& filepath, const bool in_session, const bool old_peak_name) const
 {
 {
-       if (Glib::path_is_absolute (base)) {
+       string interchange_dir_string = string (interchange_dir_name) + G_DIR_SEPARATOR;
+
+       if (Glib::path_is_absolute (filepath)) {
 
                /* rip the session dir from the audiofile source */
 
                string session_path;
 
                /* rip the session dir from the audiofile source */
 
                string session_path;
-               string interchange_dir_string = string (interchange_dir_name) + G_DIR_SEPARATOR;
                bool in_another_session = true;
                bool in_another_session = true;
-               
-               if (base.find (interchange_dir_string) != string::npos) {
-               
-                       session_path = Glib::path_get_dirname (base); /* now ends in audiofiles */
+
+               if (filepath.find (interchange_dir_string) != string::npos) {
+
+                       session_path = Glib::path_get_dirname (filepath); /* now ends in audiofiles */
                        session_path = Glib::path_get_dirname (session_path); /* now ends in session name */
                        session_path = Glib::path_get_dirname (session_path); /* now ends in interchange */
                        session_path = Glib::path_get_dirname (session_path); /* now has session path */
                        session_path = Glib::path_get_dirname (session_path); /* now ends in session name */
                        session_path = Glib::path_get_dirname (session_path); /* now ends in interchange */
                        session_path = Glib::path_get_dirname (session_path); /* now has session path */
@@ -4228,35 +4721,48 @@ Session::peak_path (string base) const
                } else {
                        in_another_session = false;
                }
                } else {
                        in_another_session = false;
                }
-               
+
 
                if (in_another_session) {
                        SessionDirectory sd (session_path);
 
                if (in_another_session) {
                        SessionDirectory sd (session_path);
-                       return Glib::build_filename (sd.peak_path(), Glib::path_get_basename (base) + peakfile_suffix);
+                       return peak_file_helper (sd.peak_path(), "", Glib::path_get_basename (filepath), !old_peak_name);
                }
        }
 
                }
        }
 
-       base = Glib::path_get_basename (base);
-       return Glib::build_filename (_session_dir->peak_path(), base + peakfile_suffix);
+       /* 1) if file belongs to this session
+        * it may be a relative path (interchange/...)
+        * or just basename (session_state, remove source)
+        * -> just use the basename
+        */
+       std::string filename = Glib::path_get_basename (filepath);
+       std::string path;
+
+       /* 2) if the file is outside our session dir:
+        * (imported but not copied) add the path for check-summming */
+       if (!in_session) {
+               path = Glib::path_get_dirname (filepath);
+       }
+
+       return peak_file_helper (_session_dir->peak_path(), path, Glib::path_get_basename (filepath), !old_peak_name);
 }
 
 string
 Session::new_audio_source_path_for_embedded (const std::string& path)
 {
 }
 
 string
 Session::new_audio_source_path_for_embedded (const std::string& path)
 {
-       /* embedded source: 
+       /* embedded source:
         *
         * we know that the filename is already unique because it exists
         *
         * we know that the filename is already unique because it exists
-        * out in the filesystem. 
+        * out in the filesystem.
         *
         * However, when we bring it into the session, we could get a
         * collision.
         *
         * Eg. two embedded files:
         *
         * However, when we bring it into the session, we could get a
         * collision.
         *
         * Eg. two embedded files:
-        * 
+        *
         *          /foo/bar/baz.wav
         *          /frob/nic/baz.wav
         *
         *          /foo/bar/baz.wav
         *          /frob/nic/baz.wav
         *
-        * When merged into session, these collide. 
+        * When merged into session, these collide.
         *
         * There will not be a conflict with in-memory sources
         * because when the source was created we already picked
         *
         * There will not be a conflict with in-memory sources
         * because when the source was created we already picked
@@ -4270,7 +4776,7 @@ Session::new_audio_source_path_for_embedded (const std::string& path)
        SessionDirectory sdir (get_best_session_directory_for_new_audio());
        string base = Glib::path_get_basename (path);
        string newpath = Glib::build_filename (sdir.sound_path(), base);
        SessionDirectory sdir (get_best_session_directory_for_new_audio());
        string base = Glib::path_get_basename (path);
        string newpath = Glib::build_filename (sdir.sound_path(), base);
-       
+
        if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
 
                MD5 md5;
        if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
 
                MD5 md5;
@@ -4278,14 +4784,14 @@ Session::new_audio_source_path_for_embedded (const std::string& path)
                md5.digestString (path.c_str());
                md5.writeToString ();
                base = md5.digestChars;
                md5.digestString (path.c_str());
                md5.writeToString ();
                base = md5.digestChars;
-               
+
                string ext = get_suffix (path);
 
                if (!ext.empty()) {
                        base += '.';
                        base += ext;
                }
                string ext = get_suffix (path);
 
                if (!ext.empty()) {
                        base += '.';
                        base += ext;
                }
-               
+
                newpath = Glib::build_filename (sdir.sound_path(), base);
 
                /* if this collides, we're screwed */
                newpath = Glib::build_filename (sdir.sound_path(), base);
 
                /* if this collides, we're screwed */
@@ -4300,14 +4806,14 @@ Session::new_audio_source_path_for_embedded (const std::string& path)
        return newpath;
 }
 
        return newpath;
 }
 
-/** Return true if there are no audio file sources that use @param name as 
- * the filename component of their path. 
+/** Return true if there are no audio file sources that use @param name as
+ * the filename component of their path.
  *
  * Return false otherwise.
  *
  *
  * Return false otherwise.
  *
- * This method MUST ONLY be used to check in-session, mono files since it 
+ * This method MUST ONLY be used to check in-session, mono files since it
  * hard-codes the channel of the audio file source we are looking for as zero.
  * hard-codes the channel of the audio file source we are looking for as zero.
- * 
+ *
  * If/when Ardour supports native files in non-mono formats, the logic here
  * will need to be revisited.
  */
  * If/when Ardour supports native files in non-mono formats, the logic here
  * will need to be revisited.
  */
@@ -4319,7 +4825,7 @@ Session::audio_source_name_is_unique (const string& name)
        uint32_t existing = 0;
 
        for (vector<string>::const_iterator i = sdirs.begin(); i != sdirs.end(); ++i) {
        uint32_t existing = 0;
 
        for (vector<string>::const_iterator i = sdirs.begin(); i != sdirs.end(); ++i) {
-               
+
                /* note that we search *without* the extension so that
                   we don't end up both "Audio 1-1.wav" and "Audio 1-1.caf"
                   in the event that this new name is required for
                /* note that we search *without* the extension so that
                   we don't end up both "Audio 1-1.wav" and "Audio 1-1.caf"
                   in the event that this new name is required for
@@ -4327,12 +4833,12 @@ Session::audio_source_name_is_unique (const string& name)
                */
 
                const string spath = *i;
                */
 
                const string spath = *i;
-               
+
                if (matching_unsuffixed_filename_exists_in (spath, name)) {
                        existing++;
                        break;
                }
                if (matching_unsuffixed_filename_exists_in (spath, name)) {
                        existing++;
                        break;
                }
-               
+
                /* it is possible that we have the path already
                 * assigned to a source that has not yet been written
                 * (ie. the write source for a diskstream). we have to
                /* it is possible that we have the path already
                 * assigned to a source that has not yet been written
                 * (ie. the write source for a diskstream). we have to
@@ -4341,8 +4847,8 @@ Session::audio_source_name_is_unique (const string& name)
                 * two Sources point to the same file with different
                 * notions of their removability.
                 */
                 * two Sources point to the same file with different
                 * notions of their removability.
                 */
-               
-               
+
+
                string possible_path = Glib::build_filename (spath, name);
 
                if (audio_source_by_path_and_channel (possible_path, 0)) {
                string possible_path = Glib::build_filename (spath, name);
 
                if (audio_source_by_path_and_channel (possible_path, 0)) {
@@ -4359,20 +4865,20 @@ Session::format_audio_source_name (const string& legalized_base, uint32_t nchan,
 {
        ostringstream sstr;
        const string ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
 {
        ostringstream sstr;
        const string ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
-       
+
        if (Profile->get_trx() && destructive) {
                sstr << 'T';
                sstr << setfill ('0') << setw (4) << cnt;
                sstr << legalized_base;
        } else {
                sstr << legalized_base;
        if (Profile->get_trx() && destructive) {
                sstr << 'T';
                sstr << setfill ('0') << setw (4) << cnt;
                sstr << legalized_base;
        } else {
                sstr << legalized_base;
-               
+
                if (take_required || related_exists) {
                        sstr << '-';
                        sstr << cnt;
                }
        }
                if (take_required || related_exists) {
                        sstr << '-';
                        sstr << cnt;
                }
        }
-       
+
        if (nchan == 2) {
                if (chan == 0) {
                        sstr << "%L";
        if (nchan == 2) {
                if (chan == 0) {
                        sstr << "%L";
@@ -4389,7 +4895,7 @@ Session::format_audio_source_name (const string& legalized_base, uint32_t nchan,
                        sstr << chan+1;
                }
        }
                        sstr << chan+1;
                }
        }
-       
+
        sstr << ext;
 
        return sstr.str();
        sstr << ext;
 
        return sstr.str();
@@ -4412,11 +4918,11 @@ Session::new_audio_source_path (const string& base, uint32_t nchan, uint32_t cha
        for (cnt = (destructive ? ++destructive_index : 1); cnt <= limit; ++cnt) {
 
                possible_name = format_audio_source_name (legalized, nchan, chan, destructive, take_required, cnt, some_related_source_name_exists);
        for (cnt = (destructive ? ++destructive_index : 1); cnt <= limit; ++cnt) {
 
                possible_name = format_audio_source_name (legalized, nchan, chan, destructive, take_required, cnt, some_related_source_name_exists);
-               
+
                if (audio_source_name_is_unique (possible_name)) {
                        break;
                }
                if (audio_source_name_is_unique (possible_name)) {
                        break;
                }
-               
+
                some_related_source_name_exists = true;
 
                if (cnt > limit) {
                some_related_source_name_exists = true;
 
                if (cnt > limit) {
@@ -4471,14 +4977,14 @@ Session::new_midi_source_path (const string& base)
 
                vector<space_and_path>::iterator i;
                uint32_t existing = 0;
 
                vector<space_and_path>::iterator i;
                uint32_t existing = 0;
-               
+
                for (vector<string>::const_iterator i = sdirs.begin(); i != sdirs.end(); ++i) {
 
                        snprintf (buf, sizeof(buf), "%s-%u.mid", legalized.c_str(), cnt);
                        possible_name = buf;
 
                        possible_path = Glib::build_filename (*i, possible_name);
                for (vector<string>::const_iterator i = sdirs.begin(); i != sdirs.end(); ++i) {
 
                        snprintf (buf, sizeof(buf), "%s-%u.mid", legalized.c_str(), cnt);
                        possible_name = buf;
 
                        possible_path = Glib::build_filename (*i, possible_name);
-                       
+
                        if (Glib::file_test (possible_path, Glib::FILE_TEST_EXISTS)) {
                                existing++;
                        }
                        if (Glib::file_test (possible_path, Glib::FILE_TEST_EXISTS)) {
                                existing++;
                        }
@@ -4517,7 +5023,7 @@ Session::create_audio_source_for_session (size_t n_chans, string const & base, u
 
        if (!path.empty()) {
                return boost::dynamic_pointer_cast<AudioFileSource> (
 
        if (!path.empty()) {
                return boost::dynamic_pointer_cast<AudioFileSource> (
-                       SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate()));
+                       SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate(), true, true));
        } else {
                throw failed_constructor ();
        }
        } else {
                throw failed_constructor ();
        }
@@ -4528,7 +5034,7 @@ boost::shared_ptr<MidiSource>
 Session::create_midi_source_for_session (string const & basic_name)
 {
        const string path = new_midi_source_path (basic_name);
 Session::create_midi_source_for_session (string const & basic_name)
 {
        const string path = new_midi_source_path (basic_name);
-       
+
        if (!path.empty()) {
                return boost::dynamic_pointer_cast<SMFSource> (
                        SourceFactory::createWritable (
        if (!path.empty()) {
                return boost::dynamic_pointer_cast<SMFSource> (
                        SourceFactory::createWritable (
@@ -4543,24 +5049,24 @@ boost::shared_ptr<MidiSource>
 Session::create_midi_source_by_stealing_name (boost::shared_ptr<Track> track)
 {
        /* the caller passes in the track the source will be used in,
 Session::create_midi_source_by_stealing_name (boost::shared_ptr<Track> track)
 {
        /* the caller passes in the track the source will be used in,
-          so that we can keep the numbering sane. 
-          
+          so that we can keep the numbering sane.
+
           Rationale: a track with the name "Foo" that has had N
           captures carried out so far will ALREADY have a write source
           named "Foo-N+1.mid" waiting to be used for the next capture.
           Rationale: a track with the name "Foo" that has had N
           captures carried out so far will ALREADY have a write source
           named "Foo-N+1.mid" waiting to be used for the next capture.
-          
+
           If we call new_midi_source_name() we will get "Foo-N+2". But
           there is no region corresponding to "Foo-N+1", so when
           "Foo-N+2" appears in the track, the gap presents the user
           with odd behaviour - why did it skip past Foo-N+1?
           If we call new_midi_source_name() we will get "Foo-N+2". But
           there is no region corresponding to "Foo-N+1", so when
           "Foo-N+2" appears in the track, the gap presents the user
           with odd behaviour - why did it skip past Foo-N+1?
-          
+
           We could explain this to the user in some odd way, but
           instead we rename "Foo-N+1.mid" as "Foo-N+2.mid", and then
           use "Foo-N+1" here.
           We could explain this to the user in some odd way, but
           instead we rename "Foo-N+1.mid" as "Foo-N+2.mid", and then
           use "Foo-N+1" here.
-          
+
           If that attempted rename fails, we get "Foo-N+2.mid" anyway.
        */
           If that attempted rename fails, we get "Foo-N+2.mid" anyway.
        */
-       
+
        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (track);
        assert (mt);
        std::string name = track->steal_write_source_name ();
        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (track);
        assert (mt);
        std::string name = track->steal_write_source_name ();
@@ -4590,45 +5096,269 @@ Session::add_playlist (boost::shared_ptr<Playlist> playlist, bool unused)
 
        playlists->add (playlist);
 
 
        playlists->add (playlist);
 
-       if (unused) {
-               playlist->release();
+       if (unused) {
+               playlist->release();
+       }
+
+       set_dirty();
+}
+
+void
+Session::remove_playlist (boost::weak_ptr<Playlist> weak_playlist)
+{
+       if (_state_of_the_state & Deletion) {
+               return;
+       }
+
+       boost::shared_ptr<Playlist> playlist (weak_playlist.lock());
+
+       if (!playlist) {
+               return;
+       }
+
+       playlists->remove (playlist);
+
+       set_dirty();
+}
+
+void
+Session::set_audition (boost::shared_ptr<Region> r)
+{
+       pending_audition_region = r;
+       add_post_transport_work (PostTransportAudition);
+       _butler->schedule_transport_work ();
+}
+
+void
+Session::audition_playlist ()
+{
+       SessionEvent* ev = new SessionEvent (SessionEvent::Audition, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
+       ev->region.reset ();
+       queue_event (ev);
+}
+
+
+void
+Session::register_lua_function (
+               const std::string& name,
+               const std::string& script,
+               const LuaScriptParamList& args
+               )
+{
+       Glib::Threads::Mutex::Lock lm (lua_lock);
+
+       lua_State* L = lua.getState();
+
+       const std::string& bytecode = LuaScripting::get_factory_bytecode (script);
+       luabridge::LuaRef tbl_arg (luabridge::newTable(L));
+       for (LuaScriptParamList::const_iterator i = args.begin(); i != args.end(); ++i) {
+               if ((*i)->optional && !(*i)->is_set) { continue; }
+               tbl_arg[(*i)->name] = (*i)->value;
        }
        }
-
+       (*_lua_add)(name, bytecode, tbl_arg); // throws luabridge::LuaException
        set_dirty();
 }
 
 void
        set_dirty();
 }
 
 void
-Session::remove_playlist (boost::weak_ptr<Playlist> weak_playlist)
+Session::unregister_lua_function (const std::string& name)
 {
 {
-       if (_state_of_the_state & Deletion) {
-               return;
-       }
+       Glib::Threads::Mutex::Lock lm (lua_lock);
+       (*_lua_del)(name); // throws luabridge::LuaException
+       lua.collect_garbage ();
+       set_dirty();
+}
 
 
-       boost::shared_ptr<Playlist> playlist (weak_playlist.lock());
+std::vector<std::string>
+Session::registered_lua_functions ()
+{
+       Glib::Threads::Mutex::Lock lm (lua_lock);
+       std::vector<std::string> rv;
 
 
-       if (!playlist) {
-               return;
-       }
+       try {
+               luabridge::LuaRef list ((*_lua_list)());
+               for (luabridge::Iterator i (list); !i.isNil (); ++i) {
+                       if (!i.key ().isString ()) { assert(0); continue; }
+                       rv.push_back (i.key ().cast<std::string> ());
+               }
+       } catch (luabridge::LuaException const& e) { }
+       return rv;
+}
 
 
-       playlists->remove (playlist);
+#ifndef NDEBUG
+static void _lua_print (std::string s) {
+       std::cout << "SessionLua: " << s << "\n";
+}
+#endif
 
 
-       set_dirty();
+void
+Session::try_run_lua (pframes_t nframes)
+{
+       if (_n_lua_scripts == 0) return;
+       Glib::Threads::Mutex::Lock tm (lua_lock, Glib::Threads::TRY_LOCK);
+       if (tm.locked ()) {
+               try { (*_lua_run)(nframes); } catch (luabridge::LuaException const& e) { }
+               lua.collect_garbage_step ();
+       }
 }
 
 void
 }
 
 void
-Session::set_audition (boost::shared_ptr<Region> r)
+Session::setup_lua ()
 {
 {
-       pending_audition_region = r;
-       add_post_transport_work (PostTransportAudition);
-       _butler->schedule_transport_work ();
+#ifndef NDEBUG
+       lua.Print.connect (&_lua_print);
+#endif
+       lua.tweak_rt_gc ();
+       lua.do_command (
+                       "function ArdourSession ()"
+                       "  local self = { scripts = {}, instances = {} }"
+                       ""
+                       "  local remove = function (n)"
+                       "   self.scripts[n] = nil"
+                       "   self.instances[n] = nil"
+                       "   Session:scripts_changed()" // call back
+                       "  end"
+                       ""
+                       "  local addinternal = function (n, f, a)"
+                       "   assert(type(n) == 'string', 'function-name must be string')"
+                       "   assert(type(f) == 'function', 'Given script is a not a function')"
+                       "   assert(type(a) == 'table' or type(a) == 'nil', 'Given argument is invalid')"
+                       "   assert(self.scripts[n] == nil, 'Callback \"'.. n ..'\" already exists.')"
+                       "   self.scripts[n] = { ['f'] = f, ['a'] = a }"
+                       "   local env = _ENV;  env.f = nil env.io = nil env.os = nil env.loadfile = nil env.require = nil env.dofile = nil env.package = nil env.debug = nil"
+                       "   local env = { print = print, tostring = tostring, assert = assert, ipairs = ipairs, error = error, select = select, string = string, type = type, tonumber = tonumber, collectgarbage = collectgarbage, pairs = pairs, math = math, table = table, pcall = pcall, Session = Session, PBD = PBD, Timecode = Timecode, Evoral = Evoral, C = C, ARDOUR = ARDOUR }"
+                       "   self.instances[n] = load (string.dump(f, true), nil, nil, env)(a)"
+                       "   Session:scripts_changed()" // call back
+                       "  end"
+                       ""
+                       "  local add = function (n, b, a)"
+                       "   assert(type(b) == 'string', 'ByteCode must be string')"
+                       "   load (b)()" // assigns f
+                       "   assert(type(f) == 'string', 'Assigned ByteCode must be string')"
+                       "   addinternal (n, load(f), a)"
+                       "  end"
+                       ""
+                       "  local run = function (...)"
+                       "   for n, s in pairs (self.instances) do"
+                       "     local status, err = pcall (s, ...)"
+                       "     if not status then"
+                       "       print ('fn \"'.. n .. '\": ', err)"
+                       "       remove (n)"
+                       "      end"
+                       "   end"
+                       "   collectgarbage()"
+                       "  end"
+                       ""
+                       "  local cleanup = function ()"
+                       "   self.scripts = nil"
+                       "   self.instances = nil"
+                       "  end"
+                       ""
+                       "  local list = function ()"
+                       "   local rv = {}"
+                       "   for n, _ in pairs (self.scripts) do"
+                       "     rv[n] = true"
+                       "   end"
+                       "   return rv"
+                       "  end"
+                       ""
+                       "  local function basic_serialize (o)"
+                       "    if type(o) == \"number\" then"
+                       "     return tostring(o)"
+                       "    else"
+                       "     return string.format(\"%q\", o)"
+                       "    end"
+                       "  end"
+                       ""
+                       "  local function serialize (name, value)"
+                       "   local rv = name .. ' = '"
+                       "   collectgarbage()"
+                       "   if type(value) == \"number\" or type(value) == \"string\" or type(value) == \"nil\" then"
+                       "    return rv .. basic_serialize(value) .. ' '"
+                       "   elseif type(value) == \"table\" then"
+                       "    rv = rv .. '{} '"
+                       "    for k,v in pairs(value) do"
+                       "     local fieldname = string.format(\"%s[%s]\", name, basic_serialize(k))"
+                       "     rv = rv .. serialize(fieldname, v) .. ' '"
+                       "     collectgarbage()" // string concatenation allocates a new string :(
+                       "    end"
+                       "    return rv;"
+                       "   elseif type(value) == \"function\" then"
+                       "     return rv .. string.format(\"%q\", string.dump(value, true))"
+                       "   else"
+                       "    error('cannot save a ' .. type(value))"
+                       "   end"
+                       "  end"
+                       ""
+                       ""
+                       "  local save = function ()"
+                       "   return (serialize('scripts', self.scripts))"
+                       "  end"
+                       ""
+                       "  local restore = function (state)"
+                       "   self.scripts = {}"
+                       "   load (state)()"
+                       "   for n, s in pairs (scripts) do"
+                       "    addinternal (n, load(s['f']), s['a'])"
+                       "   end"
+                       "  end"
+                       ""
+                       " return { run = run, add = add, remove = remove,"
+                 "          list = list, restore = restore, save = save, cleanup = cleanup}"
+                       " end"
+                       " "
+                       " sess = ArdourSession ()"
+                       " ArdourSession = nil"
+                       " "
+                       "function ardour () end"
+                       );
+
+       lua_State* L = lua.getState();
+
+       try {
+               luabridge::LuaRef lua_sess = luabridge::getGlobal (L, "sess");
+               lua.do_command ("sess = nil"); // hide it.
+               lua.do_command ("collectgarbage()");
+
+               _lua_run = new luabridge::LuaRef(lua_sess["run"]);
+               _lua_add = new luabridge::LuaRef(lua_sess["add"]);
+               _lua_del = new luabridge::LuaRef(lua_sess["remove"]);
+               _lua_list = new luabridge::LuaRef(lua_sess["list"]);
+               _lua_save = new luabridge::LuaRef(lua_sess["save"]);
+               _lua_load = new luabridge::LuaRef(lua_sess["restore"]);
+               _lua_cleanup = new luabridge::LuaRef(lua_sess["cleanup"]);
+       } catch (luabridge::LuaException const& e) {
+               fatal << string_compose (_("programming error: %1"),
+                               X_("Failed to setup Lua interpreter"))
+                       << endmsg;
+               abort(); /*NOTREACHED*/
+       }
+
+       LuaBindings::stddef (L);
+       LuaBindings::common (L);
+       LuaBindings::dsp (L);
+       luabridge::push <Session *> (L, this);
+       lua_setglobal (L, "Session");
 }
 
 void
 }
 
 void
-Session::audition_playlist ()
+Session::scripts_changed ()
 {
 {
-       SessionEvent* ev = new SessionEvent (SessionEvent::Audition, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
-       ev->region.reset ();
-       queue_event (ev);
+       assert (!lua_lock.trylock()); // must hold lua_lock
+
+       try {
+               luabridge::LuaRef list ((*_lua_list)());
+               int cnt = 0;
+               for (luabridge::Iterator i (list); !i.isNil (); ++i) {
+                       if (!i.key ().isString ()) { assert(0); continue; }
+                       ++cnt;
+               }
+               _n_lua_scripts = cnt;
+       } catch (luabridge::LuaException const& e) {
+               fatal << string_compose (_("programming error: %1"),
+                               X_("Indexing Lua Session Scripts failed."))
+                       << endmsg;
+               abort(); /*NOTREACHED*/
+       }
 }
 
 void
 }
 
 void
@@ -4669,7 +5399,7 @@ Session::RoutePublicOrderSorter::operator() (boost::shared_ptr<Route> a, boost::
        if (b->is_monitor()) {
                return false;
        }
        if (b->is_monitor()) {
                return false;
        }
-       return a->order_key () < b->order_key ();
+       return a->presentation_info().order() < b->presentation_info().order();
 }
 
 bool
 }
 
 bool
@@ -4690,7 +5420,7 @@ Session::graph_reordered ()
           from a set_state() call or creating new tracks. Ditto for deletion.
        */
 
           from a set_state() call or creating new tracks. Ditto for deletion.
        */
 
-       if ((_state_of_the_state & (InitialConnecting|Deletion)) || _adding_routes_in_progress || _reconnecting_routes_in_progress) {
+       if ((_state_of_the_state & (InitialConnecting|Deletion)) || _adding_routes_in_progress || _reconnecting_routes_in_progress || _route_deletion_in_progress) {
                return;
        }
 
                return;
        }
 
@@ -4726,7 +5456,7 @@ Session::available_capture_duration ()
        if (_total_free_4k_blocks_uncertain) {
                return boost::optional<framecnt_t> ();
        }
        if (_total_free_4k_blocks_uncertain) {
                return boost::optional<framecnt_t> ();
        }
-       
+
        float sample_bytes_on_disk = 4.0; // keep gcc happy
 
        switch (config.get_native_file_data_format()) {
        float sample_bytes_on_disk = 4.0; // keep gcc happy
 
        switch (config.get_native_file_data_format()) {
@@ -4824,6 +5554,16 @@ Session::tempo_map_changed (const PropertyChange&)
        set_dirty ();
 }
 
        set_dirty ();
 }
 
+void
+Session::gui_tempo_map_changed ()
+{
+       clear_clicks ();
+
+       playlists->update_after_tempo_map_change ();
+
+       _locations->apply (*this, &Session::update_locations_after_tempo_map_change);
+}
+
 void
 Session::update_locations_after_tempo_map_change (const Locations::LocationList& loc)
 {
 void
 Session::update_locations_after_tempo_map_change (const Locations::LocationList& loc)
 {
@@ -4855,7 +5595,7 @@ Session::next_insert_id ()
        /* this doesn't really loop forever. just think about it */
 
        while (true) {
        /* this doesn't really loop forever. just think about it */
 
        while (true) {
-               for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < insert_bitset.size(); ++n) {
+               for (boost::dynamic_bitset<uint32_t>::size_type n = 1; n < insert_bitset.size(); ++n) {
                        if (!insert_bitset[n]) {
                                insert_bitset[n] = true;
                                return n;
                        if (!insert_bitset[n]) {
                                insert_bitset[n] = true;
                                return n;
@@ -4875,7 +5615,7 @@ Session::next_send_id ()
        /* this doesn't really loop forever. just think about it */
 
        while (true) {
        /* this doesn't really loop forever. just think about it */
 
        while (true) {
-               for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < send_bitset.size(); ++n) {
+               for (boost::dynamic_bitset<uint32_t>::size_type n = 1; n < send_bitset.size(); ++n) {
                        if (!send_bitset[n]) {
                                send_bitset[n] = true;
                                return n;
                        if (!send_bitset[n]) {
                                send_bitset[n] = true;
                                return n;
@@ -4895,7 +5635,7 @@ Session::next_aux_send_id ()
        /* this doesn't really loop forever. just think about it */
 
        while (true) {
        /* this doesn't really loop forever. just think about it */
 
        while (true) {
-               for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < aux_send_bitset.size(); ++n) {
+               for (boost::dynamic_bitset<uint32_t>::size_type n = 1; n < aux_send_bitset.size(); ++n) {
                        if (!aux_send_bitset[n]) {
                                aux_send_bitset[n] = true;
                                return n;
                        if (!aux_send_bitset[n]) {
                                aux_send_bitset[n] = true;
                                return n;
@@ -4915,7 +5655,7 @@ Session::next_return_id ()
        /* this doesn't really loop forever. just think about it */
 
        while (true) {
        /* this doesn't really loop forever. just think about it */
 
        while (true) {
-               for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < return_bitset.size(); ++n) {
+               for (boost::dynamic_bitset<uint32_t>::size_type n = 1; n < return_bitset.size(); ++n) {
                        if (!return_bitset[n]) {
                                return_bitset[n] = true;
                                return n;
                        if (!return_bitset[n]) {
                                return_bitset[n] = true;
                                return n;
@@ -4996,6 +5736,7 @@ Session::unmark_aux_send_id (uint32_t id)
 void
 Session::unmark_return_id (uint32_t id)
 {
 void
 Session::unmark_return_id (uint32_t id)
 {
+       if (_state_of_the_state & Deletion) { return; }
        if (id < return_bitset.size()) {
                return_bitset[id] = false;
        }
        if (id < return_bitset.size()) {
                return_bitset[id] = false;
        }
@@ -5077,7 +5818,7 @@ Session::freeze_all (InterThreadInfo& itt)
 boost::shared_ptr<Region>
 Session::write_one_track (Track& track, framepos_t start, framepos_t end,
                          bool /*overwrite*/, vector<boost::shared_ptr<Source> >& srcs,
 boost::shared_ptr<Region>
 Session::write_one_track (Track& track, framepos_t start, framepos_t end,
                          bool /*overwrite*/, vector<boost::shared_ptr<Source> >& srcs,
-                         InterThreadInfo& itt, 
+                         InterThreadInfo& itt,
                          boost::shared_ptr<Processor> endpoint, bool include_endpoint,
                          bool for_export, bool for_freeze)
 {
                          boost::shared_ptr<Processor> endpoint, bool include_endpoint,
                          bool for_export, bool for_freeze)
 {
@@ -5138,7 +5879,7 @@ Session::write_one_track (Track& track, framepos_t start, framepos_t end,
                string path = ((track.data_type() == DataType::AUDIO)
                               ? new_audio_source_path (legal_playlist_name, diskstream_channels.n_audio(), chan_n, false, true)
                               : new_midi_source_path (legal_playlist_name));
                string path = ((track.data_type() == DataType::AUDIO)
                               ? new_audio_source_path (legal_playlist_name, diskstream_channels.n_audio(), chan_n, false, true)
                               : new_midi_source_path (legal_playlist_name));
-               
+
                if (path.empty()) {
                        goto out;
                }
                if (path.empty()) {
                        goto out;
                }
@@ -5345,6 +6086,12 @@ Session::get_scratch_buffers (ChanCount count, bool silence)
        return ProcessThread::get_scratch_buffers (count, silence);
 }
 
        return ProcessThread::get_scratch_buffers (count, silence);
 }
 
+BufferSet&
+Session::get_noinplace_buffers (ChanCount count)
+{
+       return ProcessThread::get_noinplace_buffers (count);
+}
+
 BufferSet&
 Session::get_route_buffers (ChanCount count, bool silence)
 {
 BufferSet&
 Session::get_route_buffers (ChanCount count, bool silence)
 {
@@ -5416,7 +6163,7 @@ Session::update_route_record_state ()
        while (i != rl->end ()) {
 
                boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
        while (i != rl->end ()) {
 
                boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (tr && tr->record_enabled ()) {
+                                   if (tr && tr->rec_enable_control()->get_value()) {
                        break;
                }
 
                        break;
                }
 
@@ -5433,19 +6180,19 @@ Session::update_route_record_state ()
 
        for (i = rl->begin(); i != rl->end (); ++i) {
                boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
 
        for (i = rl->begin(); i != rl->end (); ++i) {
                boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (tr && !tr->record_enabled ()) {
+               if (tr && !tr->rec_enable_control()->get_value()) {
                        break;
                }
        }
                        break;
                }
        }
-    
+
        g_atomic_int_set (&_have_rec_disabled_track, i != rl->end () ? 1 : 0);
 
        bool record_arm_state_changed = (old != g_atomic_int_get (&_have_rec_enabled_track) );
        g_atomic_int_set (&_have_rec_disabled_track, i != rl->end () ? 1 : 0);
 
        bool record_arm_state_changed = (old != g_atomic_int_get (&_have_rec_enabled_track) );
-    
+
        if (record_status() == Recording && record_arm_state_changed ) {
                RecordArmStateChanged ();
        }
        if (record_status() == Recording && record_arm_state_changed ) {
                RecordArmStateChanged ();
        }
-       
+
 }
 
 void
 }
 
 void
@@ -5461,12 +6208,15 @@ Session::listen_position_changed ()
 void
 Session::solo_control_mode_changed ()
 {
 void
 Session::solo_control_mode_changed ()
 {
-       /* cancel all solo or all listen when solo control mode changes */
-
-       if (soloing()) {
-               set_solo (get_routes(), false);
-       } else if (listening()) {
-               set_listen (get_routes(), false);
+       if (soloing() || listening()) {
+               /* We can't use ::clear_all_solo_state() here because during
+                  session loading at program startup, that will queue a call
+                  to rt_clear_all_solo_state() that will not execute until
+                  AFTER solo states have been established (thus throwing away
+                  the session's saved solo state). So just explicitly turn
+                  them all off.
+               */
+               set_controls (route_list_to_control_list (get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup);
        }
 }
 
        }
 }
 
@@ -5566,7 +6316,7 @@ Session::current_end_frame () const
 }
 
 void
 }
 
 void
-Session::add_session_range_location (framepos_t start, framepos_t end)
+Session::set_session_range_location (framepos_t start, framepos_t end)
 {
        _session_range_location = new Location (*this, start, end, _("session"), Location::IsSessionRange);
        _locations->add (_session_range_location);
 {
        _session_range_location = new Location (*this, start, end, _("session"), Location::IsSessionRange);
        _locations->add (_session_range_location);
@@ -5782,9 +6532,10 @@ Session::unknown_processors () const
 void
 Session::update_latency (bool playback)
 {
 void
 Session::update_latency (bool playback)
 {
+
        DEBUG_TRACE (DEBUG::Latency, string_compose ("JACK latency callback: %1\n", (playback ? "PLAYBACK" : "CAPTURE")));
 
        DEBUG_TRACE (DEBUG::Latency, string_compose ("JACK latency callback: %1\n", (playback ? "PLAYBACK" : "CAPTURE")));
 
-       if ((_state_of_the_state & (InitialConnecting|Deletion)) || _adding_routes_in_progress) {
+       if ((_state_of_the_state & (InitialConnecting|Deletion)) || _adding_routes_in_progress || _route_deletion_in_progress) {
                return;
        }
 
                return;
        }
 
@@ -5959,7 +6710,7 @@ Session::update_latency_compensation (bool force_whole_graph)
                                                     (some_track_latency_changed ? "yes" : "no")));
 
        DEBUG_TRACE(DEBUG::Latency, "---------------------------- DONE update latency compensation\n\n");
                                                     (some_track_latency_changed ? "yes" : "no")));
 
        DEBUG_TRACE(DEBUG::Latency, "---------------------------- DONE update latency compensation\n\n");
-       
+
        if (some_track_latency_changed || force_whole_graph)  {
                _engine.update_latencies ();
        }
        if (some_track_latency_changed || force_whole_graph)  {
                _engine.update_latencies ();
        }
@@ -5988,73 +6739,23 @@ Session::session_name_is_legal (const string& path)
        return 0;
 }
 
        return 0;
 }
 
-uint32_t 
-Session::next_control_id () const
-{
-       int subtract = 0;
-
-       /* the monitor bus remote ID is in a different
-        * "namespace" than regular routes. its existence doesn't
-        * affect normal (low) numbered routes.
-        */
-
-       if (_monitor_out) {
-               subtract++;
-       }
-
-       /* the same about masterbus in Waves Tracks */
-
-       if (Profile->get_trx() && _master_out) {
-               subtract++;
-       }
-
-       return nroutes() - subtract;
-}
-
 void
 void
-Session::notify_remote_id_change ()
+Session::notify_presentation_info_change ()
 {
        if (deletion_in_progress()) {
                return;
        }
 
 {
        if (deletion_in_progress()) {
                return;
        }
 
-       switch (Config->get_remote_model()) {
-       case MixerOrdered:
-               Route::RemoteControlIDChange (); /* EMIT SIGNAL */
-               break;
-       default:
-               break;
-       }
+       PresentationInfo::Change (); /* EMIT SIGNAL */
+       reassign_track_numbers();
 
 #ifdef USE_TRACKS_CODE_FEATURES
 
 #ifdef USE_TRACKS_CODE_FEATURES
-               /* Waves Tracks: for Waves Tracks session it's required to reconnect their IOs
-                * if track order has been changed by user
-                */
-               reconnect_existing_routes(true, true);
+       /* Waves Tracks: for Waves Tracks session it's required to reconnect their IOs
+        * if track order has been changed by user
+        */
+       reconnect_existing_routes(true, true);
 #endif
 #endif
-               
-}
-
-void
-Session::sync_order_keys ()
-{
-       if (deletion_in_progress()) {
-               return;
-       }
 
 
-       /* tell everyone that something has happened to the sort keys
-          and let them sync up with the change(s)
-          this will give objects that manage the sort order keys the
-          opportunity to keep them in sync if they wish to.
-       */
-
-       DEBUG_TRACE (DEBUG::OrderKeys, "Sync Order Keys.\n");
-
-       reassign_track_numbers();
-
-       Route::SyncOrderKeys (); /* EMIT SIGNAL */
-
-       DEBUG_TRACE (DEBUG::OrderKeys, "\tsync done\n");
 }
 
 bool
 }
 
 bool
@@ -6087,6 +6788,11 @@ Session::reconnect_ltc_input ()
                if (src != _("None") && !src.empty())  {
                        _ltc_input->nth (0)->connect (src);
                }
                if (src != _("None") && !src.empty())  {
                        _ltc_input->nth (0)->connect (src);
                }
+
+               if ( ARDOUR::Profile->get_trx () ) {
+                       // Tracks need this signal to update timecode_source_dropdown
+                       MtcOrLtcInputPortChanged (); //emit signal
+               }
        }
 }
 
        }
 }
 
@@ -6095,14 +6801,271 @@ Session::reconnect_ltc_output ()
 {
        if (_ltc_output) {
 
 {
        if (_ltc_output) {
 
-#if 0
-               string src = Config->get_ltc_sink_port();
+               string src = Config->get_ltc_output_port();
 
                _ltc_output->disconnect (this);
 
                if (src != _("None") && !src.empty())  {
                        _ltc_output->nth (0)->connect (src);
                }
 
                _ltc_output->disconnect (this);
 
                if (src != _("None") && !src.empty())  {
                        _ltc_output->nth (0)->connect (src);
                }
+       }
+}
+
+void
+Session::set_range_selection (framepos_t start, framepos_t end)
+{
+       _range_selection = Evoral::Range<framepos_t> (start, end);
+#ifdef USE_TRACKS_CODE_FEATURES
+       follow_playhead_priority ();
+#endif
+}
+
+void
+Session::set_object_selection (framepos_t start, framepos_t end)
+{
+       _object_selection = Evoral::Range<framepos_t> (start, end);
+#ifdef USE_TRACKS_CODE_FEATURES
+       follow_playhead_priority ();
+#endif
+}
+
+void
+Session::clear_range_selection ()
+{
+       _range_selection = Evoral::Range<framepos_t> (-1,-1);
+#ifdef USE_TRACKS_CODE_FEATURES
+       follow_playhead_priority ();
+#endif
+}
+
+void
+Session::clear_object_selection ()
+{
+       _object_selection = Evoral::Range<framepos_t> (-1,-1);
+#ifdef USE_TRACKS_CODE_FEATURES
+       follow_playhead_priority ();
 #endif
 #endif
+}
+
+void
+Session::auto_connect_route (boost::shared_ptr<Route> route, bool connect_inputs,
+               const ChanCount& input_start,
+               const ChanCount& output_start,
+               const ChanCount& input_offset,
+               const ChanCount& output_offset)
+{
+       Glib::Threads::Mutex::Lock lx (_auto_connect_queue_lock);
+       _auto_connect_queue.push (AutoConnectRequest (route, connect_inputs,
+                               input_start, output_start,
+                               input_offset, output_offset));
+
+       if (pthread_mutex_trylock (&_auto_connect_mutex) == 0) {
+               pthread_cond_signal (&_auto_connect_cond);
+               pthread_mutex_unlock (&_auto_connect_mutex);
+       }
+}
+
+void
+Session::queue_latency_recompute ()
+{
+       g_atomic_int_inc (&_latency_recompute_pending);
+       if (pthread_mutex_trylock (&_auto_connect_mutex) == 0) {
+               pthread_cond_signal (&_auto_connect_cond);
+               pthread_mutex_unlock (&_auto_connect_mutex);
+       }
+}
+
+void
+Session::auto_connect (const AutoConnectRequest& ar)
+{
+       boost::shared_ptr<Route> route = ar.route.lock();
+
+       if (!route) { return; }
+
+       if (!IO::connecting_legal) {
+               return;
+       }
+
+       /* If both inputs and outputs are auto-connected to physical ports,
+        * use the max of input and output offsets to ensure auto-connected
+        * port numbers always match up (e.g. the first audio input and the
+        * first audio output of the route will have the same physical
+        * port number).  Otherwise just use the lowest input or output
+        * offset possible.
+        */
+
+       const bool in_out_physical =
+               (Config->get_input_auto_connect() & AutoConnectPhysical)
+               && (Config->get_output_auto_connect() & AutoConnectPhysical)
+               && ar.connect_inputs;
+
+       const ChanCount in_offset = in_out_physical
+               ? ChanCount::max(ar.input_offset, ar.output_offset)
+               : ar.input_offset;
+
+       const ChanCount out_offset = in_out_physical
+               ? ChanCount::max(ar.input_offset, ar.output_offset)
+               : ar.output_offset;
+
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               vector<string> physinputs;
+               vector<string> physoutputs;
+
+               _engine.get_physical_outputs (*t, physoutputs);
+               _engine.get_physical_inputs (*t, physinputs);
+
+               if (!physinputs.empty() && ar.connect_inputs) {
+                       uint32_t nphysical_in = physinputs.size();
+
+                       for (uint32_t i = ar.input_start.get(*t); i < route->n_inputs().get(*t) && i < nphysical_in; ++i) {
+                               string port;
+
+                               if (Config->get_input_auto_connect() & AutoConnectPhysical) {
+                                       port = physinputs[(in_offset.get(*t) + i) % nphysical_in];
+                               }
+
+                               if (!port.empty() && route->input()->connect (route->input()->ports().port(*t, i), port, this)) {
+                                       break;
+                               }
+                       }
+               }
+
+               if (!physoutputs.empty()) {
+                       uint32_t nphysical_out = physoutputs.size();
+                       for (uint32_t i = ar.output_start.get(*t); i < route->n_outputs().get(*t); ++i) {
+                               string port;
+
+                               /* Waves Tracks:
+                                * do not create new connections if we reached the limit of physical outputs
+                                * in Multi Out mode
+                                */
+                               if (!(Config->get_output_auto_connect() & AutoConnectMaster) &&
+                                               ARDOUR::Profile->get_trx () &&
+                                               ar.output_offset.get(*t) == nphysical_out ) {
+                                       break;
+                               }
+
+                               if ((*t) == DataType::MIDI && (Config->get_output_auto_connect() & AutoConnectPhysical)) {
+                                       port = physoutputs[(out_offset.get(*t) + i) % nphysical_out];
+                               } else if ((*t) == DataType::AUDIO && (Config->get_output_auto_connect() & AutoConnectMaster)) {
+                                       /* master bus is audio only */
+                                       if (_master_out && _master_out->n_inputs().get(*t) > 0) {
+                                               port = _master_out->input()->ports().port(*t,
+                                                               i % _master_out->input()->n_ports().get(*t))->name();
+                                       }
+                               }
+
+                               if (!port.empty() && route->output()->connect (route->output()->ports().port(*t, i), port, this)) {
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
+void
+Session::auto_connect_thread_start ()
+{
+       if (_ac_thread_active) {
+               return;
+       }
+
+       while (!_auto_connect_queue.empty ()) {
+               _auto_connect_queue.pop ();
+       }
+
+       _ac_thread_active = true;
+       if (pthread_create (&_auto_connect_thread, NULL, auto_connect_thread, this)) {
+               _ac_thread_active = false;
+       }
+}
+
+void
+Session::auto_connect_thread_terminate ()
+{
+       if (!_ac_thread_active) {
+               return;
+       }
+       _ac_thread_active = false;
+
+       {
+               Glib::Threads::Mutex::Lock lx (_auto_connect_queue_lock);
+               while (!_auto_connect_queue.empty ()) {
+                       _auto_connect_queue.pop ();
+               }
+       }
+
+       if (pthread_mutex_lock (&_auto_connect_mutex) == 0) {
+               pthread_cond_signal (&_auto_connect_cond);
+               pthread_mutex_unlock (&_auto_connect_mutex);
+       }
+
+       void *status;
+       pthread_join (_auto_connect_thread, &status);
+}
+
+void *
+Session::auto_connect_thread (void *arg)
+{
+       Session *s = static_cast<Session *>(arg);
+       s->auto_connect_thread_run ();
+       pthread_exit (0);
+       return 0;
+}
+
+void
+Session::auto_connect_thread_run ()
+{
+       pthread_set_name (X_("autoconnect"));
+       SessionEvent::create_per_thread_pool (X_("autoconnect"), 1024);
+       PBD::notify_event_loops_about_thread_creation (pthread_self(), X_("autoconnect"), 1024);
+       pthread_mutex_lock (&_auto_connect_mutex);
+       while (_ac_thread_active) {
+
+               if (!_auto_connect_queue.empty ()) {
+                       // Why would we need the process lock ??
+                       // A: if ports are added while we're connecting, the backend's iterator may be invalidated:
+                       //   graph_order_callback() -> resort_routes() -> direct_feeds_according_to_reality () -> backend::connected_to()
+                       //   All ardour-internal backends use a std::vector   xxxAudioBackend::find_port()
+                       //   We have control over those, but what does jack do?
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+
+                       Glib::Threads::Mutex::Lock lx (_auto_connect_queue_lock);
+                       while (!_auto_connect_queue.empty ()) {
+                               const AutoConnectRequest ar (_auto_connect_queue.front());
+                               _auto_connect_queue.pop ();
+                               lx.release ();
+                               auto_connect (ar);
+                               lx.acquire ();
+                       }
+               }
+
+               if (!actively_recording ()) { // might not be needed,
+                       /* this is only used for updating plugin latencies, the
+                        * graph does not change. so it's safe in general.
+                        * BUT..
+                        * .. update_latency_compensation () entails set_capture_offset()
+                        * which calls Diskstream::set_capture_offset () which
+                        * modifies the capture offset... which can be a proplem
+                        * in "prepare_to_stop"
+                        */
+                       while (g_atomic_int_and (&_latency_recompute_pending, 0)) {
+                               update_latency_compensation ();
+                       }
+               }
+
+               pthread_cond_wait (&_auto_connect_cond, &_auto_connect_mutex);
        }
        }
+       pthread_mutex_unlock (&_auto_connect_mutex);
+}
+
+void
+Session::cancel_all_solo ()
+{
+       StripableList sl;
+
+       get_stripables (sl);
+
+       set_controls (stripable_list_to_control_list (sl, &Stripable::solo_control), 0.0, Controllable::NoGroup);
+       clear_all_solo_state (routes.reader());
 }
 }