Disallow empty names for Groups, automatically enumerate them
[ardour.git] / libs / ardour / route.cc
index 026ee4ec5c18ef7435d5944ac938a40591e3e286..5df58ea846b63669d26722f4e07449d5138dd346 100644 (file)
 #include "ardour/internal_return.h"
 #include "ardour/internal_send.h"
 #include "ardour/meter.h"
+#include "ardour/delayline.h"
 #include "ardour/midi_buffer.h"
 #include "ardour/midi_port.h"
 #include "ardour/monitor_processor.h"
 #include "ardour/pannable.h"
+#include "ardour/panner.h"
 #include "ardour/panner_shell.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/port.h"
@@ -69,7 +71,7 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-PBD::Signal1<void,RouteSortOrderKey> Route::SyncOrderKeys;
+PBD::Signal0<void> Route::SyncOrderKeys;
 PBD::Signal0<void> Route::RemoteControlIDChange;
 
 Route::Route (Session& sess, string name, Flag flg, DataType default_type)
@@ -78,6 +80,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , GraphNode (sess._process_graph)
        , _active (true)
        , _signal_latency (0)
+       , _signal_latency_at_amp_position (0)
        , _initial_delay (0)
        , _roll_delay (0)
        , _flags (flg)
@@ -96,7 +99,10 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _have_internal_generator (false)
        , _solo_safe (false)
        , _default_type (default_type)
+       , _order_key (0)
+       , _has_order_key (false)
        , _remote_control_id (0)
+       , _track_number (0)
        , _in_configure_processors (false)
        , _initial_io_setup (false)
        , _custom_meter_position_noted (false)
@@ -139,6 +145,11 @@ Route::init ()
        _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2));
        _output->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::output_port_count_changing, this, _1));
 
+       if (!is_master() && !is_monitor() && !is_auditioner()) {
+               _delayline.reset (new DelayLine (_session, _name));
+               add_processor (_delayline, PreFader);
+       }
+
        /* add amp processor  */
 
        _amp.reset (new Amp (_session));
@@ -149,6 +160,7 @@ Route::init ()
        */
 
        _meter.reset (new PeakMeter (_session, _name));
+       _meter->set_owner (this);
        _meter->set_display_to_user (false);
        _meter->activate ();
 
@@ -176,8 +188,7 @@ Route::init ()
        Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this)));
 
        {
-               /* run a configure so that the invisible processors get set up */
-               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                configure_processors (0);
        }
 
@@ -267,52 +278,19 @@ Route::remote_control_id() const
 }
 
 bool
-Route::has_order_key (RouteSortOrderKey key) const
+Route::has_order_key () const
 {
-       return (order_keys.find (key) != order_keys.end());
+       return _has_order_key;
 }
 
 uint32_t
-Route::order_key (RouteSortOrderKey key) const
+Route::order_key () const
 {
-       OrderKeys::const_iterator i = order_keys.find (key);
-
-       if (i == order_keys.end()) {
-               return 0;
-       }
-
-       return i->second;
+       return _order_key;
 }
 
 void
-Route::sync_order_keys (RouteSortOrderKey base)
-{
-       /* this is called after changes to 1 or more route order keys have been
-        * made, and we want to sync up.
-        */
-
-       OrderKeys::iterator i = order_keys.find (base);
-
-       if (i == order_keys.end()) {
-               return;
-       }
-
-       for (OrderKeys::iterator k = order_keys.begin(); k != order_keys.end(); ++k) {
-
-               if (k->first != base) {
-                       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 set key for %2 to %3 from %4\n",
-                                                                      name(),
-                                                                      enum_2_string (k->first),
-                                                                      i->second,
-                                                                      enum_2_string (base)));
-                                                                      
-                       k->second = i->second;
-               }
-       }
-}
-
-void
-Route::set_remote_control_id_from_order_key (RouteSortOrderKey /*key*/, uint32_t rid)
+Route::set_remote_control_id_explicit (uint32_t rid)
 {
        if (is_master() || is_monitor() || is_auditioner()) {
                /* hard-coded remote IDs, or no remote ID */
@@ -336,18 +314,18 @@ Route::set_remote_control_id_from_order_key (RouteSortOrderKey /*key*/, uint32_t
 }
 
 void
-Route::set_order_key (RouteSortOrderKey key, uint32_t n)
+Route::set_order_key (uint32_t n)
 {
-       OrderKeys::iterator i = order_keys.find (key);
+       _has_order_key = true;
 
-       if (i != order_keys.end() && i->second == n) {
+       if (_order_key == n) {
                return;
        }
 
-       order_keys[key] = n;
+       _order_key = n;
 
-       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 order key %2 set to %3\n",
-                                                      name(), enum_2_string (key), order_key (key)));
+       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 order key set to %2\n",
+                                                      name(), order_key ()));
 
        _session.set_dirty ();
 }
