forward port automation handling changes from 2.x, upto and including about rev 6981...
[ardour.git] / libs / ardour / route.cc
index 69b37fb7c3f7ff79622902bafc92d23d45e80efb..290d9209d93c1bdda31e46f055396f69c9958c5d 100644 (file)
@@ -26,6 +26,7 @@
 #include "pbd/enumwriter.h"
 #include "pbd/memento_command.h"
 #include "pbd/stacktrace.h"
+#include "pbd/convert.h"
 
 #include "evoral/Curve.hpp"
 
@@ -44,6 +45,7 @@
 #include "ardour/ladspa_plugin.h"
 #include "ardour/meter.h"
 #include "ardour/mix.h"
+#include "ardour/monitor_processor.h"
 #include "ardour/panner.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/port.h"
@@ -56,6 +58,7 @@
 #include "ardour/session.h"
 #include "ardour/timestamps.h"
 #include "ardour/utils.h"
+#include "ardour/graph.h"
 
 #include "i18n.h"
 
@@ -69,83 +72,45 @@ PBD::Signal0<void> Route::RemoteControlIDChange;
 
 Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        : SessionObject (sess, name)
-       , AutomatableControls (sess)
+       , Automatable (sess)
+       , GraphNode( sess.route_graph )
+        , _active (true)
+        , _initial_delay (0)
+        , _roll_delay (0)
        , _flags (flg)
+        , _pending_declick (true)
+        , _meter_point (MeterPostFader)
+        , _self_solo (false)
+        , _soloed_by_others_upstream (0)
+        , _soloed_by_others_downstream (0)
+        , _solo_isolated (0)
+        , _denormal_protection (false)
+        , _recordable (true)
+        , _silent (false)
+        , _declickable (false)
        , _solo_control (new SoloControllable (X_("solo"), *this))
+       , _mute_control (new MuteControllable (X_("mute"), *this))
        , _mute_master (new MuteMaster (sess, name))
+        , _have_internal_generator (false)
+        , _solo_safe (false)
        , _default_type (default_type)
-
+        , _remote_control_id (0)
+        , _in_configure_processors (false)
 {
-       init ();
-
-       /* add standard processors other than amp (added by ::init()) */
-
-       _meter.reset (new PeakMeter (_session));
-       _meter->set_display_to_user (false);
-       add_processor (_meter, PostFader);
-
-       if (_flags & ControlOut) {
-               /* where we listen to tracks */
-               _intreturn.reset (new InternalReturn (_session));
-               add_processor (_intreturn, PreFader);
-       }
-
-       _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
-       add_processor (_main_outs, PostFader);
-
-       /* now that we have _meter, its safe to connect to this */
-
-       Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this)));
-}
-
-Route::Route (Session& sess, const XMLNode& node, DataType default_type)
-       : SessionObject (sess, "toBeReset")
-       , AutomatableControls (sess)
-       , _solo_control (new SoloControllable (X_("solo"), *this))
-       , _mute_master (new MuteMaster (sess, "toBeReset"))
-       , _default_type (default_type)
-{
-       init ();
-
-       _set_state (node, Stateful::loading_state_version, false);
-
-       /* now that we have _meter, its safe to connect to this */
-
-       Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this)));
+       processor_max_streams.reset();
+       order_keys[N_("signal")] = order_key_cnt++;
 }
 
-void
+int
 Route::init ()
 {
-       _self_solo = false;
-       _soloed_by_others = 0;
-       _solo_isolated = 0;
-       _solo_safe = false;
-       _active = true;
-       processor_max_streams.reset();
-       _recordable = true;
-       order_keys[N_("signal")] = order_key_cnt++;
-       _silent = false;
-       _meter_point = MeterPostFader;
-       _initial_delay = 0;
-       _roll_delay = 0;
-       _have_internal_generator = false;
-       _declickable = false;
-       _pending_declick = true;
-       _remote_control_id = 0;
-       _in_configure_processors = false;
-       _mute_points = MuteMaster::AllPoints;
-
-       _phase_invert = 0;
-       _denormal_protection = false;
-
        /* add standard controls */
 
        _solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
-       _mute_master->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
-       
+       _mute_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
+
        add_control (_solo_control);
-       add_control (_mute_master);
+       add_control (_mute_control);
 
        /* input and output objects */
 
@@ -157,16 +122,69 @@ Route::init ()
 
        /* add amp processor  */
 
-       _amp.reset (new Amp (_session, _mute_master));
+       _amp.reset (new Amp (_session));
        add_processor (_amp, PostFader);
+
+       /* add standard processors: meter, main outs, monitor out */
+
+       _meter.reset (new PeakMeter (_session));
+       _meter->set_display_to_user (false);
+
+       add_processor (_meter, PostFader);
+
+       _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
+
+        add_processor (_main_outs, PostFader);
+
+       if (is_monitor()) {
+               /* where we listen to tracks */
+               _intreturn.reset (new InternalReturn (_session));
+               add_processor (_intreturn, PreFader);
+
+                ProcessorList::iterator i;
+
+                for (i = _processors.begin(); i != _processors.end(); ++i) {
+                        if (*i == _intreturn) {
+                                ++i;
+                                break;
+                        }
+                }
+
+                /* the thing that provides proper control over a control/monitor/listen bus 
+                   (such as per-channel cut, dim, solo, invert, etc).
+                   It always goes right after the internal return;
+                 */
+                _monitor_control.reset (new MonitorProcessor (_session));
+                add_processor (_monitor_control, i);
+
+                /* no panning on the monitor main outs */
+
+                _main_outs->panner()->set_bypassed (true);
+       }
+
+        if (is_master() || is_monitor() || is_hidden()) {
+                _mute_master->set_solo_ignore (true);
+        }
+
+       /* now that we have _meter, its safe to connect to this */
+
+       Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this)));
+
+        return 0;
 }
 
 Route::~Route ()
 {
        DEBUG_TRACE (DEBUG::Destruction, string_compose ("route %1 destructor\n", _name));
 
+       /* do this early so that we don't get incoming signals as we are going through destruction 
+        */
+
+       drop_connections ();
+
        /* don't use clear_processors here, as it depends on the session which may
-          be half-destroyed by now */
+          be half-destroyed by now 
+       */
 
        Glib::RWLock::WriterLock lm (_processor_lock);
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
@@ -194,7 +212,7 @@ Route::remote_control_id() const
        return _remote_control_id;
 }
 
-long
+int32_t
 Route::order_key (std::string const & name) const
 {
        OrderKeys::const_iterator i = order_keys.find (name);
@@ -206,17 +224,34 @@ Route::order_key (std::string const & name) const
 }
 
 void
-Route::set_order_key (std::string const & name, long n)
+Route::set_order_key (std::string const & name, int32_t n)
 {
-       order_keys[name] = n;
+       bool changed = false;
+
+       /* 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.
+       */
+
+       if (order_keys.find(name) == order_keys.end() || order_keys[name] != n) {
+               order_keys[name] = n;
+               changed = true;
+       }
 
        if (Config->get_sync_all_route_ordering()) {
                for (OrderKeys::iterator x = order_keys.begin(); x != order_keys.end(); ++x) {
-                       x->second = n;
+                       if (x->second != n) {
+                               x->second = n;
+                               changed = true;
+                       }
                }
        }
 
-       _session.set_dirty ();
+       if (changed) {
+               order_key_changed (); /* EMIT SIGNAL */
+               _session.set_dirty ();
+       }
 }
 
 /** Set all order keys to be the same as that for `base', if such a key
@@ -231,7 +266,7 @@ Route::sync_order_keys (std::string const & base)
        }
 
        OrderKeys::iterator i;
-       uint32_t key;
+       int32_t key;
 
        if ((i = order_keys.find (base)) == order_keys.end()) {
                /* key doesn't exist, use the first existing key (during session initialization) */
