fix crash when copy'ing latent plugins
[ardour.git] / libs / ardour / session.cc
index fec12290932d8e489d0f6d4422b600ee6b4487cd..61bfce14b6bfc995f0203b44e42bdf17652e60d8 100644 (file)
 #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/pthread_utils.h"
 #include "pbd/search_path.h"
 #include "pbd/stacktrace.h"
 #include "pbd/stl_delete.h"
@@ -58,6 +58,7 @@
 #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/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_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/solo_isolate_control.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/vca_manager.h"
+#include "ardour/vca.h"
 
 #include "midi++/port.h"
 #include "midi++/mmc.h"
 
 #include "LuaBridge/LuaBridge.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 #include <glibmm/checksum.h>
 
@@ -131,6 +136,7 @@ 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;
 
@@ -166,12 +172,13 @@ Session::Session (AudioEngine &eng,
        , _bounce_processing_active (false)
        , waiting_for_sync_offset (false)
        , _base_frame_rate (0)
-       , _current_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)
+       , _session_range_end_is_free (true)
        , _slave (0)
        , _silent (false)
        , _transport_speed (0)
@@ -206,7 +213,9 @@ Session::Session (AudioEngine &eng,
        , post_export_position (0)
        , _exporting (false)
        , _export_rolling (false)
+       , _realtime_export (false)
        , _export_preroll (0)
+       , _export_latency (0)
        , _pre_export_mmc_enabled (false)
        , _name (snapshot_name)
        , _is_new (true)
@@ -231,7 +240,7 @@ Session::Session (AudioEngine &eng,
        , pending_locate_flush (false)
        , pending_abort (false)
        , pending_auto_loop (false)
-       , _mempool ("Session", 1048576)
+       , _mempool ("Session", 2097152)
        , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool))
        , _n_lua_scripts (0)
        , _butler (new Butler (*this))
@@ -242,6 +251,8 @@ Session::Session (AudioEngine &eng,
        , _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)
@@ -297,22 +308,29 @@ Session::Session (AudioEngine &eng,
        , 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)
-       , _order_hint (-1)
        , ignore_route_processor_changes (false)
+       , midi_clock (0)
        , _scene_changer (0)
        , _midi_ports (0)
        , _mmc (0)
+       , _vca_manager (new VCAManager (*this))
 {
        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 (&_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);
 
@@ -325,7 +343,7 @@ Session::Session (AudioEngine &eng,
 #ifdef USE_TRACKS_CODE_FEATURES
                sr = EngineStateController::instance()->get_current_sample_rate();
 #endif
-               if (ensure_engine (sr)) {
+               if (ensure_engine (sr, true)) {
                        destroy ();
                        throw SessionException (_("Cannot connect to audio/midi engine"));
                }
@@ -373,13 +391,14 @@ Session::Session (AudioEngine &eng,
                 */
 
                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());
                        }
                }
 
-               if (ensure_engine (sr)) {
+               if (ensure_engine (sr, false)) {
                        destroy ();
                        throw SessionException (_("Cannot connect to audio/midi engine"));
                }
@@ -407,6 +426,7 @@ Session::Session (AudioEngine &eng,
        EndTimeChanged.connect_same_thread (*this, boost::bind (&Session::end_time_changed, this, _1));
 
        emit_thread_start ();
+       auto_connect_thread_start ();
 
        /* hook us up to the engine since we are now completely constructed */
 
@@ -491,7 +511,7 @@ Session::init_name_id_counter (guint n)
 }
 
 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 ... */
@@ -499,6 +519,8 @@ Session::ensure_engine (uint32_t desired_sample_rate)
                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);
@@ -511,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;
@@ -550,6 +571,7 @@ Session::immediately_post_engine ()
        }
 
        try {
+               LocaleGuard lg;
                BootMessage (_("Set up LTC"));
                setup_ltc ();
                BootMessage (_("Set up Click"));
@@ -584,8 +606,12 @@ Session::destroy ()
 
        _state_of_the_state = StateOfTheState (CannotSave|Deletion);
 
+       /* stop autoconnecting */
+       auto_connect_thread_terminate ();
+
        /* disconnect from any and all signals that we are connected to */
 
+       Port::PortSignalDrop (); /* EMIT SIGNAL */
        drop_connections ();
 
        /* shutdown control surface protocols while we still have ports
@@ -678,6 +704,11 @@ Session::destroy ()
        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 */
@@ -718,6 +749,9 @@ Session::destroy ()
        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;
 
@@ -725,13 +759,48 @@ Session::destroy ()
        delete _midi_ports; _midi_ports = 0;
        delete _locations; _locations = 0;
 
+       delete midi_clock;
        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");
 
-#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
-       boost_debug_list_ptrs ();
-#endif
+       BOOST_SHOW_POINTERS ();
 }
 
 void
