fix crash when copy'ing latent plugins
[ardour.git] / libs / ardour / route.cc
index de854e7d269d5755df83c8add4bb9774392def1e..11db73241cbd304c629a556828f02611134678c9 100644 (file)
@@ -33,7 +33,6 @@
 #include "pbd/memento_command.h"
 #include "pbd/stacktrace.h"
 #include "pbd/convert.h"
-#include "pbd/boost_debug.h"
 #include "pbd/unwind.h"
 
 #include "ardour/amp.h"
@@ -41,6 +40,7 @@
 #include "ardour/audio_track.h"
 #include "ardour/audio_port.h"
 #include "ardour/audioengine.h"
+#include "ardour/boost_debug.h"
 #include "ardour/buffer.h"
 #include "ardour/buffer_set.h"
 #include "ardour/capturing_processor.h"
@@ -58,6 +58,7 @@
 #include "ardour/panner.h"
 #include "ardour/panner_shell.h"
 #include "ardour/parameter_descriptor.h"
+#include "ardour/phase_control.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/port.h"
 #include "ardour/port_insert.h"
 #include "ardour/route_group.h"
 #include "ardour/send.h"
 #include "ardour/session.h"
+#include "ardour/solo_control.h"
+#include "ardour/solo_isolate_control.h"
 #include "ardour/unknown_processor.h"
 #include "ardour/utils.h"
+#include "ardour/vca.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-PBD::Signal0<void> Route::SyncOrderKeys;
-PBD::Signal0<void> Route::RemoteControlIDChange;
+PBD::Signal3<int,boost::shared_ptr<Route>, boost::shared_ptr<PluginInsert>, Route::PluginSetupOptions > Route::PluginSetup;
 
-Route::Route (Session& sess, string name, Flag flg, DataType default_type)
-       : SessionObject (sess, name)
-       , Automatable (sess)
+/** Base class for all routable/mixable objects (tracks and busses) */
+Route::Route (Session& sess, string name, PresentationInfo::Flag flag, DataType default_type)
+       : Stripable (sess, name, PresentationInfo (flag))
        , GraphNode (sess._process_graph)
+       , Muteable (sess, name)
+       , Automatable (sess)
        , _active (true)
        , _signal_latency (0)
        , _signal_latency_at_amp_position (0)
@@ -91,32 +96,23 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _roll_delay (0)
        , _pending_process_reorder (0)
        , _pending_signals (0)
-       , _flags (flg)
        , _pending_declick (true)
        , _meter_point (MeterPostFader)
        , _pending_meter_point (MeterPostFader)
        , _meter_type (MeterPeak)
-       , _self_solo (false)
-       , _soloed_by_others_upstream (0)
-       , _soloed_by_others_downstream (0)
-       , _solo_isolated (false)
-       , _solo_isolated_by_upstream (0)
        , _denormal_protection (false)
        , _recordable (true)
        , _silent (false)
        , _declickable (false)
-       , _mute_master (new MuteMaster (sess, name))
        , _have_internal_generator (false)
-       , _solo_safe (false)
        , _default_type (default_type)
-       , _order_key (0)
-       , _has_order_key (false)
-       , _remote_control_id (0)
        , _track_number (0)
        , _in_configure_processors (false)
        , _initial_io_setup (false)
+       , _in_sidechain_setup (false)
        , _strict_io (false)
        , _custom_meter_position_noted (false)
+       , _pinmgr_proxy (0)
 {
        processor_max_streams.reset();
 }
@@ -136,24 +132,31 @@ Route::init ()
 
        /* add standard controls */
 
-       _solo_control.reset (new SoloControllable (X_("solo"), shared_from_this ()));
-       _mute_control.reset (new MuteControllable (X_("mute"), shared_from_this ()));
-       _phase_control.reset (new PhaseControllable (X_("phase"), shared_from_this ()));
-
-       _solo_isolate_control.reset (new SoloIsolateControllable (X_("solo-iso"), shared_from_this ()));
-       _solo_safe_control.reset (new SoloSafeControllable (X_("solo-safe"), shared_from_this ()));
+       _gain_control.reset (new GainControl (_session, GainAutomation));
+       add_control (_gain_control);
 
-       _solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
-       _mute_control->set_flags (Controllable::Flag (_mute_control->flags() | Controllable::Toggle));
-       _phase_control->set_flags (Controllable::Flag (_phase_control->flags() | Controllable::Toggle));
+       _trim_control.reset (new GainControl (_session, TrimAutomation));
+       add_control (_trim_control);
 
+       _solo_control.reset (new SoloControl (_session, X_("solo"), *this, *this));
        add_control (_solo_control);
+       _solo_control->Changed.connect_same_thread (*this, boost::bind (&Route::solo_control_changed, this, _1, _2));
+
+       _mute_control.reset (new MuteControl (_session, X_("mute"), *this));
        add_control (_mute_control);
+
+       _phase_control.reset (new PhaseControl (_session, X_("phase")));
        add_control (_phase_control);
 
+       _solo_isolate_control.reset (new SoloIsolateControl (_session, X_("solo-iso"), *this, *this));
+       add_control (_solo_isolate_control);
+
+       _solo_safe_control.reset (new SoloSafeControl (_session, X_("solo-safe")));
+       add_control (_solo_safe_control);
+
        /* panning */
 
-       if (!(_flags & Route::MonitorOut)) {
+       if (!(_presentation_info.flags() & PresentationInfo::MonitorOut)) {
                _pannable.reset (new Pannable (_session));
        }
 
@@ -168,17 +171,9 @@ Route::init ()
        _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2));
        _output->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::output_port_count_changing, this, _1));
 
-#if 0 // not used - just yet
-       if (!is_master() && !is_monitor() && !is_auditioner()) {
-               _delayline.reset (new DelayLine (_session, _name));
-               add_processor (_delayline, PreFader);
-       }
-#endif
-
-       /* add amp processor  */
-
-       _gain_control = boost::shared_ptr<GainControllable> (new GainControllable (_session, GainAutomation, shared_from_this ()));
-       add_control (_gain_control);
+       /* add the amp/fader processor.
+        * it should be the first processor to be added on every route.
+        */
 
        _amp.reset (new Amp (_session, X_("Fader"), _gain_control, true));
        add_processor (_amp, PostFader);
@@ -187,10 +182,14 @@ Route::init ()
                _amp->set_display_name (_("Monitor"));
        }
 
-       /* and input trim */
+#if 0 // not used - just yet
+       if (!is_master() && !is_monitor() && !is_auditioner()) {
+               _delayline.reset (new DelayLine (_session, _name));
+               add_processor (_delayline, PreFader);
+       }
+#endif
 
-       _trim_control = boost::shared_ptr<GainControllable> (new GainControllable (_session, TrimAutomation, shared_from_this ()));
-       add_control (_trim_control);
+       /* and input trim */
 
        _trim.reset (new Amp (_session, X_("Trim"), _trim_control, false));
        _trim->set_display_to_user (false);
@@ -230,10 +229,6 @@ Route::init ()
                _monitor_control->activate ();
        }
 
-       if (is_master() || is_monitor() || is_auditioner()) {
-               _mute_master->set_solo_ignore (true);
-       }
-
        /* now that we have _meter, its safe to connect to this */
 
        {
@@ -265,120 +260,6 @@ Route::~Route ()
        _processors.clear ();
 }
 
-void
-Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
-{
-       if (Config->get_remote_model() != UserOrdered) {
-               return;
-       }
-
-       set_remote_control_id_internal (id, notify_class_listeners);
-}
-
-void
-Route::set_remote_control_id_internal (uint32_t id, bool notify_class_listeners)
-{
-       /* force IDs for master/monitor busses and prevent
-          any other route from accidentally getting these IDs
-          (i.e. legacy sessions)
-       */
-
-       if (is_master() && id != MasterBusRemoteControlID) {
-               id = MasterBusRemoteControlID;
-       }
-
-       if (is_monitor() && id != MonitorBusRemoteControlID) {
-               id = MonitorBusRemoteControlID;
-       }
-
-       if (id < 1) {
-               return;
-       }
-
-       /* don't allow it to collide */
-
-       if (!is_master () && !is_monitor() &&
-           (id == MasterBusRemoteControlID || id == MonitorBusRemoteControlID)) {
-               id += MonitorBusRemoteControlID;
-       }
-
-       if (id != remote_control_id()) {
-               _remote_control_id = id;
-               RemoteControlIDChanged ();
-
-               if (notify_class_listeners) {
-                       RemoteControlIDChange ();
-               }
-       }
-}
-
-uint32_t
-Route::remote_control_id() const
-{
-       if (is_master()) {
-               return MasterBusRemoteControlID;
-       }
-
-       if (is_monitor()) {
-               return MonitorBusRemoteControlID;
-       }
-
-       return _remote_control_id;
-}
-
-bool
-Route::has_order_key () const
-{
-       return _has_order_key;
-}
-
-uint32_t
-Route::order_key () const
-{
-       return _order_key;
-}
-
-void
-Route::set_remote_control_id_explicit (uint32_t rid)
-{
-       if (is_master() || is_monitor() || is_auditioner()) {
-               /* hard-coded remote IDs, or no remote ID */
-               return;
-       }
-
-       if (_remote_control_id != rid) {
-               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1: set edit-based RID to %2\n", name(), rid));
-               _remote_control_id = rid;
-               RemoteControlIDChanged (); /* EMIT SIGNAL (per-route) */
-       }
-
-       /* don't emit the class-level RID signal RemoteControlIDChange here,
-          leave that to the entity that changed the order key, so that we
-          don't get lots of emissions for no good reasons (e.g. when changing
-          all route order keys).
-
-          See Session::sync_remote_id_from_order_keys() for the (primary|only)
-          spot where that is emitted.
-       */
-}
-
-void
-Route::set_order_key (uint32_t n)
-{
-       _has_order_key = true;
-
-       if (_order_key == n) {
-               return;
-       }
-
-       _order_key = n;
-
-       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 order key set to %2\n",
-                                                      name(), order_key ()));
-
-       _session.set_dirty ();
-}
-
 string
 Route::ensure_track_or_route_name(string name, Session &session)
 {
@@ -391,83 +272,11 @@ Route::ensure_track_or_route_name(string name, Session &session)
        return newname;
 }
 
-void
-Route::inc_gain (gain_t factor)
-{
-       /* To be used ONLY when doing group-relative gain adjustment, from
-        * ::set_gain()
-        */
-
-       float desired_gain = _gain_control->user_double();
-
-       if (fabsf (desired_gain) < GAIN_COEFF_SMALL) {
-               // really?! what's the idea here?
-               _gain_control->route_set_value (0.000001f + (0.000001f * factor));
-       } else {
-               _gain_control->route_set_value (desired_gain + (desired_gain * factor));
-       }
-}
-
-void
-Route::set_gain (gain_t val, Controllable::GroupControlDisposition group_override)
-{
-       if (use_group (group_override, &RouteGroup::is_gain)) {
-
-               if (_route_group->is_relative()) {
-
-                       gain_t usable_gain = _gain_control->get_value();
-                       if (usable_gain < 0.000001f) {
-                               usable_gain = 0.000001f;
-                       }
-
-                       gain_t delta = val;
-                       if (delta < 0.000001f) {
-                               delta = 0.000001f;
-                       }
-
-                       delta -= usable_gain;
-
-                       if (delta == 0.0f)
-                               return;
-
-                       gain_t factor = delta / usable_gain;
-
-                       if (factor > 0.0f) {
-                               factor = _route_group->get_max_factor(factor);
-                               if (factor == 0.0f) {
-                                       _amp->gain_control()->Changed(); /* EMIT SIGNAL */
-                                       return;
-                               }
-                       } else {
-                               factor = _route_group->get_min_factor(factor);
-                               if (factor == 0.0f) {
-                                       _amp->gain_control()->Changed(); /* EMIT SIGNAL */
-                                       return;
-                               }
-                       }
-
-                       _route_group->foreach_route (boost::bind (&Route::inc_gain, _1, factor));
-
-               } else {
-
-                       _route_group->foreach_route (boost::bind (&Route::set_gain, _1, val, Controllable::NoGroup));
-               }
-
-               return;
-       }
-
-       if (val == _gain_control->get_value()) {
-               return;
-       }
-
-       _gain_control->route_set_value (val);
-}
-
 void
 Route::set_trim (gain_t val, Controllable::GroupControlDisposition /* group override */)
 {
        // TODO route group, see set_gain()
-       _trim_control->route_set_value (val);
+       // _trim_control->route_set_value (val);
 }
 
 void
