allow to customize variable i/o plugin inputs
[ardour.git] / libs / ardour / session.cc
index a3b82d9d4ba281bf2ed54bd7ae29db9b53e150f6..ef5ace53e8aa53384ab3ca17df698e9b6ecd9007 100644 (file)
@@ -42,6 +42,7 @@
 #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"
@@ -71,7 +72,9 @@
 #include "ardour/engine_state_controller.h"
 #endif
 #include "ardour/filename_extensions.h"
+#include "ardour/gain_control.h"
 #include "ardour/graph.h"
+#include "ardour/luabindings.h"
 #include "ardour/midiport_manager.h"
 #include "ardour/scene_changer.h"
 #include "ardour/midi_patch_manager.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 "midi++/port.h"
 #include "midi++/mmc.h"
 
+#include "LuaBridge/LuaBridge.h"
+
 #include "i18n.h"
 
 #include <glibmm/checksum.h>
@@ -121,11 +127,13 @@ using namespace PBD;
 
 bool Session::_disable_all_loaded_plugins = false;
 bool Session::_bypass_all_loaded_plugins = false;
+guint Session::_name_id_counter = 0;
 
 PBD::Signal1<int,uint32_t> Session::AudioEngineSetupRequired;
 PBD::Signal1<void,std::string> Session::Dialog;
 PBD::Signal0<int> Session::AskAboutPendingState;
 PBD::Signal2<int, framecnt_t, framecnt_t> Session::AskAboutSampleRateMismatch;
+PBD::Signal2<void, framecnt_t, framecnt_t> Session::NotifyAboutSampleRateMismatch;
 PBD::Signal0<void> Session::SendFeedback;
 PBD::Signal3<int,Session*,std::string,DataType> Session::MissingFile;
 
@@ -161,8 +169,8 @@ 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)
@@ -180,9 +188,10 @@ Session::Session (AudioEngine &eng,
        , current_block_size (0)
        , _worst_output_latency (0)
        , _worst_input_latency (0)
-       , _worst_track_latency (0)
+       , _worst_track_latency (0)
        , _have_captured (false)
        , _non_soloed_outs_muted (false)
+       , _listening (false)
        , _listen_cnt (0)
        , _solo_isolated_cnt (0)
        , _writable (false)
@@ -199,8 +208,8 @@ Session::Session (AudioEngine &eng,
        , post_export_sync (false)
        , post_export_position (0)
        , _exporting (false)
-       , _export_started (false)
        , _export_rolling (false)
+       , _export_preroll (0)
        , _pre_export_mmc_enabled (false)
        , _name (snapshot_name)
        , _is_new (true)
@@ -225,6 +234,9 @@ Session::Session (AudioEngine &eng,
        , pending_locate_flush (false)
        , pending_abort (false)
        , pending_auto_loop (false)
+       , _mempool ("Session", 1048576)
+       , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool))
+       , _n_lua_scripts (0)
        , _butler (new Butler (*this))
        , _post_transport_work (0)
        ,  cumulative_rf_motion (0)
@@ -233,6 +245,7 @@ Session::Session (AudioEngine &eng,
        , _ignore_skips_updates (false)
        , _rt_thread_active (false)
        , _rt_emit_pending (false)
+       , _ac_thread_active (false)
        , step_speed (0)
        , outbound_mtc_timecode_frame (0)
        , next_quarter_frame_to_send (-1)
@@ -294,6 +307,7 @@ Session::Session (AudioEngine &eng,
        ,  _speakers (new Speakers)
        , _order_hint (-1)
        , ignore_route_processor_changes (false)
+       , midi_clock (0)
        , _scene_changer (0)
        , _midi_ports (0)
        , _mmc (0)
@@ -303,8 +317,15 @@ Session::Session (AudioEngine &eng,
        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
+
        pre_engine_init (fullpath);
 
+       setup_lua ();
+
        if (_is_new) {
 
                Stateful::loading_state_version = CURRENT_SESSION_FILE_VERSION;
@@ -312,11 +333,16 @@ 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"));
                }
 
+               // set samplerate for plugins added early
+               // e.g from templates or MB channelstrip
+               set_block_size (_engine.samples_per_cycle());
+               set_frame_rate (_engine.sample_rate());
+
                if (create (mix_template, bus_profile)) {
                        destroy ();
                        throw SessionException (_("Session initialization failed"));
@@ -361,7 +387,7 @@ Session::Session (AudioEngine &eng,
                        }
                }
 
-               if (ensure_engine (sr)) {
+               if (ensure_engine (sr, false)) {
                        destroy ();
                        throw SessionException (_("Cannot connect to audio/midi engine"));
                }
@@ -389,6 +415,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 */
 
@@ -454,8 +481,26 @@ Session::~Session ()
        destroy ();
 }
 
+unsigned int
+Session::next_name_id ()
+{
+       return g_atomic_int_add (&_name_id_counter, 1);
+}
+
+unsigned int
+Session::name_id_counter ()
+{
+       return g_atomic_int_get (&_name_id_counter);
+}
+
+void
+Session::init_name_id_counter (guint n)
+{
+       g_atomic_int_set (&_name_id_counter, n);
+}
+
 int
-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 ... */
@@ -463,6 +508,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);
@@ -475,8 +522,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;
@@ -544,10 +590,16 @@ Session::destroy ()
 
        remove_pending_capture_state ();
 
+       Analyser::flush ();
+
        _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
@@ -581,8 +633,19 @@ Session::destroy ()
        delete state_tree;
        state_tree = 0;
 
-       /* reset dynamic state version back to default */
+       // unregister all lua functions, drop held references (if any)
+       (*_lua_cleanup)();
+       lua.do_command ("Session = nil");
+       delete _lua_run;
+       delete _lua_add;
+       delete _lua_del;
+       delete _lua_list;
+       delete _lua_save;
+       delete _lua_load;
+       delete _lua_cleanup;
+       lua.collect_garbage ();
 
+       /* reset dynamic state version back to default */
        Stateful::loading_state_version = 0;
 
        _butler->drop_references ();
@@ -669,6 +732,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;
 
@@ -676,6 +742,7 @@ Session::destroy ()
        delete _midi_ports; _midi_ports = 0;
        delete _locations; _locations = 0;
 
+       delete midi_clock;
        delete _tempo_map;
 
        DEBUG_TRACE (DEBUG::Destruction, "Session::destroy() done\n");
@@ -725,8 +792,12 @@ void
 Session::setup_click ()
 {
        _clicking = false;
+
+       boost::shared_ptr<AutomationList> gl (new AutomationList (Evoral::Parameter (GainAutomation)));
+       boost::shared_ptr<GainControl> gain_control = boost::shared_ptr<GainControl> (new GainControl (*this, Evoral::Parameter(GainAutomation), gl));
+
        _click_io.reset (new ClickIO (*this, X_("Click")));
-       _click_gain.reset (new Amp (*this));
+       _click_gain.reset (new Amp (*this, _("Fader"), gain_control, true));
        _click_gain->activate ();
        if (state_tree) {
                setup_click_state (state_tree->root());
@@ -1010,11 +1081,17 @@ 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");
 }
 
 void
@@ -1085,7 +1162,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()) {
 
@@ -1166,6 +1243,7 @@ Session::add_monitor_section ()
        if (auditioner) {
                auditioner->connect ();
        }
+       Config->ParameterChanged ("use-monitor-bus");
 }
 
 void
@@ -1817,6 +1895,19 @@ Session::enable_record ()
        }
 }
 
+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);
+               }
+       }
+}
+
+
 void
 Session::disable_record (bool rt_context, bool force)
 {
@@ -1956,7 +2047,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();
@@ -2079,16 +2175,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));
+                               }
                        }
                }
        }