@@ -1063,11 +1132,16 @@ Session::remove_monitor_section ()
        }
 
        remove_route (_monitor_out);
+       if (_state_of_the_state & Deletion) {
+               return;
+       }
+
        auto_connect_master_bus ();
 
        if (auditioner) {
                auditioner->connect ();
        }
+
        Config->ParameterChanged ("use-monitor-bus");
 }
 
@@ -1080,15 +1154,14 @@ Session::add_monitor_section ()
                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;
        }
 
-#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);
@@ -1099,7 +1172,7 @@ Session::add_monitor_section ()
        }
 
        rl.push_back (r);
-       add_routes (rl, false, false, false);
+       add_routes (rl, false, false, false, 0);
 
        assert (_monitor_out);
 
@@ -1139,7 +1212,7 @@ Session::add_monitor_section ()
        /* 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()) {
 
@@ -1245,8 +1318,12 @@ Session::reset_monitor_section ()
        _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);
@@ -1441,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);
-               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);
                }
@@ -1876,15 +1953,9 @@ void
 Session::set_all_tracks_record_enabled (bool enable )
 {
        boost::shared_ptr<RouteList> rl = routes.reader();
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (tr) {
-                       tr->set_record_enabled (enable, Controllable::NoGroup);
-               }
-       }
+       set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), enable, Controllable::NoGroup);
 }
 
-
 void
 Session::disable_record (bool rt_context, bool force)
 {
@@ -1959,59 +2030,55 @@ framepos_t
 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 */
-               tf = _engine.transport_frame();
+               ret = _engine.transport_frame();
        } 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
-                  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 (tf < _last_roll_or_reversal_location + offset) {
+                               if (ret < _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? */
 
-                       if (tf > _last_roll_or_reversal_location - offset) {
+                       if (ret > _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
@@ -2024,7 +2091,12 @@ Session::set_frame_rate (framecnt_t frames_per_second)
                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();
@@ -2147,16 +2219,18 @@ Session::resort_routes ()
        }
 
 #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));
+                               }
                        }
                }
        }
@@ -2238,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) {
-                       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
 
@@ -2357,8 +2430,10 @@ Session::default_track_name_pattern (DataType t)
  *  @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)
 {
        string track_name;
        uint32_t track_id = 0;
@@ -2378,7 +2453,7 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
                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;
@@ -2390,9 +2465,8 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
 
                        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)) {
@@ -2414,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));
 
-                       if (Config->get_remote_model() == UserOrdered) {
-                               track->set_remote_control_id (next_control_id());
-                       }
-
                        new_routes.push_back (track);
                        ret.push_back (track);
-
-                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
                }
 
                catch (failed_constructor &err) {
@@ -2442,14 +2510,17 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
        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 {
-                       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 (pset) {
+                                       plugin->load_preset (*pset);
+                               }
                                boost::shared_ptr<Processor> p (new PluginInsert (*this, plugin));
                                (*r)->add_processor (p, PreFader);
 
@@ -2461,7 +2532,8 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
 }
 
 RouteList
-Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name_template, boost::shared_ptr<PluginInfo> instrument)
+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)
 {
        string bus_name;
        uint32_t bus_id = 0;
@@ -2477,7 +2549,7 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name
                }
 
                try {
-                       boost::shared_ptr<Route> bus (new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO)); // XXX Editor::add_routes is not ready for ARDOUR::DataType::MIDI
+                       boost::shared_ptr<Route> bus (new Route (*this, bus_name, flag, DataType::AUDIO)); // XXX Editor::add_routes is not ready for ARDOUR::DataType::MIDI
 
                        if (bus->init ()) {
                                goto failure;
@@ -2487,9 +2559,8 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name
                                bus->set_strict_io (true);
                        }
 