@@ -504,6 +313,8 @@ Route::process_output_buffers (BufferSet& bufs,
                return;
        }
 
+       _mute_control->automation_run (start_frame, nframes);
+
        /* figure out if we're going to use gain automation */
        if (gain_automation_ok) {
                _amp->set_gain_automation_buffer (_session.gain_automation_buffer ());
@@ -544,7 +355,7 @@ Route::process_output_buffers (BufferSet& bufs,
           DENORMAL CONTROL/PHASE INVERT
           ----------------------------------------------------------------------------------------- */
 
-       if (_phase_invert.any ()) {
+       if (!_phase_control->none()) {
 
                int chn = 0;
 
@@ -553,7 +364,7 @@ Route::process_output_buffers (BufferSet& bufs,
                        for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
                                Sample* const sp = i->data();
 
-                               if (_phase_invert[chn]) {
+                               if (_phase_control->inverted (chn)) {
                                        for (pframes_t nx = 0; nx < nframes; ++nx) {
                                                sp[nx]  = -sp[nx];
                                                sp[nx] += 1.0e-27f;
@@ -570,7 +381,7 @@ Route::process_output_buffers (BufferSet& bufs,
                        for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
                                Sample* const sp = i->data();
 
-                               if (_phase_invert[chn]) {
+                               if (_phase_control->inverted (chn)) {
                                        for (pframes_t nx = 0; nx < nframes; ++nx) {
                                                sp[nx] = -sp[nx];
                                        }
@@ -600,6 +411,7 @@ Route::process_output_buffers (BufferSet& bufs,
        bool const meter_already_run = metering_state() == MeteringInput;
 
        framecnt_t latency = 0;
+       const double speed = _session.transport_speed ();
 
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
@@ -629,8 +441,13 @@ Route::process_output_buffers (BufferSet& bufs,
                if (boost::dynamic_pointer_cast<Send>(*i) != 0) {
                        boost::dynamic_pointer_cast<Send>(*i)->set_delay_in(_signal_latency - latency);
                }
+               if (boost::dynamic_pointer_cast<PluginInsert>(*i) != 0) {
+                       const framecnt_t longest_session_latency = _initial_delay + _signal_latency;
+                       boost::dynamic_pointer_cast<PluginInsert>(*i)->set_sidechain_latency (
+                                       _initial_delay + latency, longest_session_latency - latency);
+               }
 
-               (*i)->run (bufs, start_frame - latency, end_frame - latency, nframes, *i != _processors.back());
+               (*i)->run (bufs, start_frame - latency, end_frame - latency, speed, nframes, *i != _processors.back());
                bufs.set_count ((*i)->output_streams());
 
                if ((*i)->active ()) {
@@ -658,6 +475,7 @@ Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
        _trim->setup_gain_automation (start, start + nframes, nframes);
 
        latency = 0;
+       const double speed = _session.transport_speed ();
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
                if (!include_endpoint && (*i) == endpoint) {
@@ -680,7 +498,7 @@ Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
                 */
                if ((*i) == _main_outs) {
                        assert ((*i)->does_routing());
-                       (*i)->run (buffers, start - latency, start - latency + nframes, nframes, true);
+                       (*i)->run (buffers, start - latency, start - latency + nframes, speed, nframes, true);
                        buffers.set_count ((*i)->output_streams());
                }
 
@@ -688,7 +506,7 @@ Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
                 * Also don't bother with metering.
                 */
                if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
-                       (*i)->run (buffers, start - latency, start - latency + nframes, nframes, true);
+                       (*i)->run (buffers, start - latency, start - latency + nframes, 1.0, nframes, true);
                        buffers.set_count ((*i)->output_streams());
                        latency += (*i)->signal_latency ();
                }
@@ -801,291 +619,38 @@ Route::passthru_silence (framepos_t start_frame, framepos_t end_frame, pframes_t
 }
 
 void
-Route::set_listen (bool yn, Controllable::GroupControlDisposition group_override)
+Route::set_listen (bool yn)
 {
-       if (_solo_safe) {
-               return;
-       }
-
-       if (use_group (group_override, &RouteGroup::is_solo)) {
-               _route_group->foreach_route (boost::bind (&Route::set_listen, _1, yn, Controllable::ForGroup));
-               return;
-       }
-
        if (_monitor_send) {
-               if (yn != _monitor_send->active()) {
-                       if (yn) {
-                               _monitor_send->activate ();
-                               _mute_master->set_soloed_by_self (true);
-                       } else {
-                               _monitor_send->deactivate ();
-                               _mute_master->set_soloed_by_self (false);
-                       }
-                       _mute_master->set_soloed_by_others (false);
-
-                       listen_changed (group_override); /* EMIT SIGNAL */
-               }
-       }
-}
-
-bool
-Route::listening_via_monitor () const
-{
-       if (_monitor_send) {
-               return _monitor_send->active ();
-       } else {
-               return false;
-       }
-}
-
-void
-Route::set_solo_safe (bool yn, Controllable::GroupControlDisposition /* group_override */)
-{
-       if (_solo_safe != yn) {
-               _solo_safe = yn;
-               solo_safe_changed (); /* EMIT SIGNAL */
-               _solo_safe_control->Changed(); /* EMIT SIGNAL */
-       }
-}
-
-bool
-Route::solo_safe() const
-{
-       return _solo_safe;
-}
-
-void
-Route::clear_all_solo_state ()
-{
-       // ideally this function will never do anything, it only exists to forestall Murphy
-       bool emit_changed = false;
-
-#ifndef NDEBUG
-       // these are really debug messages, but of possible interest.
-       if (_self_solo) {
-               PBD::info << string_compose (_("Cleared Explicit solo: %1\n"), name());
-       }
-       if (_soloed_by_others_upstream || _soloed_by_others_downstream) {
-               PBD::info << string_compose (_("Cleared Implicit solo: %1 up:%2 down:%3\n"),
-                               name(), _soloed_by_others_upstream, _soloed_by_others_downstream);
-       }
-#endif
-
-       if (!_self_solo && (_soloed_by_others_upstream || _soloed_by_others_downstream)) {
-               // if self-soled, set_solo() will do signal emission
-               emit_changed = true;
-       }
-
-       _soloed_by_others_upstream = 0;
-       _soloed_by_others_downstream = 0;
-
-       {
-               PBD::Unwinder<bool> uw (_solo_safe, false);
-               set_solo (false, Controllable::NoGroup);
-       }
-
-       if (emit_changed) {
-               set_mute_master_solo ();
-               solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
-       }
-}
-
-void
-Route::set_solo (bool yn, Controllable::GroupControlDisposition group_override)
-{
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set solo => %2, grp ? %3 currently self-soloed ? %4\n",
-                                                 name(), yn, enum_2_string(group_override), self_soloed()));
-
-       if (_solo_safe) {
-               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change due to solo-safe\n", name()));
-               return;
-       }
-
-       if (is_master() || is_monitor() || is_auditioner()) {
-               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change (master, monitor or auditioner)\n", name()));
-               return;
-       }
-
-       if (use_group (group_override, &RouteGroup::is_solo)) {
-               _route_group->foreach_route (boost::bind (&Route::set_solo, _1, yn, Controllable::ForGroup));
-               return;
-       }
-
-       if (self_soloed() != yn) {
-               set_self_solo (yn);
-               solo_changed (true, group_override); /* EMIT SIGNAL */
-               _solo_control->Changed (); /* EMIT SIGNAL */
-       }
-
-       assert (Config->get_solo_control_is_listen_control() || !_monitor_send || !_monitor_send->active());
-
-       /* XXX TRACKS DEVELOPERS: THIS LOGIC SUGGESTS THAT YOU ARE NOT AWARE OF
-          Config->get_solo_mute_overrride().
-       */
-
-       if (yn && Profile->get_trx()) {
-               set_mute (false, Controllable::UseGroup);
-       }
-}
-
-void
-Route::set_self_solo (bool yn)
-{
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set SELF solo => %2\n", name(), yn));
-       _self_solo = yn;
-       set_mute_master_solo ();
-}
-
-void
-Route::mod_solo_by_others_upstream (int32_t delta)
-{
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-upstream by %2, current up = %3 down = %4\n",
-                                                 name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
-
-       uint32_t old_sbu = _soloed_by_others_upstream;
-
-       if (delta < 0) {
-               if (_soloed_by_others_upstream >= (uint32_t) abs (delta)) {
-                       _soloed_by_others_upstream += delta;
+               if (yn) {
+                       _monitor_send->activate ();
                } else {
-                       _soloed_by_others_upstream = 0;
+                       _monitor_send->deactivate ();
                }
-       } else {
-               _soloed_by_others_upstream += delta;
        }
-
-       DEBUG_TRACE (DEBUG::Solo, string_compose (
-                            "%1 SbU delta %2 = %3 old = %4 sbd %5 ss %6 exclusive %7\n",
-                            name(), delta, _soloed_by_others_upstream, old_sbu,
-                            _soloed_by_others_downstream, _self_solo, Config->get_exclusive_solo()));
-
-       /* push the inverse solo change to everything that feeds us.
-
-          This is important for solo-within-group. When we solo 1 track out of N that
-          feed a bus, that track will cause mod_solo_by_upstream (+1) to be called
-          on the bus. The bus then needs to call mod_solo_by_downstream (-1) on all
-          tracks that feed it. This will silence them if they were audible because
-          of a bus solo, but the newly soloed track will still be audible (because
-          it is self-soloed).
-
-          but .. do this only when we are being told to solo-by-upstream (i.e delta = +1),
-          not in reverse.
-       */
-
-       if ((_self_solo || _soloed_by_others_downstream) &&
-           ((old_sbu == 0 && _soloed_by_others_upstream > 0) ||
-            (old_sbu > 0 && _soloed_by_others_upstream == 0))) {
-
-               if (delta > 0 || !Config->get_exclusive_solo()) {
-                       DEBUG_TRACE (DEBUG::Solo, string_compose("\t ... INVERT push from %1\n", _name));
-                       for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
-                               if (i->sends_only) {
-                                       continue;
-                               }
-                               boost::shared_ptr<Route> sr = i->r.lock();
-                               if (sr) {
-                                       sr->mod_solo_by_others_downstream (-delta);
-                               }
-                       }
-               }
-       }
-
-       set_mute_master_solo ();
-       solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
-}
-
-void
-Route::mod_solo_by_others_downstream (int32_t delta)
-{
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-downstream by %2, current up = %3 down = %4\n",
-                                                 name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
-
-       if (delta < 0) {
-               if (_soloed_by_others_downstream >= (uint32_t) abs (delta)) {
-                       _soloed_by_others_downstream += delta;
-               } else {
-                       _soloed_by_others_downstream = 0;
-               }
-       } else {
-               _soloed_by_others_downstream += delta;
-       }
-
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbD delta %2 = %3\n", name(), delta, _soloed_by_others_downstream));
-
-       set_mute_master_solo ();
-       solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
 }
 
 void
-Route::set_mute_master_solo ()
+Route::solo_control_changed (bool, Controllable::GroupControlDisposition)
 {
-       _mute_master->set_soloed_by_self (self_soloed());
-       _mute_master->set_soloed_by_others (soloed_by_others_downstream() || soloed_by_others_upstream());
-}
-
-void
-Route::mod_solo_isolated_by_upstream (bool yn)
-{
-       bool old = solo_isolated ();
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod_solo_isolated_by_upstream cur: %2 d: %3\n",
-                               name(), _solo_isolated_by_upstream, yn ? "+1" : "-1"));
-
-       if (!yn) {
-               if (_solo_isolated_by_upstream >= 1) {
-                       _solo_isolated_by_upstream--;
-               } else {
-                       _solo_isolated_by_upstream = 0;
-               }
-       } else {
-               _solo_isolated_by_upstream++;
-       }
+       /* nothing to do if we're not using AFL/PFL. But if we are, we need
+          to alter the active state of the monitor send.
+       */
 
-       if (solo_isolated() != old) {
-               /* solo isolated status changed */
-               _mute_master->set_solo_ignore (solo_isolated());
-               solo_isolated_changed (); /* EMIT SIGNAL */
+       if (Config->get_solo_control_is_listen_control ()) {
+               set_listen (_solo_control->self_soloed() || _solo_control->get_masters_value());
        }
 }
 
 void
-Route::set_solo_isolated (bool yn, Controllable::GroupControlDisposition group_override)
+Route::push_solo_isolate_upstream (int32_t delta)
 {
-       if (is_master() || is_monitor() || is_auditioner()) {
-               return;
-       }
-
-       if (use_group (group_override, &RouteGroup::is_solo)) {
-               _route_group->foreach_route (boost::bind (&Route::set_solo_isolated, _1, yn, Controllable::ForGroup));
-               return;
-       }
-
-       bool changed = false;
-
-       if (yn) {
-               if (_solo_isolated == false) {
-                       _mute_master->set_solo_ignore (true);
-                       changed = true;
-               }
-               _solo_isolated = true;
-       } else {
-               if (_solo_isolated == true) {
-                       _solo_isolated = false;
-                       _mute_master->set_solo_ignore (false);
-                       changed = true;
-               }
-       }
-
-
-       if (!changed) {
-               return;
-       }
-
        /* forward propagate solo-isolate status to everything fed by this route, but not those via sends only */
 
        boost::shared_ptr<RouteList> routes = _session.get_routes ();
        for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
 
-               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+               if ((*i).get() == this || !(*i)->can_solo()) {
                        continue;
                }
 
@@ -1093,75 +658,26 @@ Route::set_solo_isolated (bool yn, Controllable::GroupControlDisposition group_o
                bool does_feed = feeds (*i, &sends_only);
 
                if (does_feed && !sends_only) {
-                       (*i)->mod_solo_isolated_by_upstream (yn);
+                       (*i)->solo_isolate_control()->mod_solo_isolated_by_upstream (delta);
                }
        }
-
-       /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */
-
-       solo_isolated_changed (); /* EMIT SIGNAL */
-       _solo_isolate_control->Changed(); /* EMIT SIGNAL */
-}
-
-bool
-Route::solo_isolated () const
-{
-       return (_solo_isolated == true) || (_solo_isolated_by_upstream > 0);
-}
-
-void
-Route::set_mute_points (MuteMaster::MutePoint mp)
-{
-       _mute_master->set_mute_points (mp);
-       mute_points_changed (); /* EMIT SIGNAL */
-
-       if (_mute_master->muted_by_self()) {
-               mute_changed (); /* EMIT SIGNAL */
-               _mute_control->Changed (); /* EMIT SIGNAL */
-       }
 }
 
 void
-Route::set_mute (bool yn, Controllable::GroupControlDisposition group_override)
+Route::push_solo_upstream (int delta)
 {
-       if (use_group (group_override, &RouteGroup::is_mute)) {
-               _route_group->foreach_route (boost::bind (&Route::set_mute, _1, yn, Controllable::ForGroup));
-               return;
-       }
-
-       if (muted() != yn) {
-               _mute_master->set_muted_by_self (yn);
-               /* allow any derived classes to respond to the mute change
-                  before anybody else knows about it.
-               */
-               act_on_mute ();
-               /* tell everyone else */
-               mute_changed (); /* EMIT SIGNAL */
-               _mute_control->Changed (); /* EMIT SIGNAL */
+       DEBUG_TRACE (DEBUG::Solo, string_compose("\t ... INVERT push from %1\n", _name));
+       for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
+               if (i->sends_only) {
+                       continue;
+               }
+               boost::shared_ptr<Route> sr (i->r.lock());
+               if (sr) {
+                       sr->solo_control()->mod_solo_by_others_downstream (-delta);
+               }
        }
 }
 
-bool
-Route::muted () const
-{
-       return _mute_master->muted_by_self();
-}
-
-bool
-Route::muted_by_others () const
-{
-       // This method is only used by route_ui for display state.
-       // The real thing is MuteMaster::muted_by_others_at()
-
-       //master is never muted by others
-       if (is_master())
-               return false;
-
-       //now check to see if something is soloed (and I am not)
-       //see also MuteMaster::mute_gain_at()
-       return (_session.soloing() && !soloed() && !solo_isolated());
-}
-
 #if 0
 static void
 dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs)
@@ -1254,96 +770,37 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
        DEBUG_TRACE (DEBUG::Processors, string_compose (
                             "%1 adding processor %2\n", name(), processor->name()));
 
-       if (!AudioEngine::instance()->connected() || !processor) {
-               return 1;
-       }
+       ProcessorList pl;
 
-       if (_strict_io) {
-               boost::shared_ptr<PluginInsert> pi;
-               if ((pi = boost::dynamic_pointer_cast<PluginInsert>(processor)) != 0) {
-                       pi->set_strict_io (true);
-               }
-       }
-
-       {
-               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
-               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
-               ProcessorState pstate (this);
+       pl.push_back (processor);
+       int rv = add_processors (pl, before, err);
 
-               boost::shared_ptr<PluginInsert> pi;
-               boost::shared_ptr<PortInsert> porti;
-
-               if (processor == _amp) {
-                       /* Ensure that only one amp is in the list at any time */
-                       ProcessorList::iterator check = find (_processors.begin(), _processors.end(), processor);
-                       if (check != _processors.end()) {
-                               if (before == _amp) {
-                                       /* Already in position; all is well */
-                                       return 0;
-                               } else {
-                                       _processors.erase (check);
-                               }
-                       }
-               }
-
-               assert (find (_processors.begin(), _processors.end(), processor) == _processors.end ());
-
-               ProcessorList::iterator loc;
-               if (before) {
-                       /* inserting before a processor; find it */
-                       loc = find (_processors.begin(), _processors.end(), before);
-                       if (loc == _processors.end ()) {
-                               /* Not found */
-                               return 1;
-                       }
-               } else {
-                       /* inserting at end */
-                       loc = _processors.end ();
-               }
-
-               _processors.insert (loc, processor);
-               processor->set_owner (this);
-
-               // Set up processor list channels.  This will set processor->[input|output]_streams(),
-               // configure redirect ports properly, etc.
-
-               {
-                       if (configure_processors_unlocked (err)) {
-                               pstate.restore ();
-                               configure_processors_unlocked (0); // it worked before we tried to add it ...
-                               return -1;
-                       }
-               }
-
-               if ((pi = boost::dynamic_pointer_cast<PluginInsert>(processor)) != 0) {
-
-                       if (pi->has_no_inputs ()) {
-                               /* generator plugin */
-                               _have_internal_generator = true;
-                       }
-
-               }
-
-               if (activation_allowed && (!_session.get_bypass_all_loaded_plugins () || !processor->display_to_user ())) {
-                       processor->activate ();
-               }
-
-               processor->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false));
-
-               _output->set_user_latency (0);
+       if (rv) {
+               return rv;
        }
 
-       reset_instrument_info ();
-       processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
-       set_processor_positions ();
+       if (activation_allowed && (!_session.get_bypass_all_loaded_plugins () || !processor->display_to_user ())) {
+               processor->activate ();
+       }
 
        return 0;
 }
 
+void
+Route::processor_selfdestruct (boost::weak_ptr<Processor> wp)
+{
+       /* We cannot destruct the processor here (usually RT-thread
+        * with various locks held - in case of sends also io_locks).
+        * Queue for deletion in low-priority thread.
+        */
+       Glib::Threads::Mutex::Lock lx (selfdestruct_lock);
+       selfdestruct_sequence.push_back (wp);
+}
+
 bool
 Route::add_processor_from_xml_2X (const XMLNode& node, int version)
 {
-       const XMLProperty *prop;
+       XMLProperty const * prop;
 
        try {
                boost::shared_ptr<Processor> processor;
@@ -1381,6 +838,7 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
                                                processor.reset (new UnknownProcessor (_session, node));
                                        } else {
                                                processor.reset (new PluginInsert (_session));
+                                               processor->set_owner (this);
                                        }
 
                                } else {
@@ -1424,24 +882,31 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
        }
 }
 
+
+inline Route::PluginSetupOptions operator|= (Route::PluginSetupOptions& a, const Route::PluginSetupOptions& b) {
+       return a = static_cast<Route::PluginSetupOptions> (static_cast <int>(a) | static_cast<int> (b));
+}
+
+inline Route::PluginSetupOptions operator&= (Route::PluginSetupOptions& a, const Route::PluginSetupOptions& b) {
+       return a = static_cast<Route::PluginSetupOptions> (static_cast <int>(a) & static_cast<int> (b));
+}
+
 int
 Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor> before, ProcessorStreams* err)
 {
-       /* NOTE: this is intended to be used ONLY when copying
-          processors from another Route. Hence the subtle
-          differences between this and ::add_processor()
-       */
-
        ProcessorList::iterator loc;
 
        if (before) {
                loc = find(_processors.begin(), _processors.end(), before);
+               if (loc == _processors.end ()) {
+                       return 1;
+               }
        } else {
                /* nothing specified - at end */
                loc = _processors.end ();
        }
 
-       if (!_session.engine().connected()) {
+       if (!AudioEngine::instance()->connected()) {
                return 1;
        }
 
@@ -1449,6 +914,59 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                return 0;
        }
 
+       ProcessorList to_skip;
+
+       // check if there's an instrument to replace or configure
+       for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) {
+               boost::shared_ptr<PluginInsert> pi;
+               if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) == 0) {
+                       continue;
+               }
+               if (!pi->plugin ()->get_info ()->is_instrument ()) {
+                       continue;
+               }
+               boost::shared_ptr<Processor> instrument = the_instrument ();
+               ChanCount in (DataType::MIDI, 1);
+               ChanCount out (DataType::AUDIO, 2); // XXX route's out?!
+
+               PluginSetupOptions flags = None;
+               if (instrument) {
+                       flags |= CanReplace;
+                       in = instrument->input_streams ();
+                       out = instrument->output_streams ();
+               }
+               if (pi->has_output_presets (in, out)) {
+                       flags |= MultiOut;
+               }
+
+               pi->set_strict_io (_strict_io);
+
+               PluginSetupOptions mask = None;
+               if (Config->get_ask_replace_instrument ()) {
+                       mask |= CanReplace;
+               }
+               if (Config->get_ask_setup_instrument ()) {
+                       mask |= MultiOut;
+               }
+
+               flags &= mask;
+
+               if (flags != None) {
+                       boost::optional<int> rv = PluginSetup (shared_from_this (), pi, flags);  /* EMIT SIGNAL */
+                       switch (rv.get_value_or (0)) {
+                               case 1:
+                                       to_skip.push_back (*i); // don't add this one;
+                                       break;
+                               case 2:
+                                       replace_processor (instrument, *i, err);
+                                       to_skip.push_back (*i);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+       }
+
        {
                Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
@@ -1459,31 +977,59 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                        if (*i == _meter) {
                                continue;
                        }
+                       ProcessorList::iterator check = find (to_skip.begin(), to_skip.end(), *i);
+                       if (check != to_skip.end()) {
+                               continue;
+                       }
 
                        boost::shared_ptr<PluginInsert> pi;
 
                        if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
-                               pi->set_count (1); // why? configure_processors_unlocked() will re-do this
                                pi->set_strict_io (_strict_io);
                        }
 
+                       if (*i == _amp) {
+                               /* Ensure that only one amp is in the list at any time */
+                               ProcessorList::iterator check = find (_processors.begin(), _processors.end(), *i);
+                               if (check != _processors.end()) {
+                                       if (before == _amp) {
+                                               /* Already in position; all is well */
+                                               continue;
+                                       } else {
+                                               _processors.erase (check);
+                                       }
+                               }
+                       }
+
+                       assert (find (_processors.begin(), _processors.end(), *i) == _processors.end ());
+
                        _processors.insert (loc, *i);
                        (*i)->set_owner (this);
 
-                       if ((*i)->active()) {
-                               (*i)->activate ();
-                       }
-
-                       /* Think: does this really need to be called for every processor in the loop? */
                        {
-                               if (configure_processors_unlocked (err)) {
+                               if (configure_processors_unlocked (err, &lm)) {
                                        pstate.restore ();
-                                       configure_processors_unlocked (0); // it worked before we tried to add it ...
+                                       configure_processors_unlocked (0, &lm); // it worked before we tried to add it ...
                                        return -1;
                                }
                        }
 
+                       if (pi && pi->has_sidechain ()) {
+                               pi->sidechain_input ()->changed.connect_same_thread (*this, boost::bind (&Route::sidechain_change_handler, this, _1, _2));
+                       }
+
+                       if ((*i)->active()) {
+                               // emit ActiveChanged() and latency_changed() if needed
+                               (*i)->activate ();
+                       }
+
                        (*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false));
+
+                       boost::shared_ptr<Send> send;
+                       if ((send = boost::dynamic_pointer_cast<Send> (*i))) {
+                               send->SelfDestruct.connect_same_thread (*this,
+                                               boost::bind (&Route::processor_selfdestruct, this, boost::weak_ptr<Processor> (*i)));
+                       }
                }
 
                for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
@@ -1532,7 +1078,7 @@ Route::disable_processors (Placement p)
        placement_range(p, start, end);
 
        for (ProcessorList::iterator i = start; i != end; ++i) {
-               (*i)->deactivate ();
+               (*i)->enable (false);
        }
 
        _session.set_dirty ();
@@ -1546,7 +1092,7 @@ Route::disable_processors ()
        Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               (*i)->deactivate ();
+               (*i)->enable (false);
        }
 
        _session.set_dirty ();
@@ -1565,7 +1111,7 @@ Route::disable_plugins (Placement p)
 
        for (ProcessorList::iterator i = start; i != end; ++i) {
                if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
-                       (*i)->deactivate ();
+                       (*i)->enable (false);
                }
        }
 
@@ -1581,7 +1127,7 @@ Route::disable_plugins ()
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
-                       (*i)->deactivate ();
+                       (*i)->enable (false);
                }
        }
 
@@ -1605,8 +1151,8 @@ Route::ab_plugins (bool forward)
                                continue;
                        }
 
