fix an assert failure due to incorrect process locking when adding a send
[ardour.git] / libs / ardour / route.cc
index f5fd4a682cf17185e8d66d1d313eea1d774c3332..d5a36481e5eecc12faabe14fc10664fe8ebd84a8 100644 (file)
@@ -65,7 +65,6 @@
 #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"
 
@@ -82,7 +81,7 @@ 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)
@@ -104,9 +103,18 @@ 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++;
+
+       if (is_master()) {
+               set_remote_control_id (MasterBusRemoteControlID);
+       } else if (is_monitor()) {
+               set_remote_control_id (MonitorBusRemoteControlID);
+       }
+               
 }
 
 int
@@ -125,11 +133,9 @@ Route::init ()
 
        /* panning */
 
-        Pannable* p = new Pannable (_session);
-#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
-       boost_debug_shared_ptr_mark_interesting (p, "Pannable");
-#endif
-       _pannable.reset (p);
+       if (!(_flags & Route::MonitorOut)) {
+               _pannable.reset (new Pannable (_session));
+       }
 
        /* input and output objects */
 
@@ -160,7 +166,7 @@ Route::init ()
                _intreturn.reset (new InternalReturn (_session));
                _intreturn->activate ();
 
-               /* the thing that provides proper control over a control/monitor/listen bus 
+               /* the thing that provides proper control over a control/monitor/listen bus
                   (such as per-channel cut, dim, solo, invert, etc).
                */
                _monitor_control.reset (new MonitorProcessor (_session));
@@ -188,13 +194,13 @@ 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 
+       /* 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);
@@ -208,6 +214,26 @@ Route::~Route ()
 void
 Route::set_remote_control_id (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;
+       }
+
+       /* 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 ();
@@ -291,7 +317,7 @@ Route::sync_order_keys (std::string const & base)
        }
 
        bool changed = false;
-       
+
        for (; i != order_keys.end(); ++i) {
                if (i->second != key) {
                        i->second = key;
@@ -399,12 +425,9 @@ 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) {
@@ -413,8 +436,11 @@ Route::process_output_buffers (BufferSet& bufs,
                _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);
 
 
        /* -------------------------------------------------------------------------------------------
@@ -480,12 +506,20 @@ 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 (boost::dynamic_pointer_cast<PeakMeter> (*i) && meter_already_run) {
+                       /* 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) {
@@ -496,7 +530,8 @@ Route::process_output_buffers (BufferSet& bufs,
                                abort ();
                        }
                }
-#endif                
+#endif
+
                /* should we NOT run plugins here if the route is inactive?
                   do we catch route != active somewhere higher?
                */
@@ -549,16 +584,17 @@ Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes
        }
 
        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
@@ -568,6 +604,11 @@ Route::set_listen (bool yn, void* src)
                return;
        }
 
+       if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_solo()) {
+               _route_group->foreach_route (boost::bind (&Route::set_listen, _1, yn, _route_group));
+               return;
+       }
+
        if (_monitor_send) {
                if (yn != _monitor_send->active()) {
                        if (yn) {
@@ -599,7 +640,7 @@ Route::set_solo_safe (bool yn, void *src)
        if (_solo_safe != yn) {
                _solo_safe = yn;
                solo_safe_changed (src);
-       } 
+       }
 }
 
 bool
@@ -655,16 +696,16 @@ Route::mod_solo_by_others_upstream (int32_t 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, 
+                            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. 
+       /* 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 
+          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),
@@ -672,7 +713,7 @@ Route::mod_solo_by_others_upstream (int32_t delta)
        */
 
        if ((_self_solo || _soloed_by_others_downstream) &&
-           ((old_sbu == 0 && _soloed_by_others_upstream > 0) || 
+           ((old_sbu == 0 && _soloed_by_others_upstream > 0) ||
             (old_sbu > 0 && _soloed_by_others_upstream == 0))) {
 
                if (delta > 0 || !Config->get_exclusive_solo()) {
@@ -683,7 +724,7 @@ Route::mod_solo_by_others_upstream (int32_t delta)
                                        sr->mod_solo_by_others_downstream (-delta);
                                }
                        }
-               } 
+               }
        }
 
        set_mute_master_solo ();
