tweaks to NO_PLUGIN_STATE logic
[ardour.git] / libs / ardour / route.cc
index 8d1c1c8397764513d28f67def554df53b1090c51..9d7dc8792b17ee7b5e9e4ad9614206eb2919b94f 100644 (file)
@@ -26,6 +26,8 @@
 #include <cassert>
 #include <algorithm>
 
+#include <boost/algorithm/string.hpp>
+
 #include "pbd/xml++.h"
 #include "pbd/enumwriter.h"
 #include "pbd/memento_command.h"
 #include "pbd/convert.h"
 #include "pbd/boost_debug.h"
 
-#include "evoral/Curve.hpp"
-
 #include "ardour/amp.h"
+#include "ardour/audio_buffer.h"
 #include "ardour/audio_port.h"
 #include "ardour/audioengine.h"
 #include "ardour/buffer.h"
 #include "ardour/buffer_set.h"
-#include "ardour/configuration.h"
-#include "ardour/cycle_timer.h"
+#include "ardour/capturing_processor.h"
 #include "ardour/debug.h"
 #include "ardour/delivery.h"
-#include "ardour/dB.h"
-#include "ardour/internal_send.h"
 #include "ardour/internal_return.h"
-#include "ardour/ladspa_plugin.h"
+#include "ardour/internal_send.h"
 #include "ardour/meter.h"
-#include "ardour/mix.h"
+#include "ardour/midi_buffer.h"
+#include "ardour/midi_port.h"
 #include "ardour/monitor_processor.h"
 #include "ardour/pannable.h"
-#include "ardour/panner.h"
 #include "ardour/panner_shell.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/port.h"
 #include "ardour/port_insert.h"
 #include "ardour/processor.h"
-#include "ardour/profile.h"
 #include "ardour/route.h"
 #include "ardour/route_group.h"
 #include "ardour/send.h"
 #include "ardour/session.h"
-#include "ardour/timestamps.h"
-#include "ardour/utils.h"
-#include "ardour/graph.h"
 #include "ardour/unknown_processor.h"
-#include "ardour/capturing_processor.h"
+#include "ardour/utils.h"
 
 #include "i18n.h"
 
@@ -75,14 +69,13 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-uint32_t Route::order_key_cnt = 0;
-PBD::Signal1<void,string const&> Route::SyncOrderKeys;
+PBD::Signal1<void,RouteSortOrderKey> Route::SyncOrderKeys;
 PBD::Signal0<void> Route::RemoteControlIDChange;
 
 Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        : SessionObject (sess, name)
        , Automatable (sess)
-       , GraphNode( sess.route_graph )
+       , GraphNode (sess._process_graph)
        , _active (true)
        , _signal_latency (0)
        , _initial_delay (0)
@@ -90,6 +83,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _flags (flg)
        , _pending_declick (true)
        , _meter_point (MeterPostFader)
+       , _meter_type (MeterPeak)
        , _self_solo (false)
        , _soloed_by_others_upstream (0)
        , _soloed_by_others_downstream (0)
@@ -104,9 +98,10 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _default_type (default_type)
        , _remote_control_id (0)
        , _in_configure_processors (false)
+       , _custom_meter_position_noted (false)
+       , _last_custom_meter_was_at_end (false)
 {
        processor_max_streams.reset();
-       order_keys[N_("signal")] = order_key_cnt++;
 }
 
 int
@@ -126,11 +121,7 @@ Route::init ()
        /* panning */
 
        if (!(_flags & Route::MonitorOut)) {
-               Pannable* p = new Pannable (_session);
-#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
-               boost_debug_shared_ptr_mark_interesting (p, "Pannable");
-#endif
-               _pannable.reset (p);
+               _pannable.reset (new Pannable (_session));
        }
 
        /* input and output objects */
@@ -141,6 +132,8 @@ Route::init ()
        _input->changed.connect_same_thread (*this, boost::bind (&Route::input_change_handler, this, _1, _2));
        _input->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::input_port_count_changing, this, _1));
 
+       _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2));
+
        /* add amp processor  */
 
        _amp.reset (new Amp (_session));
@@ -150,7 +143,7 @@ Route::init ()
           they will be added to _processors by setup_invisible_processors ()
        */
 
-       _meter.reset (new PeakMeter (_session));
+       _meter.reset (new PeakMeter (_session, _name));
        _meter->set_display_to_user (false);
        _meter->activate ();
 
@@ -169,7 +162,7 @@ Route::init ()
                _monitor_control->activate ();
        }
 
-       if (is_master() || is_monitor() || is_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                _mute_master->set_solo_ignore (true);
        }
 
@@ -179,7 +172,7 @@ Route::init ()
 
        {
                /* run a configure so that the invisible processors get set up */
-               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                configure_processors (0);
        }
 
@@ -199,7 +192,7 @@ Route::~Route ()
           be half-destroyed by now
        */
 
-       Glib::RWLock::WriterLock lm (_processor_lock);
+       Glib::Threads::RWLock::WriterLock lm (_processor_lock);
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->drop_references ();
        }
@@ -210,9 +203,44 @@ Route::~Route ()
 void
 Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
 {
-       if (id != _remote_control_id) {
+       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 ();
                }
@@ -222,88 +250,101 @@ Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
 uint32_t
 Route::remote_control_id() const
 {
+       if (is_master()) {
+               return MasterBusRemoteControlID;
+       } 
+
+       if (is_monitor()) {
+               return MonitorBusRemoteControlID;
+       }
+
        return _remote_control_id;
 }
 
-int32_t
-Route::order_key (std::string const & name) const
+bool
+Route::has_order_key (RouteSortOrderKey key) const
+{
+       return (order_keys.find (key) != order_keys.end());
+}
+
+uint32_t
+Route::order_key (RouteSortOrderKey key) const
 {
-       OrderKeys::const_iterator i = order_keys.find (name);
+       OrderKeys::const_iterator i = order_keys.find (key);
+
        if (i == order_keys.end()) {
-               return -1;
+               return 0;
        }
 
        return i->second;
 }
 
 void
-Route::set_order_key (std::string const & name, int32_t n)
+Route::sync_order_keys (RouteSortOrderKey base)
 {
-       bool changed = false;
+       /* this is called after changes to 1 or more route order keys have been
+        * made, and we want to sync up.
+        */
 
-       /* This method looks more complicated than it should, but
-          it's important that we don't emit order_key_changed unless
-          it actually has, as expensive things happen on receipt of that
-          signal.
-       */
+       OrderKeys::iterator i = order_keys.find (base);
 
-       if (order_keys.find(name) == order_keys.end() || order_keys[name] != n) {
-               order_keys[name] = n;
-               changed = true;
+       if (i == order_keys.end()) {
+               return;
        }
 
-       if (Config->get_sync_all_route_ordering()) {
-               for (OrderKeys::iterator x = order_keys.begin(); x != order_keys.end(); ++x) {
-                       if (x->second != n) {
-                               x->second = n;
-                               changed = true;
-                       }
-               }
-       }
+       for (OrderKeys::iterator k = order_keys.begin(); k != order_keys.end(); ++k) {
 
-       if (changed) {
-               order_key_changed (); /* EMIT SIGNAL */
-               _session.set_dirty ();
+               if (k->first != base) {
+                       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 set key for %2 to %3 from %4\n",
+                                                                      name(),
+                                                                      enum_2_string (k->first),
+                                                                      i->second,
+                                                                      enum_2_string (base)));
+                                                                      
+                       k->second = i->second;
+               }
        }
 }
 
-/** Set all order keys to be the same as that for `base', if such a key
- *  exists in this route.
- *  @param base Base key.
- */
 void
-Route::sync_order_keys (std::string const & base)
+Route::set_remote_control_id_from_order_key (RouteSortOrderKey /*key*/, uint32_t rid)
 {
-       if (order_keys.empty()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
+               /* hard-coded remote IDs, or no remote ID */
                return;
        }
 
-       OrderKeys::iterator i;
-       int32_t key;
-
-       if ((i = order_keys.find (base)) == order_keys.end()) {
-               /* key doesn't exist, use the first existing key (during session initialization) */
-               i = order_keys.begin();
-               key = i->second;
-               ++i;
-       } else {
-               /* key exists - use it and reset all others (actually, itself included) */
-               key = i->second;
-               i = order_keys.begin();
+       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) */
        }
 
-       bool changed = false;
+       /* 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).
 
-       for (; i != order_keys.end(); ++i) {
-               if (i->second != key) {
-                       i->second = key;
-                       changed = true;
-               }
-       }
+          See Session::sync_remote_id_from_order_keys() for the (primary|only)
+          spot where that is emitted.
+       */
+}
 