@@ -244,8 +279,17 @@ Route::sync_order_keys (std::string const & base)
                i = order_keys.begin();
        }
 
+       bool changed = false;
+       
        for (; i != order_keys.end(); ++i) {
-               i->second = key;
+               if (i->second != key) {
+                       i->second = key;
+                       changed = true;
+               }
+       }
+
+       if (changed) {
+               order_key_changed (); /* EMIT SIGNAL */
        }
 }
 
@@ -254,8 +298,8 @@ Route::ensure_track_or_route_name(string name, Session &session)
 {
        string newname = name;
 
-       while (session.route_by_name (newname) != NULL) {
-               newname = bump_name_once (newname);
+       while (!session.io_name_is_legal (newname)) {
+               newname = bump_name_once (newname, '.');
        }
 
        return newname;
@@ -271,7 +315,7 @@ Route::inc_gain (gain_t fraction, void *src)
 void
 Route::set_gain (gain_t val, void *src)
 {
-       if (src != 0 && _route_group && src != _route_group && _route_group->active_property (RouteGroup::Gain)) {
+       if (src != 0 && _route_group && src != _route_group && _route_group->is_active() && _route_group->is_gain()) {
 
                if (_route_group->is_relative()) {
 
@@ -368,9 +412,9 @@ Route::process_output_buffers (BufferSet& bufs,
           ----------------------------------------------------------------------------------------- */
 
        if (declick > 0) {
-               Amp::apply_gain (bufs, nframes, 0.0, 1.0);
+               Amp::declick (bufs, nframes, 1);
        } else if (declick < 0) {
-               Amp::apply_gain (bufs, nframes, 1.0, 0.0);
+               Amp::declick (bufs, nframes, -1);
        }
 
        _pending_declick = 0;
@@ -379,7 +423,7 @@ Route::process_output_buffers (BufferSet& bufs,
           DENORMAL CONTROL/PHASE INVERT
           ----------------------------------------------------------------------------------------- */
 
-       if (_phase_invert) {
+       if (_phase_invert.any ()) {
 
                int chn = 0;
 
@@ -388,7 +432,7 @@ Route::process_output_buffers (BufferSet& bufs,
                        for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
                                Sample* const sp = i->data();
 
-                               if (_phase_invert & chn) {
+                               if (_phase_invert[chn]) {
                                        for (nframes_t nx = 0; nx < nframes; ++nx) {
                                                sp[nx]  = -sp[nx];
                                                sp[nx] += 1.0e-27f;
@@ -405,7 +449,7 @@ Route::process_output_buffers (BufferSet& bufs,
                        for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
                                Sample* const sp = i->data();
 
-                               if (_phase_invert & chn) {
+                               if (_phase_invert[chn]) {
                                        for (nframes_t nx = 0; nx < nframes; ++nx) {
                                                sp[nx] = -sp[nx];
                                        }
@@ -431,25 +475,17 @@ Route::process_output_buffers (BufferSet& bufs,
           and go ....
           ----------------------------------------------------------------------------------------- */
 
-       Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
-
-       if (rm.locked()) {
-               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-
-                       if (bufs.count() != (*i)->input_streams()) {
-                               cerr << _name << " bufs = " << bufs.count()
-                                    << " input for " << (*i)->name() << " = " << (*i)->input_streams()
-                                    << endl;
-                       }
-                       assert (bufs.count() == (*i)->input_streams());
-
-                       (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back());
-                       bufs.set_count (ChanCount::max(bufs.count(), (*i)->output_streams()));
-               }
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
-               if (!_processors.empty()) {
-                       bufs.set_count (ChanCount::max (bufs.count(), _processors.back()->output_streams()));
+               if (bufs.count() != (*i)->input_streams()) {
+                       cerr << _name << " bufs = " << bufs.count()
+                            << " input for " << (*i)->name() << " = " << (*i)->input_streams()
+                            << endl;
                }
+               assert (bufs.count() == (*i)->input_streams());
+               
+               (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back());
+               bufs.set_count ((*i)->output_streams());
        }
 }
 
@@ -466,21 +502,20 @@ Route::passthru (sframes_t start_frame, sframes_t end_frame, nframes_t nframes,
 
        _silent = false;
 
-       assert (bufs.available() >= _input->n_ports());
+       assert (bufs.available() >= input_streams());
 
        if (_input->n_ports() == ChanCount::ZERO) {
-               silence (nframes);
+               silence_unlocked (nframes);
        }
 
-       bufs.set_count (_input->n_ports());
+       bufs.set_count (input_streams());
 
-       if (is_control() && _session.listening()) {
+       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 {
@@ -512,12 +547,18 @@ Route::passthru_silence (sframes_t start_frame, sframes_t end_frame, nframes_t n
 void
 Route::set_listen (bool yn, void* src)
 {
-       if (_control_outs) {
-               if (yn != _control_outs->active()) {
+        if (_solo_safe) {
+                return;
+        }
+
+       if (_monitor_send) {
+               if (yn != _monitor_send->active()) {
                        if (yn) {
-                               _control_outs->activate ();
-                       } else {
-                               _control_outs->deactivate ();
+                               _monitor_send->activate ();
+                                _mute_master->set_soloed (true);
+                        } else {
+                               _monitor_send->deactivate ();
+                                _mute_master->set_soloed (false);
                        }
 
                        listen_changed (src); /* EMIT SIGNAL */
@@ -528,8 +569,8 @@ Route::set_listen (bool yn, void* src)
 bool
 Route::listening () const
 {
-       if (_control_outs) {
-               return _control_outs->active ();
+       if (_monitor_send) {
+               return _monitor_send->active ();
        } else {
                return false;
        }
@@ -557,15 +598,15 @@ Route::set_solo (bool yn, void *src)
                return;
        }
 
-       if (_route_group && src != _route_group && _route_group->active_property (RouteGroup::Solo)) {
+       if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_solo()) {
                _route_group->apply (&Route::set_solo, yn, _route_group);
                return;
        }
 
        if (self_soloed() != yn) {
                set_self_solo (yn);
-               set_delivery_solo ();
-               solo_changed (src); /* EMIT SIGNAL */
+                set_mute_master_solo ();
+               solo_changed (true, src); /* EMIT SIGNAL */
                _solo_control->Changed (); /* EMIT SIGNAL */
        }
 }
@@ -573,52 +614,101 @@ Route::set_solo (bool yn, void *src)
 void
 Route::set_self_solo (bool yn)
 {
-       _self_solo = yn;
+        _self_solo = yn;
 }
 
 void
-Route::mod_solo_by_others (int32_t delta)
+Route::mod_solo_by_others_upstream (int32_t delta)
 {
+        if (_solo_safe) {
+                return;
+        }
+
+        uint32_t old_sbu = _soloed_by_others_upstream;
+
        if (delta < 0) {
-               if (_soloed_by_others >= (uint32_t) delta) {
-                       _soloed_by_others += delta;
+               if (_soloed_by_others_upstream >= (uint32_t) abs (delta)) {
+                       _soloed_by_others_upstream += delta;
                } else {
-                       _soloed_by_others = 0;
+                       _soloed_by_others_upstream = 0;
                }
        } else {
-               _soloed_by_others += delta;
-       }
-
-       set_delivery_solo ();
+               _soloed_by_others_upstream += delta;
+       }
+
+        DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbU delta %2 = %3 old = %4 sbd %5 ss %6 exclusive %7\n",
+                                                  name(), delta, _soloed_by_others_upstream, old_sbu, 
+                                                  _soloed_by_others_downstream, _self_solo, Config->get_exclusive_solo()));
+
+        /* push the inverse solo change to everything that feeds us. 
+           
+           This is important for solo-within-group. When we solo 1 track out of N that
+           feed a bus, that track will cause mod_solo_by_upstream (+1) to be called
+           on the bus. The bus then needs to call mod_solo_by_downstream (-1) on all
+           tracks that feed it. This will silence them if they were audible because
+           of a bus solo, but the newly soloed track will still be audible (because 
+           it is self-soloed).
+           
+           but .. do this only when we are being told to solo-by-upstream (i.e delta = +1),
+           not in reverse.
+         */
+
+        if ((_self_solo || _soloed_by_others_downstream) &&
+            ((old_sbu == 0 && _soloed_by_others_upstream > 0) || 
+             (old_sbu > 0 && _soloed_by_others_upstream == 0))) {
+                
+                if (delta > 0 || !Config->get_exclusive_solo()) {
+                        DEBUG_TRACE (DEBUG::Solo, "\t ... INVERT push\n");
+                        for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
+                                boost::shared_ptr<Route> sr = i->r.lock();
+                                if (sr) {
+                                        sr->mod_solo_by_others_downstream (-delta);
+                                }
+                        }
+                } 
+        }
+
+        set_mute_master_solo ();
+        solo_changed (false, this);
 }
 
 void
-Route::set_delivery_solo ()
+Route::mod_solo_by_others_downstream (int32_t delta)
 {
-       /* tell all delivery processors what the solo situation is, so that they keep
-          delivering even though Session::soloing() is true and they were not
-          explicitly soloed.
-       */
+        if (_solo_safe) {
+                return;
+        }
 
-       Glib::RWLock::ReaderLock rm (_processor_lock);
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               boost::shared_ptr<Delivery> d;
-               
-               if ((d = boost::dynamic_pointer_cast<Delivery> (*i)) != 0) {
-                       d->set_solo_level (soloed ());
-                       d->set_solo_isolated (solo_isolated());
+        if (delta < 0) {
+               if (_soloed_by_others_downstream >= (uint32_t) abs (delta)) {
+                       _soloed_by_others_downstream += delta;
+               } else {
+                       _soloed_by_others_downstream = 0;
                }
+       } else {
+               _soloed_by_others_downstream += delta;
        }
+
+        DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbD delta %2 = %3\n", name(), delta, _soloed_by_others_downstream));
+
+        set_mute_master_solo ();
+        solo_changed (false, this);
+}
+
+void
+Route::set_mute_master_solo ()
+{
+        _mute_master->set_soloed (self_soloed() || soloed_by_others_downstream() || soloed_by_others_upstream());
 }
 
 void
 Route::set_solo_isolated (bool yn, void *src)
 {
-       if (is_master() || is_control() || is_hidden()) {
+       if (is_master() || is_monitor() || is_hidden()) {
                return;
        }
 
-       if (_route_group && src != _route_group && _route_group->active_property (RouteGroup::Solo)) {
+       if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_solo()) {
                _route_group->apply (&Route::set_solo_isolated, yn, _route_group);
                return;
        }
@@ -627,32 +717,42 @@ 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()) {
+                        continue;
+                }
+
                bool sends_only;
-               bool does_feed = feeds (*i, &sends_only);
+               bool does_feed = direct_feeds (*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());
                }
        }
 
-       bool changed = false;
+        /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */
+
+        bool changed = false;
 
        if (yn) {
-               if (_solo_isolated == 0) {
-                       changed = true;
-               }
+                if (_solo_isolated == 0) {
+                        _mute_master->set_solo_ignore (true);
+                        changed = true;
+                }
                _solo_isolated++;
        } else {
-               changed = (_solo_isolated == 1);
                if (_solo_isolated > 0) {
                        _solo_isolated--;
+                        if (_solo_isolated == 0) {
+                                _mute_master->set_solo_ignore (false);
+                                changed = true;
+                        }
                }
        }
 
-       if (changed) {
-               set_delivery_solo ();
-               solo_isolated_changed (src);
-       }
+        if (changed) {
+                solo_isolated_changed (src);
+        }
 }
 
 bool
@@ -664,38 +764,32 @@ Route::solo_isolated () const
 void
 Route::set_mute_points (MuteMaster::MutePoint mp)
 {
-       _mute_points = mp;
-       mute_points_changed (); /* EMIT SIGNAL */
-
-       if (_mute_master->muted()) {
-               _mute_master->mute_at (_mute_points);
-               mute_changed (this); /* EMIT SIGNAL */
-       }
+        _mute_master->set_mute_points (mp);
+        mute_points_changed (); /* EMIT SIGNAL */
+        
+        if (_mute_master->muted_by_self()) {
+                mute_changed (this); /* EMIT SIGNAL */
+        }
 }
 
 void
 Route::set_mute (bool yn, void *src)
 {
-       if (_route_group && src != _route_group && _route_group->active_property (RouteGroup::Mute)) {
+       if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_mute()) {
                _route_group->apply (&Route::set_mute, yn, _route_group);
                return;
        }
 
        if (muted() != yn) {
-               if (yn) {
-                       _mute_master->mute_at (_mute_points);
-               } else {
-                       _mute_master->clear_mute ();
-               }
-
+                _mute_master->set_muted_by_self (yn);
                mute_changed (src); /* EMIT SIGNAL */
        }
 }
 
 bool
-Route::muted() const
+Route::muted () const
 {
-       return _mute_master->muted ();
+        return _mute_master->muted_by_self();
 }
 
 #if 0
@@ -733,12 +827,12 @@ Route::add_processor (boost::shared_ptr<Processor> processor, Placement placemen
 
 
 /** Add a processor to the route.
- * If @a iter is not NULL, it must point to an iterator in _processors and the new
+ * @a iter must point to an iterator in _processors and the new
  * processor will be inserted immediately before this location.  Otherwise,
  * @a position is used.
  */
 int
-Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::iterator iter, ProcessorStreams* err)
+Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::iterator iter, ProcessorStreams* err, bool activation_allowed)
 {
        ChanCount old_pms = processor_max_streams;
 
@@ -796,8 +890,15 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
 
                }
 
-               if (_control_outs != processor) {
-                       // XXX: do we want to emit the signal here ? change call order.
+                /* is this the monitor send ? if so, make sure we keep track of it */
+
+                boost::shared_ptr<InternalSend> isend = boost::dynamic_pointer_cast<InternalSend> (processor);
+
+                if (isend && _session.monitor_out() && (isend->target_id() == _session.monitor_out()->id())) {
+                        _monitor_send = isend;
+                }
+
+               if (activation_allowed && (processor != _monitor_send)) {
                        processor->activate ();
                }
 
@@ -807,126 +908,11 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
        }
 
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       set_processor_positions ();
 
        return 0;
 }
 
-bool
-Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter)
-{
-       const XMLProperty *prop;
-
-       if (node.name() != "Processor") {
-               return false;
-       }
-
-       try {
-               if ((prop = node.property ("type")) != 0) {
-
-                       boost::shared_ptr<Processor> processor;
-
-                       if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
-                           prop->value() == "lv2" ||
-                           prop->value() == "vst" ||
-                           prop->value() == "audiounit") {
-
-                               processor.reset (new PluginInsert(_session, node));
-
-                       } else if (prop->value() == "port") {
-
-                               processor.reset (new PortInsert (_session, _mute_master, node));
-
-                       } else if (prop->value() == "send") {
-
-                               processor.reset (new Send (_session, _mute_master, node));
-
-                       } else if (prop->value() == "meter") {
-
-                               if (_meter) {
-                                       if (_meter->set_state (node, Stateful::loading_state_version)) {
-                                               return false;
-                                       } else {
-                                               return true;
-                                       }
-                               }
-
-                               _meter.reset (new PeakMeter (_session, node));
-                               _meter->set_display_to_user (_meter_point == MeterCustom);
-                               processor = _meter;
-
-                       } else if (prop->value() == "amp") {
-
-                               /* amp always exists */
-
-                               processor = _amp;
-                               if (processor->set_state (node, Stateful::loading_state_version)) {
-                                       return false;
-                               } else {
-                                       /* never any reason to add it */
-                                       return true;
-                               }
-
-                       } else if (prop->value() == "intsend") {
-
-                               processor.reset (new InternalSend (_session, _mute_master, node));
-
-                       } else if (prop->value() == "intreturn") {
-
-                               if (_intreturn) {
-                                       if (_intreturn->set_state (node, Stateful::loading_state_version)) {
-                                               return false;
-                                       } else {
-                                               return true;
-                                       }
-                               }
-                               _intreturn.reset (new InternalReturn (_session, node));
-                               processor = _intreturn;
-
-                       } else if (prop->value() == "main-outs") {
-
-                               if (_main_outs) {
-                                       if (_main_outs->set_state (node, Stateful::loading_state_version)) {
-                                               return false;
-                                       } else {
-                                               return true;
-                                       }
-                               }
-
-                               _main_outs.reset (new Delivery (_session, _output, _mute_master, node));
-                               processor = _main_outs;
-
-                       } else {
-                               error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
-                               return false;
-                       }
-
-                       if (iter == _processors.end() && processor->display_to_user() && !_processors.empty()) {
-                               /* check for invisible processors stacked at the end and leave them there */
-                               ProcessorList::iterator p;
-                               p = _processors.end();
-                               --p;
-                               while (!(*p)->display_to_user() && p != _processors.begin()) {
-                                       --p;
-                               }
-                               ++p;
-                               iter = p;
-                       }
-
-                       return (add_processor (processor, iter) == 0);
-
-               } else {
-                       error << _("Processor XML node has no type property") << endmsg;
-                       return false;
-               }
-       }
-
-       catch (failed_constructor &err) {
-               warning << _("processor could not be created. Ignored.") << endmsg;
-               return false;
-       }
-}
-
-
 bool
 Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorList::iterator iter)
 {
@@ -944,18 +930,18 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorLis
                                                prop->value() == "vst" ||
                                                prop->value() == "audiounit") {
 
-                                       processor.reset (new PluginInsert (_session, node));
+                                       processor.reset (new PluginInsert (_session));
 
                                } else {
 
-                                       processor.reset (new PortInsert (_session, _mute_master, node));
+                                       processor.reset (new PortInsert (_session, _mute_master));
                                }
 
                        }
 
                } else if (node.name() == "Send") {
 
-                       processor.reset (new Send (_session, _mute_master, node, version));
+                       processor.reset (new Send (_session, _mute_master));
 
                } else {
 
@@ -963,6 +949,10 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorLis
                        return false;
                }
 
+                if (processor->set_state (node, version)) {
+                        return false;
+                }
+
                if (iter == _processors.end() && processor->display_to_user() && !_processors.empty()) {
                        /* check for invisible processors stacked at the end and leave them there */
                        ProcessorList::iterator p;
@@ -1063,6 +1053,7 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter
        }
 
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       set_processor_positions ();
 
        return 0;
 }
@@ -1263,6 +1254,7 @@ Route::clear_processors (Placement p)
        processor_max_streams.reset();
        _have_internal_generator = false;
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       set_processor_positions ();
 
        if (!already_deleting) {
                _session.clear_deletion_in_progress();
@@ -1354,6 +1346,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
 
        processor->drop_references ();
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       set_processor_positions ();
 
        return 0;
 }
@@ -1362,7 +1355,6 @@ int
 Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* err)
 {
        ProcessorList deleted;
-       ProcessorList as_we_were;
 
        if (!_session.engine().connected()) {
                return 1;
@@ -1375,7 +1367,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
                ProcessorList::iterator i;
                boost::shared_ptr<Processor> processor;
 
-               as_we_were = _processors;
+               ProcessorList as_we_were = _processors;
 
                for (i = _processors.begin(); i != _processors.end(); ) {
 
@@ -1446,6 +1438,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
        }
 
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       set_processor_positions ();
 
        return 0;
 }
@@ -1461,6 +1454,12 @@ Route::configure_processors (ProcessorStreams* err)
        return 0;
 }
 
+ChanCount
+Route::input_streams () const
+{
+        return _input->n_ports ();
+}
+
 /** Configure the input/output configuration of each processor in the processors list.
  * Return 0 on success, otherwise configuration is impossible.
  */
@@ -1474,24 +1473,22 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
        _in_configure_processors = true;
 
        // Check each processor in order to see if we can configure as requested
-       ChanCount in = _input->n_ports ();
+       ChanCount in = input_streams ();
        ChanCount out;
        list< pair<ChanCount,ChanCount> > configuration;
        uint32_t index = 0;
 
        DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configure processors\n", _name));
-#ifndef NDEBUG
        DEBUG_TRACE (DEBUG::Processors, "{\n");
        for (list<boost::shared_ptr<Processor> >::const_iterator p = _processors.begin(); p != _processors.end(); ++p) {
                DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1 ID = %2\n", (*p)->name(), (*p)->id()));
        }
        DEBUG_TRACE (DEBUG::Processors, "}\n");
-#endif
 
        for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++index) {
 
                if ((*p)->can_support_io_configuration(in, out)) {
-                       DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1in = %2 out = %3\n",(*p)->name(), in, out));
+                       DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1 in = %2 out = %3\n",(*p)->name(), in, out));
                        configuration.push_back(make_pair(in, out));
                        in = out;
                } else {
@@ -1519,7 +1516,12 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
 
        /* make sure we have sufficient scratch buffers to cope with the new processor
           configuration */
-       _session.ensure_buffers (n_process_buffers ());
+       {
+               Glib::Mutex::Lock em (_session.engine().process_lock ());
+               _session.ensure_buffers (n_process_buffers ());
+       }
+
+       DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configuration complete\n", _name));
 
        _in_configure_processors = false;
        return 0;
@@ -1680,7 +1682,10 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
                }
        }
 
-       processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+        if (true) {
+                processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+               set_processor_positions ();
+        }
 
        return 0;
 }
@@ -1714,7 +1719,9 @@ Route::state(bool full_state)
        }
 
        node->add_property("active", _active?"yes":"no");
-       node->add_property("phase-invert", _phase_invert?"yes":"no");
+       string p;
+       boost::to_string (_phase_invert, p);
+       node->add_property("phase-invert", p);
        node->add_property("denormal-protection", _denormal_protection?"yes":"no");
        node->add_property("meter-point", enum_2_string (_meter_point));
 
@@ -1741,8 +1748,10 @@ Route::state(bool full_state)
        }
        node->add_property ("order-keys", order_string);
        node->add_property ("self-solo", (_self_solo ? "yes" : "no"));
-       snprintf (buf, sizeof (buf), "%d", _soloed_by_others);
-       node->add_property ("soloed-by-others", buf);
+       snprintf (buf, sizeof (buf), "%d", _soloed_by_others_upstream);
+       node->add_property ("soloed-by-upstream", buf);
+       snprintf (buf, sizeof (buf), "%d", _soloed_by_others_downstream);
+       node->add_property ("soloed-by-downstream", buf);
 
        node->add_child_nocopy (_input->state (full_state));
        node->add_child_nocopy (_output->state (full_state));
@@ -1808,6 +1817,10 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                _flags = Flag (0);
        }
 
+        if (is_master() || is_monitor() || is_hidden()) {
+                _mute_master->set_solo_ignore (true);
+        }
+
        /* add all processors (except amp, which is always present) */
 
        nlist = node.children();
@@ -1840,9 +1853,14 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                set_self_solo (string_is_affirmative (prop->value()));
        }
 
-       if ((prop = node.property ("soloed-by-others")) != 0) {
-               _soloed_by_others = 0; // needed for mod_solo_by_others () to work
-               mod_solo_by_others (atoi (prop->value()));
+       if ((prop = node.property ("soloed-by-upstream")) != 0) {
+               _soloed_by_others_upstream = 0; // needed for mod_.... () to work
+               mod_solo_by_others_upstream (atoi (prop->value()));
+       }
+
+       if ((prop = node.property ("soloed-by-downstream")) != 0) {
+               _soloed_by_others_downstream = 0; // needed for mod_.... () to work
+               mod_solo_by_others_downstream (atoi (prop->value()));
        }
 
        if ((prop = node.property ("solo-isolated")) != 0) {
@@ -1850,7 +1868,7 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
        }
 
        if ((prop = node.property (X_("phase-invert"))) != 0) {
-               set_phase_invert (string_is_affirmative (prop->value()));
+               set_phase_invert (boost::dynamic_bitset<> (prop->value ()));
        }
 
        if ((prop = node.property (X_("denormal-protection"))) != 0) {
@@ -1864,7 +1882,8 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
        }
 
        if ((prop = node.property (X_("meter-point"))) != 0) {
-               _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point));
+               MeterPoint mp = MeterPoint (string_2_enum (prop->value (), _meter_point));
+                set_meter_point (mp);
                if (_meter) {
                        _meter->set_display_to_user (_meter_point == MeterCustom);
                }
@@ -1872,7 +1891,7 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
 
        if ((prop = node.property (X_("order-keys"))) != 0) {
 
-               long n;
+               int32_t n;
 
                string::size_type colon, equal;
                string remaining = prop->value();
@@ -1883,7 +1902,7 @@ 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 {
-                               if (sscanf (remaining.substr (equal+1).c_str(), "%ld", &n) != 1) {
+                               if (sscanf (remaining.substr (equal+1).c_str(), "%d", &n) != 1) {
                                        error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
                                              << endmsg;
                                } else {
@@ -1948,11 +1967,6 @@ Route::_set_state_2X (const XMLNode& node, int version)
 
        /* 2X things which still remain to be handled:
         * default-type
-        * muted
-        * mute-affects-pre-fader
-        * mute-affects-post-fader
-        * mute-affects-control-outs
-        * mute-affects-main-outs
         * automation
         * controlouts
         */
@@ -1967,57 +1981,13 @@ Route::_set_state_2X (const XMLNode& node, int version)
        } else {
                _flags = Flag (0);
        }
-
-       /* add standard processors */
-
-       _meter.reset (new PeakMeter (_session));
-       add_processor (_meter, PreFader);
-
-       if (_flags & ControlOut) {
-               /* where we listen to tracks */
-               _intreturn.reset (new InternalReturn (_session));
-               add_processor (_intreturn, PreFader);
-       }
-
-       _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
-       add_processor (_main_outs, PostFader);
-
-       /* IOs */
-
-       nlist = node.children ();
-       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
-
-               child = *niter;
-
-               if (child->name() == IO::state_node_name) {
-
-                       /* there is a note in IO::set_state_2X() about why we have to call
-                          this directly.
-                          */
-
-                       _input->set_state_2X (*child, version, true);
-                       _output->set_state_2X (*child, version, false);
-
-                       if ((prop = child->property (X_("name"))) != 0) {
-                               set_name (prop->value ());
-                       }
-
-                       if ((prop = child->property (X_("id"))) != 0) {
-                               _id = prop->value ();
-                       }
-
-                       if ((prop = child->property (X_("active"))) != 0) {
-                               bool yn = string_is_affirmative (prop->value());
-                               _active = !yn; // force switch
-                               set_active (yn);
-                       }
-               }
-
-               /* XXX: panners? */
-       }
-
+       
        if ((prop = node.property (X_("phase-invert"))) != 0) {
-               set_phase_invert (string_is_affirmative (prop->value()));
+               boost::dynamic_bitset<> p (_input->n_ports().n_audio ());
+               if (string_is_affirmative (prop->value ())) {
+                       p.set ();
+               }                       
+               set_phase_invert (p);
        }
 
        if ((prop = node.property (X_("denormal-protection"))) != 0) {
@@ -2032,6 +2002,65 @@ Route::_set_state_2X (const XMLNode& node, int version)
                set_solo (yn, this);
        }
 
+       if ((prop = node.property (X_("muted"))) != 0) {
+               
+               bool first = true;
+               bool muted = string_is_affirmative (prop->value());
+               
+               if (muted){
+                 
+                       string mute_point;
+                       
+                       if ((prop = node.property (X_("mute-affects-pre-fader"))) != 0) {
+                         
+                               if (string_is_affirmative (prop->value())){
+                                       mute_point = mute_point + "PreFader";
+                                       first = false;
+                               }
+                       }
+                       
+                       if ((prop = node.property (X_("mute-affects-post-fader"))) != 0) {
+                         
+                               if (string_is_affirmative (prop->value())){
+                                 
+                                       if (!first) {
+                                               mute_point = mute_point + ",";
+                                       }
+                                       
+                                       mute_point = mute_point + "PostFader";
+                                       first = false;
+                               }
+                       }
+
+                       if ((prop = node.property (X_("mute-affects-control-outs"))) != 0) {
+                         
+                               if (string_is_affirmative (prop->value())){
+                                 
+                                       if (!first) {
+                                               mute_point = mute_point + ",";
+                                       }
+                                       
+                                       mute_point = mute_point + "Listen";
+                                       first = false;
+                               }
+                       }
+
+                       if ((prop = node.property (X_("mute-affects-main-outs"))) != 0) {
+                         
+                               if (string_is_affirmative (prop->value())){
+                                 
+                                       if (!first) {
+                                               mute_point = mute_point + ",";
+                                       }
+                                       
+                                       mute_point = mute_point + "Main";
+                               }
+                       }
+                       
+                       _mute_master->set_mute_points (mute_point);
+               }
+       }
+
        if ((prop = node.property (X_("meter-point"))) != 0) {
                _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point));
        }
@@ -2042,7 +2071,7 @@ Route::_set_state_2X (const XMLNode& node, int version)
 
        if ((prop = node.property (X_("order-keys"))) != 0) {
 
-               long n;
+               int32_t n;
 
                string::size_type colon, equal;
                string remaining = prop->value();
@@ -2053,7 +2082,7 @@ 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 {
-                               if (sscanf (remaining.substr (equal+1).c_str(), "%ld", &n) != 1) {
+                               if (sscanf (remaining.substr (equal+1).c_str(), "%d", &n) != 1) {
                                        error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
                                                << endmsg;
                                } else {
@@ -2071,6 +2100,78 @@ Route::_set_state_2X (const XMLNode& node, int version)
                }
        }
 
+       /* add standard processors */
+
+       //_meter.reset (new PeakMeter (_session));
+       //add_processor (_meter, PreFader);
+
+       if (is_monitor()) {
+               /* where we listen to tracks */
+               _intreturn.reset (new InternalReturn (_session));
+               add_processor (_intreturn, PreFader);
+
+                _monitor_control.reset (new MonitorProcessor (_session));
+                add_processor (_monitor_control, PostFader);
+       }
+
+       _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
+       add_processor (_main_outs, PostFader);
+
+       /* IOs */
+
+       nlist = node.children ();
+       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+
+               child = *niter;
+
+               if (child->name() == IO::state_node_name) {
+
+                       /* there is a note in IO::set_state_2X() about why we have to call
+                          this directly.
+                          */
+
+                       _input->set_state_2X (*child, version, true);
+                       _output->set_state_2X (*child, version, false);
+
+                       if ((prop = child->property (X_("name"))) != 0) {
+                               Route::set_name (prop->value ());
+                       }
+
+                       if ((prop = child->property (X_("id"))) != 0) {
+                               _id = prop->value ();
+                       }
+
+                       if ((prop = child->property (X_("active"))) != 0) {
+                               bool yn = string_is_affirmative (prop->value());
+                               _active = !yn; // force switch
+                               set_active (yn);
+                       }
+                       
+                       if ((prop = child->property (X_("gain"))) != 0) {
+                               gain_t val;
+
+                               if (sscanf (prop->value().c_str(), "%f", &val) == 1) {
+                                       _amp->gain_control()->set_value (val);
+                               }
+                       }
+                       
+                       /* Set up Panners in the IO */
+                       XMLNodeList io_nlist = child->children ();
+                       
+                       XMLNodeConstIterator io_niter;
+                       XMLNode *io_child;
+                       
+                       for (io_niter = io_nlist.begin(); io_niter != io_nlist.end(); ++io_niter) {
+
+                               io_child = *io_niter;
+                               
+                               if (io_child->name() == X_("Panner")) {
+                                       _main_outs->panner()->set_state(*io_child, version);
+                               }
+                       }
+               }
+       }
+
        XMLNodeList redirect_nodes;
 
        for (niter = nlist.begin(); niter != nlist.end(); ++niter){
@@ -2149,101 +2250,95 @@ Route::set_processor_state (const XMLNode& node)
 {
        const XMLNodeList &nlist = node.children();
        XMLNodeConstIterator niter;
-       ProcessorList::iterator i, o;
-
-       // Iterate through existing processors, remove those which are not in the state list
-
-       for (i = _processors.begin(); i != _processors.end(); ) {
-
-               /* leave amp alone, always */
-
-               if ((*i) == _amp) {
-                       ++i;
-                       continue;
-               }
-
-               ProcessorList::iterator tmp = i;
-               ++tmp;
-
-               bool processorInStateList = false;
-
-               for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
-
-                       XMLProperty* id_prop = (*niter)->property(X_("id"));
-
-                       if (id_prop && (*i)->id() == id_prop->value()) {
-                               processorInStateList = true;
-                               break;
-                       }
-               }
-
-               if (!processorInStateList) {
-                       remove_processor (*i);
-               }
-
-               i = tmp;
-       }
-
-       // Iterate through state list and make sure all processors are on the track and in the correct order,
-       // set the state of existing processors according to the new state on the same go
-
-       i = _processors.begin();
+        ProcessorList new_order;
+        bool must_configure = false;
 
-       for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) {
+       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
 
                XMLProperty* prop = (*niter)->property ("type");
 
-               o = i;
-
-               // Check whether the next processor in the list is the right one,
-               // except for "amp" which is always there and may not have the
-               // old ID since it is always created anew in every Route
-
-               if (prop->value() != "amp") {
-                       while (o != _processors.end()) {
+               if (prop->value() == "amp") {
+                        _amp->set_state (**niter, Stateful::current_state_version);
+                        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);
+                        new_order.push_back (_main_outs);
+                } else if (prop->value() == "intreturn") {
+                        if (!_intreturn) {
+                                _intreturn.reset (new InternalReturn (_session));
+                                must_configure = true;
+                        }
+                        _intreturn->set_state (**niter, Stateful::current_state_version);
+                        new_order.push_back (_intreturn);
+                } else if (is_monitor() && prop->value() == "monitor") {
+                        if (!_monitor_control) {
+                                _monitor_control.reset (new MonitorProcessor (_session));
+                                must_configure = true;
+                        }
+                        _monitor_control->set_state (**niter, Stateful::current_state_version);
+                        new_order.push_back (_monitor_control);
+                } else {
+                        ProcessorList::iterator o;
+
+                       for (o = _processors.begin(); o != _processors.end(); ++o) {
                                XMLProperty* id_prop = (*niter)->property(X_("id"));
                                if (id_prop && (*o)->id() == id_prop->value()) {
+                                        (*o)->set_state (**niter, Stateful::current_state_version);
+                                        new_order.push_back (*o);
                                        break;
                                }
-
-                               ++o;
-                       }
-               }
-
-               // If the processor (*niter) is not on the route,
-               // create it and move it to the correct location
-
-               if (o == _processors.end()) {
-
-                       if (add_processor_from_xml (**niter, i)) {
-                               --i; // move iterator to the newly inserted processor
-                       } else {
-                               cerr << "Error restoring route: unable to restore processor" << endl;
-                       }
-
-               } else {
-
-                       // Otherwise, the processor already exists; just
-                       // ensure it is at the location provided in the XML state
-
-                       if (i != o) {
-                               boost::shared_ptr<Processor> tmp = (*o);
-                               _processors.erase (o); // remove the old copy
-                               _processors.insert (i, tmp); // insert the processor at the correct location
-                               --i; // move iterator to the correct processor
                        }
 
-                       // and make it (just) so
-
-                       (*i)->set_state (**niter, Stateful::current_state_version);
-               }
-       }
-
-       /* note: there is no configure_processors() call because we figure that
-          the XML state represents a working signal route.
-       */
+                        // If the processor (*niter) is not on the route then create it 
+                        
+                        if (o == _processors.end()) {
+                                
+                                boost::shared_ptr<Processor> processor;
+
+                                if (prop->value() == "intsend") {
+                                        
+                                        processor.reset (new InternalSend (_session, _mute_master, boost::shared_ptr<Route>(), Delivery::Role (0)));
+                                        
+                                } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
+                                           prop->value() == "lv2" ||
+                                           prop->value() == "vst" ||
+                                           prop->value() == "audiounit") {
+                                        
+                                        processor.reset (new PluginInsert(_session));
+                                        
+                                } else if (prop->value() == "port") {
+                                        
+                                        processor.reset (new PortInsert (_session, _mute_master));
+                                        
+                                } else if (prop->value() == "send") {
+                                        
+                                        processor.reset (new Send (_session, _mute_master));
+                                        
+                                } else {
+                                        error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
+                                        continue;
+                                }
+
+                                processor->set_state (**niter, Stateful::current_state_version);
+                                new_order.push_back (processor);
+                                must_configure = true;
+                        }
+                }
+        }
+
+        { 
+               Glib::RWLock::WriterLock lm (_processor_lock);
+                _processors = new_order;
+                if (must_configure) {
+                        configure_processors_unlocked (0);
+                }
+        }
 
-       processors_changed (RouteProcessorChange ());
+        processors_changed (RouteProcessorChange ());
+       set_processor_positions ();
 }
 
 void
@@ -2256,31 +2351,37 @@ Route::curve_reallocate ()
 void
 Route::silence (nframes_t nframes)
 {
-       if (!_silent) {
-
-               _output->silence (nframes);
-
-               {
-                       Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+       Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+       if (!lm.locked()) {
+               return;
+       }
 
-                       if (lm.locked()) {
-                               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-                                       boost::shared_ptr<PluginInsert> pi;
+       silence_unlocked (nframes);
+}
 
-                                       if (!_active && (pi = boost::dynamic_pointer_cast<PluginInsert> (*i)) != 0) {
-                                               // skip plugins, they don't need anything when we're not active
-                                               continue;
-                                       }
+void
+Route::silence_unlocked (nframes_t nframes)
+{
+       /* Must be called with the processor lock held */
+       
+       if (!_silent) {
 
-                                       (*i)->silence (nframes);
-                               }
+               _output->silence (nframes);
 
-                               if (nframes == _session.get_block_size()) {
-                                       // _silent = true;
-                               }
+               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+                       boost::shared_ptr<PluginInsert> pi;
+                       
+                       if (!_active && (pi = boost::dynamic_pointer_cast<PluginInsert> (*i)) != 0) {
+                               // skip plugins, they don't need anything when we're not active
+                               continue;
                        }
+                       
+                       (*i)->silence (nframes);
+               }
+               
+               if (nframes == _session.get_block_size()) {
+                       // _silent = true;
                }
-
        }
 }
 
@@ -2343,8 +2444,8 @@ Route::listen_via (boost::shared_ptr<Route> route, Placement placement, bool /*a
                                   we take note of which i-send is doing that.
                                */
 
-                               if (route == _session.control_out()) {
-                                       _control_outs = boost::dynamic_pointer_cast<Delivery>(d);
+                               if (route == _session.monitor_out()) {
+                                       _monitor_send = boost::dynamic_pointer_cast<Delivery>(d);
                                }
 
                                /* already listening via the specified IO: do nothing */
@@ -2357,17 +2458,35 @@ Route::listen_via (boost::shared_ptr<Route> route, Placement placement, bool /*a
        boost::shared_ptr<InternalSend> listener;
 
        try {
-               listener.reset (new InternalSend (_session, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
+
+                if (is_master()) {
+                        
+                        if (route == _session.monitor_out()) {
+                                /* master never sends to control outs */
+                                return 0;
+                        } else {
+                                listener.reset (new InternalSend (_session, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
+                        }
+
+                } else {
+                        listener.reset (new InternalSend (_session, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
+                }
 
        } catch (failed_constructor& err) {
                return -1;
        }
 
-       if (route == _session.control_out()) {
-               _control_outs = listener;
+       if (route == _session.monitor_out()) {
+               _monitor_send = listener;
        }
 
-       add_processor (listener, placement);
+        if (placement == PostFader) {
+                /* put it *really* at the end, not just after the panner (main outs)
+                 */
+                add_processor (listener, _processors.end());
+        } else {
+                add_processor (listener, PreFader);
+        }
 
        return 0;
 }
@@ -2401,8 +2520,8 @@ Route::drop_listen (boost::shared_ptr<Route> route)
 
        rl.release ();
 
-       if (route == _session.control_out()) {
-               _control_outs.reset ();
+       if (route == _session.monitor_out()) {
+               _monitor_send.reset ();
        }
 }
 
@@ -2415,7 +2534,53 @@ Route::set_comment (string cmt, void *src)
 }
 
 bool
-Route::feeds (boost::shared_ptr<Route> other, bool* only_send)
+Route::add_fed_by (boost::shared_ptr<Route> other, bool via_sends_only)
+{
+        FeedRecord fr (other, via_sends_only);
+
+        pair<FedBy::iterator,bool> result =  _fed_by.insert (fr);
+
+        if (!result.second) {
+
+                /* already a record for "other" - make sure sends-only information is correct */
+                if (!via_sends_only && result.first->sends_only) {
+                        FeedRecord* frp = const_cast<FeedRecord*>(&(*result.first));
+                        frp->sends_only = false;
+                }
+        }
+        
+        return result.second;
+}
+
+void
+Route::clear_fed_by ()
+{
+        _fed_by.clear ();
+}
+
+bool
+Route::feeds (boost::shared_ptr<Route> other, bool* via_sends_only)
+{
+        const FedBy& fed_by (other->fed_by());
+
+        for (FedBy::iterator f = fed_by.begin(); f != fed_by.end(); ++f) {
+                boost::shared_ptr<Route> sr = f->r.lock();
+
+                if (sr && (sr.get() == this)) {
+
+                        if (via_sends_only) {
+                                *via_sends_only = f->sends_only;
+                        }
+
+                        return true;
+                }
+        }
+
+        return false;
+}
+
+bool
+Route::direct_feeds (boost::shared_ptr<Route> other, bool* only_send)
 {
        DEBUG_TRACE (DEBUG::Graph, string_compose ("Feeds? %1\n", _name));
 
@@ -2429,7 +2594,7 @@ Route::feeds (boost::shared_ptr<Route> other, bool* only_send)
        }
 
        
-       for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); r++) {
+       for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) {
 
                boost::shared_ptr<IOProcessor> iop;
 
@@ -2456,7 +2621,7 @@ Route::feeds (boost::shared_ptr<Route> other, bool* only_send)
 void
 Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors)
 {
-       nframes_t now = _session.transport_frame();
+       framepos_t now = _session.transport_frame();
 
        {
                Glib::RWLock::ReaderLock lm (_processor_lock);
@@ -2465,11 +2630,14 @@ Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool c
                        automation_snapshot (now, true);
                }
 
+                Automatable::transport_stopped (now);
+
                for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
                        if (Config->get_plugins_stop_with_transport() && can_flush_processors) {
                                (*i)->deactivate ();
                                (*i)->activate ();
+                                (*i)->flush ();
                        }
 
                        (*i)->transport_stopped (now);
@@ -2484,6 +2652,8 @@ Route::input_change_handler (IOChange change, void * /*src*/)
 {
        if ((change & ConfigurationChanged)) {
                configure_processors (0);
+               _phase_invert.resize (_input->n_ports().n_audio ());
+               io_changed (); /* EMIT SIGNAL */
        }
 }
 
@@ -2512,14 +2682,33 @@ int
 Route::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
                bool session_state_changing, bool /*can_record*/, bool /*rec_monitors_input*/)
 {
+       Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+       if (!lm.locked()) {
+               return 0;
+       }
+
        if (n_outputs().n_total() == 0) {
                return 0;
        }
 
-       if (session_state_changing || !_active || n_inputs() == ChanCount::ZERO)  {
-               silence (nframes);
+       if (!_active || n_inputs() == ChanCount::ZERO)  {
+               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)
+                          so we cannot use them. Be silent till this is over.
+                          
+                          XXX note the absurdity of ::no_roll() being called when we ARE rolling!
+                       */
+                       silence_unlocked (nframes);
+                       return 0;
+               }
+               /* we're really not rolling, so we're either delivery silence or actually
+                  monitoring, both of which are safe to do while session_state_changing is true.
+               */
+       }
 
        _amp->apply_gain_automation (false);
        passthru (start_frame, end_frame, nframes, 0);
@@ -2533,14 +2722,14 @@ Route::check_initial_delay (nframes_t nframes, nframes_t& transport_frame)
        if (_roll_delay > nframes) {
 
                _roll_delay -= nframes;
-               silence (nframes);
+               silence_unlocked (nframes);
                /* transport frame is not legal for caller to use */
                return 0;
 
        } else if (_roll_delay > 0) {
 
                nframes -= _roll_delay;
-               silence (_roll_delay);
+               silence_unlocked (_roll_delay);
                /* we've written _roll_delay of samples into the
                   output ports, so make a note of that for
                   future reference.
@@ -2556,24 +2745,21 @@ Route::check_initial_delay (nframes_t nframes, nframes_t& transport_frame)
 
 int
 Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick,
-            bool /*can_record*/, bool /*rec_monitors_input*/)
+            bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */)
 {
-       {
-               // automation snapshot can also be called from the non-rt context
-               // and it uses the processor list, so we try to acquire the lock here
-               Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
-
-               if (lm.locked()) {
-                       automation_snapshot (_session.transport_frame(), false);
-               }
+       Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+       if (!lm.locked()) {
+               return 0;
        }
+       
+       automation_snapshot (_session.transport_frame(), false);
 
        if (n_outputs().n_total() == 0) {
                return 0;
        }
 
        if (!_active || n_inputs().n_total() == 0) {
-               silence (nframes);
+               silence_unlocked (nframes);
                return 0;
        }
 
@@ -2592,7 +2778,7 @@ Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int
 
 int
 Route::silent_roll (nframes_t nframes, sframes_t /*start_frame*/, sframes_t /*end_frame*/,
-                   bool /*can_record*/, bool /*rec_monitors_input*/)
+                   bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */)
 {
        silence (nframes);
        return 0;
@@ -2644,13 +2830,12 @@ Route::flush_processors ()
        Glib::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               (*i)->deactivate ();
-               (*i)->activate ();
+                (*i)->flush ();
        }
 }
 
 void
-Route::set_meter_point (MeterPoint p, void *src)
+Route::set_meter_point (MeterPoint p)
 {
        /* CAN BE CALLED FROM PROCESS CONTEXT */
 
@@ -2712,7 +2897,7 @@ Route::set_meter_point (MeterPoint p, void *src)
        }
 
        _meter_point = p;
-       meter_change (src); /* EMIT SIGNAL */
+       meter_change (); /* EMIT SIGNAL */
 
        bool const meter_visibly_changed = (_meter->display_to_user() != meter_was_visible_to_user);
        
@@ -2720,17 +2905,16 @@ Route::set_meter_point (MeterPoint p, void *src)
 }
 
 void
-Route::put_control_outs_at (Placement p)
+Route::put_monitor_send_at (Placement p)
 {
-       if (!_control_outs) {
+       if (!_monitor_send) {
                return;
        }
 
        {
                Glib::RWLock::WriterLock lm (_processor_lock);
                ProcessorList as_it_was (_processors);
-               // Move meter in the processors list
-               ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), _control_outs);
+               ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), _monitor_send);
                _processors.erase(loc);
                
                switch (p) {
@@ -2741,13 +2925,11 @@ Route::put_control_outs_at (Placement p)
                        }
                        break;
                case PostFader:
-                       loc = find(_processors.begin(), _processors.end(), _amp);
-                       assert (loc != _processors.end());
-                       loc++;
+                       loc = _processors.end();
                        break;
                }
                
-               _processors.insert(loc, _control_outs);
+               _processors.insert (loc, _monitor_send);
 
                if (configure_processors_unlocked (0)) {
                        _processors = as_it_was;
@@ -2828,6 +3010,8 @@ Route::set_latency_delay (nframes_t longest_session_latency)
 void
 Route::automation_snapshot (nframes_t now, bool force)
 {
+       panner()->automation_snapshot (now, force);
+       
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->automation_snapshot (now, force);
        }
@@ -2843,17 +3027,63 @@ Route::SoloControllable::SoloControllable (std::string name, Route& r)
 }
 
 void
-Route::SoloControllable::set_value (float val)
+Route::SoloControllable::set_value (double val)
 {
        bool bval = ((val >= 0.5f) ? true: false);
+# if 0
+       this is how it should be done 
+
+       boost::shared_ptr<RouteList> rl (new RouteList);
+       rl->push_back (route);
 
+       if (Config->get_solo_control_is_listen_control()) {
+               _session.set_listen (rl, bval);
+       } else {
+               _session.set_solo (rl, bval);
+       }
+#else
        route.set_solo (bval, this);
+#endif
 }
 
-float
+double
 Route::SoloControllable::get_value (void) const
 {
-       return route.self_soloed() ? 1.0f : 0.0f;
+       if (Config->get_solo_control_is_listen_control()) {
+               return route.listening() ? 1.0f : 0.0f;
+       } else {
+               return route.self_soloed() ? 1.0f : 0.0f;
+       }
+}
+
+Route::MuteControllable::MuteControllable (std::string name, Route& r)
+       : AutomationControl (r.session(), Evoral::Parameter (MuteAutomation),
+                            boost::shared_ptr<AutomationList>(), name)
+       , route (r)
+{
+       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(MuteAutomation)));
+       set_list (gl);
+}
+
+void
+Route::MuteControllable::set_value (double val)
+{
+       bool bval = ((val >= 0.5f) ? true: false);
+# if 0
+       this is how it should be done 
+
+       boost::shared_ptr<RouteList> rl (new RouteList);
+       rl->push_back (route);
+       _session.set_mute (rl, bval);
+#else
+       route.set_mute (bval, this);
+#endif
+}
+
+double
+Route::MuteControllable::get_value (void) const
+{
+       return route.muted() ? 1.0f : 0.0f;
 }
 
 void
@@ -3002,19 +3232,39 @@ Route::internal_send_for (boost::shared_ptr<const Route> target) const
        return boost::shared_ptr<Send>();
 }
 