@@ -2214,9 +2312,14 @@ Session::find_route_name (string const & base, uint32_t& id, string& name, bool
 
        for (vector<string>::const_iterator reserved = reserved_io_names.begin(); reserved != reserved_io_names.end(); ++reserved) {
                if (base == *reserved) {
-                       definitely_add_number = true;
-                       if (id < 1) {
-                               id = 1;
+                       /* Check if this reserved name already exists, and if
+                          so, disallow it without a numeric suffix.
+                       */
+                       if (route_by_name (*reserved)) {
+                               definitely_add_number = true;
+                               if (id < 1) {
+                                       id = 1;
+                               }
                        }
                        break;
                }
@@ -2311,6 +2414,10 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
                                goto failed;
                        }
 
+                       if (Profile->get_mixbus ()) {
+                               track->set_strict_io (true);
+                       }
+
                        track->use_new_diskstream();
 
 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
@@ -2383,154 +2490,119 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
        return ret;
 }
 
-void
-Session::midi_output_change_handler (IOChange change, void * /*src*/, boost::weak_ptr<Route> wmt)
+RouteList
+Session::new_midi_route (RouteGroup* route_group, uint32_t how_many, string name_template, boost::shared_ptr<PluginInfo> instrument)
 {
-        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;
+       string bus_name;
+       uint32_t bus_id = 0;
+       string port;
+       RouteList ret;
 
-                auto_connect_route (midi_track, dummy, dummy, false, false, ChanCount(), change.before);
-        }
-}
+       bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Midi Bus");
 