-                       if ((*i)->active()) {
-                               (*i)->deactivate ();
+                       if ((*i)->enabled ()) {
+                               (*i)->enable (false);
                                (*i)->set_next_ab_is_active (true);
                        } else {
                                (*i)->set_next_ab_is_active (false);
@@ -1623,11 +1169,7 @@ Route::ab_plugins (bool forward)
                                continue;
                        }
 
-                       if ((*i)->get_next_ab_is_active()) {
-                               (*i)->activate ();
-                       } else {
-                               (*i)->deactivate ();
-                       }
+                       (*i)->enable ((*i)->get_next_ab_is_active ());
                }
        }
 
@@ -1696,7 +1238,7 @@ Route::clear_processors (Placement p)
                }
 
                _processors = new_list;
-               configure_processors_unlocked (&err); // this can't fail
+               configure_processors_unlocked (&err, &lm); // this can't fail
        }
 
        processor_max_streams.reset();
@@ -1768,9 +1310,15 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                                   run.
                                */
 
-                               boost::shared_ptr<IOProcessor> iop;
+                               boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor> (*i);
+                               boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(*i);
 
-                               if ((iop = boost::dynamic_pointer_cast<IOProcessor> (*i)) != 0) {
+                               if (pi != 0) {
+                                       assert (iop == 0);
+                                       iop = pi->sidechain();
+                               }
+
+                               if (iop != 0) {
                                        iop->disconnect ();
                                }
 
@@ -1790,10 +1338,10 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                        return 1;
                }
 