@@ -730,7 +771,7 @@ Route::set_solo_isolated (bool yn, void *src)
                _route_group->foreach_route (boost::bind (&Route::set_solo_isolated, _1, yn, _route_group));
                return;
        }
-       
+
        /* forward propagate solo-isolate status to everything fed by this route, but not those via sends only */
 
        boost::shared_ptr<RouteList> routes = _session.get_routes ();
@@ -741,8 +782,8 @@ Route::set_solo_isolated (bool yn, void *src)
                }
 
                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());
                }
@@ -801,6 +842,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 */
        }
@@ -819,14 +865,14 @@ dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& p
        cerr << name << " {" << endl;
        for (list<boost::shared_ptr<Processor> >::const_iterator p = procs.begin();
                        p != procs.end(); ++p) {
-               cerr << "\t" << (*p)->name() << " ID = " << (*p)->id() << endl;
+               cerr << "\t" << (*p)->name() << " ID = " << (*p)->id() << " @ " << (*p) << endl;
        }
        cerr << "}" << endl;
 }
 #endif
 
 int
-Route::add_processor (boost::shared_ptr<Processor> processor, Placement placement, ProcessorStreams* err)
+Route::add_processor (boost::shared_ptr<Processor> processor, Placement placement, ProcessorStreams* err, bool activation_allowed)
 {
        ProcessorList::iterator loc;
 
@@ -842,10 +888,38 @@ Route::add_processor (boost::shared_ptr<Processor> processor, Placement placemen
                loc = find (_processors.begin(), _processors.end(), _main_outs);
        }
 
-       return add_processor (processor, loc, err);
+       return add_processor (processor, loc, 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.
+ */
+
+int
+Route::add_processor_by_index (boost::shared_ptr<Processor> processor, int index, ProcessorStreams* err, bool activation_allowed)
+{
+       /* 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.
+       */
+
+       if (index == -1) {
+               return add_processor (processor, _processors.end(), err, activation_allowed);
+       }
+       
+       ProcessorList::iterator i = _processors.begin ();
+       int j = 0;
+       while (i != _processors.end() && j < index) {
+               if ((*i)->display_to_user()) {
+                       ++j;
+               }
+               
+               ++i;
+       }
+       
+       return add_processor (processor, i, 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.
  */
@@ -857,8 +931,6 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
 
        DEBUG_TRACE (DEBUG::Processors, string_compose (
                             "%1 adding processor %2\n", name(), processor->name()));
-       
-       ChanCount old_pms = processor_max_streams;
 
        if (!_session.engine().connected() || !processor) {
                return 1;
@@ -909,7 +981,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
 
                if ((pi = boost::dynamic_pointer_cast<PluginInsert>(processor)) != 0) {
 
-                       if (pi->natural_input_streams() == ChanCount::ZERO) {
+                       if (pi->has_no_inputs ()) {
                                /* generator plugin */
                                _have_internal_generator = true;
                        }
@@ -945,7 +1017,7 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
 
                XMLNodeList const & children = node.children ();
                XMLNodeList::const_iterator i = children.begin ();
-               
+
                while (i != children.end() && (*i)->name() != X_("Redirect")) {
                        ++i;
                }
@@ -962,9 +1034,10 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
 
                        if ((prop = node.property ("type")) != 0) {
 
-                               if (prop->value() == "ladspa" || prop->value() == "Ladspa" || 
+                               if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                                prop->value() == "lv2" ||
                                                prop->value() == "vst" ||
+                                               prop->value() == "lxvst" ||
                                                prop->value() == "audiounit") {
 
                                        processor.reset (new PluginInsert (_session));
@@ -1016,8 +1089,6 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                loc = _processors.end ();
        }
 
-       ChanCount old_pms = processor_max_streams;
-
        if (!_session.engine().connected()) {
                return 1;
        }
@@ -1042,7 +1113,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                                pi->set_count (1);
                        }
 
-                       ProcessorList::iterator inserted = _processors.insert (loc, *i);
+                       _processors.insert (loc, *i);
 
                        if ((*i)->active()) {
                                (*i)->activate ();
@@ -1064,7 +1135,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                        boost::shared_ptr<PluginInsert> pi;
 
                        if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
-                               if (pi->is_generator()) {
+                               if (pi->has_no_inputs ()) {
                                        _have_internal_generator = true;
                                        break;
                                }
@@ -1214,8 +1285,6 @@ Route::ab_plugins (bool forward)
 void
 Route::clear_processors (Placement p)
 {
-       const ChanCount old_pms = processor_max_streams;
-
        if (!_session.engine().connected()) {
                return;
        }
@@ -1288,7 +1357,7 @@ Route::clear_processors (Placement p)
 }
 
 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)
 {
        /* these can never be removed */
 
@@ -1296,8 +1365,6 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                return 0;
        }
 
-       ChanCount old_pms = processor_max_streams;
-
        if (!_session.engine().connected()) {
                return 1;
        }
@@ -1307,7 +1374,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
        {
                Glib::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
-               
+
                ProcessorList::iterator i;
                bool removed = false;
 
@@ -1348,11 +1415,18 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                if (!removed) {
                        /* what? */
                        return 1;
-               }
+               } 
 
-               {
+               if (need_process_lock) {
                        Glib::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 :) */
@@ -1367,7 +1441,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                        boost::shared_ptr<PluginInsert> pi;
 
                        if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
-                               if (pi->is_generator()) {
+                               if (pi->has_no_inputs ()) {
                                        _have_internal_generator = true;
                                        break;
                                }
@@ -1396,7 +1470,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
        {
                Glib::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
-               
+
                ProcessorList::iterator i;
                boost::shared_ptr<Processor> processor;
 
@@ -1442,7 +1516,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
 
                {
                        Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-               
+
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
                                /* we know this will work, because it worked before :) */
@@ -1457,7 +1531,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
                        boost::shared_ptr<PluginInsert> pi;
 
                        if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
-                               if (pi->is_generator()) {
+                               if (pi->has_no_inputs ()) {
                                        _have_internal_generator = true;
                                        break;
                                }
@@ -1482,12 +1556,12 @@ int
 Route::configure_processors (ProcessorStreams* err)
 {
        assert (!AudioEngine::instance()->process_lock().trylock());
-       
+
        if (!_in_configure_processors) {
                Glib::RWLock::WriterLock lm (_processor_lock);
                return configure_processors_unlocked (err);
        }
-       
+
        return 0;
 }
 
@@ -1522,7 +1596,7 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
                        DEBUG_TRACE (DEBUG::Processors, "--- CONFIGURE ABORTED due to unknown processor.\n");
                        break;
                }
-               
+
                if ((*p)->can_support_io_configuration(in, out)) {
                        DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1 ID=%2 in=%3 out=%4\n",(*p)->name(), (*p)->id(), in, out));
                        configuration.push_back(make_pair(in, out));
@@ -1540,7 +1614,7 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
        }
 
        DEBUG_TRACE (DEBUG::Processors, "}\n");
-       
+
        return configuration;
 }
 
@@ -1577,7 +1651,7 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
                if (boost::dynamic_pointer_cast<UnknownProcessor> (*p)) {
                        break;
                }
-               
+
                (*p)->configure_io(c->first, c->second);
                processor_max_streams = ChanCount::max(processor_max_streams, c->first);
                processor_max_streams = ChanCount::max(processor_max_streams, c->second);
@@ -1589,7 +1663,8 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
        }
 
        /* make sure we have sufficient scratch buffers to cope with the new processor
-          configuration */
+          configuration 
+       */
        _session.ensure_buffers (n_process_buffers ());
 
        DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configuration complete\n", _name));
@@ -1598,86 +1673,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);
 
        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)
 {
@@ -1690,7 +1712,7 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
        {
                Glib::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
-               
+
                ProcessorList::iterator oiter;
                ProcessorList::const_iterator niter;
                ProcessorList as_it_will_be;
@@ -1746,9 +1768,12 @@ 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 ());
-               
+
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
                                return -1;
@@ -1843,30 +1868,36 @@ Route::state(bool full_state)
                cmt->add_content (_comment);
        }
 
-       node->add_child_nocopy (_pannable->state (full_state));
+       if (_pannable) {
+               node->add_child_nocopy (_pannable->state (full_state));
+       }
 
        for (i = _processors.begin(); i != _processors.end(); ++i) {
                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;
@@ -1883,9 +1914,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));
@@ -1897,11 +1926,21 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                _mute_master->set_solo_ignore (true);
        }
 
+       if (is_monitor()) {
+               /* monitor bus does not get a panner, but if (re)created
+                  via XML, it will already have one by the time we
+                  call ::set_state(). so ... remove it.
+               */
+               unpan ();
+       }
+
        /* add all processors (except amp, which is always present) */
 
        nlist = node.children();
        XMLNode processor_state (X_("processor_state"));
 
+       Stateful::save_extra_xml (node);
+
        for (niter = nlist.begin(); niter != nlist.end(); ++niter){
 
                child = *niter;
@@ -1924,7 +1963,19 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
 
 
                if (child->name() == X_("Pannable")) {
-                       _pannable->set_state (*child, version);
+                       if (_pannable) {
+                               _pannable->set_state (*child, version);
+                       } else {
+                               warning << string_compose (_("Pannable state found for route (%1) without a panner!"), name()) << endmsg;
+                       }
+               }
+       }
+
+       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);
                }
        }
 
@@ -1966,14 +2017,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;
@@ -2005,6 +2048,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::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;
 
@@ -2015,10 +2076,6 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                        XMLNode *cmt = *(child->children().begin());
                        _comment = cmt->content();
 
-               } else if (child->name() == X_("Extra")) {
-
-                       _extra_xml = new XMLNode (*child);
-
                } else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) {
                        if (prop->value() == "solo") {
                                _solo_control->set_state (*child, version);
@@ -2040,7 +2097,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;
@@ -2063,12 +2120,12 @@ Route::_set_state_2X (const XMLNode& node, int version)
        } else {
                _flags = Flag (0);
        }
-       
+
        if ((prop = node.property (X_("phase-invert"))) != 0) {
                boost::dynamic_bitset<> p (_input->n_ports().n_audio ());
                if (string_is_affirmative (prop->value ())) {
                        p.set ();
-               }                       
+               }
                set_phase_invert (p);
        }
 
@@ -2085,60 +2142,60 @@ Route::_set_state_2X (const XMLNode& node, int version)
        }
 
        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);
                        _mute_master->set_muted_by_self (true);
                }