@@ -449,12 +427,19 @@ Route::process_output_buffers (BufferSet& bufs,
                               framepos_t start_frame, framepos_t end_frame, pframes_t nframes,
                               int declick, bool gain_automation_ok)
 {
-       bufs.set_is_silent (false);
+       /* Caller must hold process lock */
+       assert (!AudioEngine::instance()->process_lock().trylock());
+
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+       assert(lm.locked());
 
        /* figure out if we're going to use gain automation */
        if (gain_automation_ok) {
                _amp->set_gain_automation_buffer (_session.gain_automation_buffer ());
-               _amp->setup_gain_automation (start_frame, end_frame, nframes);
+               _amp->setup_gain_automation (
+                               start_frame + _signal_latency_at_amp_position,
+                               end_frame + _signal_latency_at_amp_position,
+                               nframes);
        } else {
                _amp->apply_gain_automation (false);
        }
@@ -532,6 +517,8 @@ Route::process_output_buffers (BufferSet& bufs,
        /* set this to be true if the meter will already have been ::run() earlier */
        bool const meter_already_run = metering_state() == MeteringInput;
 
+       framecnt_t latency = 0;
+
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
                if (meter_already_run && boost::dynamic_pointer_cast<PeakMeter> (*i)) {
@@ -557,11 +544,120 @@ Route::process_output_buffers (BufferSet& bufs,
                   do we catch route != active somewhere higher?
                */
 
-               (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back());
+               if (boost::dynamic_pointer_cast<Send>(*i) != 0) {
+                       boost::dynamic_pointer_cast<Send>(*i)->set_delay_in(_signal_latency - latency);
+               }
+
+               (*i)->run (bufs, start_frame - latency, end_frame - latency, nframes, *i != _processors.back());
                bufs.set_count ((*i)->output_streams());
+
+               if ((*i)->active ()) {
+                       latency += (*i)->signal_latency ();
+               }
        }
 }
 
+void
+Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
+               boost::shared_ptr<Processor> endpoint,
+               bool include_endpoint, bool for_export, bool for_freeze)
+{
+       /* If no processing is required, there's no need to go any further. */
+       if (!endpoint && !include_endpoint) {
+               return;
+       }
+
+       framecnt_t latency = bounce_get_latency(_amp, false, for_export, for_freeze);
+       _amp->set_gain_automation_buffer (_session.gain_automation_buffer ());
+       _amp->setup_gain_automation (start - latency, start - latency + nframes, nframes);
+
+       latency = 0;
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+
+               if (!include_endpoint && (*i) == endpoint) {
+                       break;
+               }
+
+               /* if we're not exporting, stop processing if we come across a routing processor. */
+               if (!for_export && boost::dynamic_pointer_cast<PortInsert>(*i)) {
+                       break;
+               }
+               if (!for_export && for_freeze && (*i)->does_routing() && (*i)->active()) {
+                       break;
+               }
+
+               /* don't run any processors that does routing.
+                * oh, and don't bother with the peak meter either.
+                */
+               if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
+                       (*i)->run (buffers, start - latency, start - latency + nframes, nframes, true);
+                       buffers.set_count ((*i)->output_streams());
+                       latency += (*i)->signal_latency ();
+               }
+
+               if ((*i) == endpoint) {
+                       break;
+               }
+       }
+}
+
+framecnt_t
+Route::bounce_get_latency (boost::shared_ptr<Processor> endpoint,
+               bool include_endpoint, bool for_export, bool for_freeze) const
+{
+       framecnt_t latency = 0;
+       if (!endpoint && !include_endpoint) {
+               return latency;
+       }
+
+       for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               if (!include_endpoint && (*i) == endpoint) {
+                       break;
+               }
+               if (!for_export && boost::dynamic_pointer_cast<PortInsert>(*i)) {
+                       break;
+               }
+               if (!for_export && for_freeze && (*i)->does_routing() && (*i)->active()) {
+                       break;
+               }
+               if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
+                       latency += (*i)->signal_latency ();
+               }
+               if ((*i) == endpoint) {
+                       break;
+               }
+       }
+       return latency;
+}
+
+ChanCount
+Route::bounce_get_output_streams (ChanCount &cc, boost::shared_ptr<Processor> endpoint,
+               bool include_endpoint, bool for_export, bool for_freeze) const
+{
+       if (!endpoint && !include_endpoint) {
+               return cc;
+       }
+
+       for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               if (!include_endpoint && (*i) == endpoint) {
+                       break;
+               }
+               if (!for_export && boost::dynamic_pointer_cast<PortInsert>(*i)) {
+                       break;
+               }
+               if (!for_export && for_freeze && (*i)->does_routing() && (*i)->active()) {
+                       break;
+               }
+               if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
+                       cc = (*i)->output_streams();
+               }
+               if ((*i) == endpoint) {
+                       break;
+               }
+       }
+       return cc;
+}
+
 ChanCount
 Route::n_process_buffers ()
 {
@@ -573,6 +669,7 @@ Route::monitor_run (framepos_t start_frame, framepos_t end_frame, pframes_t nfra
 {
        assert (is_monitor());
        BufferSet& bufs (_session.get_route_buffers (n_process_buffers()));
+       fill_buffers_with_input (bufs, _input, nframes);
        passthru (bufs, start_frame, end_frame, nframes, declick);
 }
 
@@ -976,6 +1073,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
        }
 
        {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
@@ -1011,13 +1109,12 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
                }
 
                _processors.insert (loc, processor);
+               processor->set_owner (this);
 
                // Set up processor list channels.  This will set processor->[input|output]_streams(),
                // configure redirect ports properly, etc.
 
                {
-                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
                                configure_processors_unlocked (0); // it worked before we tried to add it ...
@@ -1098,7 +1195,8 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
 
                } else if (node.name() == "Send") {
 
-                       processor.reset (new Send (_session, _pannable, _mute_master));
+                       boost::shared_ptr<Pannable> sendpan (new Pannable (_session));
+                       processor.reset (new Send (_session, sendpan, _mute_master));
 
                } else {
 
@@ -1145,6 +1243,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
        }
 
        {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
@@ -1161,13 +1260,14 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                        }
 
                        _processors.insert (loc, *i);
+                       (*i)->set_owner (this);
 
                        if ((*i)->active()) {
                                (*i)->activate ();
                        }
 
+                       /* Think: does this really need to be called for every processor in the loop? */
                        {
-                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                                if (configure_processors_unlocked (err)) {
                                        pstate.restore ();
                                        configure_processors_unlocked (0); // it worked before we tried to add it ...
@@ -1343,6 +1443,7 @@ Route::clear_processors (Placement p)
        }
 
        {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorList new_list;
                ProcessorStreams err;
@@ -1354,7 +1455,7 @@ Route::clear_processors (Placement p)
                                seen_amp = true;
                        }
 
-                       if ((*i) == _amp || (*i) == _meter || (*i) == _main_outs) {
+                       if ((*i) == _amp || (*i) == _meter || (*i) == _main_outs || (*i) == _delayline) {
 
                                /* you can't remove these */
 
@@ -1387,11 +1488,7 @@ Route::clear_processors (Placement p)
                }
 
                _processors = new_list;
-
-               {
-                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-                       configure_processors_unlocked (&err); // this can't fail
-               }
+               configure_processors_unlocked (&err); // this can't fail
        }
 
        processor_max_streams.reset();
@@ -1411,12 +1508,21 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
 {
        // TODO once the export point can be configured properly, do something smarter here
        if (processor == _capturing_processor) {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
+               if (need_process_lock) {
+                       lx.acquire();
+               }
+
                _capturing_processor.reset();
+
+               if (need_process_lock) {
+                       lx.release();
+               }
        }
 
        /* these can never be removed */
 
-       if (processor == _amp || processor == _meter || processor == _main_outs) {
+       if (processor == _amp || processor == _meter || processor == _main_outs || processor == _delayline) {
                return 0;
        }
 
@@ -1427,7 +1533,16 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
        processor_max_streams.reset();
 
        {
-               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
+               if (need_process_lock) {
+                       lx.acquire();
+               }
+
+               /* Caller must hold process lock */
+               assert (!AudioEngine::instance()->process_lock().trylock());
+
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock); // XXX deadlock after export
+
                ProcessorState pstate (this);
 
                ProcessorList::iterator i;
@@ -1467,22 +1582,11 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                        return 1;
                } 
 
-               if (need_process_lock) {
-                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-
-                       if (configure_processors_unlocked (err)) {
-                               pstate.restore ();
-                               /* we know this will work, because it worked before :) */
-                               configure_processors_unlocked (0);
-                               return -1;
-                       }
-               } else {
-                       if (configure_processors_unlocked (err)) {
-                               pstate.restore ();
-                               /* we know this will work, because it worked before :) */
-                               configure_processors_unlocked (0);
-                               return -1;
-                       }
+               if (configure_processors_unlocked (err)) {
+                       pstate.restore ();
+                       /* we know this will work, because it worked before :) */
+                       configure_processors_unlocked (0);
+                       return -1;
                }
 
                _have_internal_generator = false;
@@ -1497,6 +1601,9 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                                }
                        }
                }
+               if (need_process_lock) {
+                       lx.release();
+               }
        }
 
        reset_instrument_info ();
