fix crash when copy'ing latent plugins
[ardour.git] / libs / ardour / route.cc
index 7da7e42abf6953ea43df120a2a489f2a14b8055b..11db73241cbd304c629a556828f02611134678c9 100644 (file)
 #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;
 
 /** Base class for all routable/mixable objects (tracks and busses) */
-Route::Route (Session& sess, string name, Flag flg, DataType default_type)
-       : Stripable (sess, name)
+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)
-       , GraphNode (sess._process_graph)
        , _active (true)
        , _signal_latency (0)
        , _signal_latency_at_amp_position (0)
@@ -98,7 +96,6 @@ 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)
@@ -109,9 +106,6 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _declickable (false)
        , _have_internal_generator (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)
@@ -145,12 +139,10 @@ Route::init ()
        add_control (_trim_control);
 
        _solo_control.reset (new SoloControl (_session, X_("solo"), *this, *this));
-       _solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
        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));
-       _mute_control->set_flags (Controllable::Flag (_mute_control->flags() | Controllable::Toggle));
        add_control (_mute_control);
 
        _phase_control.reset (new PhaseControl (_session, X_("phase")));
@@ -164,7 +156,7 @@ Route::init ()
 
        /* panning */
 
-       if (!(_flags & Route::MonitorOut)) {
+       if (!(_presentation_info.flags() & PresentationInfo::MonitorOut)) {
                _pannable.reset (new Pannable (_session));
        }
 
@@ -237,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 */
 
        {
@@ -272,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)
 {
@@ -439,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 ());
@@ -535,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) {
 
@@ -564,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 ()) {
@@ -593,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) {
@@ -615,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());
                }
 
@@ -623,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 ();
                }
@@ -755,17 +638,7 @@ Route::solo_control_changed (bool, Controllable::GroupControlDisposition)
        */
 
        if (Config->get_solo_control_is_listen_control ()) {
-               set_listen (_solo_control->self_soloed());
-       }
-}
-
-bool
-Route::listening_via_monitor () const
-{
-       if (_monitor_send) {
-               return _monitor_send->active ();
-       } else {
-               return false;
+               set_listen (_solo_control->self_soloed() || _solo_control->get_masters_value());
        }
 }
 
@@ -1141,7 +1014,12 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                                }
                        }
 
+                       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 ();
                        }
 
@@ -1200,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 ();
@@ -1214,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 ();
@@ -1233,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);
                }
        }
 
@@ -1249,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);
                }
        }
 
@@ -1273,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);
@@ -1291,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 ());
                }
        }
 
@@ -1536,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) {
@@ -1580,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));
@@ -1749,8 +1623,8 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
 
                        if (boost::dynamic_pointer_cast<Delivery> (*p)
                                        && boost::dynamic_pointer_cast<Delivery> (*p)->role() == Delivery::Main
-                                       && !(is_monitor() || is_auditioner())
-                                       && ( _strict_io || Profile->get_mixbus ())) {
+                                       && !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.
                                 *
@@ -1762,8 +1636,9 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
                                 * Delivery::configure_io() will do the actual removal
                                 * by calling _output->ensure_io()
                                 */
-                               if (!is_master() && _session.master_out ()) {
-                                       /* ..but at least as many as there are master-inputs */
+                               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 ());
@@ -1954,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 ();
@@ -2369,9 +2239,7 @@ 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;
@@ -2384,9 +2252,6 @@ 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_child_nocopy (_solo_control->get_state ());
        node->add_child_nocopy (_solo_isolate_control->get_state ());
        node->add_child_nocopy (_solo_safe_control->get_state ());
@@ -2402,11 +2267,6 @@ Route::state(bool 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);
@@ -2457,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;
 }
 
@@ -2484,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 (!can_solo()) {
-               _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
@@ -2527,36 +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;
                        }
-               }
-
-               if (child->name() == Controllable::xml_node_name) {
-                       if ((prop = child->property (X_("name"))) == 0) {
-                               continue;
-                       }
-
-                       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 (child->name() == Slavable::xml_node_name) {
+                       Slavable::set_state (*child, version);
                }
        }
 
@@ -2588,46 +2423,6 @@ Route::set_state (const XMLNode& node, int version)
                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);
@@ -2652,20 +2447,24 @@ 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() == MuteMaster::xml_node_name) {
                        _mute_master->set_state (*child, version);
 
@@ -2697,17 +2496,7 @@ 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);
-       }
+       Stripable::set_state (node, version);
 
        if ((prop = node.property (X_("denormal-protection"))) != 0) {
                set_denormal_protection (string_is_affirmative (prop->value()));
@@ -2777,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 ();
@@ -2906,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);
-                       }
-
                }
        }
 
@@ -3073,9 +2815,14 @@ 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, &lm);
@@ -3125,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);
@@ -3137,7 +2886,7 @@ Route::silence_unlocked (framecnt_t nframes)
                                continue;
                        }
 
-                       (*i)->silence (nframes);
+                       (*i)->silence (nframes, now);
                }
 
                if (nframes == _session.get_block_size()) {
@@ -3411,6 +3160,11 @@ Route::direct_feeds_according_to_reality (boost::shared_ptr<Route> other, bool*
 
                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) {
@@ -3629,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)
 {
@@ -3667,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;
 }
 
@@ -3707,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;
 }
 
@@ -3719,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;
 }
 
@@ -3942,7 +3717,9 @@ 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, &lw);
@@ -4720,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) {
@@ -4731,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) {
@@ -4745,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);
                }
        }
 
@@ -5446,36 +5226,25 @@ Route::master_send_enable_controllable () const
 }
 
 bool
-Route::slaved_to (boost::shared_ptr<VCA> vca) const
+Route::slaved () const
 {
-       if (!vca || !_gain_control) {
+       if (!_gain_control) {
                return false;
        }
-
-       return _gain_control->slaved_to (vca->gain_control());
+       /* just test one particular control, not all of them */
+       return _gain_control->slaved ();
 }
 
-void
-Route::vca_assign (boost::shared_ptr<VCA> vca)
-{
-       _gain_control->add_master (vca->gain_control());
-       _solo_control->add_master (vca->solo_control());
-       _mute_control->add_master (vca->mute_control());
-}
-
-void
-Route::vca_unassign (boost::shared_ptr<VCA> vca)
+bool
+Route::slaved_to (boost::shared_ptr<VCA> vca) const
 {
-       if (!vca) {
-               /* unassign from all */
-               _gain_control->clear_masters ();
-               _solo_control->clear_masters ();
-               _mute_control->clear_masters ();
-       } else {
-               _gain_control->remove_master (vca->gain_control());
-               _solo_control->remove_master (vca->solo_control());
-               _mute_control->remove_master (vca->mute_control());
+       if (!vca || !_gain_control) {
+               return false;
        }
+
+       /* just test one particular control, not all of them */
+
+       return _gain_control->slaved_to (vca->gain_control());
 }
 
 bool
@@ -5485,9 +5254,7 @@ Route::muted_by_others_soloing () const
                return false;
        }
 
-       /* XXX something needed here re: mute-overrides-solo */
-
-       return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
+       return  _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
 }
 
 void