-       if (changed) {
-               order_key_changed (); /* EMIT SIGNAL */
+void
+Route::set_order_key (RouteSortOrderKey key, uint32_t n)
+{
+       OrderKeys::iterator i = order_keys.find (key);
+
+       if (i != order_keys.end() && i->second == n) {
+               return;
        }
+
+       order_keys[key] = n;
+
+       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 order key %2 set to %3\n",
+                                                      name(), enum_2_string (key), order_key (key)));
+
+       _session.set_dirty ();
 }
 
 string
@@ -401,23 +442,24 @@ Route::maybe_declick (BufferSet&, framecnt_t, int)
 void
 Route::process_output_buffers (BufferSet& bufs,
                               framepos_t start_frame, framepos_t end_frame, pframes_t nframes,
-                              bool /*with_processors*/, int declick,
-                               bool gain_automation_ok)
+                              int declick, bool gain_automation_ok)
 {
-       bool monitor = should_monitor ();
-
-       bufs.is_silent (false);
+       bufs.set_is_silent (false);
 
        /* figure out if we're going to use gain automation */
        if (gain_automation_ok) {
+               _amp->set_gain_automation_buffer (_session.gain_automation_buffer ());
                _amp->setup_gain_automation (start_frame, end_frame, nframes);
        } else {
                _amp->apply_gain_automation (false);
        }
 
-       /* tell main outs what to do about monitoring */
-       _main_outs->no_outs_cuz_we_no_monitor (!monitor);
+       /* Tell main outs what to do about monitoring.  We do this so that
+          on a transition between monitoring states we get a de-clicking gain
+          change in the _main_outs delivery.
+       */
 
+       _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
 
        /* -------------------------------------------------------------------------------------------
           GLOBAL DECLICK (for transport changes etc.)
@@ -482,23 +524,31 @@ Route::process_output_buffers (BufferSet& bufs,
           and go ....
           ----------------------------------------------------------------------------------------- */
 
+       /* set this to be true if the meter will already have been ::run() earlier */
+       bool const meter_already_run = metering_state() == MeteringInput;
+
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
-               if (boost::dynamic_pointer_cast<UnknownProcessor> (*i)) {
-                       break;
+               if (meter_already_run && boost::dynamic_pointer_cast<PeakMeter> (*i)) {
+                       /* don't ::run() the meter, otherwise it will have its previous peak corrupted */
+                       continue;
                }
 
 #ifndef NDEBUG
                /* if it has any inputs, make sure they match */
-               if ((*i)->input_streams() != ChanCount::ZERO) {
+               if (boost::dynamic_pointer_cast<UnknownProcessor> (*i) == 0 && (*i)->input_streams() != ChanCount::ZERO) {
                        if (bufs.count() != (*i)->input_streams()) {
-                               cerr << _name << " bufs = " << bufs.count()
-                                    << " input for " << (*i)->name() << " = " << (*i)->input_streams()
-                                    << endl;
-                               abort ();
+                               DEBUG_TRACE (
+                                       DEBUG::Processors, string_compose (
+                                               "%1 bufs = %2 input for %3 = %4\n",
+                                               _name, bufs.count(), (*i)->name(), (*i)->input_streams()
+                                               )
+                                       );
+                               continue;
                        }
                }
 #endif
+
                /* should we NOT run plugins here if the route is inactive?
                   do we catch route != active somewhere higher?
                */
@@ -515,52 +565,40 @@ Route::n_process_buffers ()
 }
 
 void
-Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+Route::monitor_run (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
 {
-       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+       assert (is_monitor());
+       BufferSet& bufs (_session.get_scratch_buffers (n_process_buffers()));
+       passthru (bufs, start_frame, end_frame, nframes, declick);
+}
 
+void
+Route::passthru (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+{
        _silent = false;
 
-       assert (bufs.available() >= input_streams());
-
-       if (_input->n_ports() == ChanCount::ZERO) {
-               silence_unlocked (nframes);
-       }
-
-       bufs.set_count (input_streams());
-
        if (is_monitor() && _session.listening() && !_session.is_auditioning()) {
 
                /* control/monitor bus ignores input ports when something is
                   feeding the listen "stream". data will "arrive" into the
                   route from the intreturn processor element.
                */
-               bufs.silence (nframes, 0);
-
-       } else {
 
-               for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-
-                       BufferSet::iterator o = bufs.begin(*t);
-                       PortSet& ports (_input->ports());
-
-                       for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) {
-                               o->read_from (i->get_buffer(nframes), nframes);
-                       }
-               }
+               bufs.silence (nframes, 0);
        }
 
        write_out_of_band_data (bufs, start_frame, end_frame, nframes);
-       process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick, true);
+       process_output_buffers (bufs, start_frame, end_frame, nframes, declick, true);
 }
 
 void
 Route::passthru_silence (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
 {
        BufferSet& bufs (_session.get_silent_buffers (n_process_buffers()));
+
        bufs.set_count (_input->n_ports());
        write_out_of_band_data (bufs, start_frame, end_frame, nframes);
-       process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick, false);
+       process_output_buffers (bufs, start_frame, end_frame, nframes, declick, false);
 }
 
 void
@@ -619,6 +657,7 @@ void
 Route::set_solo (bool yn, void *src)
 {
        if (_solo_safe) {
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change due to solo-safe\n", name()));
                return;
        }
 
@@ -627,6 +666,9 @@ Route::set_solo (bool yn, void *src)
                return;
        }
 
+       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set solo => %2, src: %3 grp ? %4 currently self-soloed ? %5\n", 
+                                                 name(), yn, src, (src == _route_group), self_soloed()));
+
        if (self_soloed() != yn) {
                set_self_solo (yn);
                set_mute_master_solo ();
@@ -638,6 +680,7 @@ Route::set_solo (bool yn, void *src)
 void
 Route::set_self_solo (bool yn)
 {
+       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set SELF solo => %2\n", name(), yn));
        _self_solo = yn;
 }
 
@@ -645,9 +688,13 @@ void
 Route::mod_solo_by_others_upstream (int32_t delta)
 {
        if (_solo_safe) {
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo-by-upstream due to solo-safe\n", name()));
                return;
        }
 
+       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) {
@@ -701,9 +748,13 @@ void
 Route::mod_solo_by_others_downstream (int32_t delta)
 {
        if (_solo_safe) {
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo-by-downstream due to solo safe\n", name()));
                return;
        }
 
+       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;
@@ -729,7 +780,7 @@ Route::set_mute_master_solo ()
 void
 Route::set_solo_isolated (bool yn, void *src)
 {
-       if (is_master() || is_monitor() || is_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                return;
        }
 
@@ -743,12 +794,12 @@ Route::set_solo_isolated (bool yn, void *src)
        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_hidden()) {
+               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
                        continue;
                }
 
                bool sends_only;
-               bool does_feed = direct_feeds (*i, &sends_only); // we will recurse anyway, so don't use ::feeds()
+               bool does_feed = direct_feeds_according_to_graph (*i, &sends_only); // we will recurse anyway, so don't use ::feeds()
 
                if (does_feed && !sends_only) {
                        (*i)->set_solo_isolated (yn, (*i)->route_group());
@@ -808,6 +859,11 @@ Route::set_mute (bool yn, void *src)
 
        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 (src); /* EMIT SIGNAL */
                _mute_control->Changed (); /* EMIT SIGNAL */
        }
@@ -832,16 +888,17 @@ dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& p
 }
 #endif
 
-int
-Route::add_processor (boost::shared_ptr<Processor> processor, Placement placement, ProcessorStreams* err, bool activation_allowed)
+/** Supposing that we want to insert a Processor at a given Placement, return
+ *  the processor to add the new one before (or 0 to add at the end).
+ */
+boost::shared_ptr<Processor>
+Route::before_processor_for_placement (Placement p)
 {
-       ProcessorList::iterator loc;
-
-       /* XXX this is not thread safe - we don't hold the lock across determining the iter
-          to add before and actually doing the insertion. dammit.
-       */
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
-       if (placement == PreFader) {
+       ProcessorList::iterator loc;
+       
+       if (p == PreFader) {
                /* generic pre-fader: insert immediately before the amp */
                loc = find (_processors.begin(), _processors.end(), _amp);
        } else {
@@ -849,15 +906,60 @@ Route::add_processor (boost::shared_ptr<Processor> processor, Placement placemen
                loc = find (_processors.begin(), _processors.end(), _main_outs);
        }
 
-       return add_processor (processor, loc, err, activation_allowed);
+       return loc != _processors.end() ? *loc : boost::shared_ptr<Processor> ();
+}
+
+/** Supposing that we want to insert a Processor at a given index, return
+ *  the processor to add the new one before (or 0 to add at the end).
+ */
+boost::shared_ptr<Processor>
+Route::before_processor_for_index (int index)
+{
+       if (index == -1) {
+               return boost::shared_ptr<Processor> ();
+       }
+
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+       
+       ProcessorList::iterator i = _processors.begin ();
+       int j = 0;
+       while (i != _processors.end() && j < index) {
+               if ((*i)->display_to_user()) {
+                       ++j;
+               }
+               
+               ++i;
+       }
+
+       return (i != _processors.end() ? *i : boost::shared_ptr<Processor> ());
+}
+
+/** Add a processor either pre- or post-fader
+ *  @return 0 on success, non-0 on failure.
+ */
+int
+Route::add_processor (boost::shared_ptr<Processor> processor, Placement placement, ProcessorStreams* err, bool activation_allowed)
+{
+       return add_processor (processor, before_processor_for_placement (placement), err, activation_allowed);
 }
 
 
+/** Add a processor to a route such that it ends up with a given index into the visible processors.
+ *  @param index Index to add the processor at, or -1 to add at the end of the list.
+ *  @return 0 on success, non-0 on failure.
+ */
+int
+Route::add_processor_by_index (boost::shared_ptr<Processor> processor, int index, ProcessorStreams* err, bool activation_allowed)
+{
+       return add_processor (processor, before_processor_for_index (index), err, activation_allowed);
+}
+
 /** Add a processor to the route.
- *  @param iter an iterator in _processors; the new processor will be inserted immediately before this location.
+ *  @param before An existing processor in the list, or 0; the new processor will be inserted immediately before it (or at the end).
+ *  @return 0 on success, non-0 on failure.
  */
 int
-Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::iterator iter, ProcessorStreams* err, bool activation_allowed)
+Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<Processor> before, ProcessorStreams* err, bool activation_allowed)
 {
        assert (processor != _meter);
        assert (processor != _main_outs);
@@ -870,31 +972,38 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
        }
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                boost::shared_ptr<PluginInsert> pi;
                boost::shared_ptr<PortInsert> porti;
 
-               ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), processor);
-
                if (processor == _amp) {
-                       // Ensure only one amp is in the list at any time
-                       if (loc != _processors.end()) {
-                               if (iter == loc) { // Already in place, do nothing
+                       /* 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 { // New position given, relocate
-                                       _processors.erase (loc);
+                               } else {
+                                       _processors.erase (check);
                                }
                        }
+               }
 
-               } else {
-                       if (loc != _processors.end()) {
-                               cerr << "ERROR: Processor added to route twice!" << endl;
+               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;
                        }
-
-                       loc = iter;
+               } else {
+                       /* inserting at end */
+                       loc = _processors.end ();
                }
 
                _processors.insert (loc, processor);
@@ -903,7 +1012,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
                // configure redirect ports properly, etc.
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
@@ -921,7 +1030,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
 
                }
 
-               if (activation_allowed) {
+               if (activation_allowed && !_session.get_disable_all_loaded_plugins()) {
                        processor->activate ();
                }
 
@@ -930,6 +1039,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
                _output->set_user_latency (0);
        }
 
+       reset_instrument_info ();
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
        set_processor_positions ();
 
@@ -969,7 +1079,8 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
 
                                if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                                prop->value() == "lv2" ||
-                                               prop->value() == "vst" ||
+                                               prop->value() == "windows-vst" ||
+                                               prop->value() == "lxvst" ||
                                                prop->value() == "audiounit") {
 
                                        processor.reset (new PluginInsert (_session));
@@ -1030,7 +1141,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
        }
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) {
@@ -1052,7 +1163,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                        }
 
                        {
-                               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                                if (configure_processors_unlocked (err)) {
                                        pstate.restore ();
                                        configure_processors_unlocked (0); // it worked before we tried to add it ...
@@ -1077,6 +1188,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                _output->set_user_latency (0);
        }
 
+       reset_instrument_info ();
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
        set_processor_positions ();
 
@@ -1102,7 +1214,7 @@ Route::placement_range(Placement p, ProcessorList::iterator& start, ProcessorLis
 void
 Route::disable_processors (Placement p)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        ProcessorList::iterator start, end;
        placement_range(p, start, end);
@@ -1119,7 +1231,7 @@ Route::disable_processors (Placement p)
 void
 Route::disable_processors ()
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->deactivate ();
@@ -1134,7 +1246,7 @@ Route::disable_processors ()
 void
 Route::disable_plugins (Placement p)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        ProcessorList::iterator start, end;
        placement_range(p, start, end);
@@ -1153,7 +1265,7 @@ Route::disable_plugins (Placement p)
 void
 Route::disable_plugins ()
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
@@ -1168,7 +1280,7 @@ Route::disable_plugins ()
 void
 Route::ab_plugins (bool forward)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        if (forward) {
 
@@ -1227,7 +1339,7 @@ Route::clear_processors (Placement p)
        }
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorList new_list;
                ProcessorStreams err;
                bool seen_amp = false;
@@ -1273,7 +1385,7 @@ Route::clear_processors (Placement p)
                _processors = new_list;
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                        configure_processors_unlocked (&err); // this can't fail
                }
        }