-#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
-                       // boost_debug_shared_ptr_mark_interesting (bus.get(), "Route");
-#endif
+                       BOOST_MARK_ROUTE(bus);
+
                        {
                                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
@@ -2508,13 +2579,9 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name
                        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 ();
                        ret.push_back (bus);
-                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
-                       ARDOUR::GUIIdle ();
                }
 
                catch (failed_constructor &err) {
@@ -2534,11 +2601,14 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name
   failure:
        if (!ret.empty()) {
                StateProtector sp (this);
-               add_routes (ret, false, false, false);
+               add_routes (ret, false, false, false, order);
 
                if (instrument) {
                        for (RouteList::iterator r = ret.begin(); r != ret.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);
                        }
@@ -2553,151 +2623,26 @@ Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name
 void
 Session::midi_output_change_handler (IOChange change, void * /*src*/, boost::weak_ptr<Route> wmt)
 {
-        boost::shared_ptr<Route> midi_track (wmt.lock());
-
-        if (!midi_track) {
-                return;
-        }
-
-       if ((change.type & IOChange::ConfigurationChanged) && Config->get_output_auto_connect() != ManualConnect) {
-
-                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.
-                */
-
-                ChanCount dummy;
+       boost::shared_ptr<Route> midi_track (wmt.lock());
 
-                auto_connect_route (midi_track, dummy, dummy, false, false, ChanCount(), change.before);
-        }
-}
-
-/** @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) {
+       if (!midi_track) {
                return;
        }
 
-       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
-
-       if (with_lock) {
-               lm.acquire ();
-       }
-
-       /* 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.
-       */
-
-       DEBUG_TRACE (DEBUG::Graph,
-                    string_compose("Auto-connect: existing in = %1 out = %2\n",
-                                   existing_inputs, existing_outputs));
-
-       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();
-
-                       DEBUG_TRACE (DEBUG::Graph,
-                                    string_compose("There are %1 physical inputs of type %2\n",
-                                                   nphysical_in, *t));
-
-                       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];
-                               }
-
-                               DEBUG_TRACE (DEBUG::Graph,
-                                            string_compose("Connect route %1 IN to %2\n",
-                                                           route->name(), port));
-
-                               if (!port.empty() && route->input()->connect (route->input()->ports().port(*t, i), port, this)) {
-                                       break;
-                               }
+       if ((change.type & IOChange::ConfigurationChanged) && Config->get_output_auto_connect() != ManualConnect) {
 
-                                ChanCount one_added (*t, 1);
-                                existing_inputs += one_added;
-                       }
+               if (change.after.n_audio() <= change.before.n_audio()) {
+                       return;
                }
 