@@ -2203,16 +2260,14 @@ 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());
                                _active = !yn; // force switch
                                set_active (yn, this);
                        }
-                       
+
                        if ((prop = child->property (X_("gain"))) != 0) {
                                gain_t val;
 
@@ -2220,17 +2275,17 @@ Route::_set_state_2X (const XMLNode& node, int version)
                                        _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_shell()->set_state(*io_child, version);
                                } else if (io_child->name() == X_("Automation")) {
@@ -2255,6 +2310,8 @@ Route::_set_state_2X (const XMLNode& node, int version)
 
        set_processor_state_2X (redirect_nodes, version);
 
+       Stateful::save_extra_xml (node);
+
        for (niter = nlist.begin(); niter != nlist.end(); ++niter){
                child = *niter;
 
@@ -2265,10 +2322,6 @@ Route::_set_state_2X (const XMLNode& node, int version)
                        XMLNode *cmt = *(child->children().begin());
                        _comment = cmt->content();
 
-               } else if (child->name() == X_("extra")) {
-
-                       _extra_xml = new XMLNode (*child);
-
                } else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) {
                        if (prop->value() == X_("solo")) {
                                _solo_control->set_state (*child, version);
@@ -2283,7 +2336,7 @@ Route::_set_state_2X (const XMLNode& node, int version)
                                set_remote_control_id (x);
                        }
 
-               } 
+               }
        }
 
        return 0;