@@ -1283,14 +1395,21 @@ Route::clear_processors (Placement p)
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
        set_processor_positions ();
 
+       reset_instrument_info ();
+
        if (!already_deleting) {
                _session.clear_deletion_in_progress();
        }
 }
 
 int
-Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err)
+Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err, bool need_process_lock)
 {
+       // TODO once the export point can be configured properly, do something smarter here
+       if (processor == _capturing_processor) {
+               _capturing_processor.reset();
+       }
+
        /* these can never be removed */
 
        if (processor == _amp || processor == _meter || processor == _main_outs) {
@@ -1304,7 +1423,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
        processor_max_streams.reset();
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                ProcessorList::iterator i;
@@ -1325,12 +1444,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                                boost::shared_ptr<IOProcessor> iop;
 
                                if ((iop = boost::dynamic_pointer_cast<IOProcessor> (*i)) != 0) {
-                                       if (iop->input()) {
-                                               iop->input()->disconnect (this);
-                                       }
-                                       if (iop->output()) {
-                                               iop->output()->disconnect (this);
-                                       }
+                                       iop->disconnect ();
                                }
 
                                i = _processors.erase (i);
@@ -1347,11 +1461,18 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                if (!removed) {
                        /* what? */
                        return 1;
-               }
+               } 
 
-               {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+               if (need_process_lock) {
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
+                       if (configure_processors_unlocked (err)) {
+                               pstate.restore ();
+                               /* we know this will work, because it worked before :) */
+                               configure_processors_unlocked (0);
+                               return -1;
+                       }
+               } else {
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
                                /* we know this will work, because it worked before :) */
@@ -1374,6 +1495,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                }
        }
 
+       reset_instrument_info ();
        processor->drop_references ();
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
        set_processor_positions ();
@@ -1393,7 +1515,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
        processor_max_streams.reset();
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                ProcessorList::iterator i;
@@ -1440,7 +1562,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
                _output->set_user_latency (0);
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
@@ -1470,12 +1592,22 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
                (*i)->drop_references ();
        }
 
+       reset_instrument_info ();
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
        set_processor_positions ();
 
        return 0;
 }
 
+void
+Route::reset_instrument_info ()
+{
+       boost::shared_ptr<Processor> instr = the_instrument();
+       if (instr) {
+               _instrument_info.set_internal_instrument (instr);
+       }
+}
+
 /** Caller must hold process lock */
 int
 Route::configure_processors (ProcessorStreams* err)
@@ -1483,7 +1615,7 @@ Route::configure_processors (ProcessorStreams* err)
        assert (!AudioEngine::instance()->process_lock().trylock());
 
        if (!_in_configure_processors) {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                return configure_processors_unlocked (err);
        }
 