-               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;
-
-                               /* 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();
-                                       }
-                               }
-
-                               DEBUG_TRACE (DEBUG::Graph,
-                                            string_compose("Connect route %1 OUT to %2\n",
-                                                           route->name(), port));
-
-                               if (!port.empty() && route->output()->connect (route->output()->ports().port(*t, i), port, this)) {
-                                       break;
-                               }
-
-                                ChanCount one_added (*t, 1);
-                                existing_outputs += one_added;
-                       }
-               }
+               /* 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);
        }
 }
 
@@ -2859,8 +2804,6 @@ Session::reconnect_existing_routes (bool withLock, bool reconnect_master, bool r
                                        }
                                }
                        }
-
-                       //auto_connect_route (*rIter, inputs, outputs, false, reconnectIputs);
                }
 
                _master_out->output()->disconnect (this);
@@ -2985,12 +2928,40 @@ Session::reconnect_mmc_ports(bool inputs)
 
 #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> >
-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)
 {
        string track_name;
        uint32_t track_id = 0;
@@ -3011,7 +2982,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                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;
@@ -3021,7 +2992,6 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                                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:
@@ -3032,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) {
-                                       track->set_gain (dB_to_coefficient (0), Controllable::NoGroup);
+                                       track->gain_control()->set_value (dB_to_coefficient (0), Controllable::NoGroup);
                                }
                        }
 
                        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 ());
 
@@ -3068,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));
-                       if (Config->get_remote_model() == UserOrdered) {
-                               track->set_remote_control_id (next_control_id());
-                       }
 
                        new_routes.push_back (track);
                        ret.push_back (track);
-
-                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
                }
 
                catch (failed_constructor &err) {
@@ -3096,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()) {
-                       add_routes (new_routes, false, false, false);
+                       add_routes (new_routes, false, false, false, order);
                } else {
-                       add_routes (new_routes, true, true, false);
+                       add_routes (new_routes, true, true, false, order);
                }
        }
 
@@ -3109,7 +3073,8 @@ 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
-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)
 {
        string bus_name;
        uint32_t bus_id = 0;
@@ -3125,7 +3090,7 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
                }
 
                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;
@@ -3135,9 +3100,8 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
                                bus->set_strict_io (true);
                        }
 
-#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
-                       // boost_debug_shared_ptr_mark_interesting (bus.get(), "Route");
-#endif
+                       BOOST_MARK_ROUTE(bus);
+
                        {
                                Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
@@ -3160,20 +3124,11 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
                        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 ();
-
                        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;
@@ -3192,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()) {
-                       add_routes (ret, false, false, false);
+                       add_routes (ret, false, false, false, order);
                } else {
-                       add_routes (ret, false, true, true); // autoconnect // outputs only
+                       add_routes (ret, false, true, true, order); // autoconnect // outputs only
                }
        }
 
@@ -3218,7 +3173,6 @@ RouteList
 Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::string& name_base, PlaylistDisposition pd)
 {
        RouteList ret;
-       uint32_t control_id;
        uint32_t number = 0;
        const uint32_t being_added = how_many;
        /* This will prevent the use of any existing XML-provided PBD::ID
@@ -3227,8 +3181,6 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
        Stateful::ForceIDRegeneration force_ids;
        IO::disable_connecting ();
 
-       control_id = next_control_id ();
-
        while (how_many) {
 
                /* We're going to modify the node contents a bit so take a
@@ -3270,6 +3222,7 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
                        case NewPlaylist:
                                rename_playlist = true;
                                break;
+                       default:
                        case CopyPlaylist:
                        case SharePlaylist:
                                rename_playlist = false;
@@ -3281,10 +3234,52 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
                        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"));
                                        }
+                                       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");
+                                       }
                                }
                        }
 
@@ -3310,9 +3305,6 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
                                route->output()->changed (change, this);
                        }
 
-                       route->set_remote_control_id (control_id);
-                       ++control_id;
-
                        boost::shared_ptr<Track> track;
 
                        if ((track = boost::dynamic_pointer_cast<Track> (route))) {
@@ -3329,8 +3321,6 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
                        };
 
                        ret.push_back (route);
-
-                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
                }
 
                catch (failed_constructor &err) {
@@ -3350,9 +3340,9 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
        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 {
-                       add_routes (ret, true, true, false);
+                       add_routes (ret, true, true, false, PresentationInfo::max_order);
                }
                IO::enable_connecting ();
        }
@@ -3361,11 +3351,11 @@ Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::s
 }
 
 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);
-               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;
@@ -3382,54 +3372,53 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
                save_state (_current_snapshot_name);
        }
 
-       reassign_track_numbers();
-
        update_route_record_state ();
 
        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());
+               n_routes = r->size();
 
                /* 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);
                }
        }
 
-       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);
 
-               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, wpr));
-               r->mute_changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this));
+               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->processor_latency_changed.connect_same_thread (*this, boost::bind (&Session::queue_latency_recompute, this));
 
                if (r->is_master()) {
                        _master_out = r;
@@ -3443,36 +3432,54 @@ 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));
-                       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));
-                                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 {
-                               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 ();
        }
 
@@ -3483,12 +3490,14 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
                        if ((*x)->is_monitor()) {
                                /* relax */
                        } else if ((*x)->is_master()) {
-                                       /* relax */
+                               /* relax */
                        } else {
                                (*x)->enable_monitor_send ();
                        }
                }
        }
+
+       reassign_track_numbers ();
 }
 
 void
@@ -3577,7 +3586,6 @@ Session::add_internal_send (boost::shared_ptr<Route> dest, boost::shared_ptr<Pro
        graph_reordered ();
 }
 
-
 void
 Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
 {
@@ -3593,7 +3601,7 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
                                continue;
                        }
 
-                       (*iter)->set_solo (false, Controllable::NoGroup);
+                       (*iter)->solo_control()->set_value (0.0, Controllable::NoGroup);
 
                        rs->remove (*iter);
 
@@ -3647,7 +3655,6 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
        } // end of RCU Writer scope
 
        update_route_solo_state ();
-       RouteAddedOrRemoved (false); /* EMIT SIGNAL */
        update_latency_compensation ();
        set_dirty();
 
@@ -3663,7 +3670,7 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
                resort_routes ();
 #endif
 
-       if (_process_graph) {
+       if (_process_graph && !(_state_of_the_state & Deletion)) {
                _process_graph->clear_other_chain ();
        }
 
@@ -3680,7 +3687,11 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
                (*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 */
 
@@ -3688,7 +3699,6 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
                save_history (_current_snapshot_name);
        }
 
-       reassign_track_numbers();
        update_route_record_state ();
 }
 