-/** @param connect_inputs true to connect inputs as well as outputs, false to connect just outputs.
- *  @param input_start Where to start from when auto-connecting inputs; e.g. if this is 0, auto-connect starting from input 0.
- *  @param output_start As \a input_start, but for outputs.
- */
-void
-Session::auto_connect_route (boost::shared_ptr<Route> route, ChanCount& existing_inputs, ChanCount& existing_outputs,
-                             bool with_lock, bool connect_inputs, ChanCount input_start, ChanCount output_start)
-{
-       if (!IO::connecting_legal) {
-               return;
-       }
-
-       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
+       while (how_many) {
+               if (!find_route_name (name_template.empty () ? _("Midi Bus") : name_template, ++bus_id, bus_name, use_number)) {
+                       error << "cannot find name for new midi bus" << endmsg;
+                       goto failure;
+               }
 
-       if (with_lock) {
-               lm.acquire ();
-       }
+               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
 
-       /* If both inputs and outputs are auto-connected to physical ports,
-          use the max of input and output offsets to ensure auto-connected
-          port numbers always match up (e.g. the first audio input and the
-          first audio output of the route will have the same physical
-          port number).  Otherwise just use the lowest input or output
-          offset possible.
-       */
+                       if (bus->init ()) {
+                               goto failure;
+                       }
 
-       DEBUG_TRACE (DEBUG::Graph,
-                    string_compose("Auto-connect: existing in = %1 out = %2\n",
-                                   existing_inputs, existing_outputs));
+                       if (Profile->get_mixbus ()) {
+                               bus->set_strict_io (true);
+                       }
 
-       const bool in_out_physical =
-               (Config->get_input_auto_connect() & AutoConnectPhysical)
-               && (Config->get_output_auto_connect() & AutoConnectPhysical)
-               && connect_inputs;
+#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
+                       // boost_debug_shared_ptr_mark_interesting (bus.get(), "Route");
+#endif
+                       {
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
-       const ChanCount in_offset = in_out_physical
-               ? ChanCount::max(existing_inputs, existing_outputs)
-                : existing_inputs;
+                               if (bus->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
+                                       error << _("cannot configure new midi bus input") << endmsg;
+                                       goto failure;
+                               }
 
-       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;
+                               if (bus->output()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
+                                       error << _("cannot configure new midi bus output") << endmsg;
+                                       goto failure;
+                               }
+                       }
 
-               _engine.get_physical_outputs (*t, physoutputs);
-               _engine.get_physical_inputs (*t, physinputs);
+                       if (route_group) {
+                               route_group->add (bus);
+                       }
+                       if (Config->get_remote_model() == UserOrdered) {
+                               bus->set_remote_control_id (next_control_id());
+                       }
 
-               if (!physinputs.empty() && connect_inputs) {
-                       uint32_t nphysical_in = physinputs.size();
+                       ret.push_back (bus);
+                       RouteAddedOrRemoved (true); /* EMIT SIGNAL */
+                       ARDOUR::GUIIdle ();
+               }
 
-                       DEBUG_TRACE (DEBUG::Graph,
-                                    string_compose("There are %1 physical inputs of type %2\n",
-                                                   nphysical_in, *t));
+               catch (failed_constructor &err) {
+                       error << _("Session: could not create new audio route.") << endmsg;
+                       goto failure;
+               }
 
-                       for (uint32_t i = input_start.get(*t); i < route->n_inputs().get(*t) && i < nphysical_in; ++i) {
-                               string port;
+               catch (AudioEngine::PortRegistrationFailure& pfe) {
+                       error << pfe.what() << endmsg;
+                       goto failure;
+               }
 
-                               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));
+               --how_many;
+       }
 
-                               if (!port.empty() && route->input()->connect (route->input()->ports().port(*t, i), port, this)) {
-                                       break;
-                               }
+  failure:
+       if (!ret.empty()) {
+               StateProtector sp (this);
+               add_routes (ret, false, false, false);
 
-                                ChanCount one_added (*t, 1);
-                                existing_inputs += one_added;
+               if (instrument) {
+                       for (RouteList::iterator r = ret.begin(); r != ret.end(); ++r) {
+                               PluginPtr plugin = instrument->load (*this);
+                               boost::shared_ptr<Processor> p (new PluginInsert (*this, plugin));
+                               (*r)->add_processor (p, PreFader);
                        }
                }
+       }
 
-               if (!physoutputs.empty()) {
-                       uint32_t nphysical_out = physoutputs.size();
-                       for (uint32_t i = output_start.get(*t); i < route->n_outputs().get(*t); ++i) {
-                               string port;
+       return ret;
 
-                               /* Waves Tracks:
-                                * do not create new connections if we reached the limit of physical outputs
-                                * in Multi Out mode
-                                */
+}
 
-                               if (!(Config->get_output_auto_connect() & AutoConnectMaster) &&
-                                   ARDOUR::Profile->get_trx () &&
-                                   existing_outputs.get(*t) == nphysical_out ) {
-                                       break;
-                               }
 
-                               if ((*t) == DataType::MIDI && (Config->get_output_auto_connect() & AutoConnectPhysical)) {
-                                       port = physoutputs[(out_offset.get(*t) + i) % nphysical_out];
-                               } else if ((*t) == DataType::AUDIO && (Config->get_output_auto_connect() & AutoConnectMaster)) {
-                                        /* master bus is audio only */
-                                       if (_master_out && _master_out->n_inputs().get(*t) > 0) {
-                                               port = _master_out->input()->ports().port(*t,
-                                                               i % _master_out->input()->n_ports().get(*t))->name();
-                                       }
-                               }
+void
+Session::midi_output_change_handler (IOChange change, void * /*src*/, boost::weak_ptr<Route> wmt)
+{
+       boost::shared_ptr<Route> midi_track (wmt.lock());
 
-                               DEBUG_TRACE (DEBUG::Graph,
-                                            string_compose("Connect route %1 OUT to %2\n",
-                                                           route->name(), port));
+       if (!midi_track) {
+               return;
+       }
 
-                               if (!port.empty() && route->output()->connect (route->output()->ports().port(*t, i), port, this)) {
-                                       break;
-                               }
+       if ((change.type & IOChange::ConfigurationChanged) && Config->get_output_auto_connect() != ManualConnect) {
 
-                                ChanCount one_added (*t, 1);
-                                existing_outputs += one_added;
-                       }
+               if (change.after.n_audio() <= change.before.n_audio()) {
+                       return;
                }
+
+               /* new audio ports: make sure the audio goes somewhere useful,
+                * unless the user has no-auto-connect selected.
+                *
+                * The existing ChanCounts don't matter for this call as they are only
+                * to do with matching input and output indices, and we are only changing
+                * outputs here.
+                */
+               auto_connect_route (midi_track, false, ChanCount(), change.before);
        }
 }
 