@@ -1499,7 +1631,7 @@ Route::input_streams () const
 list<pair<ChanCount, ChanCount> >
 Route::try_configure_processors (ChanCount in, ProcessorStreams* err)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        return try_configure_processors_unlocked (in, err);
 }
@@ -1598,86 +1730,33 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
        return 0;
 }
 
-void
-Route::all_processors_flip ()
-{
-       Glib::RWLock::ReaderLock lm (_processor_lock);
-
-       if (_processors.empty()) {
-               return;
-       }
-
-       bool first_is_on = _processors.front()->active();
-
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               if (first_is_on) {
-                       (*i)->deactivate ();
-               } else {
-                       (*i)->activate ();
-               }
-       }
-
-       _session.set_dirty ();
-}
-
-/** Set all processors with a given placement to a given active state.
- * @param p Placement of processors to change.
- * @param state New active state for those processors.
+/** Set all visible processors to a given active state (except Fader, whose state is not changed)
+ *  @param state New active state for those processors.
  */
 void
-Route::all_processors_active (Placement p, bool state)
+Route::all_visible_processors_active (bool state)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        if (_processors.empty()) {
                return;
        }
-       ProcessorList::iterator start, end;
-       placement_range(p, start, end);
-
-       bool before_amp = true;
+       
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               if ((*i) == _amp) {
-                       before_amp = false;
+               if (!(*i)->display_to_user() || boost::dynamic_pointer_cast<Amp> (*i)) {
                        continue;
                }
-               if (p == PreFader && before_amp) {
-                       if (state) {
-                               (*i)->activate ();
-                       } else {
-                               (*i)->deactivate ();
-                       }
+               
+               if (state) {
+                       (*i)->activate ();
+               } else {
+                       (*i)->deactivate ();
                }
        }
 
        _session.set_dirty ();
 }
 
-bool
-Route::processor_is_prefader (boost::shared_ptr<Processor> p)
-{
-       bool pre_fader = true;
-       Glib::RWLock::ReaderLock lm (_processor_lock);
-
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-
-               /* semantic note: if p == amp, we want to return true, so test
-                  for equality before checking if this is the amp
-               */
-
-               if ((*i) == p) {
-                       break;
-               }
-
-               if ((*i) == _amp) {
-                       pre_fader = false;
-                       break;
-               }
-       }
-
-       return pre_fader;
-}
-
 int
 Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err)
 {
@@ -1688,7 +1767,7 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
        */
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                ProcessorList::iterator oiter;
@@ -1746,8 +1825,11 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
 
                _processors.insert (oiter, as_it_will_be.begin(), as_it_will_be.end());
 
+               /* If the meter is in a custom position, find it and make a rough note of its position */
+               maybe_note_meter_position ();
+
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
@@ -1797,6 +1879,8 @@ Route::state(bool full_state)
        node->add_property("denormal-protection", _denormal_protection?"yes":"no");
        node->add_property("meter-point", enum_2_string (_meter_point));
 
+       node->add_property("meter-type", enum_2_string (_meter_type));
+
        if (_route_group) {
                node->add_property("route-group", _route_group->name());
        }
@@ -1805,9 +1889,9 @@ Route::state(bool full_state)
        OrderKeys::iterator x = order_keys.begin();
 
        while (x != order_keys.end()) {
-               order_string += string ((*x).first);
+               order_string += enum_2_string ((*x).first);
                order_string += '=';
-               snprintf (buf, sizeof(buf), "%ld", (*x).second);
+               snprintf (buf, sizeof(buf), "%" PRId32, (*x).second);
                order_string += buf;
 
                ++x;
@@ -1848,27 +1932,49 @@ Route::state(bool 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;
+
+                       if ((is = boost::dynamic_pointer_cast<InternalSend> (*i)) != 0) {
+                               if (is->role() == Delivery::Listen) {
+                                       continue;
+                               }
+                       }
+               }
                node->add_child_nocopy((*i)->state (full_state));
        }
 
-       if (_extra_xml){
+       if (_extra_xml) {
                node->add_child_copy (*_extra_xml);
        }
 
+       if (_custom_meter_position_noted) {
+               boost::shared_ptr<Processor> after = _processor_after_last_custom_meter.lock ();
+               if (after) {
+                       after->id().print (buf, sizeof (buf));
+                       node->add_property (X_("processor-after-last-custom-meter"), buf);
+               }
+
+               node->add_property (X_("last-custom-meter-was-at-end"), _last_custom_meter_was_at_end ? "yes" : "no");
+       }
+
        return *node;
 }
 
 int
 Route::set_state (const XMLNode& node, int version)
-{
-       return _set_state (node, version, true);
-}
-
-int
-Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
 {
        if (version < 3000) {
-               return _set_state_2X (node, version);
+               return set_state_2X (node, version);
        }
 
        XMLNodeList nlist;
@@ -1885,9 +1991,7 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                Route::set_name (prop->value());
        }
 
-       if ((prop = node.property ("id")) != 0) {
-               _id = prop->value ();
-       }
+       set_id (node);
 
        if ((prop = node.property (X_("flags"))) != 0) {
                _flags = Flag (string_2_enum (prop->value(), _flags));
@@ -1895,7 +1999,7 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                _flags = Flag (0);
        }
 
-       if (is_master() || is_monitor() || is_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                _mute_master->set_solo_ignore (true);
        }
 
@@ -1934,7 +2038,6 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                        processor_state.add_child_copy (*child);
                }
 
-
                if (child->name() == X_("Pannable")) {
                        if (_pannable) {
                                _pannable->set_state (*child, version);
@@ -1944,8 +2047,23 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                }
        }
 
+       if ((prop = node.property (X_("meter-point"))) != 0) {
+               MeterPoint mp = MeterPoint (string_2_enum (prop->value (), _meter_point));
+               set_meter_point (mp, true);
+               if (_meter) {
+                       _meter->set_display_to_user (_meter_point == MeterCustom);
+               }
+       }
+
+       if ((prop = node.property (X_("meter-type"))) != 0) {
+               _meter_type = MeterType (string_2_enum (prop->value (), _meter_type));
+       }
+
        set_processor_state (processor_state);
 
+       // 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()));
        }
@@ -1982,14 +2100,6 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                set_active (yn, this);
        }
 
-       if ((prop = node.property (X_("meter-point"))) != 0) {
-               MeterPoint mp = MeterPoint (string_2_enum (prop->value (), _meter_point));
-               set_meter_point (mp, true);
-               if (_meter) {
-                       _meter->set_display_to_user (_meter_point == MeterCustom);
-               }
-       }
-
        if ((prop = node.property (X_("order-keys"))) != 0) {
 
                int32_t n;
@@ -2007,7 +2117,18 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                                        error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
                                              << endmsg;
                                } else {
-                                       set_order_key (remaining.substr (0, equal), n);
+                                       string keyname = remaining.substr (0, equal);
+                                       RouteSortOrderKey sk;
+
+                                       if (keyname == "signal") {
+                                               sk = MixerSort;
+                                       } else if (keyname == "editor") {
+                                               sk = EditorSort;
+                                       } else {
+                                               sk = (RouteSortOrderKey) string_2_enum (remaining.substr (0, equal), sk);
+                                       }
+
+                                       set_order_key (sk, n);
                                }
                        }
 
@@ -2021,6 +2142,24 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                }
        }
 
+       if ((prop = node.property (X_("processor-after-last-custom-meter"))) != 0) {
+               PBD::ID id (prop->value ());
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+               ProcessorList::const_iterator i = _processors.begin ();
+               while (i != _processors.end() && (*i)->id() != id) {
+                       ++i;
+               }
+
+               if (i != _processors.end ()) {
+                       _processor_after_last_custom_meter = *i;
+                       _custom_meter_position_noted = true;
+               }
+       }
+
+       if ((prop = node.property (X_("last-custom-meter-was-at-end"))) != 0) {
+               _last_custom_meter_was_at_end = string_is_affirmative (prop->value ());
+       }
+
        for (niter = nlist.begin(); niter != nlist.end(); ++niter){
                child = *niter;
 
@@ -2034,13 +2173,15 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                } 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() == X_("RemoteControl")) {
                        if ((prop = child->property (X_("id"))) != 0) {
                                int32_t x;
                                sscanf (prop->value().c_str(), "%d", &x);
-                               set_remote_control_id (x);
+                               set_remote_control_id_internal (x);
                        }
 
                } else if (child->name() == X_("MuteMaster")) {
@@ -2052,7 +2193,7 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
 }
 
 int