+/** @param c Audio channel index.
+ *  @param yn true to invert phase, otherwise false.
+ */
+void
+Route::set_phase_invert (uint32_t c, bool yn)
+{
+       if (_phase_invert[c] != yn) {
+               _phase_invert[c] = yn;
+               phase_invert_changed (); /* EMIT SIGNAL */
+                _session.set_dirty ();
+       }
+}
+
 void
-Route::set_phase_invert (bool yn)
+Route::set_phase_invert (boost::dynamic_bitset<> p)
 {
-       if (_phase_invert != yn) {
-               _phase_invert = 0xffff; // XXX all channels
+       if (_phase_invert != p) {
+               _phase_invert = p;
                phase_invert_changed (); /* EMIT SIGNAL */
+                _session.set_dirty ();
        }
 }
 
 bool
+Route::phase_invert (uint32_t c) const
+{
+       return _phase_invert[c];
+}
+
+boost::dynamic_bitset<>
 Route::phase_invert () const
 {
-       return _phase_invert != 0;
+       return _phase_invert;
 }
 
 void
@@ -3068,14 +3318,12 @@ Route::meter ()
 boost::shared_ptr<Panner>
 Route::panner() const
 {
-
        return _main_outs->panner();
 }
 
 boost::shared_ptr<AutomationControl>
 Route::gain_control() const
 {
-
        return _amp->gain_control();
 }
 
@@ -3084,7 +3332,7 @@ Route::get_control (const Evoral::Parameter& param)
 {
        /* either we own the control or .... */
 
-       boost::shared_ptr<AutomationControl> c = boost::dynamic_pointer_cast<AutomationControl>(data().control (param));
+       boost::shared_ptr<AutomationControl> c = boost::dynamic_pointer_cast<AutomationControl>(control (param));
 
        if (!c) {
 
@@ -3092,7 +3340,7 @@ Route::get_control (const Evoral::Parameter& param)
 
                Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
                for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-                       if ((c = boost::dynamic_pointer_cast<AutomationControl>((*i)->data().control (param))) != 0) {
+                       if ((c = boost::dynamic_pointer_cast<AutomationControl>((*i)->control (param))) != 0) {
                                break;
                        }
                }
@@ -3133,15 +3381,51 @@ Route::nth_send (uint32_t n)
        ProcessorList::iterator i;
 
        for (i = _processors.begin(); i != _processors.end(); ++i) {
-               cerr << "check " << (*i)->name() << endl;
                if (boost::dynamic_pointer_cast<Send> (*i)) {
                        if (n-- == 0) {
                                return *i;
                        }
-               } else {
-                       cerr << "\tnot a send\n";
-               }
+               } 
        }
 
        return boost::shared_ptr<Processor> ();
 }
+
+bool
+Route::has_io_processor_named (const string& name)
+{
+        Glib::RWLock::ReaderLock lm (_processor_lock);
+        ProcessorList::iterator i;
+        
+        for (i = _processors.begin(); i != _processors.end(); ++i) {
+                if (boost::dynamic_pointer_cast<Send> (*i) ||
+                    boost::dynamic_pointer_cast<PortInsert> (*i)) {
+                        if ((*i)->name() == name) {
+                                return true;
+                        }
+                }
+        }
+        
+        return false;
+}
+
+MuteMaster::MutePoint
+Route::mute_points () const
+{
+       return _mute_master->mute_points ();
+}
+
+void
+Route::set_processor_positions ()
+{
+       Glib::RWLock::ReaderLock lm (_processor_lock);
+
+       bool had_amp = false;
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               (*i)->set_pre_fader (!had_amp);
+               if (boost::dynamic_pointer_cast<Amp> (*i)) {
+                       had_amp = true;
+               }
+       }
+}
+