@@ -2692,8 +2764,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);
@@ -2850,6 +2920,11 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                                goto failed;
                        }
 
+                       if (Profile->get_mixbus ()) {
+                               track->set_strict_io (true);
+                       }
+
+
                        if (ARDOUR::Profile->get_trx ()) {
                                // TRACKS considers it's not a USE CASE, it's
                                // a piece of behavior of the session model:
@@ -2860,7 +2935,7 @@ 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), 0);
+                                       track->set_gain (dB_to_coefficient (0), Controllable::NoGroup);
                                }
                        }
 
@@ -2959,6 +3034,10 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
                                goto failure;
                        }
 
+                       if (Profile->get_mixbus ()) {
+                               bus->set_strict_io (true);
+                       }
+
 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
                        // boost_debug_shared_ptr_mark_interesting (bus.get(), "Route");
 #endif
@@ -3027,30 +3106,39 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
 }
 
 RouteList
-Session::new_route_from_template (uint32_t how_many, const std::string& template_path, const std::string& name_base)
+Session::new_route_from_template (uint32_t how_many, const std::string& template_path, const std::string& name_base, PlaylistDisposition pd)
 {
-       RouteList ret;
-       uint32_t control_id;
        XMLTree tree;
-       uint32_t number = 0;
-       const uint32_t being_added = how_many;
 
        if (!tree.read (template_path.c_str())) {
-               return ret;
+               return RouteList();
        }
 
-       XMLNode* node = tree.root();
+       return new_route_from_template (how_many, *tree.root(), name_base, pd);
+}
 
+RouteList
+Session::new_route_from_template (uint32_t how_many, XMLNode& node, const std::string& name_base, PlaylistDisposition pd)
+{
+       RouteList ret;
+       uint32_t 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
+          values by Stateful.
+       */
+       Stateful::ForceIDRegeneration force_ids;
        IO::disable_connecting ();
 
        control_id = next_control_id ();
 
        while (how_many) {
 
-               XMLNode node_copy (*node);
+               /* We're going to modify the node contents a bit so take a
+                * copy. The node may be re-used when duplicating more than once.
+                */
 
-               /* Remove IDs of everything so that new ones are used */
-               node_copy.remove_property_recursively (X_("id"));
+               XMLNode node_copy (node);
 
                try {
                        string name;
@@ -3079,16 +3167,65 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                        }
 
                        /* set this name in the XML description that we are about to use */
-                       Route::set_name_in_state (node_copy, name);
+
+                       bool rename_playlist;
+                       switch (pd) {
+                       case NewPlaylist:
+                               rename_playlist = true;
+                               break;
+                       case CopyPlaylist:
+                       case SharePlaylist:
+                               rename_playlist = false;
+                       }
+
+                       Route::set_name_in_state (node_copy, name, rename_playlist);
 
                        /* trim bitslots from listen sends so that new ones are used */
                        XMLNodeList children = node_copy.children ();
                        for (XMLNodeList::iterator i = children.begin(); i != children.end(); ++i) {
                                if ((*i)->name() == X_("Processor")) {
+                                       /* ForceIDRegeneration does not catch the following */
                                        XMLProperty* role = (*i)->property (X_("role"));
+                                       XMLProperty* 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* 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_("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");
+                                       }
                                }
                        }
 
@@ -3117,6 +3254,21 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                        route->set_remote_control_id (control_id);
                        ++control_id;
 
+                       boost::shared_ptr<Track> track;
+
+                       if ((track = boost::dynamic_pointer_cast<Track> (route))) {
+                               switch (pd) {
+                               case NewPlaylist:
+                                       track->use_new_playlist ();
+                                       break;
+                               case CopyPlaylist:
+                                       track->use_copy_playlist ();
+                                       break;
+                               case SharePlaylist:
+                                       break;
+                               }
+                       };
+
                        ret.push_back (route);
 
                        RouteAddedOrRemoved (true); /* EMIT SIGNAL */
@@ -3181,16 +3333,17 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
 void
 Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect)
 {
-        ChanCount existing_inputs;
-        ChanCount existing_outputs;
+       ChanCount existing_inputs;
+       ChanCount existing_outputs;
        uint32_t order = next_control_id();
 
+
        if (_order_hint > -1) {
                order = _order_hint;
                _order_hint = -1;
        }
 
-        count_existing_track_channels (existing_inputs, existing_outputs);
+       count_existing_track_channels (existing_inputs, existing_outputs);
 
        {
                RCUWriter<RouteList> writer (routes);
@@ -3198,10 +3351,10 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
                r->insert (r->end(), new_routes.begin(), new_routes.end());
 
                /* 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);
@@ -3213,10 +3366,10 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
                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, _2, wpr));
-               r->solo_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_changed, this, _1, _3, wpr));
-               r->solo_isolated_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_isolated_changed, this, _1, wpr));
-               r->mute_changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this, _1));
+               r->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->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));
 
@@ -3237,19 +3390,20 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
                        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 (input_auto_connect || output_auto_connect) {
-                       auto_connect_route (r, existing_inputs, existing_outputs, true, input_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();
                }
 
                /* 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.
-               */
+                        reasonable defaults because they also affect the remote control
+                        ID in most situations.
+                        */
 
                if (!r->has_order_key ()) {
                        if (r->is_auditioner()) {
@@ -3272,7 +3426,7 @@ 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 ();
                        }
@@ -3288,7 +3442,7 @@ Session::globally_set_send_gains_to_zero (boost::shared_ptr<Route> dest)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
-                       s->amp()->gain_control()->set_value (GAIN_COEFF_ZERO);
+                       s->amp()->gain_control()->set_value (GAIN_COEFF_ZERO, Controllable::NoGroup);
                }
        }
 }