-Route::_set_state_2X (const XMLNode& node, int version)
+Route::set_state_2X (const XMLNode& node, int version)
 {
        XMLNodeList nlist;
        XMLNodeConstIterator niter;
@@ -2071,13 +2212,19 @@ Route::_set_state_2X (const XMLNode& node, int version)
        }
 
        if ((prop = node.property (X_("flags"))) != 0) {
-               _flags = Flag (string_2_enum (prop->value(), _flags));
+               string f = prop->value ();
+               boost::replace_all (f, "ControlOut", "MonitorOut");
+               _flags = Flag (string_2_enum (f, _flags));
        } else {
                _flags = Flag (0);
        }
 
-       if ((prop = node.property (X_("phase-invert"))) != 0) {
-               boost::dynamic_bitset<> p (_input->n_ports().n_audio ());
+       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 ();
                }
@@ -2181,7 +2328,18 @@ Route::_set_state_2X (const XMLNode& node, int version)
                                        error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
                                                << endmsg;
                                } else {
-                                       set_order_key (remaining.substr (0, equal), n);
+                                       string keyname = remaining.substr (0, equal);
+                                       RouteSortOrderKey sk;
+
+                                       if (keyname == "signal") {
+                                               sk = MixerSort;
+                                       } else if (keyname == "editor") {
+                                               sk = EditorSort;
+                                       } else {
+                                               sk = (RouteSortOrderKey) string_2_enum (remaining.substr (0, equal), sk);
+                                       }
+
+                                       set_order_key (sk, n);
                                }
                        }
 
@@ -2215,9 +2373,7 @@ Route::_set_state_2X (const XMLNode& node, int version)
                                Route::set_name (prop->value ());
                        }
 
-                       if ((prop = child->property (X_("id"))) != 0) {
-                               _id = prop->value ();
-                       }
+                       set_id (*child);
 
                        if ((prop = child->property (X_("active"))) != 0) {
                                bool yn = string_is_affirmative (prop->value());
@@ -2290,7 +2446,7 @@ Route::_set_state_2X (const XMLNode& node, int version)
                        if ((prop = child->property (X_("id"))) != 0) {
                                int32_t x;
                                sscanf (prop->value().c_str(), "%d", &x);
-                               set_remote_control_id (x);
+                               set_remote_control_id_internal (x);
                        }
 
                }
@@ -2341,6 +2497,7 @@ Route::set_processor_state (const XMLNode& node)
                        new_order.push_back (_amp);
                } else if (prop->value() == "meter") {
                        _meter->set_state (**niter, Stateful::current_state_version);
+                       new_order.push_back (_meter);
                } else if (prop->value() == "main-outs") {
                        _main_outs->set_state (**niter, Stateful::current_state_version);
                } else if (prop->value() == "intreturn") {
@@ -2356,7 +2513,8 @@ Route::set_processor_state (const XMLNode& node)
                        }
                        _monitor_control->set_state (**niter, Stateful::current_state_version);
                } else if (prop->value() == "capture") {
-                       _capturing_processor.reset (new CapturingProcessor (_session));
+                       /* CapturingProcessor should never be restored, it's always
+                          added explicitly when needed */
                } else {
                        ProcessorList::iterator o;
 
@@ -2381,7 +2539,8 @@ Route::set_processor_state (const XMLNode& node)
 
                                } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                           prop->value() == "lv2" ||
-                                          prop->value() == "vst" ||
+                                          prop->value() == "windows-vst" ||
+                                          prop->value() == "lxvst" ||
                                           prop->value() == "audiounit") {
 
                                        processor.reset (new PluginInsert(_session));
@@ -2399,9 +2558,24 @@ Route::set_processor_state (const XMLNode& node)
                                        continue;
                                }
 
-                               if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
-                                       /* This processor could not be configured.  Turn it into a UnknownProcessor */
-                                       processor.reset (new UnknownProcessor (_session, **niter));
+                               if (boost::dynamic_pointer_cast<PluginInsert>(processor)) {     
+#ifndef NO_PLUGIN_STATE
+                                       if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
+                                               /* This processor could not be configured.  Turn it into a UnknownProcessor */
+                                               processor.reset (new UnknownProcessor (_session, **niter));
+                                       }
+#else
+                                       /* plugin, with NO_PLUGIN_STATE defined
+                                        * =>::set_state() not allowed. Do not
+                                        * display a message here - things will
+                                        * get too verbose.
+                                        */
+#endif
+                               } else {
+                                       if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
+                                               /* This processor could not be configured.  Turn it into a UnknownProcessor */
+                                               processor.reset (new UnknownProcessor (_session, **niter));
+                                       }
                                }
 
                                /* we have to note the monitor send here, otherwise a new one will be created
@@ -2423,11 +2597,11 @@ Route::set_processor_state (const XMLNode& node)
        }
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                _processors = new_order;
 
                if (must_configure) {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                        configure_processors_unlocked (0);
                }
 
@@ -2446,6 +2620,7 @@ Route::set_processor_state (const XMLNode& node)
                }
        }
 
+       reset_instrument_info ();
        processors_changed (RouteProcessorChange ());
        set_processor_positions ();
 }
@@ -2460,7 +2635,7 @@ Route::curve_reallocate ()
 void
 Route::silence (framecnt_t nframes)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
        if (!lm.locked()) {
                return;
        }
@@ -2506,7 +2681,7 @@ Route::add_internal_return ()
 void
 Route::add_send_to_internal_return (InternalSend* send)
 {
-       Glib::RWLock::ReaderLock rm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock rm (_processor_lock);
 
        for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
                boost::shared_ptr<InternalReturn> d = boost::dynamic_pointer_cast<InternalReturn>(*x);
@@ -2520,7 +2695,7 @@ Route::add_send_to_internal_return (InternalSend* send)
 void
 Route::remove_send_from_internal_return (InternalSend* send)
 {
-       Glib::RWLock::ReaderLock rm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock rm (_processor_lock);
 
        for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
                boost::shared_ptr<InternalReturn> d = boost::dynamic_pointer_cast<InternalReturn>(*x);
@@ -2531,11 +2706,13 @@ Route::remove_send_from_internal_return (InternalSend* send)
        }
 }
 
-/** Add a monitor send (if we don't already have one) but don't activate it */
-int
-Route::listen_via_monitor ()
+void
+Route::enable_monitor_send ()
 {
-       /* master never sends to control outs */
+       /* Caller must hold process lock */
+       assert (!AudioEngine::instance()->process_lock().trylock());
+
+       /* master never sends to monitor section via the normal mechanism */
        assert (!is_master ());
 
        /* make sure we have one */
@@ -2545,23 +2722,20 @@ Route::listen_via_monitor ()
        }
 
        /* set it up */
-       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
        configure_processors (0);
-
-       return 0;
 }
 
-/** Add an internal send to a route.
+/** Add an aux send to a route.
  *  @param route route to send to.
- *  @param placement placement for the send.
+ *  @param before Processor to insert before, or 0 to insert at the end.
  */
 int