-               if (configure_processors_unlocked (err)) {
+               if (configure_processors_unlocked (err, &lm)) {
                        pstate.restore ();
                        /* we know this will work, because it worked before :) */
-                       configure_processors_unlocked (0);
+                       configure_processors_unlocked (0, &lm);
                        return -1;
                }
 
@@ -1862,7 +1410,7 @@ Route::replace_processor (boost::shared_ptr<Processor> old, boost::shared_ptr<Pr
 
                ProcessorList::iterator i;
                bool replaced = false;
-               bool enable = old->active ();
+               bool enable = old->enabled ();
 
                for (i = _processors.begin(); i != _processors.end(); ) {
                        if (*i == old) {
@@ -1887,9 +1435,9 @@ Route::replace_processor (boost::shared_ptr<Processor> old, boost::shared_ptr<Pr
                        }
                }
 
-               if (configure_processors_unlocked (err)) {
+               if (configure_processors_unlocked (err, &lm)) {
                        pstate.restore ();
-                       configure_processors_unlocked (0);
+                       configure_processors_unlocked (0, &lm);
                        return -1;
                }
 
@@ -1906,7 +1454,7 @@ Route::replace_processor (boost::shared_ptr<Processor> old, boost::shared_ptr<Pr
                }
 
                if (enable) {
-                       sub->activate ();
+                       sub->enable (true);
                }
 
                sub->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false));
@@ -1962,9 +1510,14 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
                           run.
                        */
 
-                       boost::shared_ptr<IOProcessor> iop;
+                       boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor>(processor);
+                       boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(processor);
+                       if (pi != 0) {
+                               assert (iop == 0);
+                               iop = pi->sidechain();
+                       }
 
-                       if ((iop = boost::dynamic_pointer_cast<IOProcessor> (processor)) != 0) {
+                       if (iop != 0) {
                                iop->disconnect ();
                        }
 
@@ -1979,10 +1532,10 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
 
                _output->set_user_latency (0);
 
-               if (configure_processors_unlocked (err)) {
+               if (configure_processors_unlocked (err, &lm)) {
                        pstate.restore ();
                        /* we know this will work, because it worked before :) */
-                       configure_processors_unlocked (0);
+                       configure_processors_unlocked (0, &lm);
                        return -1;
                }
                //lx.unlock();
@@ -2033,7 +1586,7 @@ Route::configure_processors (ProcessorStreams* err)
 
        if (!_in_configure_processors) {
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
-               return configure_processors_unlocked (err);
+               return configure_processors_unlocked (err, &lm);
        }
 
        return 0;
@@ -2067,6 +1620,33 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
        for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++index) {
 
                if ((*p)->can_support_io_configuration(in, out)) {
+
+                       if (boost::dynamic_pointer_cast<Delivery> (*p)
+                                       && boost::dynamic_pointer_cast<Delivery> (*p)->role() == Delivery::Main
+                                       && !is_auditioner()
+                                       && (is_monitor() || _strict_io || Profile->get_mixbus ())) {
+                               /* with strict I/O the panner + output are forced to
+                                * follow the last processor's output.
+                                *
+                                * Delivery::can_support_io_configuration() will only add ports,
+                                * but not remove excess ports.
+                                *
+                                * This works because the delivery only requires
+                                * as many outputs as there are inputs.
+                                * Delivery::configure_io() will do the actual removal
+                                * by calling _output->ensure_io()
+                                */
+                               if (!is_master() && _session.master_out () && in.n_audio() > 0) {
+                                       /* ..but at least as many as there are master-inputs, if
+                                        * the delivery is dealing with audio */
+                                       // XXX this may need special-casing for mixbus (master-outputs)
+                                       // and should maybe be a preference anyway ?!
+                                       out = ChanCount::max (in, _session.master_out ()->n_inputs ());
+                               } else {
+                                       out = in;
+                               }
+                       }
+
                        DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1 ID=%2 in=%3 out=%4\n",(*p)->name(), (*p)->id(), in, out));
                        configuration.push_back(make_pair(in, out));
 
@@ -2123,7 +1703,7 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
  *  Return 0 on success, otherwise configuration is impossible.
  */
 int
-Route::configure_processors_unlocked (ProcessorStreams* err)
+Route::configure_processors_unlocked (ProcessorStreams* err, Glib::Threads::RWLock::WriterLock* lm)
 {
 #ifndef PLATFORM_WINDOWS
        assert (!AudioEngine::instance()->process_lock().trylock());
@@ -2150,26 +1730,54 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
        processor_out_streams = _input->n_ports();
        processor_max_streams.reset();
 
+       /* processor configure_io() may result in adding ports
+        * e.g. Delivery::configure_io -> ARDOUR::IO::ensure_io ()
+        *
+        * with jack2 adding ports results in a graph-order callback,
+        * which calls Session::resort_routes() and eventually
+        * Route::direct_feeds_according_to_reality()
+        * which takes a ReaderLock (_processor_lock).
+        *
+        * so we can't hold a WriterLock here until jack2 threading
+        * is fixed.
+        *
+        * NB. we still hold the process lock
+        *
+        * (ardour's own engines do call graph-order from the
+        * process-thread and hence do not have this issue; besides
+        * merely adding ports won't trigger a graph-order, only
+        * making connections does)
+        */
+       lm->release ();
+
+       // TODO check for a potential ReaderLock after ReaderLock ??
+       Glib::Threads::RWLock::ReaderLock lr (_processor_lock);
+
        list< pair<ChanCount,ChanCount> >::iterator c = configuration.begin();
        for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++c) {
 
                if (!(*p)->configure_io(c->first, c->second)) {
                        DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configuration failed\n", _name));
+                       _in_configure_processors = false;
+                       lr.release ();
+                       lm->acquire ();
                        return -1;
                }
                processor_max_streams = ChanCount::max(processor_max_streams, c->first);
                processor_max_streams = ChanCount::max(processor_max_streams, c->second);
 
+               boost::shared_ptr<IOProcessor> iop;
                boost::shared_ptr<PluginInsert> pi;
                if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*p)) != 0) {
                        /* plugins connected via Split or Hide Match may have more channels.
                         * route/scratch buffers are needed for all of them
                         * The configuration may only be a subset (both input and output)
                         */
-                       processor_max_streams = ChanCount::max(processor_max_streams, pi->input_streams());
-                       processor_max_streams = ChanCount::max(processor_max_streams, pi->output_streams());
-                       processor_max_streams = ChanCount::max(processor_max_streams, pi->natural_input_streams() * pi->get_count());
-                       processor_max_streams = ChanCount::max(processor_max_streams, pi->natural_output_streams() * pi->get_count());
+                       processor_max_streams = ChanCount::max(processor_max_streams, pi->required_buffers());
+               }
+               else if ((iop = boost::dynamic_pointer_cast<IOProcessor>(*p)) != 0) {
+                       processor_max_streams = ChanCount::max(processor_max_streams, iop->natural_input_streams());
+                       processor_max_streams = ChanCount::max(processor_max_streams, iop->natural_output_streams());
                }
                out = c->second;
 
@@ -2186,6 +1794,9 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
                }
        }
 
+       lr.release ();
+       lm->acquire ();
+
 
        if (_meter) {
                _meter->set_max_channels (processor_max_streams);
@@ -2218,12 +1829,7 @@ Route::all_visible_processors_active (bool state)
                if (!(*i)->display_to_user() || boost::dynamic_pointer_cast<Amp> (*i)) {
                        continue;
                }
-
-               if (state) {
-                       (*i)->activate ();
-               } else {
-                       (*i)->deactivate ();
-               }
+               (*i)->enable (state);
        }
 
        _session.set_dirty ();
@@ -2379,7 +1985,7 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
 
                apply_processor_order (new_order);
 
-               if (configure_processors_unlocked (err)) {
+               if (configure_processors_unlocked (err, &lm)) {
                        pstate.restore ();
                        return -1;
                }
@@ -2390,47 +1996,138 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
                processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
                set_processor_positions ();
 
-       } else {
-               DEBUG_TRACE (DEBUG::Processors, "Queue clickless processor re-order.\n");
-               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+       } else {
+               DEBUG_TRACE (DEBUG::Processors, "Queue clickless processor re-order.\n");
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+
+               // _pending_processor_order is protected by _processor_lock
+               _pending_processor_order = new_order;
+               g_atomic_int_set (&_pending_process_reorder, 1);
+       }
+
+       return 0;
+}
+
+bool
+Route::add_remove_sidechain (boost::shared_ptr<Processor> proc, bool add)
+{
+       boost::shared_ptr<PluginInsert> pi;
+       if ((pi = boost::dynamic_pointer_cast<PluginInsert>(proc)) == 0) {
+               return false;
+       }
+
+       if (pi->has_sidechain () == add) {
+               return true; // ?? call failed, but result is as expected.
+       }
+
+       {
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+               ProcessorList::iterator i = find (_processors.begin(), _processors.end(), proc);
+               if (i == _processors.end ()) {
+                       return false;
+               }
+       }
+
+       {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); // take before Writerlock to avoid deadlock
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+               PBD::Unwinder<bool> uw (_in_sidechain_setup, true);
+
+               lx.release (); // IO::add_port() and ~IO takes process lock  - XXX check if this is safe
+               if (add) {
+                       if (!pi->add_sidechain ()) {
+                               return false;
+                       }
+               } else {
+                       if (!pi->del_sidechain ()) {
+                               return false;
+                       }
+               }
+
+               lx.acquire ();
+               list<pair<ChanCount, ChanCount> > c = try_configure_processors_unlocked (n_inputs (), 0);
+               lx.release ();
+
+               if (c.empty()) {
+                       if (add) {
+                               pi->del_sidechain ();
+                       } else {
+                               pi->add_sidechain ();
+                               // TODO restore side-chain's state.
+                       }
+                       return false;
+               }
+               lx.acquire ();
+               configure_processors_unlocked (0, &lm);
+       }
+
+       if (pi->has_sidechain ()) {
+               pi->sidechain_input ()->changed.connect_same_thread (*this, boost::bind (&Route::sidechain_change_handler, this, _1, _2));
+       }
+
+       processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       _session.set_dirty ();
+       return true;
+}
+
+bool
+Route::plugin_preset_output (boost::shared_ptr<Processor> proc, ChanCount outs)
+{
+       boost::shared_ptr<PluginInsert> pi;
+       if ((pi = boost::dynamic_pointer_cast<PluginInsert>(proc)) == 0) {
+               return false;
+       }
+
+       {
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+               ProcessorList::iterator i = find (_processors.begin(), _processors.end(), proc);
+               if (i == _processors.end ()) {
+                       return false;
+               }
+       }
+
+       {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+
+               const ChanCount& old (pi->preset_out ());
+               if (!pi->set_preset_out (outs)) {
+                       return true; // no change, OK
+               }
 
-               // _pending_processor_order is protected by _processor_lock
-               _pending_processor_order = new_order;
-               g_atomic_int_set (&_pending_process_reorder, 1);
+               list<pair<ChanCount, ChanCount> > c = try_configure_processors_unlocked (n_inputs (), 0);
+               if (c.empty()) {
+                       /* not possible */
+                       pi->set_preset_out (old);
+                       return false;
+               }
+               configure_processors_unlocked (0, &lm);
        }
 
-       return 0;
+       processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       _session.set_dirty ();
+       return true;
 }
 
 bool
 Route::reset_plugin_insert (boost::shared_ptr<Processor> proc)
 {
        ChanCount unused;
-       return customize_plugin_insert (proc, 0, unused);
+       return customize_plugin_insert (proc, 0, unused, unused);
 }
 
 bool