@@ -3301,7 +3455,7 @@ Session::globally_set_send_gains_to_unity (boost::shared_ptr<Route> dest)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
-                       s->amp()->gain_control()->set_value (GAIN_COEFF_UNITY);
+                       s->amp()->gain_control()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup);
                }
        }
 }
@@ -3314,7 +3468,7 @@ Session::globally_set_send_gains_from_track(boost::shared_ptr<Route> dest)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
-                       s->amp()->gain_control()->set_value ((*i)->gain_control()->get_value());
+                       s->amp()->gain_control()->set_value ((*i)->gain_control()->get_value(), Controllable::NoGroup);
                }
        }
 }
@@ -3382,7 +3536,7 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
                                continue;
                        }
 
-                       (*iter)->set_solo (false, this);
+                       (*iter)->set_solo (false, Controllable::NoGroup);
 
                        rs->remove (*iter);
 
@@ -3452,7 +3606,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 ();
        }
 
@@ -3469,6 +3623,10 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
                (*iter)->drop_references ();
        }
 
+       if (_state_of_the_state & Deletion) {
+               return;
+       }
+
        Route::RemoteControlIDChange(); /* EMIT SIGNAL */
 
        /* save the new state of the world */
@@ -3490,13 +3648,13 @@ Session::remove_route (boost::shared_ptr<Route> route)
 }
 
 void
-Session::route_mute_changed (void* /*src*/)
+Session::route_mute_changed ()
 {
        set_dirty ();
 }
 
 void
-Session::route_listen_changed (bool group_override, boost::weak_ptr<Route> wpr)
+Session::route_listen_changed (Controllable::GroupControlDisposition group_override, boost::weak_ptr<Route> wpr)
 {
        boost::shared_ptr<Route> route = wpr.lock();
        if (!route) {
@@ -3507,18 +3665,32 @@ Session::route_listen_changed (bool group_override, boost::weak_ptr<Route> wpr)
        if (route->listening_via_monitor ()) {
 
                if (Config->get_exclusive_solo()) {
-                       /* new listen: disable all other listen, except solo-grouped channels */
+
                        RouteGroup* rg = route->route_group ();
-                       bool leave_group_alone = (rg && rg->is_active() && rg->is_solo());
-                       if (group_override && rg) {
-                               leave_group_alone = !leave_group_alone;
-                       }
+                       const bool group_already_accounted_for = route->use_group (group_override, &RouteGroup::is_solo);
+
                        boost::shared_ptr<RouteList> r = routes.reader ();
+
                        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                               if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner() || (leave_group_alone && ((*i)->route_group() == rg))) {
+                               if ((*i) == route) {
+                                       /* already changed */
+                                       continue;
+                               }
+
+                               if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                                       /* route does not get solo propagated to it */
+                                       continue;
+                               }
+
+                               if ((group_already_accounted_for && (*i)->route_group() && (*i)->route_group() == rg)) {
+                                       /* this route is a part of the same solo group as the route
+                                        * that was changed. Changing that route did change or will
+                                        * change all group members appropriately, so we can ignore it
+                                        * here
+                                        */
                                        continue;
                                }
-                               (*i)->set_listen (false, this, group_override);
+                               (*i)->set_listen (false, Controllable::NoGroup);
                        }
                }
 
@@ -3532,7 +3704,7 @@ Session::route_listen_changed (bool group_override, boost::weak_ptr<Route> wpr)
        update_route_solo_state ();
 }
 void
-Session::route_solo_isolated_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
+Session::route_solo_isolated_changed (boost::weak_ptr<Route> wpr)
 {
        boost::shared_ptr<Route> route = wpr.lock ();
 
@@ -3562,7 +3734,7 @@ Session::route_solo_isolated_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
 }
 
 void