-Route::listen_via (boost::shared_ptr<Route> route, Placement placement)
+Route::add_aux_send (boost::shared_ptr<Route> route, boost::shared_ptr<Processor> before)
 {
        assert (route != _session.monitor_out ());
 
        {
-               Glib::RWLock::ReaderLock rm (_processor_lock);
+               Glib::Threads::RWLock::ReaderLock rm (_processor_lock);
 
                for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ++x) {
 
@@ -2575,8 +2749,15 @@ Route::listen_via (boost::shared_ptr<Route> route, Placement placement)
        }
 
        try {
-               boost::shared_ptr<InternalSend> listener (new InternalSend (_session, _pannable, _mute_master, route, Delivery::Aux));
-               add_processor (listener, placement);
+
+               boost::shared_ptr<InternalSend> listener;
+
+               {
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       listener.reset (new InternalSend (_session, _pannable, _mute_master, route, Delivery::Aux));
+               }
+
+               add_processor (listener, before);
 
        } catch (failed_constructor& err) {
                return -1;
@@ -2586,36 +2767,39 @@ Route::listen_via (boost::shared_ptr<Route> route, Placement placement)
 }
 
 void
-Route::drop_listen (boost::shared_ptr<Route> route)
+Route::remove_aux_or_listen (boost::shared_ptr<Route> route)
 {
        ProcessorStreams err;
        ProcessorList::iterator tmp;
 
-       Glib::RWLock::ReaderLock rl(_processor_lock);
-       rl.acquire ();
-
-  again:
-       for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ) {
-
-               boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
-
-               if (d && d->target_route() == route) {
-                       rl.release ();
-                       remove_processor (*x, &err);
-                       rl.acquire ();
+       {
+               Glib::Threads::RWLock::ReaderLock rl(_processor_lock);
 
-                       /* list could have been demolished while we dropped the lock
-                          so start over.
-                       */
+               /* have to do this early because otherwise processor reconfig
+                * will put _monitor_send back in the list
+                */
 
-                       goto again;
+               if (route == _session.monitor_out()) {
+                       _monitor_send.reset ();
                }
-       }
 
-       rl.release ();
+         again:
+               for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ++x) {
+                       
+                       boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
+                       
+                       if (d && d->target_route() == route) {
+                               rl.release ();
+                               remove_processor (*x, &err, false);
+                               rl.acquire ();
 
-       if (route == _session.monitor_out()) {
-               _monitor_send.reset ();
+                               /* list could have been demolished while we dropped the lock
+                                  so start over.
+                               */
+                               
+                               goto again;
+                       }
+               }
        }
 }
 
@@ -2674,14 +2858,14 @@ Route::feeds (boost::shared_ptr<Route> other, bool* via_sends_only)
 }
 
 bool
-Route::direct_feeds (boost::shared_ptr<Route> other, bool* only_send)
+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())) {
                DEBUG_TRACE (DEBUG::Graph, string_compose ("\tdirect FEEDS %2\n", other->name()));
-               if (only_send) {
-                       *only_send = false;
+               if (via_send_only) {
+                       *via_send_only = false;
                }
 
                return true;
@@ -2695,8 +2879,8 @@ Route::direct_feeds (boost::shared_ptr<Route> other, bool* only_send)
                if ((iop = boost::dynamic_pointer_cast<IOProcessor>(*r)) != 0) {
                        if (iop->feeds (other)) {
                                DEBUG_TRACE (DEBUG::Graph,  string_compose ("\tIOP %1 does feed %2\n", iop->name(), other->name()));
-                               if (only_send) {
-                                       *only_send = true;
+                               if (via_send_only) {
+                                       *via_send_only = true;
                                }
                                return true;
                        } else {
@@ -2712,18 +2896,20 @@ Route::direct_feeds (boost::shared_ptr<Route> other, bool* only_send)
        return false;
 }
 
+bool
+Route::direct_feeds_according_to_graph (boost::shared_ptr<Route> other, bool* via_send_only)
+{
+       return _session._current_route_graph.has (shared_from_this (), other, via_send_only);
+}
+
 /** 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)
+Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool /*did_locate*/, bool can_flush_processors)
 {
        framepos_t now = _session.transport_frame();
 
        {
-               Glib::RWLock::ReaderLock lm (_processor_lock);
-
-               if (!did_locate) {
-                       automation_snapshot (now, true);
-               }
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
                Automatable::transport_stopped (now);
 
@@ -2740,15 +2926,63 @@ Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool did_lo
        _roll_delay = _initial_delay;
 }
 
-/** Called with the process lock held if change contains ConfigurationChanged */
 void
 Route::input_change_handler (IOChange change, void * /*src*/)
 {
+       bool need_to_queue_solo_change = true;
+
        if ((change.type & IOChange::ConfigurationChanged)) {
+               /* This is called with the process lock held if change 
+                  contains ConfigurationChanged 
+               */
+               need_to_queue_solo_change = false;
                configure_processors (0);
                _phase_invert.resize (_input->n_ports().n_audio ());
                io_changed (); /* EMIT SIGNAL */
        }
+
+       if (!_input->connected() && _soloed_by_others_upstream) {
+               if (need_to_queue_solo_change) {
+                       _session.cancel_solo_after_disconnect (shared_from_this(), true);
+               } else {
+                       cancel_solo_after_disconnect (true);
+               }
+       }
+}
+
+void
+Route::output_change_handler (IOChange change, void * /*src*/)
+{
+       bool need_to_queue_solo_change = true;
+
+       if ((change.type & IOChange::ConfigurationChanged)) {
+               /* This is called with the process lock held if change 
+                  contains ConfigurationChanged 
+               */
+               need_to_queue_solo_change = false;
+               configure_processors (0);
+               io_changed (); /* EMIT SIGNAL */
+       }
+
+       if (!_output->connected() && _soloed_by_others_downstream) {
+               if (need_to_queue_solo_change) {
+                       _session.cancel_solo_after_disconnect (shared_from_this(), false);
+               } else {
+                       cancel_solo_after_disconnect (false);
+               }
+       }
+}
+
+void
+Route::cancel_solo_after_disconnect (bool upstream)
+{
+       if (upstream) {
+               _soloed_by_others_upstream = 0;
+       } else {
+               _soloed_by_others_downstream = 0;
+       }
+       set_mute_master_solo ();
+       solo_changed (false, this);
 }
 
 uint32_t
@@ -2762,10 +2996,10 @@ Route::pans_required () const
 }
 
 int
-Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
-               bool session_state_changing, bool /*can_record*/, bool /*rec_monitors_input*/)
+Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+
        if (!lm.locked()) {
                return 0;
        }
@@ -2778,6 +3012,7 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
                silence_unlocked (nframes);
                return 0;
        }
+
        if (session_state_changing) {
                if (_session.transport_speed() != 0.0f) {
                        /* we're rolling but some state is changing (e.g. our diskstream contents)
@@ -2793,59 +3028,28 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
                */
        }
 
-       _amp->apply_gain_automation (false);
-       passthru (start_frame, end_frame, nframes, 0);
-
-       return 0;
-}
-
-framecnt_t
-Route::check_initial_delay (framecnt_t nframes, framecnt_t& transport_frame)
-{
-       if (_roll_delay > nframes) {
-
-               _roll_delay -= nframes;
-               silence_unlocked (nframes);
-               /* transport frame is not legal for caller to use */
-               return 0;
-
-       } else if (_roll_delay > 0) {
-
-               nframes -= _roll_delay;
-               silence_unlocked (_roll_delay);
-               transport_frame += _roll_delay;
-
-               /* shuffle all the port buffers for things that lead "out" of this Route
-                  to reflect that we just wrote _roll_delay frames of silence.
-               */
-
-               Glib::RWLock::ReaderLock lm (_processor_lock);
-               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-                       boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor> (*i);
-                       if (iop) {
-                               iop->increment_port_buffer_offset (_roll_delay);
-                       }
-               }
-               _output->increment_port_buffer_offset (_roll_delay);
+       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
 
-               _roll_delay = 0;
+       fill_buffers_with_input (bufs, _input, nframes);
 
+       if (_meter_point == MeterInput) {
+               _meter->run (bufs, start_frame, end_frame, nframes, true);
        }
 
-       return nframes;
+       _amp->apply_gain_automation (false);
+       passthru (bufs, start_frame, end_frame, nframes, 0);
+
+       return 0;
 }
 
 int
-Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick,
-            bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */)
+Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& /* need_butler */)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
        if (!lm.locked()) {
                return 0;
        }
 
-       automation_snapshot (_session.transport_frame(), false);
-
        if (n_outputs().n_total() == 0) {
                return 0;
        }
@@ -2855,7 +3059,7 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in
                return 0;
        }
 
-       framecnt_t unused = 0;
+       framepos_t unused = 0;
 
        if ((nframes = check_initial_delay (nframes, unused)) == 0) {
                return 0;
@@ -2863,55 +3067,26 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in
 
        _silent = false;
 
-       passthru (start_frame, end_frame, nframes, declick);
+       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+       fill_buffers_with_input (bufs, _input, nframes);
+
+       if (_meter_point == MeterInput) {
+               _meter->run (bufs, start_frame, end_frame, nframes, true);
+       }
+
+       passthru (bufs, start_frame, end_frame, nframes, declick);
 
        return 0;
 }
 
 int
-Route::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/,
-                   bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */)
+Route::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/, bool& /* need_butler */)
 {
        silence (nframes);
        return 0;
 }
 