@@ -2331,6 +2384,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") {
@@ -2359,7 +2413,7 @@ Route::set_processor_state (const XMLNode& node)
                                }
                        }
 
-                       // If the processor (*niter) is not on the route then create it 
+                       // If the processor (*niter) is not on the route then create it
 
                        if (o == _processors.end()) {
 
@@ -2368,9 +2422,11 @@ Route::set_processor_state (const XMLNode& node)
                                if (prop->value() == "intsend") {
 
                                        processor.reset (new InternalSend (_session, _pannable, _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() == "lxvst" ||
                                           prop->value() == "audiounit") {
 
                                        processor.reset (new PluginInsert(_session));
@@ -2427,7 +2483,7 @@ Route::set_processor_state (const XMLNode& node)
                        boost::shared_ptr<PluginInsert> pi;
 
                        if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
-                               if (pi->is_generator()) {
+                               if (pi->has_no_inputs ()) {
                                        _have_internal_generator = true;
                                        break;
                                }
@@ -2461,22 +2517,22 @@ void
 Route::silence_unlocked (framecnt_t nframes)
 {
        /* Must be called with the processor lock held */
-       
+
        if (!_silent) {
 
                _output->silence (nframes);
 
                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;
                }
@@ -2495,6 +2551,7 @@ Route::add_internal_return ()
 void
 Route::add_send_to_internal_return (InternalSend* send)
 {
+       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
        Glib::RWLock::ReaderLock rm (_processor_lock);
 
        for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
@@ -2509,6 +2566,7 @@ Route::add_send_to_internal_return (InternalSend* send)
 void
 Route::remove_send_from_internal_return (InternalSend* send)
 {
+       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
        Glib::RWLock::ReaderLock rm (_processor_lock);
 
        for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
@@ -2520,35 +2578,34 @@ 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 */
        if (!_monitor_send) {
                _monitor_send.reset (new InternalSend (_session, _pannable, _mute_master, _session.monitor_out(), Delivery::Listen));
                _monitor_send->set_display_to_user (false);
        }
-       
+
        /* 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.
  */
 int
-Route::listen_via (boost::shared_ptr<Route> route, Placement placement)
+Route::add_aux_send (boost::shared_ptr<Route> route, Placement placement)
 {
        assert (route != _session.monitor_out ());
-       
+
        {
                Glib::RWLock::ReaderLock rm (_processor_lock);
 
@@ -2564,7 +2621,14 @@ 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));
+
+               boost::shared_ptr<InternalSend> listener;
+
+               {
+                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       listener.reset (new InternalSend (_session, _pannable, _mute_master, route, Delivery::Aux));
+               }
+
                add_processor (listener, placement);
 
        } catch (failed_constructor& err) {
@@ -2575,36 +2639,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::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;
+                       }
+               }
        }
 }
 
@@ -2663,20 +2730,20 @@ 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;
        }
 
-       
+
        for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) {
 
                boost::shared_ptr<IOProcessor> iop;
@@ -2684,8 +2751,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 {
@@ -2694,13 +2761,19 @@ Route::direct_feeds (boost::shared_ptr<Route> other, bool* only_send)
                } else {
                        DEBUG_TRACE (DEBUG::Graph,  string_compose ("\tPROC %1 is not an IOP\n", (*r)->name()));
                }
-                       
+
        }
 
        DEBUG_TRACE (DEBUG::Graph,  string_compose ("\tdoes NOT feed %1\n", other->name()));
        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)
@@ -2751,8 +2824,7 @@ 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);
        if (!lm.locked()) {
@@ -2771,7 +2843,7 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
                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);