-Session::route_solo_changed (bool self_solo_change, bool group_override,  boost::weak_ptr<Route> wpr)
+Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDisposition group_override,  boost::weak_ptr<Route> wpr)
 {
        DEBUG_TRACE (DEBUG::Solo, string_compose ("route solo change, self = %1\n", self_solo_change));
 
@@ -3583,21 +3755,51 @@ Session::route_solo_changed (bool self_solo_change, bool group_override,  boost:
                delta = -1;
        }
 
+       /* the route may be a member of a group that has shared-solo
+        * semantics. If so, then all members of that group should follow the
+        * solo of the changed route. But ... this is optional, controlled by a
+        * Controllable::GroupControlDisposition.
+        *
+        * The first argument to the signal that this method is connected to is the
+        * GroupControlDisposition value that was used to change solo.
+        *
+        * If the solo change was done with group semantics (either InverseGroup
+        * (force the entire group to change even if the group shared solo is
+        * disabled) or UseGroup (use the group, which may or may not have the
+        * shared solo property enabled)) then as we propagate the change to
+        * the entire session we should IGNORE THE GROUP that the changed route
+        * belongs to.
+        */
+
        RouteGroup* rg = route->route_group ();
-       bool leave_group_alone = (rg && rg->is_active() && rg->is_solo());
-       if (group_override && rg) {
-               leave_group_alone = !leave_group_alone;
-       }
+       const bool group_already_accounted_for = (group_override == Controllable::ForGroup);
+
        if (delta == 1 && Config->get_exclusive_solo()) {
 
                /* new solo: disable all other solos, but not the group if its solo-enabled */
 
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       if ((*i) == route || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner() ||
-                           (leave_group_alone && ((*i)->route_group() == rg))) {
+
+                       if ((*i) == route) {
+                               /* already changed */
+                               continue;
+                       }
+
+                       if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                               /* route does not get solo propagated to it */
+                               continue;
+                       }
+
+                       if ((group_already_accounted_for && (*i)->route_group() && (*i)->route_group() == rg)) {
+                               /* this route is a part of the same solo group as the route
+                                * that was changed. Changing that route did change or will
+                                * change all group members appropriately, so we can ignore it
+                                * here
+                                */
                                continue;
                        }
-                       (*i)->set_solo (false, this, group_override);
+
+                       (*i)->set_solo (false, group_override);
                }
        }
 
@@ -3611,8 +3813,22 @@ Session::route_solo_changed (bool self_solo_change, bool group_override,  boost:
                bool via_sends_only;
                bool in_signal_flow;
 
-               if ((*i) == route || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner() ||
-                   (leave_group_alone && ((*i)->route_group() == rg))) {
+               if ((*i) == route) {
+                       /* already changed */
+                       continue;
+               }
+
+               if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                       /* route does not get solo propagated to it */
+                       continue;
+               }
+
+               if ((group_already_accounted_for && (*i)->route_group() && (*i)->route_group() == rg)) {
+                       /* this route is a part of the same solo group as the route
+                        * that was changed. Changing that route did change or will
+                        * change all group members appropriately, so we can ignore it
+                        * here
+                        */
                        continue;
                }
 
@@ -3678,7 +3894,7 @@ Session::route_solo_changed (bool self_solo_change, bool group_override,  boost:
        for (RouteList::iterator i = uninvolved.begin(); i != uninvolved.end(); ++i) {
                DEBUG_TRACE (DEBUG::Solo, string_compose ("mute change for %1, which neither feeds or is fed by %2\n", (*i)->name(), route->name()));
                (*i)->act_on_mute ();
-               (*i)->mute_changed (this);
+               (*i)->mute_changed ();
        }
 
        SoloChanged (); /* EMIT SIGNAL */
@@ -3691,6 +3907,7 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
        /* now figure out if anything that matters is soloed (or is "listening")*/
 
        bool something_soloed = false;
+       bool something_listening = false;
        uint32_t listeners = 0;
        uint32_t isolated = 0;
 
@@ -3706,8 +3923,9 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
                if (!(*i)->is_auditioner() && (*i)->listening_via_monitor()) {
                        if (Config->get_solo_control_is_listen_control()) {
                                listeners++;
+                               something_listening = true;
                        } else {
-                               (*i)->set_listen (false, this);
+                               (*i)->set_listen (false, Controllable::NoGroup);
                        }
                }
 
@@ -3721,6 +3939,11 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
                SoloActive (_non_soloed_outs_muted); /* EMIT SIGNAL */
        }
 
+       if (something_listening != _listening) {
+               _listening = something_listening;
+               SoloActive (_listening);
+       }
+
        _listen_cnt = listeners;
 
        if (isolated != _solo_isolated_cnt) {
@@ -3753,6 +3976,11 @@ Session::io_name_is_legal (const std::string& name)
 
        for (vector<string>::const_iterator reserved = reserved_io_names.begin(); reserved != reserved_io_names.end(); ++reserved) {
                if (name == *reserved) {
+                       if (!route_by_name (*reserved)) {
+                               /* first instance of a reserved name is allowed */
+                               return true;
+                       }
+                       /* all other instances of a reserved name are not allowed */
                        return false;
                }
        }
@@ -3878,6 +4106,21 @@ Session::route_by_id (PBD::ID id)
        return boost::shared_ptr<Route> ((Route*) 0);
 }
 
+boost::shared_ptr<Processor>
+Session::processor_by_id (PBD::ID id) const
+{
+       boost::shared_ptr<RouteList> r = routes.reader ();
+
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               boost::shared_ptr<Processor> p = (*i)->Route::processor_by_id (id);
+               if (p) {
+                       return p;
+               }
+       }
+
+       return boost::shared_ptr<Processor> ();
+}
+
 boost::shared_ptr<Track>
 Session::track_by_diskstream_id (PBD::ID id)
 {
@@ -3908,6 +4151,19 @@ Session::route_by_remote_id (uint32_t id)
 }
 
 