@@ -3709,18 +3719,20 @@ Session::route_mute_changed ()
 void
 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) {
-               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_listen_changed")) << endmsg;
                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()) {
 
                        RouteGroup* rg = route->route_group ();
-                       const bool group_already_accounted_for = route->use_group (group_override, &RouteGroup::is_solo);
+                       const bool group_already_accounted_for = (group_override == Controllable::ForGroup);
 
                        boost::shared_ptr<RouteList> r = routes.reader ();
 
@@ -3730,7 +3742,7 @@ Session::route_listen_changed (Controllable::GroupControlDisposition group_overr
                                        continue;
                                }
 
-                               if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                               if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) {
                                        /* route does not get solo propagated to it */
                                        continue;
                                }
@@ -3743,7 +3755,7 @@ Session::route_listen_changed (Controllable::GroupControlDisposition group_overr
                                         */
                                        continue;
                                }
-                               (*i)->set_listen (false, Controllable::NoGroup);
+                               (*i)->solo_control()->set_value (0.0, Controllable::NoGroup);
                        }
                }
 
@@ -3756,20 +3768,19 @@ Session::route_listen_changed (Controllable::GroupControlDisposition group_overr
 
        update_route_solo_state ();
 }
+
 void
 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) {
-               /* should not happen */
-               error << string_compose (_("programming error: %1"), X_("invalid route weak ptr passed to route_solo_isolated_changed")) << endmsg;
                return;
        }
 
        bool send_changed = false;
 
-       if (route->solo_isolated()) {
+       if (route->solo_isolate_control()->solo_isolated()) {
                if (_solo_isolated_cnt == 0) {
                        send_changed = true;
                }
@@ -3787,27 +3798,42 @@ Session::route_solo_isolated_changed (boost::weak_ptr<Route> wpr)
 }
 
 void
-Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDisposition group_override,  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));
+
+       boost::shared_ptr<Route> route (wpr.lock());
 
-       if (!self_solo_change) {
-               // session doesn't care about changes to soloed-by-others
+       if (!route) {
                return;
        }
 
-       boost::shared_ptr<Route> route = wpr.lock ();
-       assert (route);
+       if (Config->get_solo_control_is_listen_control()) {
+               route_listen_changed (group_override, wpr);
+               return;
+       }
 
-       boost::shared_ptr<RouteList> r = routes.reader ();
-       int32_t delta;
+       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()));
 
-       if (route->self_soloed()) {
-               delta = 1;
-       } else {
-               delta = -1;
+       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->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
@@ -3838,7 +3864,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
                                continue;
                        }
 
-                       if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                       if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) {
                                /* route does not get solo propagated to it */
                                continue;
                        }
@@ -3852,7 +3878,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
                                continue;
                        }
 
-                       (*i)->set_solo (false, group_override);
+                       (*i)->solo_control()->set_value (0.0, group_override);
                }
        }
 
@@ -3871,8 +3897,10 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
                        continue;
                }
 
-               if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+               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;
                }
 
@@ -3893,7 +3921,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
                        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");
                                }
@@ -3914,15 +3942,15 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
                           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) {
                                //NB. Triggers Invert Push, which handles soloed by downstream
                                DEBUG_TRACE (DEBUG::Solo, string_compose ("\tmod %1 by %2\n", (*i)->name(), delta));
-                               (*i)->mod_solo_by_others_upstream (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()));
                        }
@@ -3947,7 +3975,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
        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 ();
+               (*i)->mute_control()->Changed (false, Controllable::NoGroup);
        }
 
        SoloChanged (); /* EMIT SIGNAL */
@@ -3969,20 +3997,21 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
        }
 
        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()) {
-                               listeners++;
-                               something_listening = true;
+                               if ((*i)->self_soloed() || (*i)->solo_control()->get_masters_value()) {
+                                       listeners++;
+                                       something_listening = true;
+                               }
                        } else {
-                               (*i)->set_listen (false, Controllable::NoGroup);
+                               (*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++;
                }
        }
@@ -4008,6 +4037,16 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
                                                  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
 {
@@ -4023,7 +4062,7 @@ Session::get_routes_with_internal_returns() const
 }
 
 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 ();
 
@@ -4132,7 +4171,7 @@ Session::routes_using_input_from (const string& str, RouteList& rl)
 }
 
 boost::shared_ptr<Route>