@@ -1519,6 +1626,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
        processor_max_streams.reset();
 
        {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
@@ -1531,7 +1639,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
 
                        /* these can never be removed */
 
-                       if (processor == _amp || processor == _meter || processor == _main_outs) {
+                       if (processor == _amp || processor == _meter || processor == _main_outs || processor == _delayline) {
                                ++i;
                                continue;
                        }
@@ -1565,16 +1673,13 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
 
                _output->set_user_latency (0);
 
-               {
-                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-
-                       if (configure_processors_unlocked (err)) {
-                               pstate.restore ();
-                               /* we know this will work, because it worked before :) */
-                               configure_processors_unlocked (0);
-                               return -1;
-                       }
+               if (configure_processors_unlocked (err)) {
+                       pstate.restore ();
+                       /* we know this will work, because it worked before :) */
+                       configure_processors_unlocked (0);
+                       return -1;
                }
+               //lx.unlock();
 
                _have_internal_generator = false;
 
@@ -1792,6 +1897,7 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
        */
 
        {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
@@ -1853,13 +1959,9 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
                /* If the meter is in a custom position, find it and make a rough note of its position */
                maybe_note_meter_position ();
 
-               {
-                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-
-                       if (configure_processors_unlocked (err)) {
-                               pstate.restore ();
-                               return -1;
-                       }
+               if (configure_processors_unlocked (err)) {
+                       pstate.restore ();
+                       return -1;
                }
        }
 
@@ -1910,24 +2012,8 @@ Route::state(bool full_state)
                node->add_property("route-group", _route_group->name());
        }
 
-       string order_string;
-       OrderKeys::iterator x = order_keys.begin();
-
-       while (x != order_keys.end()) {
-               order_string += enum_2_string ((*x).first);
-               order_string += '=';
-               snprintf (buf, sizeof(buf), "%" PRId32, (*x).second);
-               order_string += buf;
-
-               ++x;
-
-               if (x == order_keys.end()) {
-                       break;
-               }
-
-               order_string += ':';
-       }
-       node->add_property ("order-keys", order_string);
+       snprintf (buf, sizeof (buf), "%d", _order_key);
+       node->add_property ("order-key", buf);
        node->add_property ("self-solo", (_self_solo ? "yes" : "no"));
        snprintf (buf, sizeof (buf), "%d", _soloed_by_others_upstream);
        node->add_property ("soloed-by-upstream", buf);
@@ -2128,7 +2214,11 @@ Route::set_state (const XMLNode& node, int version)
                set_active (yn, this);
        }
 
-       if ((prop = node.property (X_("order-keys"))) != 0) {
+       if ((prop = node.property (X_("order-key"))) != 0) { // New order key (no separate mixer/editor ordering)
+               set_order_key (atoi(prop->value()));
+       }
+
+       if ((prop = node.property (X_("order-keys"))) != 0) { // Deprecated order keys
 
                int32_t n;
 
@@ -2146,17 +2236,11 @@ Route::set_state (const XMLNode& node, int version)
                                              << endmsg;
                                } else {
                                        string keyname = remaining.substr (0, equal);
-                                       RouteSortOrderKey sk;
 
-                                       if (keyname == "signal") {
-                                               sk = MixerSort;
-                                       } else if (keyname == "editor") {
-                                               sk = EditorSort;
-                                       } else {
-                                               sk = (RouteSortOrderKey) string_2_enum (remaining.substr (0, equal), sk);
+                                       if ((keyname == "EditorSort") || (keyname == "editor")) {
+                                               cerr << "Setting " << name() << " order key to " << n << " using saved Editor order." << endl;
+                                               set_order_key (n);
                                        }
-
-                                       set_order_key (sk, n);
                                }
                        }
 
@@ -2357,17 +2441,11 @@ Route::set_state_2X (const XMLNode& node, int version)
                                                << endmsg;
                                } else {
                                        string keyname = remaining.substr (0, equal);
-                                       RouteSortOrderKey sk;
 
-                                       if (keyname == "signal") {
-                                               sk = MixerSort;
-                                       } else if (keyname == "editor") {
-                                               sk = EditorSort;
-                                       } else {
-                                               sk = (RouteSortOrderKey) string_2_enum (remaining.substr (0, equal), sk);
+                                       if (keyname == "EditorSort" || keyname == "editor") {
+                                               info << string_compose(_("Converting deprecated order key for %1 using Editor order %2"), name (), n) << endmsg;
+                                               set_order_key (n);
                                        }
-
-                                       set_order_key (sk, n);
                                }
                        }
 
@@ -2526,6 +2604,9 @@ Route::set_processor_state (const XMLNode& node)
                } else if (prop->value() == "meter") {
                        _meter->set_state (**niter, Stateful::current_state_version);
                        new_order.push_back (_meter);
+               } else if (prop->value() == "delay") {
+                       _delayline->set_state (**niter, Stateful::current_state_version);
+                       new_order.push_back (_delayline);
                } else if (prop->value() == "main-outs") {
                        _main_outs->set_state (**niter, Stateful::current_state_version);
                } else if (prop->value() == "intreturn") {
@@ -2563,7 +2644,7 @@ 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)));
+                                       processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), boost::shared_ptr<Route>(), Delivery::Aux, true));
 
                                } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                           prop->value() == "lv2" ||