+boost::shared_ptr<Route>
+Session::route_by_selected_count (uint32_t id)
+{
+       boost::shared_ptr<RouteList> r = routes.reader ();
+
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               /* NOT IMPLEMENTED */
+       }
+
+       return boost::shared_ptr<Route> ((Route*) 0);
+}
+
+
 void
 Session::reassign_track_numbers ()
 {
@@ -4730,6 +4986,228 @@ Session::audition_playlist ()
        queue_event (ev);
 }
 
+
+void
+Session::register_lua_function (
+               const std::string& name,
+               const std::string& script,
+               const LuaScriptParamList& args
+               )
+{
+       Glib::Threads::Mutex::Lock lm (lua_lock);
+
+       lua_State* L = lua.getState();
+
+       const std::string& bytecode = LuaScripting::get_factory_bytecode (script);
+       luabridge::LuaRef tbl_arg (luabridge::newTable(L));
+       for (LuaScriptParamList::const_iterator i = args.begin(); i != args.end(); ++i) {
+               if ((*i)->optional && !(*i)->is_set) { continue; }
+               tbl_arg[(*i)->name] = (*i)->value;
+       }
+       (*_lua_add)(name, bytecode, tbl_arg); // throws luabridge::LuaException
+       set_dirty();
+}
+
+void
+Session::unregister_lua_function (const std::string& name)
+{
+       Glib::Threads::Mutex::Lock lm (lua_lock);
+       (*_lua_del)(name); // throws luabridge::LuaException
+       lua.collect_garbage ();
+       set_dirty();
+}
+
+std::vector<std::string>
+Session::registered_lua_functions ()
+{
+       Glib::Threads::Mutex::Lock lm (lua_lock);
+       std::vector<std::string> rv;
+
+       try {
+               luabridge::LuaRef list ((*_lua_list)());
+               for (luabridge::Iterator i (list); !i.isNil (); ++i) {
+                       if (!i.key ().isString ()) { assert(0); continue; }
+                       rv.push_back (i.key ().cast<std::string> ());
+               }
+       } catch (luabridge::LuaException const& e) { }
+       return rv;
+}
+
+#ifndef NDEBUG
+static void _lua_print (std::string s) {
+       std::cout << "SessionLua: " << s << "\n";
+}
+#endif
+
+void
+Session::try_run_lua (pframes_t nframes)
+{
+       if (_n_lua_scripts == 0) return;
+       Glib::Threads::Mutex::Lock tm (lua_lock, Glib::Threads::TRY_LOCK);
+       if (tm.locked ()) {
+               try { (*_lua_run)(nframes); } catch (luabridge::LuaException const& e) { }
+       }
+}
+
+void
+Session::setup_lua ()
+{
+#ifndef NDEBUG
+       lua.Print.connect (&_lua_print);
+#endif
+       lua.do_command (
+                       "function ArdourSession ()"
+                       "  local self = { scripts = {}, instances = {} }"
+                       ""
+                       "  local remove = function (n)"
+                       "   self.scripts[n] = nil"
+                       "   self.instances[n] = nil"
+                       "   Session:scripts_changed()" // call back
+                       "  end"
+                       ""
+                       "  local addinternal = function (n, f, a)"
+                       "   assert(type(n) == 'string', 'function-name must be string')"
+                       "   assert(type(f) == 'function', 'Given script is a not a function')"
+                       "   assert(type(a) == 'table' or type(a) == 'nil', 'Given argument is invalid')"
+                       "   assert(self.scripts[n] == nil, 'Callback \"'.. n ..'\" already exists.')"
+                       "   self.scripts[n] = { ['f'] = f, ['a'] = a }"
+                       "   local env = _ENV;  env.f = nil env.io = nil env.os = nil env.loadfile = nil env.require = nil env.dofile = nil env.package = nil env.debug = nil"
+                       "   local env = { print = print, 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 }"
+                       "   self.instances[n] = load (string.dump(f, true), nil, nil, env)(a)"
+                       "   Session:scripts_changed()" // call back
+                       "  end"
+                       ""
+                       "  local add = function (n, b, a)"
+                       "   assert(type(b) == 'string', 'ByteCode must be string')"
+                       "   load (b)()" // assigns f
+                       "   assert(type(f) == 'string', 'Assigned ByteCode must be string')"
+                       "   addinternal (n, load(f), a)"
+                       "  end"
+                       ""
+                       "  local run = function (...)"
+                       "   for n, s in pairs (self.instances) do"
+                       "     local status, err = pcall (s, ...)"
+                       "     if not status then"
+                       "       print ('fn \"'.. n .. '\": ', err)"
+                       "       remove (n)"
+                       "      end"
+                       "   end"
+                       "   collectgarbage()"
+                       "  end"
+                       ""
+                       "  local cleanup = function ()"
+                       "   self.scripts = nil"
+                       "   self.instances = nil"
+                       "  end"
+                       ""
+                       "  local list = function ()"
+                       "   local rv = {}"
+                       "   for n, _ in pairs (self.scripts) do"
+                       "     rv[n] = true"
+                       "   end"
+                       "   return rv"
+                       "  end"
+                       ""
+                       "  local function basic_serialize (o)"
+                       "    if type(o) == \"number\" then"
+                       "     return tostring(o)"
+                       "    else"
+                       "     return string.format(\"%q\", o)"
+                       "    end"
+                       "  end"
+                       ""
+                       "  local function serialize (name, value)"
+                       "   local rv = name .. ' = '"
+                       "   collectgarbage()"
+                       "   if type(value) == \"number\" or type(value) == \"string\" or type(value) == \"nil\" then"
+                       "    return rv .. basic_serialize(value) .. ' '"
+                       "   elseif type(value) == \"table\" then"
+                       "    rv = rv .. '{} '"
+                       "    for k,v in pairs(value) do"
+                       "     local fieldname = string.format(\"%s[%s]\", name, basic_serialize(k))"
+                       "     rv = rv .. serialize(fieldname, v) .. ' '"
+                       "     collectgarbage()" // string concatenation allocates a new string :(
+                       "    end"
+                       "    return rv;"
+                       "   elseif type(value) == \"function\" then"
+                       "     return rv .. string.format(\"%q\", string.dump(value, true))"
+                       "   else"
+                       "    error('cannot save a ' .. type(value))"
+                       "   end"
+                       "  end"
+                       ""
+                       ""
+                       "  local save = function ()"
+                       "   return (serialize('scripts', self.scripts))"
+                       "  end"
+                       ""
+                       "  local restore = function (state)"
+                       "   self.scripts = {}"
+                       "   load (state)()"
+                       "   for n, s in pairs (scripts) do"
+                       "    addinternal (n, load(s['f']), s['a'])"
+                       "   end"
+                       "  end"
+                       ""
+                       " return { run = run, add = add, remove = remove,"
+                 "          list = list, restore = restore, save = save, cleanup = cleanup}"
+                       " end"
+                       " "
+                       " sess = ArdourSession ()"
+                       " ArdourSession = nil"
+                       " "
+                       "function ardour () end"
+                       );
+
+       lua_State* L = lua.getState();
+
+       try {
+               luabridge::LuaRef lua_sess = luabridge::getGlobal (L, "sess");
+               lua.do_command ("sess = nil"); // hide it.
+               lua.do_command ("collectgarbage()");
+
+               _lua_run = new luabridge::LuaRef(lua_sess["run"]);
+               _lua_add = new luabridge::LuaRef(lua_sess["add"]);
+               _lua_del = new luabridge::LuaRef(lua_sess["remove"]);
+               _lua_list = new luabridge::LuaRef(lua_sess["list"]);
+               _lua_save = new luabridge::LuaRef(lua_sess["save"]);
+               _lua_load = new luabridge::LuaRef(lua_sess["restore"]);
+               _lua_cleanup = new luabridge::LuaRef(lua_sess["cleanup"]);
+       } catch (luabridge::LuaException const& e) {
+               fatal << string_compose (_("programming error: %1"),
+                               X_("Failed to setup Lua interpreter"))
+                       << endmsg;
+               abort(); /*NOTREACHED*/
+       }
+
+       LuaBindings::stddef (L);
+       LuaBindings::common (L);
+       LuaBindings::dsp (L);
+       luabridge::push <Session *> (L, this);
+       lua_setglobal (L, "Session");
+}
+
+void
+Session::scripts_changed ()
+{
+       assert (!lua_lock.trylock()); // must hold lua_lock
+
+       try {
+               luabridge::LuaRef list ((*_lua_list)());
+               int cnt = 0;
+               for (luabridge::Iterator i (list); !i.isNil (); ++i) {
+                       if (!i.key ().isString ()) { assert(0); continue; }
+                       ++cnt;
+               }
+               _n_lua_scripts = cnt;
+       } catch (luabridge::LuaException const& e) {
+               fatal << string_compose (_("programming error: %1"),
+                               X_("Indexing Lua Session Scripts failed."))
+                       << endmsg;
+               abort(); /*NOTREACHED*/
+       }
+}
+
 void
 Session::non_realtime_set_audition ()
 {
@@ -4954,7 +5432,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;
@@ -4974,7 +5452,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;
@@ -4994,7 +5472,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;
@@ -5014,7 +5492,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;
@@ -5095,6 +5573,7 @@ Session::unmark_aux_send_id (uint32_t id)
 void
 Session::unmark_return_id (uint32_t id)
 {
+       if (_state_of_the_state & Deletion) { return; }
        if (id < return_bitset.size()) {
                return_bitset[id] = false;
        }
@@ -5404,6 +5883,7 @@ Session::write_one_track (Track& track, framepos_t start, framepos_t end,
        }
 
        unblock_processing ();
+       itt.done = true;
 
        return result;
 }
@@ -5444,6 +5924,12 @@ Session::get_scratch_buffers (ChanCount count, bool silence)
        return ProcessThread::get_scratch_buffers (count, silence);
 }
 
+BufferSet&
+Session::get_noinplace_buffers (ChanCount count)
+{
+       return ProcessThread::get_noinplace_buffers (count);
+}
+
 BufferSet&
 Session::get_route_buffers (ChanCount count, bool silence)
 {
@@ -6244,3 +6730,191 @@ 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::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 ();
+                       }
+               }
+
+               pthread_cond_wait (&_auto_connect_cond, &_auto_connect_mutex);
+       }
+       pthread_mutex_unlock (&_auto_connect_mutex);
+}