-Session::route_by_name (string name)
+Session::route_by_name (string name) const
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
@@ -4146,7 +4185,7 @@ Session::route_by_name (string name)
 }
 
 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 ();
 
@@ -4175,7 +4214,7 @@ Session::processor_by_id (PBD::ID id) const
 }
 
 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 ();
 
@@ -4190,22 +4229,52 @@ Session::track_by_diskstream_id (PBD::ID id)
 }
 
 boost::shared_ptr<Route>
-Session::route_by_remote_id (uint32_t id)
+Session::get_remote_nth_route (PresentationInfo::order_t n) const
 {
-       boost::shared_ptr<RouteList> r = routes.reader ();
+       return boost::dynamic_pointer_cast<Route> (get_remote_nth_stripable (n, PresentationInfo::Route));
+}
 
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if ((*i)->remote_control_id() == id) {
-                       return *i;
+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;
+                       }
                }
        }
 
-       return boost::shared_ptr<Route> ((Route*) 0);
+       /* 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)
+Session::route_by_selected_count (uint32_t id) const
 {
        boost::shared_ptr<RouteList> r = routes.reader ();
 
@@ -4216,6 +4285,19 @@ Session::route_by_selected_count (uint32_t id)
        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 ()
@@ -4223,7 +4305,7 @@ Session::reassign_track_numbers ()
        int64_t tn = 0;
        int64_t bn = 0;
        RouteList r (*(routes.reader ()));
-       SignalOrderRouteSorter sorter;
+       PresentationOrderSorter sorter;
        r.sort (sorter);
 
        StateProtector sp (this);
@@ -4250,6 +4332,16 @@ Session::reassign_track_numbers ()
                // 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
@@ -4315,12 +4407,18 @@ Session::maybe_update_session_range (framepos_t a, framepos_t b)
                        _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);
                }
        }
 }
 
+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)
 {
@@ -5099,6 +5197,7 @@ Session::try_run_lua (pframes_t nframes)
        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 ();
        }
 }
 
@@ -5108,6 +5207,7 @@ Session::setup_lua ()
 #ifndef NDEBUG
        lua.Print.connect (&_lua_print);
 #endif
+       lua.tweak_rt_gc ();
        lua.do_command (
                        "function ArdourSession ()"
                        "  local self = { scripts = {}, instances = {} }"
@@ -5125,7 +5225,7 @@ Session::setup_lua ()
                        "   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, Session = Session, 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 }"
+                       "   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"
@@ -5299,7 +5399,7 @@ Session::RoutePublicOrderSorter::operator() (boost::shared_ptr<Route> a, boost::
        if (b->is_monitor()) {
                return false;
        }
-       return a->order_key () < b->order_key ();
+       return a->presentation_info().order() < b->presentation_info().order();
 }
 
 bool
@@ -5454,6 +5554,16 @@ Session::tempo_map_changed (const PropertyChange&)
        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)
 {
@@ -5485,7 +5595,7 @@ Session::next_insert_id ()
        /* 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;
@@ -5505,7 +5615,7 @@ Session::next_send_id ()
        /* 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;
@@ -5525,7 +5635,7 @@ Session::next_aux_send_id ()
        /* 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;
@@ -5545,7 +5655,7 @@ Session::next_return_id ()
        /* 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;
@@ -5936,7 +6046,6 @@ Session::write_one_track (Track& track, framepos_t start, framepos_t end,
        }
 
        unblock_processing ();
-       itt.done = true;
 
        return result;
 }
@@ -6054,7 +6163,7 @@ Session::update_route_record_state ()
        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;
                }
 
@@ -6071,7 +6180,7 @@ Session::update_route_record_state ()
 
        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;
                }
        }
@@ -6099,12 +6208,15 @@ Session::listen_position_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);
        }
 }
 
@@ -6420,9 +6532,10 @@ Session::unknown_processors () const
 void
 Session::update_latency (bool playback)
 {
+
        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;
        }
 
@@ -6626,75 +6739,25 @@ Session::session_name_is_legal (const string& path)
        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
-Session::notify_remote_id_change ()
+Session::notify_presentation_info_change ()
 {
        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
-               /* 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
 
 }
 
-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
 Session::operation_in_progress (GQuark op) const
 {
@@ -6783,3 +6846,226 @@ Session::clear_object_selection ()
        follow_playhead_priority ();
 #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());
+}