-void
-Route::toggle_monitor_input ()
-{
-       for (PortSet::iterator i = _input->ports().begin(); i != _input->ports().end(); ++i) {
-               i->ensure_monitor_input( ! i->monitoring_input());
-       }
-}
-
-bool
-Route::has_external_redirects () const
-{
-       // FIXME: what about sends? - they don't return a signal back to ardour?
-
-       boost::shared_ptr<const PortInsert> pi;
-
-       for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
-
-               if ((pi = boost::dynamic_pointer_cast<const PortInsert>(*i)) != 0) {
-
-                       for (PortSet::const_iterator port = pi->output()->ports().begin(); port != pi->output()->ports().end(); ++port) {
-
-                               string port_name = port->name();
-                               string client_name = port_name.substr (0, port_name.find(':'));
-
-                               /* only say "yes" if the redirect is actually in use */
-
-                               if (client_name != "ardour" && pi->active()) {
-                                       return true;
-                               }
-                       }
-               }
-       }
-
-       return false;
-}
-
 void
 Route::flush_processors ()
 {
@@ -2919,7 +3094,7 @@ Route::flush_processors ()
           this is called from the RT audio thread.
        */
 
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->flush ();
@@ -2929,18 +3104,18 @@ Route::flush_processors ()
 void
 Route::set_meter_point (MeterPoint p, bool force)
 {
-       /* CAN BE CALLED FROM PROCESS CONTEXT */
-
        if (_meter_point == p && !force) {
                return;
        }
 
-       _meter_point = p;
-
        bool meter_was_visible_to_user = _meter->display_to_user ();
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+
+               maybe_note_meter_position ();
+
+               _meter_point = p;
 
                if (_meter_point != MeterCustom) {
 
@@ -2948,32 +3123,48 @@ Route::set_meter_point (MeterPoint p, bool force)
 
                        setup_invisible_processors ();
 
-                       ProcessorList::iterator loc = find (_processors.begin(), _processors.end(), _meter);
+               } else {
 
-                       ChanCount m_in;
+                       _meter->set_display_to_user (true);
 
-                       if (loc == _processors.begin()) {
-                               m_in = _input->n_ports();
-                       } else {
-                               ProcessorList::iterator before = loc;
-                               --before;
-                               m_in = (*before)->output_streams ();
+                       /* If we have a previous position for the custom meter, try to put it there */
+                       if (_custom_meter_position_noted) {
+                               boost::shared_ptr<Processor> after = _processor_after_last_custom_meter.lock ();
+                               
+                               if (after) {
+                                       ProcessorList::iterator i = find (_processors.begin(), _processors.end(), after);
+                                       if (i != _processors.end ()) {
+                                               _processors.remove (_meter);
+                                               _processors.insert (i, _meter);
+                                       }
+                               } else if (_last_custom_meter_was_at_end) {
+                                       _processors.remove (_meter);
+                                       _processors.push_back (_meter);
+                               }
                        }
+               }
 
-                       _meter->reflect_inputs (m_in);
-
-                       /* we do not need to reconfigure the processors, because the meter
-                          (a) is always ready to handle processor_max_streams
-                          (b) is always an N-in/N-out processor, and thus moving
-                          it doesn't require any changes to the other processors.
-                       */
+               /* Set up the meter for its new position */
 
+               ProcessorList::iterator loc = find (_processors.begin(), _processors.end(), _meter);
+               
+               ChanCount m_in;
+               
+               if (loc == _processors.begin()) {
+                       m_in = _input->n_ports();
                } else {
-
-                       // just make it visible and let the user move it
-
-                       _meter->set_display_to_user (true);
+                       ProcessorList::iterator before = loc;
+                       --before;
+                       m_in = (*before)->output_streams ();
                }
+               
+               _meter->reflect_inputs (m_in);
+               
+               /* we do not need to reconfigure the processors, because the meter
+                  (a) is always ready to handle processor_max_streams
+                  (b) is always an N-in/N-out processor, and thus moving
+                  it doesn't require any changes to the other processors.
+               */
        }
 
        meter_change (); /* EMIT SIGNAL */
@@ -2987,11 +3178,11 @@ void
 Route::listen_position_changed ()
 {
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                        if (configure_processors_unlocked (0)) {
                                pstate.restore ();
@@ -3014,7 +3205,7 @@ Route::add_export_point()
                _capturing_processor->activate ();
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                        configure_processors (0);
                }
 
@@ -3076,18 +3267,6 @@ Route::set_latency_compensation (framecnt_t longest_session_latency)
        }
 }
 
-void
-Route::automation_snapshot (framepos_t now, bool force)
-{
-       if (_pannable) {
-               _pannable->automation_snapshot (now, force);
-       }
-
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               (*i)->automation_snapshot (now, force);
-       }
-}
-
 Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr<Route> r)
        : AutomationControl (r->session(), Evoral::Parameter (SoloAutomation),
                             boost::shared_ptr<AutomationList>(), name)
@@ -3186,19 +3365,20 @@ Route::protect_automation ()
                (*i)->protect_automation();
 }
 
+/** @param declick 1 to set a pending declick fade-in,
+ *                -1 to set a pending declick fade-out
+ */
 void
 Route::set_pending_declick (int declick)
 {
        if (_declickable) {
-               /* this call is not allowed to turn off a pending declick unless "force" is true */
+               /* this call is not allowed to turn off a pending declick */
                if (declick) {
                        _pending_declick = declick;
                }
-               // cerr << _name << ": after setting to " << declick << " pending declick = " << _pending_declick << endl;
        } else {
                _pending_declick = 0;
        }
-
 }
 
 /** Shift automation forwards from a particular place, thereby inserting time.
@@ -3239,7 +3419,7 @@ Route::shift (framepos_t pos, framecnt_t frames)
 
        /* redirect automation */
        {
-               Glib::RWLock::ReaderLock lm (_processor_lock);
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
                for (ProcessorList::iterator i = _processors.begin (); i != _processors.end (); ++i) {
 
                        set<Evoral::Parameter> parameters = (*i)->what_can_be_automated();
@@ -3304,10 +3484,42 @@ Route::set_name (const string& str)
        return ret;
 }
 
+/** Set the name of a route in an XML description.
+ *  @param node XML <Route> node to set the name in.
+ *  @param name New name.
+ */
+void
+Route::set_name_in_state (XMLNode& node, string const & name)
+{
+       node.add_property (X_("name"), name);
+
+       XMLNodeList children = node.children();
+       for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) {
+               
+               if ((*i)->name() == X_("IO")) {
+
+                       IO::set_name_in_state (**i, name);
+
+               } else if ((*i)->name() == X_("Processor")) {
+
+                       XMLProperty* role = (*i)->property (X_("role"));
+                       if (role && role->value() == X_("Main")) {
+                               (*i)->add_property (X_("name"), name);
+                       }
+                       
+               } else if ((*i)->name() == X_("Diskstream")) {
+
+                       (*i)->add_property (X_("playlist"), string_compose ("%1.1", name).c_str());
+                       (*i)->add_property (X_("name"), name);
+                       
+               }
+       }
+}
+
 boost::shared_ptr<Send>
 Route::internal_send_for (boost::shared_ptr<const Route> target) const
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
                boost::shared_ptr<InternalSend> send;
@@ -3385,13 +3597,14 @@ Route::set_active (bool yn, void* src)
                _input->set_active (yn);
                _output->set_active (yn);
                active_changed (); // EMIT SIGNAL
+               _session.set_dirty ();
        }
 }
 
 void
 Route::meter ()
 {
-       Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
+       Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK);
 
        assert (_meter);
 
@@ -3446,7 +3659,7 @@ Route::get_control (const Evoral::Parameter& param)
 
                /* maybe one of our processors does or ... */
 