@@ -2788,51 +2860,14 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
        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);
-
-               _roll_delay = 0;
-
-       } 
-
-       return nframes;
-}
-
 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);
        if (!lm.locked()) {
                return 0;
        }
-       
+
        automation_snapshot (_session.transport_frame(), false);
 
        if (n_outputs().n_total() == 0) {
@@ -2858,21 +2893,12 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in
 }
 
 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
 {
@@ -2924,51 +2950,69 @@ Route::set_meter_point (MeterPoint p, bool force)
                return;
        }
 
-       _meter_point = p;
-       
        bool meter_was_visible_to_user = _meter->display_to_user ();
 
        {
                Glib::RWLock::WriterLock lm (_processor_lock);
-       
+
+               maybe_note_meter_position ();
+
+               _meter_point = p;
+
                if (_meter_point != MeterCustom) {
 
                        _meter->set_display_to_user (false);
-                       
+
                        setup_invisible_processors ();
-                       
-                       ProcessorList::iterator loc = find (_processors.begin(), _processors.end(), _meter);
 
-                       ChanCount m_in;
-                       
-                       if (loc == _processors.begin()) {
-                               m_in = _input->n_ports();
-                       } else {
-                               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.
-                       */
-                       
                } else {
-                       
-                       // just make it visible and let the user move it
-                       
+
                        _meter->set_display_to_user (true);
+
+                       /* 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);
+                               }
+                       }
+               }
+
+               /* 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 {
+                       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 */
 
        bool const meter_visibly_changed = (_meter->display_to_user() != meter_was_visible_to_user);
-       
+
        processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, meter_visibly_changed)); /* EMIT SIGNAL */
 }
 