@@ -2579,7 +2660,7 @@ Route::set_processor_state (const XMLNode& node)
 
                                } else if (prop->value() == "send") {
 
-                                       processor.reset (new Send (_session, _pannable, _mute_master));
+                                       processor.reset (new Send (_session, _pannable, _mute_master, Delivery::Send, true));
 
                                } else {
                                        error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
@@ -2610,16 +2691,17 @@ Route::set_processor_state (const XMLNode& node)
        }
 
        {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                _processors = new_order;
 
                if (must_configure) {
-                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                        configure_processors_unlocked (0);
                }
 
                for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
+                       (*i)->set_owner (this);
                        (*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false));
 
                        boost::shared_ptr<PluginInsert> pi;
@@ -2727,10 +2809,11 @@ Route::enable_monitor_send ()
 
        /* master never sends to monitor section via the normal mechanism */
        assert (!is_master ());
+       assert (!is_monitor ());
 
        /* make sure we have one */
        if (!_monitor_send) {
-               _monitor_send.reset (new InternalSend (_session, _pannable, _mute_master, _session.monitor_out(), Delivery::Listen));
+               _monitor_send.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), _session.monitor_out(), Delivery::Listen));
                _monitor_send->set_display_to_user (false);
        }
 
@@ -2767,7 +2850,8 @@ Route::add_aux_send (boost::shared_ptr<Route> route, boost::shared_ptr<Processor
 
                {
                        Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-                       listener.reset (new InternalSend (_session, _pannable, _mute_master, route, Delivery::Aux));
+                       boost::shared_ptr<Pannable> sendpan (new Pannable (_session));
+                       listener.reset (new InternalSend (_session, sendpan, _mute_master, boost::dynamic_pointer_cast<ARDOUR::Route>(shared_from_this()), route, Delivery::Aux));
                }
 
                add_processor (listener, before);
@@ -3127,6 +3211,7 @@ Route::set_meter_point (MeterPoint p, bool force)
        bool meter_was_visible_to_user = _meter->display_to_user ();
 
        {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
 
                maybe_note_meter_position ();
@@ -3194,17 +3279,14 @@ void
 Route::listen_position_changed ()
 {
        {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
-               {
-                       Glib::Threads::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 ...
-                               return;
-                       }
+               if (configure_processors_unlocked (0)) {
+                       pstate.restore ();
+                       configure_processors_unlocked (0); // it worked before we tried to add it ...
+                       return;
                }
        }
 
@@ -3215,15 +3297,16 @@ Route::listen_position_changed ()
 boost::shared_ptr<CapturingProcessor>
 Route::add_export_point()
 {
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        if (!_capturing_processor) {
+               lm.release();
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
+               Glib::Threads::RWLock::WriterLock lw (_processor_lock);
 
                _capturing_processor.reset (new CapturingProcessor (_session));
                _capturing_processor->activate ();
 
-               {
-                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-                       configure_processors (0);
-               }
+               configure_processors_unlocked (0);
 
        }
 
@@ -3234,15 +3317,24 @@ framecnt_t
 Route::update_signal_latency ()
 {
        framecnt_t l = _output->user_latency();
+       framecnt_t lamp = 0;
+       bool before_amp = true;
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if ((*i)->active ()) {
                        l += (*i)->signal_latency ();
                }
+               if ((*i) == _amp) {
+                       before_amp = false;
+               }
+               if (before_amp) {
+                       lamp = l;
+               }
        }
 
        DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: internal signal latency = %2\n", _name, l));
 
+       _signal_latency_at_amp_position = lamp;
        if (_signal_latency != l) {
                _signal_latency = l;
                signal_latency_changed (); /* EMIT SIGNAL */
@@ -3471,14 +3563,14 @@ Route::save_as_template (const string& path, const string& name)
 bool
 Route::set_name (const string& str)
 {
-       bool ret;
-       string ioproc_name;
-       string name;
+       if (str == name()) {
+               return true;
+       }
 
-       name = Route::ensure_track_or_route_name (str, _session);
+       string name = Route::ensure_track_or_route_name (str, _session);
        SessionObject::set_name (name);
 
-       ret = (_input->set_name(name) && _output->set_name(name));
+       bool ret = (_input->set_name(name) && _output->set_name(name));
 
        if (ret) {
                /* rename the main outs. Leave other IO processors
@@ -3603,6 +3695,10 @@ Route::denormal_protection () const
 void
 Route::set_active (bool yn, void* src)
 {
+       if (_session.transport_rolling()) {
+               return;
+       }
+
        if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_route_active()) {
                _route_group->foreach_route (boost::bind (&Route::set_active, _1, yn, _route_group));
                return;
@@ -3953,7 +4049,7 @@ Route::setup_invisible_processors ()
                ++amp;
        }
 
-       assert (amp != _processors.end ());
+       assert (amp != new_processors.end ());
 
        /* and the processor after the amp */
 
@@ -4045,6 +4141,10 @@ Route::setup_invisible_processors ()
                }
        }
 
+       if (!is_master() && !is_monitor() && !is_auditioner()) {
+               new_processors.push_front (_delayline);
+       }
+
        /* MONITOR CONTROL */
 
        if (_monitor_control && is_monitor ()) {
@@ -4174,7 +4274,7 @@ Route::has_external_redirects () const
 boost::shared_ptr<Processor>
 Route::the_instrument () const
 {
-       Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        return the_instrument_unlocked ();
 }
 
@@ -4201,8 +4301,13 @@ Route::non_realtime_locate (framepos_t pos)
                _pannable->transport_located (pos);
        }
 
+       if (_delayline.get()) {
+               _delayline.get()->flush();
+       }
+
        {
-               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+               //Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
                
                for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                        (*i)->transport_located (pos);