-Route::customize_plugin_insert (boost::shared_ptr<Processor> proc, uint32_t count, ChanCount outs)
+Route::customize_plugin_insert (boost::shared_ptr<Processor> proc, uint32_t count, ChanCount outs, ChanCount sinks)
 {
-       if (_strict_io) {
-               return false;
-       }
-
        boost::shared_ptr<PluginInsert> pi;
        if ((pi = boost::dynamic_pointer_cast<PluginInsert>(proc)) == 0) {
                return false;
        }
 
        {
-               bool found = false;
                Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
-               for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p) {
-                       if (*p == proc) {
-                               found = true;
-                               break;
-                       }
-               }
-               if (!found) {
+               ProcessorList::iterator i = find (_processors.begin(), _processors.end(), proc);
+               if (i == _processors.end ()) {
                        return false;
                }
        }
@@ -2438,12 +2135,11 @@ Route::customize_plugin_insert (boost::shared_ptr<Processor> proc, uint32_t coun
        {
                Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
-               ProcessorState pstate (this);
 
-               assert (!pi->strict_io ());
-               bool      old_cust = pi->custom_cfg ();
-               uint32_t  old_cnt  = pi->get_count ();
-               ChanCount old_chan = pi->output_streams ();
+               bool      old_cust  = pi->custom_cfg ();
+               uint32_t  old_cnt   = pi->get_count ();
+               ChanCount old_chan  = pi->output_streams ();
+               ChanCount old_sinks = pi->natural_input_streams ();
 
                if (count == 0) {
                        pi->set_custom_cfg (false);
@@ -2451,6 +2147,7 @@ Route::customize_plugin_insert (boost::shared_ptr<Processor> proc, uint32_t coun
                        pi->set_custom_cfg (true);
                        pi->set_count (count);
                        pi->set_outputs (outs);
+                       pi->set_sinks (sinks);
                }
 
                list<pair<ChanCount, ChanCount> > c = try_configure_processors_unlocked (n_inputs (), 0);
@@ -2458,12 +2155,13 @@ Route::customize_plugin_insert (boost::shared_ptr<Processor> proc, uint32_t coun
                        /* not possible */
 
                        pi->set_count (old_cnt);
+                       pi->set_sinks (old_sinks);
                        pi->set_outputs (old_chan);
                        pi->set_custom_cfg (old_cust);
 
                        return false;
                }
-               configure_processors_unlocked (0);
+               configure_processors_unlocked (0, &lm);
        }
 
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
@@ -2474,6 +2172,8 @@ Route::customize_plugin_insert (boost::shared_ptr<Processor> proc, uint32_t coun
 bool
 Route::set_strict_io (const bool enable)
 {
+       Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
+
        if (_strict_io != enable) {
                _strict_io = enable;
                Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
@@ -2499,10 +2199,9 @@ Route::set_strict_io (const bool enable)
                }
                lm.release ();
 
-               {
-                       Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
-                       configure_processors (0);
-               }
+               configure_processors (0);
+               lx.release ();
+
                processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
                _session.set_dirty ();
        }
@@ -2524,6 +2223,7 @@ Route::get_template()
 XMLNode&
 Route::state(bool full_state)
 {
+       LocaleGuard lg;
        if (!_session._template_state_dir.empty()) {
                assert (!full_state); // only for templates
                foreach_processor (sigc::bind (sigc::mem_fun (*this, &Route::set_plugin_state_dir), _session._template_state_dir));
@@ -2539,14 +2239,10 @@ Route::state(bool full_state)
        node->add_property("default-type", _default_type.to_string());
        node->add_property ("strict-io", _strict_io);
 
-       if (_flags) {
-               node->add_property("flags", enum_2_string (_flags));
-       }
+       node->add_child_nocopy (_presentation_info.get_state());
 
        node->add_property("active", _active?"yes":"no");
        string p;
-       boost::to_string (_phase_invert, p);
-       node->add_property("phase-invert", p);
        node->add_property("denormal-protection", _denormal_protection?"yes":"no");
        node->add_property("meter-point", enum_2_string (_meter_point));
 
@@ -2556,31 +2252,21 @@ Route::state(bool full_state)
                node->add_property("route-group", _route_group->name());
        }
 
-       snprintf (buf, sizeof (buf), "%d", _order_key);
-       node->add_property ("order-key", buf);
-       node->add_property ("self-solo", (_self_solo ? "yes" : "no"));
-       snprintf (buf, sizeof (buf), "%d", _soloed_by_others_upstream);
-       node->add_property ("soloed-by-upstream", buf);
-       snprintf (buf, sizeof (buf), "%d", _soloed_by_others_downstream);
-       node->add_property ("soloed-by-downstream", buf);
-       node->add_property ("solo-isolated", solo_isolated() ? "yes" : "no");
-       node->add_property ("solo-safe", _solo_safe ? "yes" : "no");
+       node->add_child_nocopy (_solo_control->get_state ());
+       node->add_child_nocopy (_solo_isolate_control->get_state ());
+       node->add_child_nocopy (_solo_safe_control->get_state ());
 
        node->add_child_nocopy (_input->state (full_state));
        node->add_child_nocopy (_output->state (full_state));
-       node->add_child_nocopy (_solo_control->get_state ());
-       node->add_child_nocopy (_mute_control->get_state ());
        node->add_child_nocopy (_mute_master->get_state ());
 
+       node->add_child_nocopy (_mute_control->get_state ());
+       node->add_child_nocopy (_phase_control->get_state ());
+
        if (full_state) {
                node->add_child_nocopy (Automatable::get_automation_xml_state ());
        }
 
-       XMLNode* remote_control_node = new XMLNode (X_("RemoteControl"));
-       snprintf (buf, sizeof (buf), "%d", _remote_control_id);
-       remote_control_node->add_property (X_("id"), buf);
-       node->add_child_nocopy (*remote_control_node);
-
        if (_comment.length()) {
                XMLNode *cmt = node->add_child ("Comment");
                cmt->add_content (_comment);
@@ -2590,26 +2276,29 @@ Route::state(bool full_state)
                node->add_child_nocopy (_pannable->state (full_state));
        }
 
-       for (i = _processors.begin(); i != _processors.end(); ++i) {
-               if (!full_state) {
-                       /* template save: do not include internal sends functioning as
-                          aux sends because the chance of the target ID
-                          in the session where this template is used
-                          is not very likely.
-
-                          similarly, do not save listen sends which connect to
-                          the monitor section, because these will always be
-                          added if necessary.
-                       */
-                       boost::shared_ptr<InternalSend> is;
+       {
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+               for (i = _processors.begin(); i != _processors.end(); ++i) {
+                       if (!full_state) {
+                               /* template save: do not include internal sends functioning as
+                                        aux sends because the chance of the target ID
+                                        in the session where this template is used
+                                        is not very likely.
+
+                                        similarly, do not save listen sends which connect to
+                                        the monitor section, because these will always be
+                                        added if necessary.
+                                        */
+                               boost::shared_ptr<InternalSend> is;
 
-                       if ((is = boost::dynamic_pointer_cast<InternalSend> (*i)) != 0) {
-                               if (is->role() == Delivery::Listen) {
-                                       continue;
+                               if ((is = boost::dynamic_pointer_cast<InternalSend> (*i)) != 0) {
+                                       if (is->role() == Delivery::Listen) {
+                                               continue;
+                                       }
                                }
                        }
+                       node->add_child_nocopy((*i)->state (full_state));
                }
-               node->add_child_nocopy((*i)->state (full_state));
        }
 
        if (_extra_xml) {
@@ -2628,6 +2317,8 @@ Route::state(bool full_state)
                foreach_processor (sigc::bind (sigc::mem_fun (*this, &Route::set_plugin_state_dir), ""));
        }
 
+       node->add_child_copy (Slavable::get_state());
+
        return *node;
 }
 
@@ -2641,7 +2332,7 @@ Route::set_state (const XMLNode& node, int version)
        XMLNodeList nlist;
        XMLNodeConstIterator niter;
        XMLNode *child;
-       const XMLProperty *prop;
+       XMLProperty const * prop;
 
        if (node.name() != "Route"){
                error << string_compose(_("Bad node sent to Route::set_state() [%1]"), node.name()) << endmsg;
@@ -2655,20 +2346,12 @@ Route::set_state (const XMLNode& node, int version)
        set_id (node);
        _initial_io_setup = true;
 
-       if ((prop = node.property (X_("flags"))) != 0) {
-               _flags = Flag (string_2_enum (prop->value(), _flags));
-       } else {
-               _flags = Flag (0);
-       }
+       Stripable::set_state (node, version);
 
        if ((prop = node.property (X_("strict-io"))) != 0) {
                _strict_io = string_is_affirmative (prop->value());
        }
 
-       if (is_master() || is_monitor() || is_auditioner()) {
-               _mute_master->set_solo_ignore (true);
-       }
-
        if (is_monitor()) {
                /* monitor bus does not get a panner, but if (re)created
                   via XML, it will already have one by the time we
@@ -2698,18 +2381,17 @@ Route::set_state (const XMLNode& node, int version)
                        } else if (prop->value() == "Output") {
                                _output->set_state (*child, version);
                        }
-               }
 
-               if (child->name() == X_("Processor")) {
+               } else if (child->name() == X_("Processor")) {
                        processor_state.add_child_copy (*child);
-               }
-
-               if (child->name() == X_("Pannable")) {
+               } else if (child->name() == X_("Pannable")) {
                        if (_pannable) {
                                _pannable->set_state (*child, version);
                        } else {
                                warning << string_compose (_("Pannable state found for route (%1) without a panner!"), name()) << endmsg;
                        }
+               } else if (child->name() == Slavable::xml_node_name) {
+                       Slavable::set_state (*child, version);
                }
        }
 
@@ -2732,82 +2414,15 @@ Route::set_state (const XMLNode& node, int version)
        // this looks up the internal instrument in processors
        reset_instrument_info();
 
-       if ((prop = node.property ("self-solo")) != 0) {
-               set_self_solo (string_is_affirmative (prop->value()));
-       }
-
-       if ((prop = node.property ("soloed-by-upstream")) != 0) {
-               _soloed_by_others_upstream = 0; // needed for mod_.... () to work
-               mod_solo_by_others_upstream (atoi (prop->value()));
-       }
-
-       if ((prop = node.property ("soloed-by-downstream")) != 0) {
-               _soloed_by_others_downstream = 0; // needed for mod_.... () to work
-               mod_solo_by_others_downstream (atoi (prop->value()));
-       }
-
-       if ((prop = node.property ("solo-isolated")) != 0) {
-               set_solo_isolated (string_is_affirmative (prop->value()), Controllable::NoGroup);
-       }
-
-       if ((prop = node.property ("solo-safe")) != 0) {
-               set_solo_safe (string_is_affirmative (prop->value()), Controllable::NoGroup);
-       }
-
-       if ((prop = node.property (X_("phase-invert"))) != 0) {
-               set_phase_invert (boost::dynamic_bitset<> (prop->value ()));
-       }
-
        if ((prop = node.property (X_("denormal-protection"))) != 0) {
                set_denormal_protection (string_is_affirmative (prop->value()));
        }
 
        if ((prop = node.property (X_("active"))) != 0) {
                bool yn = string_is_affirmative (prop->value());
-               _active = !yn; // force switch
                set_active (yn, this);
        }
 
-       if ((prop = node.property (X_("order-key"))) != 0) { // New order key (no separate mixer/editor ordering)
-               set_order_key (atoi(prop->value()));
-       }
-
-       if ((prop = node.property (X_("order-keys"))) != 0) { // Deprecated order keys
-
-               int32_t n;
-
-               string::size_type colon, equal;
-               string remaining = prop->value();
-
-               while (remaining.length()) {
-
-                       if ((equal = remaining.find_first_of ('=')) == string::npos || equal == remaining.length()) {
-                               error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
-                                     << endmsg;
-                       } else {
-                               if (sscanf (remaining.substr (equal+1).c_str(), "%d", &n) != 1) {
-                                       error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
-                                             << endmsg;
-                               } else {
-                                       string keyname = remaining.substr (0, equal);
-
-                                       if ((keyname == "EditorSort") || (keyname == "editor")) {
-                                               cerr << "Setting " << name() << " order key to " << n << " using saved Editor order." << endl;
-                                               set_order_key (n);
-                                       }
-                               }
-                       }
-
-                       colon = remaining.find_first_of (':');
-
-                       if (colon != string::npos) {
-                               remaining = remaining.substr (colon+1);
-                       } else {
-                               break;
-                       }
-               }
-       }
-
        if ((prop = node.property (X_("processor-after-last-custom-meter"))) != 0) {
                PBD::ID id (prop->value ());
                Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
@@ -2832,21 +2447,25 @@ Route::set_state (const XMLNode& node, int version)
                        XMLNode *cmt = *(child->children().begin());
                        _comment = cmt->content();
 
-               } else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) {
-                       if (prop->value() == "solo") {
-                               _solo_control->set_state (*child, version);
-                       } else if (prop->value() == "mute") {
-                               _mute_control->set_state (*child, version);
+               }  else if (child->name() == Controllable::xml_node_name) {
+                       if ((prop = child->property (X_("name"))) == 0) {
+                               continue;
                        }
 
-               } else if (child->name() == X_("RemoteControl")) {
-                       if ((prop = child->property (X_("id"))) != 0) {
-                               int32_t x;
-                               sscanf (prop->value().c_str(), "%d", &x);
-                               set_remote_control_id_internal (x);
+                       if (prop->value() == _gain_control->name()) {
+                               _gain_control->set_state (*child, version);
+                       } else if (prop->value() == _solo_control->name()) {
+                               _solo_control->set_state (*child, version);
+                       } else if (prop->value() == _solo_safe_control->name()) {
+                               _solo_safe_control->set_state (*child, version);
+                       } else if (prop->value() == _solo_isolate_control->name()) {
+                               _solo_isolate_control->set_state (*child, version);
+                       } else if (prop->value() == _solo_control->name()) {
+                               _mute_control->set_state (*child, version);
+                       } else if (prop->value() == _phase_control->name()) {
+                               _phase_control->set_state (*child, version);
                        }
-
-               } else if (child->name() == X_("MuteMaster")) {
+               } else if (child->name() == MuteMaster::xml_node_name) {
                        _mute_master->set_state (*child, version);
 
                } else if (child->name() == Automatable::xml_node_name) {
@@ -2860,11 +2479,11 @@ Route::set_state (const XMLNode& node, int version)
 int
 Route::set_state_2X (const XMLNode& node, int version)
 {
-       LocaleGuard lg (X_("C"));
+       LocaleGuard lg;
        XMLNodeList nlist;
        XMLNodeConstIterator niter;
        XMLNode *child;
-       const XMLProperty *prop;
+       XMLProperty const * prop;
 
        /* 2X things which still remain to be handled:
         * default-type
@@ -2877,38 +2496,12 @@ Route::set_state_2X (const XMLNode& node, int version)
                return -1;
        }
 
-       if ((prop = node.property (X_("flags"))) != 0) {
-               string f = prop->value ();
-               boost::replace_all (f, "ControlOut", "MonitorOut");
-               _flags = Flag (string_2_enum (f, _flags));
-       } else {
-               _flags = Flag (0);
-       }
-
-       if (is_master() || is_monitor() || is_auditioner()) {
-               _mute_master->set_solo_ignore (true);
-       }
-
-       if ((prop = node.property (X_("phase-invert"))) != 0) {
-               boost::dynamic_bitset<> p (_input->n_ports().n_audio ());
-               if (string_is_affirmative (prop->value ())) {
-                       p.set ();
-               }
-               set_phase_invert (p);
-       }
+       Stripable::set_state (node, version);
 
        if ((prop = node.property (X_("denormal-protection"))) != 0) {
                set_denormal_protection (string_is_affirmative (prop->value()));
        }
 
-       if ((prop = node.property (X_("soloed"))) != 0) {
-               bool yn = string_is_affirmative (prop->value());
-
-               /* XXX force reset of solo status */
-
-               set_solo (yn);
-       }
-
        if ((prop = node.property (X_("muted"))) != 0) {
 
                bool first = true;
@@ -2973,46 +2566,6 @@ Route::set_state_2X (const XMLNode& node, int version)
                _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point));
        }
 
-       /* do not carry over edit/mix groups from 2.X because (a) its hard (b) they
-          don't mean the same thing.
-       */
-
-       if ((prop = node.property (X_("order-keys"))) != 0) {
-
-               int32_t n;
-
-               string::size_type colon, equal;
-               string remaining = prop->value();
-
-               while (remaining.length()) {
-
-                       if ((equal = remaining.find_first_of ('=')) == string::npos || equal == remaining.length()) {
-                               error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
-                                       << endmsg;
-                       } else {
-                               if (sscanf (remaining.substr (equal+1).c_str(), "%d", &n) != 1) {
-                                       error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
-                                               << endmsg;
-                               } else {
-                                       string keyname = remaining.substr (0, equal);
-
-                                       if (keyname == "EditorSort" || keyname == "editor") {
-                                               info << string_compose(_("Converting deprecated order key for %1 using Editor order %2"), name (), n) << endmsg;
-                                               set_order_key (n);
-                                       }
-                               }
-                       }
-
-                       colon = remaining.find_first_of (':');
-
-                       if (colon != string::npos) {
-                               remaining = remaining.substr (colon+1);
-                       } else {
-                               break;
-                       }
-               }
-       }
-
        /* IOs */
 
        nlist = node.children ();
@@ -3102,13 +2655,6 @@ Route::set_state_2X (const XMLNode& node, int version)
                                _mute_control->set_state (*child, version);
                        }
 
-               } else if (child->name() == X_("RemoteControl")) {
-                       if ((prop = child->property (X_("id"))) != 0) {
-                               int32_t x;
-                               sscanf (prop->value().c_str(), "%d", &x);
-                               set_remote_control_id_internal (x);
-                       }
-
                }
        }
 
@@ -3187,7 +2733,7 @@ Route::set_processor_state (const XMLNode& node)
                        ProcessorList::iterator o;
 
                        for (o = _processors.begin(); o != _processors.end(); ++o) {
-                               XMLProperty* id_prop = (*niter)->property(X_("id"));
+                               XMLProperty const * id_prop = (*niter)->property(X_("id"));
                                if (id_prop && (*o)->id() == id_prop->value()) {
                                        (*o)->set_state (**niter, Stateful::current_state_version);
                                        new_order.push_back (*o);
@@ -3216,6 +2762,7 @@ Route::set_processor_state (const XMLNode& node)
                                                processor.reset (new UnknownProcessor (_session, **niter));
                                        } else {
                                                processor.reset (new PluginInsert (_session));
+                                               processor->set_owner (this);
                                                if (_strict_io) {
                                                        boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(processor);
                                                        pi->set_strict_io (true);
@@ -3229,6 +2776,9 @@ Route::set_processor_state (const XMLNode& node)
                                } else if (prop->value() == "send") {
 
                                        processor.reset (new Send (_session, _pannable, _mute_master, Delivery::Send, true));
+                                       boost::shared_ptr<Send> send = boost::dynamic_pointer_cast<Send> (processor);
+                                       send->SelfDestruct.connect_same_thread (*this,
+                                                       boost::bind (&Route::processor_selfdestruct, this, boost::weak_ptr<Processor> (processor)));
 
                                } else {
                                        error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
@@ -3240,6 +2790,12 @@ Route::set_processor_state (const XMLNode& node)
                                        processor.reset (new UnknownProcessor (_session, **niter));
                                }
 
+                               /* subscribe to Sidechain IO changes */
+                               boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
+                               if (pi && pi->has_sidechain ()) {
+                                       pi->sidechain_input ()->changed.connect_same_thread (*this, boost::bind (&Route::sidechain_change_handler, this, _1, _2));
+                               }
+
                                /* we have to note the monitor send here, otherwise a new one will be created
                                   and the state of this one will be lost.
                                */
@@ -3259,12 +2815,17 @@ Route::set_processor_state (const XMLNode& node)
        }
 
        {
-               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+               /* re-assign _processors w/o process-lock.
+                * if there's an IO-processor present in _processors but
+                * not in new_order, it will be deleted and ~IO takes
+                * a process lock.
+                */
                _processors = new_order;
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
 
                if (must_configure) {
-                       configure_processors_unlocked (0);
+                       configure_processors_unlocked (0, &lm);
                }
 
                for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
@@ -3311,6 +2872,8 @@ Route::silence_unlocked (framecnt_t nframes)
 {
        /* Must be called with the processor lock held */
 
+       const framepos_t now = _session.transport_frame ();
+
        if (!_silent) {
 
                _output->silence (nframes);
@@ -3323,7 +2886,7 @@ Route::silence_unlocked (framecnt_t nframes)
                                continue;
                        }
 
-                       (*i)->silence (nframes);
+                       (*i)->silence (nframes, now);
                }
 
                if (nframes == _session.get_block_size()) {
@@ -3529,12 +3092,53 @@ Route::feeds (boost::shared_ptr<Route> other, bool* via_sends_only)
        return false;
 }
 
+IOVector
+Route::all_inputs () const
+{
+       /* TODO, if this works as expected,
+        * cache the IOVector and maintain it via
+        * input_change_handler(), sidechain_change_handler() etc
+        */
+       IOVector ios;
+       ios.push_back (_input);
+
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+       for (ProcessorList::const_iterator r = _processors.begin(); r != _processors.end(); ++r) {
+
+               boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor>(*r);
+               boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(*r);
+               if (pi != 0) {
+                       assert (iop == 0);
+                       iop = pi->sidechain();
+               }
+
+               if (iop != 0 && iop->input()) {
+                       ios.push_back (iop->input());
+               }
+       }
+       return ios;
+}
+
+IOVector
+Route::all_outputs () const
+{
+       IOVector ios;
+       // _output is included via Delivery
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+       for (ProcessorList::const_iterator r = _processors.begin(); r != _processors.end(); ++r) {
+               boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor>(*r);
+               if (iop != 0 && iop->output()) {
+                       ios.push_back (iop->output());
+               }
+       }
+       return ios;
+}
+
 bool
 Route::direct_feeds_according_to_reality (boost::shared_ptr<Route> other, bool* via_send_only)
 {
        DEBUG_TRACE (DEBUG::Graph, string_compose ("Feeds? %1\n", _name));
-
-       if (_output->connected_to (other->input())) {
+       if (other->all_inputs().fed_by (_output)) {
                DEBUG_TRACE (DEBUG::Graph, string_compose ("\tdirect FEEDS %2\n", other->name()));
                if (via_send_only) {
                        *via_send_only = false;
@@ -3543,13 +3147,25 @@ Route::direct_feeds_according_to_reality (boost::shared_ptr<Route> other, bool*
                return true;
        }
 
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) {
 
-               boost::shared_ptr<IOProcessor> iop;
+               boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor>(*r);
+               boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(*r);
+               if (pi != 0) {
+                       assert (iop == 0);
+                       iop = pi->sidechain();
+               }
 
-               if ((iop = boost::dynamic_pointer_cast<IOProcessor>(*r)) != 0) {
-                       if (iop->feeds (other)) {
+               if (iop != 0) {
+                       boost::shared_ptr<const IO> iop_out = iop->output();
+                       if (other.get() == this && iop_out && iop->input() && iop_out->connected_to (iop->input())) {
+                               // TODO this needs a delaylines in the Insert to align connections (!)
+                               DEBUG_TRACE (DEBUG::Graph,  string_compose ("\tIOP %1 does feed its own return (%2)\n", iop->name(), other->name()));
+                               continue;
+                       }
+                       if ((iop_out && other->all_inputs().fed_by (iop_out)) || iop->feeds (other)) {
                                DEBUG_TRACE (DEBUG::Graph,  string_compose ("\tIOP %1 does feed %2\n", iop->name(), other->name()));
                                if (via_send_only) {
                                        *via_send_only = true;
@@ -3574,6 +3190,12 @@ Route::direct_feeds_according_to_graph (boost::shared_ptr<Route> other, bool* vi
        return _session._current_route_graph.has (shared_from_this (), other, via_send_only);
 }
 
+bool
+Route::feeds_according_to_graph (boost::shared_ptr<Route> other)
+{
+       return _session._current_route_graph.feeds (shared_from_this (), other);
+}
+
 /** Called from the (non-realtime) butler thread when the transport is stopped */
 void
 Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool /*did_locate*/, bool can_flush_processors)
@@ -3606,11 +3228,11 @@ Route::input_change_handler (IOChange change, void * /*src*/)
                   contains ConfigurationChanged
                */
                configure_processors (0);
-               _phase_invert.resize (_input->n_ports().n_audio ());
+               _phase_control->resize (_input->n_ports().n_audio ());
                io_changed (); /* EMIT SIGNAL */
        }
 
-       if (_soloed_by_others_upstream || _solo_isolated_by_upstream) {
+       if (_solo_control->soloed_by_others_upstream() || _solo_isolate_control->solo_isolated_by_upstream()) {
                int sbou = 0;
                int ibou = 0;
                boost::shared_ptr<RouteList> routes = _session.get_routes ();
@@ -3625,38 +3247,36 @@ Route::input_change_handler (IOChange change, void * /*src*/)
                                        if ((*i)->soloed()) {
                                                ++sbou;
                                        }
-                                       if ((*i)->solo_isolated()) {
+                                       if ((*i)->solo_isolate_control()->solo_isolated()) {
                                                ++ibou;
                                        }
                                }
                        }
                }
 
-               int delta  = sbou - _soloed_by_others_upstream;
-               int idelta = ibou - _solo_isolated_by_upstream;
+               int delta  = sbou - _solo_control->soloed_by_others_upstream();
+               int idelta = ibou - _solo_isolate_control->solo_isolated_by_upstream();
 
                if (idelta < -1) {
                        PBD::warning << string_compose (
                                        _("Invalid Solo-Isolate propagation: from:%1 new:%2 - old:%3 = delta:%4"),
-                                       _name, ibou, _solo_isolated_by_upstream, idelta)
+                                       _name, ibou, _solo_isolate_control->solo_isolated_by_upstream(), idelta)
                                     << endmsg;
 
                }
 
-               if (_soloed_by_others_upstream) {
+               if (_solo_control->soloed_by_others_upstream()) {
                        // ignore new connections (they're not propagated)
                        if (delta <= 0) {
-                               mod_solo_by_others_upstream (delta);
+                               _solo_control->mod_solo_by_others_upstream (delta);
                        }
                }
 
-               if (_solo_isolated_by_upstream) {
+               if (_solo_isolate_control->solo_isolated_by_upstream()) {
                        // solo-isolate currently only propagates downstream
                        if (idelta < 0) {
-                               mod_solo_isolated_by_upstream (false);
+                               _solo_isolate_control->mod_solo_isolated_by_upstream (1);
                        }
-                       // TODO think: mod_solo_isolated_by_upstream() does not take delta arg,
-                       // but idelta can't be smaller than -1, can it?
                        //_solo_isolated_by_upstream = ibou;
                }
 
@@ -3669,11 +3289,11 @@ Route::input_change_handler (IOChange change, void * /*src*/)
                        bool sends_only;
                        bool does_feed = feeds (*i, &sends_only);
                        if (delta <= 0 && does_feed && !sends_only) {
-                               (*i)->mod_solo_by_others_upstream (delta);
+                               (*i)->solo_control()->mod_solo_by_others_upstream (delta);
                        }
 
                        if (idelta < 0 && does_feed && !sends_only) {
-                               (*i)->mod_solo_isolated_by_upstream (false);
+                               (*i)->solo_isolate_control()->mod_solo_isolated_by_upstream (-1);
                        }
                }
        }
@@ -3699,7 +3319,7 @@ Route::output_change_handler (IOChange change, void * /*src*/)
                io_changed (); /* EMIT SIGNAL */
        }
 
-       if (_soloed_by_others_downstream) {
+       if (_solo_control->soloed_by_others_downstream()) {
                int sbod = 0;
                /* checking all all downstream routes for
                 * explicit of implict solo is a rather drastic measure,
@@ -3722,20 +3342,20 @@ Route::output_change_handler (IOChange change, void * /*src*/)
                                }
                        }
                }
-               int delta = sbod - _soloed_by_others_downstream;
+               int delta = sbod - _solo_control->soloed_by_others_downstream();
                if (delta <= 0) {
                        // do not allow new connections to change implicit solo (no propagation)
-                       mod_solo_by_others_downstream (delta);
+                       _solo_control->mod_solo_by_others_downstream (delta);
                        // Session::route_solo_changed() does not propagate indirect solo-changes
                        // propagate upstream to tracks
                        for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
-                               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                               if ((*i).get() == this || !can_solo()) {
                                        continue;
                                }
                                bool sends_only;
                                bool does_feed = (*i)->feeds (shared_from_this(), &sends_only);
                                if (delta != 0 && does_feed && !sends_only) {
-                                       (*i)->mod_solo_by_others_downstream (delta);
+                                       (*i)->solo_control()->mod_solo_by_others_downstream (delta);
                                }
                        }
 
@@ -3743,6 +3363,16 @@ Route::output_change_handler (IOChange change, void * /*src*/)
        }
 }
 
+void
+Route::sidechain_change_handler (IOChange change, void* src)
+{
+       if (_initial_io_setup || _in_sidechain_setup) {
+               return;
+       }
+
+       input_change_handler (change, src);
+}
+
 uint32_t
 Route::pans_required () const
 {
@@ -3753,6 +3383,22 @@ Route::pans_required () const
        return max (n_inputs ().n_audio(), processor_max_streams.n_audio());
 }
 
+void
+Route::flush_processor_buffers_locked (framecnt_t nframes)
+{
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery> (*i);
+               if (d) {
+                       d->flush_buffers (nframes);
+               } else {
+                       boost::shared_ptr<PortInsert> p = boost::dynamic_pointer_cast<PortInsert> (*i);
+                       if (p) {
+                               p->flush_buffers (nframes);
+                       }
+               }
+       }
+}
+
 int
 Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
 {
@@ -3791,13 +3437,15 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
        fill_buffers_with_input (bufs, _input, nframes);
 
        if (_meter_point == MeterInput) {
-               _meter->run (bufs, start_frame, end_frame, nframes, true);
+               _meter->run (bufs, start_frame, end_frame, 0.0, nframes, true);
        }
 
        _amp->apply_gain_automation (false);
        _trim->apply_gain_automation (false);
        passthru (bufs, start_frame, end_frame, nframes, 0);
 
+       flush_processor_buffers_locked (nframes);
+
        return 0;
 }
 
@@ -3831,11 +3479,13 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in
        fill_buffers_with_input (bufs, _input, nframes);
 
        if (_meter_point == MeterInput) {
-               _meter->run (bufs, start_frame, end_frame, nframes, true);
+               _meter->run (bufs, start_frame, end_frame, 1.0, nframes, true);
        }
 
        passthru (bufs, start_frame, end_frame, nframes, declick);
 
+       flush_processor_buffers_locked (nframes);
+
        return 0;
 }
 
@@ -3843,6 +3493,7 @@ int
 Route::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/, bool& /* need_butler */)
 {
        silence (nframes);
+       flush_processor_buffers_locked (nframes);
        return 0;
 }
 
@@ -3900,13 +3551,12 @@ Route::apply_processor_changes_rt ()
                g_atomic_int_set (&_pending_signals, emissions);
                return true;
        }
-       return false;
+       return (!selfdestruct_sequence.empty ());
 }
 
 void
 Route::emit_pending_signals ()
 {
-
        int sig = g_atomic_int_and (&_pending_signals, 0);
        if (sig & EmitMeterChanged) {
                _meter->emit_configuration_changed();
@@ -3920,6 +3570,24 @@ Route::emit_pending_signals ()
        if (sig & EmitRtProcessorChange) {
                processors_changed (RouteProcessorChange (RouteProcessorChange::RealTimeChange)); /* EMIT SIGNAL */
        }
+
+       /* this would be a job for the butler.
+        * Conceptually we should not take processe/processor locks here.
+        * OTOH its more efficient (less overhead for summoning the butler and
+        * telling her what do do) and signal emission is called
+        * directly after the process callback, which decreases the chance
+        * of x-runs when taking the locks.
+        */
+       while (!selfdestruct_sequence.empty ()) {
+               Glib::Threads::Mutex::Lock lx (selfdestruct_lock);
+               if (selfdestruct_sequence.empty ()) { break; } // re-check with lock
+               boost::shared_ptr<Processor> proc = selfdestruct_sequence.back ().lock ();
+               selfdestruct_sequence.pop_back ();
+               lx.release ();
+               if (proc) {
+                       remove_processor (proc);
+               }
+       }
 }
 
 void
@@ -4028,10 +3696,10 @@ Route::listen_position_changed ()
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
-               if (configure_processors_unlocked (0)) {
+               if (configure_processors_unlocked (0, &lm)) {
                        DEBUG_TRACE (DEBUG::Processors, "---- CONFIGURATION FAILED.\n");
                        pstate.restore ();
-                       configure_processors_unlocked (0); // it worked before we tried to add it ...
+                       configure_processors_unlocked (0, &lm); // it worked before we tried to add it ...
                        return;
                }
        }
@@ -4049,10 +3717,12 @@ Route::add_export_point()
                Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lw (_processor_lock);
 
-               _capturing_processor.reset (new CapturingProcessor (_session));
+               // this aligns all tracks; but not tracks + busses
+               assert (_session.worst_track_latency () >= _initial_delay);
+               _capturing_processor.reset (new CapturingProcessor (_session, _session.worst_track_latency () - _initial_delay));
                _capturing_processor->activate ();
 
-               configure_processors_unlocked (0);
+               configure_processors_unlocked (0, &lw);
 
        }
 
@@ -4314,7 +3984,7 @@ Route::set_name_in_state (XMLNode& node, string const & name, bool rename_playli
 
                } else if ((*i)->name() == X_("Processor")) {
 
-                       XMLProperty* role = (*i)->property (X_("role"));
+                       XMLProperty const * role = (*i)->property (X_("role"));
                        if (role && role->value() == X_("Main")) {
                                (*i)->add_property (X_("name"), name);
                        }
@@ -4348,42 +4018,6 @@ Route::internal_send_for (boost::shared_ptr<const Route> target) const
        return boost::shared_ptr<Send>();
 }
 
-/** @param c Audio channel index.
- *  @param yn true to invert phase, otherwise false.
- */
-void
-Route::set_phase_invert (uint32_t c, bool yn)
-{
-       if (_phase_invert[c] != yn) {
-               _phase_invert[c] = yn;
-               phase_invert_changed (); /* EMIT SIGNAL */
-               _phase_control->Changed(); /* EMIT SIGNAL */
-               _session.set_dirty ();
-       }
-}
-
-void
-Route::set_phase_invert (boost::dynamic_bitset<> p)
-{
-       if (_phase_invert != p) {
-               _phase_invert = p;
-               phase_invert_changed (); /* EMIT SIGNAL */
-               _session.set_dirty ();
-       }
-}
-
-bool
-Route::phase_invert (uint32_t c) const
-{
-       return _phase_invert[c];
-}
-
-boost::dynamic_bitset<>
-Route::phase_invert () const
-{
-       return _phase_invert;
-}
-
 void
 Route::set_denormal_protection (bool yn)
 {
@@ -4451,14 +4085,10 @@ Route::trim_control() const
        return _trim_control;
 }
 
-boost::shared_ptr<Route::PhaseControllable>
+boost::shared_ptr<PhaseControl>
 Route::phase_control() const
 {
-       if (phase_invert().size()) {
-               return _phase_control;
-       } else {
-               return boost::shared_ptr<PhaseControllable>();
-       }
+       return _phase_control;
 }
 
 boost::shared_ptr<AutomationControl>
@@ -4551,12 +4181,6 @@ Route::has_io_processor_named (const string& name)
        return false;
 }
 
-MuteMaster::MutePoint
-Route::mute_points () const
-{
-       return _mute_master->mute_points ();
-}
-
 void
 Route::set_processor_positions ()
 {
@@ -4591,6 +4215,9 @@ Route::input_port_count_changing (ChanCount to)
 bool
 Route::output_port_count_changing (ChanCount to)
 {
+       if (_strict_io && !_in_configure_processors) {
+               return true;
+       }
        for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
                if (processor_out_streams.get(*t) > to.get(*t)) {
                        return true;
@@ -4764,12 +4391,13 @@ Route::setup_invisible_processors ()
 
        /* find the amp */
 
-       ProcessorList::iterator amp = new_processors.begin ();
-       while (amp != new_processors.end() && *amp != _amp) {
-               ++amp;
-       }
+       ProcessorList::iterator amp = find (new_processors.begin(), new_processors.end(), _amp);
 
-       assert (amp != new_processors.end ());
+       if (amp == new_processors.end ()) {
+               error << string_compose (_("Amp/Fader on Route '%1' went AWOL. Re-added."), name()) << endmsg;
+               new_processors.push_front (_amp);
+               amp = find (new_processors.begin(), new_processors.end(), _amp);
+       }
 
        /* and the processor after the amp */
 
@@ -4869,10 +4497,17 @@ Route::setup_invisible_processors ()
                new_processors.insert (amp, _monitor_control);
        }
 
+       /* TRIM CONTROL */
+
+       if (_trim && _trim->active()) {
+               assert (!_trim->display_to_user ());
+               new_processors.push_front (_trim);
+       }
+
        /* INTERNAL RETURN */
 
-       /* doing this here means that any monitor control will come just after
-          the return.
+       /* doing this here means that any monitor control will come after
+          the return and trim.
        */
 
        if (_intreturn) {
@@ -4880,10 +4515,6 @@ Route::setup_invisible_processors ()
                new_processors.push_front (_intreturn);
        }
 
-       if (_trim && _trim->active()) {
-               assert (!_trim->display_to_user ());
-               new_processors.push_front (_trim);
-       }
        /* EXPORT PROCESSOR */
 
        if (_capturing_processor) {
@@ -4894,8 +4525,8 @@ Route::setup_invisible_processors ()
        _processors = new_processors;
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               if (!(*i)->display_to_user () && !(*i)->active () && (*i) != _monitor_send) {
-                       (*i)->activate ();
+               if (!(*i)->display_to_user () && !(*i)->enabled () && (*i) != _monitor_send) {
+                       (*i)->enable (true);
                }
        }
 
@@ -5023,11 +4654,9 @@ boost::shared_ptr<Processor>
 Route::the_instrument_unlocked () const
 {
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               if (boost::dynamic_pointer_cast<PluginInsert>(*i)) {
-                       if ((*i)->input_streams().n_midi() > 0 &&
-                           (*i)->output_streams().n_audio() > 0) {
-                               return (*i);
-                       }
+               boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(*i);
+               if (pi && pi->plugin ()->get_info ()->is_instrument ()) {
+                       return (*i);
                }
        }
        return boost::shared_ptr<Processor>();
@@ -5595,3 +5224,47 @@ Route::master_send_enable_controllable () const
        return boost::shared_ptr<AutomationControl>();
 #endif
 }
+
+bool
+Route::slaved () const
+{
+       if (!_gain_control) {
+               return false;
+       }
+       /* just test one particular control, not all of them */
+       return _gain_control->slaved ();
+}
+
+bool
+Route::slaved_to (boost::shared_ptr<VCA> vca) const
+{
+       if (!vca || !_gain_control) {
+               return false;
+       }
+
+       /* just test one particular control, not all of them */
+
+       return _gain_control->slaved_to (vca->gain_control());
+}
+
+bool
+Route::muted_by_others_soloing () const
+{
+       if (!can_be_muted_by_others ()) {
+               return false;
+       }
+
+       return  _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
+}
+
+void
+Route::clear_all_solo_state ()
+{
+       double v = _solo_safe_control->get_value ();
+
+       _solo_control->clear_all_solo_state ();
+
+       if (v != 0.0) {
+               _solo_safe_control->set_value (v, Controllable::NoGroup);
+       }
+}