@@ -2981,7 +3025,7 @@ Route::listen_position_changed ()
 
                {
                        Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-                       
+
                        if (configure_processors_unlocked (0)) {
                                pstate.restore ();
                                configure_processors_unlocked (0); // it worked before we tried to add it ...
@@ -2998,7 +3042,7 @@ boost::shared_ptr<CapturingProcessor>
 Route::add_export_point()
 {
        if (!_capturing_processor) {
-               
+
                _capturing_processor.reset (new CapturingProcessor (_session));
                _capturing_processor->activate ();
 
@@ -3008,7 +3052,7 @@ Route::add_export_point()
                }
 
        }
-       
+
        return _capturing_processor;
 }
 
@@ -3068,7 +3112,10 @@ Route::set_latency_compensation (framecnt_t longest_session_latency)
 void
 Route::automation_snapshot (framepos_t now, bool force)
 {
-       _pannable->automation_snapshot (now, force);
+       if (_pannable) {
+               _pannable->automation_snapshot (now, force);
+       }
+
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->automation_snapshot (now, force);
        }
@@ -3094,7 +3141,7 @@ Route::SoloControllable::set_value (double val)
        if (!r) {
                return;
        }
-       
+
        rl->push_back (r);
 
        if (Config->get_solo_control_is_listen_control()) {
@@ -3111,7 +3158,7 @@ Route::SoloControllable::get_value () const
        if (!r) {
                return 0;
        }
-       
+
        if (Config->get_solo_control_is_listen_control()) {
                return r->listening_via_monitor() ? 1.0f : 0.0f;
        } else {
@@ -3139,7 +3186,7 @@ Route::MuteControllable::set_value (double val)
        if (!r) {
                return;
        }
-       
+
        rl->push_back (r);
        _session.set_mute (rl, bval);
 }
@@ -3151,7 +3198,7 @@ Route::MuteControllable::get_value () const
        if (!r) {
                return 0;
        }
-       
+
        return r->muted() ? 1.0f : 0.0f;
 }
 
@@ -3161,7 +3208,7 @@ Route::set_block_size (pframes_t nframes)
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->set_block_size (nframes);
        }
-       
+
        _session.ensure_buffers (n_process_buffers ());
 }
 
@@ -3208,7 +3255,7 @@ Route::shift (framepos_t pos, framecnt_t frames)
        }
 
        /* pan automation */