-               Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
+               Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK);
                for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                        if ((c = boost::dynamic_pointer_cast<AutomationControl>((*i)->control (param))) != 0) {
                                break;
@@ -3468,7 +3681,7 @@ Route::get_control (const Evoral::Parameter& param)
 boost::shared_ptr<Processor>
 Route::nth_plugin (uint32_t n)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        ProcessorList::iterator i;
 
        for (i = _processors.begin(); i != _processors.end(); ++i) {
@@ -3485,7 +3698,7 @@ Route::nth_plugin (uint32_t n)
 boost::shared_ptr<Processor>
 Route::nth_send (uint32_t n)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        ProcessorList::iterator i;
 
        for (i = _processors.begin(); i != _processors.end(); ++i) {
@@ -3502,7 +3715,7 @@ Route::nth_send (uint32_t n)
 bool
 Route::has_io_processor_named (const string& name)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        ProcessorList::iterator i;
 
        for (i = _processors.begin(); i != _processors.end(); ++i) {
@@ -3526,7 +3739,7 @@ Route::mute_points () const
 void
 Route::set_processor_positions ()
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        bool had_amp = false;
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
@@ -3558,7 +3771,7 @@ Route::unknown_processors () const
 {
        list<string> p;
 
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<UnknownProcessor const> (*i)) {
                        p.push_back ((*i)->name ());
@@ -3578,21 +3791,26 @@ Route::update_port_latencies (PortSet& from, PortSet& to, bool playback, framecn
 
        jack_latency_range_t all_connections;
 
-       all_connections.min = ~((jack_nframes_t) 0);
-       all_connections.max = 0;
-
-       /* iterate over all "from" ports and determine the latency range for all of their
-          connections to the "outside" (outside of this Route).
-       */
-
-       for (PortSet::iterator p = from.begin(); p != from.end(); ++p) {
-
-               jack_latency_range_t range;
-
-               p->get_connected_latency_range (range, playback);
-
-               all_connections.min = min (all_connections.min, range.min);
-               all_connections.max = max (all_connections.max, range.max);
+       if (from.empty()) {
+               all_connections.min = 0;
+               all_connections.max = 0;
+       } else {
+               all_connections.min = ~((jack_nframes_t) 0);
+               all_connections.max = 0;
+               
+               /* iterate over all "from" ports and determine the latency range for all of their
+                  connections to the "outside" (outside of this Route).
+               */
+               
+               for (PortSet::iterator p = from.begin(); p != from.end(); ++p) {
+                       
+                       jack_latency_range_t range;
+                       
+                       p->get_connected_latency_range (range, playback);
+                       
+                       all_connections.min = min (all_connections.min, range.min);
+                       all_connections.max = max (all_connections.max, range.max);
+               }
        }
 
        /* set the "from" port latencies to the max/min range of all their connections */
@@ -3678,7 +3896,7 @@ void
 Route::setup_invisible_processors ()
 {
 #ifndef NDEBUG
-       Glib::RWLock::WriterLock lm (_processor_lock, Glib::TRY_LOCK);
+       Glib::Threads::RWLock::WriterLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
        assert (!lm.locked ());
 #endif
 
@@ -3831,26 +4049,11 @@ Route::setup_invisible_processors ()
        }
 }
 
-bool
-Route::should_monitor () const
-{
-       switch (Config->get_monitoring_model()) {
-       case HardwareMonitoring:
-       case ExternalMonitoring:
-               return !record_enabled() || (_session.config.get_auto_input() && !_session.actively_recording());
-               break;
-       default:
-               break;
-       }
-
-       return true;
-}
-
 void
 Route::unpan ()
 {
-       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-       Glib::RWLock::ReaderLock lp (_processor_lock);
+       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+       Glib::Threads::RWLock::ReaderLock lp (_processor_lock);
 
        _pannable.reset ();
 
@@ -3861,3 +4064,209 @@ Route::unpan ()
                }
        }
 }
+
+/** If the meter point is `Custom', make a note of where the meter is.
+ *  This is so that if the meter point is subsequently set to something else,
+ *  and then back to custom, we can put the meter back where it was last time
+ *  custom was enabled.
+ *
+ *  Must be called with the _processor_lock held.
+ */
+void
+Route::maybe_note_meter_position ()
+{
+       if (_meter_point != MeterCustom) {
+               return;
+       }
+       
+       _custom_meter_position_noted = true;
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               if (boost::dynamic_pointer_cast<PeakMeter> (*i)) {
+                       ProcessorList::iterator j = i;
+                       ++j;
+                       if (j != _processors.end ()) {
+                               _processor_after_last_custom_meter = *j;
+                               _last_custom_meter_was_at_end = false;
+                       } else {
+                               _last_custom_meter_was_at_end = true;
+                       }
+               }
+       }
+}
+
+boost::shared_ptr<Processor>
+Route::processor_by_id (PBD::ID id) const
+{
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+       for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               if ((*i)->id() == id) {
+                       return *i;
+               }
+       }
+
+       return boost::shared_ptr<Processor> ();
+}
+
+/** @return the monitoring state, or in other words what data we are pushing
+ *  into the route (data from the inputs, data from disk or silence)
+ */
+MonitorState
+Route::monitoring_state () const
+{
+       return MonitoringInput;
+}
+
+/** @return what we should be metering; either the data coming from the input
+ *  IO or the data that is flowing through the route.
+ */
+MeterState
+Route::metering_state () const
+{
+       return MeteringRoute;
+}
+
+bool
+Route::has_external_redirects () const
+{
+       for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+
+               /* ignore inactive processors and obviously ignore the main
+                * outs since everything has them and we don't care.
+                */
+                
+               if ((*i)->active() && (*i) != _main_outs && (*i)->does_routing()) {
+                       return true;;
+               }
+       }
+
+       return false;
+}
+
+boost::shared_ptr<Processor>
+Route::the_instrument () const
+{
+       Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+       return the_instrument_unlocked ();
+}
+
+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);
+                       }
+               }
+       }
+       return boost::shared_ptr<Processor>();
+}
+
+
+
+void
+Route::non_realtime_locate (framepos_t pos)
+{
+       if (_pannable) {
+               _pannable->transport_located (pos);
+       }
+
+       {
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+               
+               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+                       (*i)->transport_located (pos);
+               }
+       }
+}
+
+void
+Route::fill_buffers_with_input (BufferSet& bufs, boost::shared_ptr<IO> io, pframes_t nframes)
+{
+       size_t n_buffers;
+       size_t i;
+       
+       /* MIDI 
+        *  
+        * We don't currently mix MIDI input together, so we don't need the
+        * complex logic of the audio case.
+        */
+
+       n_buffers = bufs.count().n_midi ();
+
+       for (i = 0; i < n_buffers; ++i) {
+
+               boost::shared_ptr<MidiPort> source_port = io->midi (i);
+               MidiBuffer& buf (bufs.get_midi (i));
+               
+               if (source_port) {
+                       buf.copy (source_port->get_midi_buffer(nframes));
+               } else {
+                       buf.silence (nframes);
+               }
+       }
+
+       /* AUDIO */
+
+       n_buffers = bufs.count().n_audio();
+
+       size_t n_ports = io->n_ports().n_audio();
+       float scaling = 1.0f;
+
+       if (n_ports > n_buffers) {
+               scaling = ((float) n_buffers) / n_ports;
+       }
+       
+       for (i = 0; i < n_ports; ++i) {
+               
+               /* if there are more ports than buffers, map them onto buffers
+                * in a round-robin fashion
+                */
+
+               boost::shared_ptr<AudioPort> source_port = io->audio (i);
+               AudioBuffer& buf (bufs.get_audio (i%n_buffers));
+                       
+
+               if (i < n_buffers) {
+                       
+                       /* first time through just copy a channel into
+                          the output buffer.
+                       */
+
+                       buf.read_from (source_port->get_audio_buffer (nframes), nframes);
+
+                       if (scaling != 1.0f) {
+                               buf.apply_gain (scaling, nframes);
+                       }
+                       
+               } else {
+                       
+                       /* on subsequent times around, merge data from
+                        * the port with what is already there 
+                        */
+
+                       if (scaling != 1.0f) {
+                               buf.accumulate_with_gain_from (source_port->get_audio_buffer (nframes), nframes, 0, scaling);
+                       } else {
+                               buf.accumulate_from (source_port->get_audio_buffer (nframes), nframes);
+                       }
+               }
+       }
+
+       /* silence any remaining buffers */
+
+       for (; i < n_buffers; ++i) {
+               AudioBuffer& buf (bufs.get_audio (i));
+               buf.silence (nframes);
+       }
+
+       /* establish the initial setup of the buffer set, reflecting what was
+          copied into it. unless, of course, we are the auditioner, in which
+          case nothing was fed into it from the inputs at all.
+       */
+
+       if (!is_auditioner()) {
+               bufs.set_count (io->n_ports());
+       }
+}