-       {
+       if (_pannable) {
                ControlSet::Controls& c (_pannable->controls());
 
                for (ControlSet::Controls::const_iterator ci = c.begin(); ci != c.end(); ++ci) {
@@ -3271,25 +3318,55 @@ Route::set_name (const string& str)
        ret = (_input->set_name(name) && _output->set_name(name));
 
        if (ret) {
+               /* rename the main outs. Leave other IO processors
+                * with whatever name they already have, because its
+                * just fine as it is (it will not contain the route
+                * name if its a port insert, port send or port return).
+                */
+
+               if (_main_outs) {
+                       if (_main_outs->set_name (name)) {
+                               /* XXX returning false here is stupid because
+                                  we already changed the route name.
+                               */
+                               return false;
+                       }
+               }
+       }
 
-               Glib::RWLock::ReaderLock lm (_processor_lock);
+       return ret;
+}
 
-               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+/** 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);
 
-                       /* rename all I/O processors that have inputs or outputs */
+       XMLNodeList children = node.children();
+       for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) {
+               
+               if ((*i)->name() == X_("IO")) {
 
-                       boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor> (*i);
+                       IO::set_name_in_state (**i, name);
 
-                       if (iop && (iop->output() || iop->input())) {
-                               if (!iop->set_name (name)) {
-                                       ret = false;
-                               }
+               } 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);
+                       
+               }
        }
-
-       return ret;
 }
 
 boost::shared_ptr<Send>
@@ -3367,7 +3444,7 @@ Route::set_active (bool yn, void* src)
                _route_group->foreach_route (boost::bind (&Route::set_active, _1, yn, _route_group));
                return;
        }
-       
+
        if (_active != yn) {
                _active = yn;
                _input->set_active (yn);
@@ -3481,7 +3558,7 @@ Route::nth_send (uint32_t n)
                        if (n-- == 0) {
                                return *i;
                        }
-               } 
+               }
        }
 
        return boost::shared_ptr<Processor> ();
@@ -3545,7 +3622,7 @@ list<string>
 Route::unknown_processors () const
 {
        list<string> p;
-       
+
        Glib::RWLock::ReaderLock lm (_processor_lock);
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<UnknownProcessor const> (*i)) {
@@ -3566,21 +3643,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 */
@@ -3676,11 +3758,11 @@ Route::setup_invisible_processors ()
        }
 
        /* we'll build this new list here and then use it */
-       
+
        ProcessorList new_processors;
 
        /* find visible processors */
-       
+
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if ((*i)->display_to_user ()) {
                        new_processors.push_back (*i);
@@ -3766,6 +3848,7 @@ Route::setup_invisible_processors ()
                                        new_processors.insert (amp, _monitor_send);
                                        break;
                                }
+                               _monitor_send->set_can_pan (false);
                                break;
                        case AfterFaderListen:
                                switch (Config->get_afl_position ()) {
@@ -3776,10 +3859,12 @@ Route::setup_invisible_processors ()
                                        new_processors.insert (new_processors.end(), _monitor_send);
                                        break;
                                }
+                               _monitor_send->set_can_pan (true);
                                break;
                        }
                }  else {
                        new_processors.insert (new_processors.end(), _monitor_send);
+                       _monitor_send->set_can_pan (false);
                }
        }
 
@@ -3789,7 +3874,7 @@ Route::setup_invisible_processors ()
                assert (!_monitor_control->display_to_user ());
                new_processors.push_front (_monitor_control);
        }
-       
+
        /* INTERNAL RETURN */
 
        /* doing this here means that any monitor control will come just after
@@ -3802,7 +3887,7 @@ Route::setup_invisible_processors ()
        }
 
        /* EXPORT PROCESSOR */
-       
+
        if (_capturing_processor) {
                assert (!_capturing_processor->display_to_user ());
                new_processors.push_front (_capturing_processor);
@@ -3816,18 +3901,78 @@ Route::setup_invisible_processors ()
        }
 }
 
-bool
-Route::should_monitor () const
+void
+Route::unpan ()
 {
-       switch (Config->get_monitoring_model()) {
-       case HardwareMonitoring:
-       case ExternalMonitoring:
-               return !record_enabled() || (_session.config.get_auto_input() && !_session.actively_recording());
-               break;
-       default:
-               break;
+       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+       Glib::RWLock::ReaderLock lp (_processor_lock);
+
+       _pannable.reset ();
+
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery>(*i);
+               if (d) {
+                       d->unpan ();
+               }
        }
+}
 
-       return true;
+/** 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::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;
+}