Mute automation via normal mute button.
[ardour.git] / libs / ardour / route.cc
index f6af17b1b885cedceb37b4b54679bcc6f81696bc..b9acae45eb13ab804ed2d83bfd2014d49fe254a7 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,13 @@ 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 0 // not used - just yet
+       if (!is_master() && !is_monitor() && !is_auditioner()) {
+               _delayline.reset (new DelayLine (_session, _name));
+               add_processor (_delayline, PreFader);
+       }
+#endif
+
        /* add amp processor  */
 
        _amp.reset (new Amp (_session));
@@ -177,8 +190,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);
        }
 
@@ -268,52 +280,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;
-}
-
-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;
-               }
-       }
+       return _order_key;
 }
 
 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 */
@@ -337,18 +316,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 ();
 }
@@ -450,12 +429,22 @@ 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);
+       if (!lm.locked()) {
+               bufs.silence (nframes, 0);
+               return;
+       }
 
        /* 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);
        }
@@ -464,8 +453,13 @@ Route::process_output_buffers (BufferSet& bufs,
           on a transition between monitoring states we get a de-clicking gain
           change in the _main_outs delivery.
        */
+       bool silence = monitoring_state () == MonitoringSilence;
 
-       _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
+       //but we override this in the case where we have an internal generator
+       if ( _have_internal_generator )
+               silence = false;
+
+       _main_outs->no_outs_cuz_we_no_monitor (silence);
 
        /* -------------------------------------------------------------------------------------------
           GLOBAL DECLICK (for transport changes etc.)
@@ -533,6 +527,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)) {
@@ -558,9 +554,118 @@ 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
@@ -574,6 +679,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);
 }
 
@@ -977,6 +1083,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);
 
@@ -1018,8 +1125,6 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
                // 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 ...
@@ -1100,7 +1205,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 {
 
@@ -1147,6 +1253,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);
 
@@ -1169,8 +1276,8 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                                (*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 ...
@@ -1346,6 +1453,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;
@@ -1357,7 +1465,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 */
 
@@ -1390,11 +1498,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();
@@ -1414,12 +1518,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;
        }
 
@@ -1430,7 +1543,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;
@@ -1470,22 +1592,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;
@@ -1500,6 +1611,9 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                                }
                        }
                }
+               if (need_process_lock) {
+                       lx.release();
+               }
        }
 
        reset_instrument_info ();
@@ -1522,6 +1636,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);
 
@@ -1534,7 +1649,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;
                        }
@@ -1568,16 +1683,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;
 
@@ -1619,7 +1731,9 @@ Route::reset_instrument_info ()
 int
 Route::configure_processors (ProcessorStreams* err)
 {
+#ifndef PLATFORM_WINDOWS
        assert (!AudioEngine::instance()->process_lock().trylock());
+#endif
 
        if (!_in_configure_processors) {
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
@@ -1690,7 +1804,9 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
 int
 Route::configure_processors_unlocked (ProcessorStreams* err)
 {
+#ifndef PLATFORM_WINDOWS
        assert (!AudioEngine::instance()->process_lock().trylock());
+#endif
 
        if (_in_configure_processors) {
                return 0;
@@ -1791,6 +1907,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);
 
@@ -1852,13 +1969,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;
                }
        }
 
@@ -1909,24 +2022,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);
@@ -1941,6 +2038,10 @@ Route::state(bool full_state)
        node->add_child_nocopy (_mute_control->get_state ());
        node->add_child_nocopy (_mute_master->get_state ());
 
+       if (full_state) {
+               node->add_child_nocopy (Automatable::get_automation_xml_state ());
+       }
+
        XMLNode* remote_control_node = new XMLNode (X_("RemoteControl"));
        snprintf (buf, sizeof (buf), "%d", _remote_control_id);
        remote_control_node->add_property (X_("id"), buf);
@@ -2127,7 +2228,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;
 
@@ -2145,17 +2250,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);
                                }
                        }
 
@@ -2213,6 +2312,9 @@ Route::set_state (const XMLNode& node, int version)
 
                } else if (child->name() == X_("MuteMaster")) {
                        _mute_master->set_state (*child, version);
+
+               } else if (child->name() == Automatable::xml_node_name) {
+                       set_automation_xml_state (*child, Evoral::Parameter(NullAutomation));
                }
        }
 
@@ -2356,17 +2458,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);
                                }
                        }
 
@@ -2525,6 +2621,11 @@ 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") {
+                       if (_delayline) {
+                               _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") {
@@ -2562,7 +2663,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" ||
@@ -2578,7 +2679,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;
@@ -2609,11 +2710,11 @@ 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);
                }
 
@@ -2727,10 +2828,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 +2869,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);
@@ -2854,7 +2957,7 @@ Route::feeds (boost::shared_ptr<Route> other, bool* via_sends_only)
 {
        const FedBy& fed_by (other->fed_by());
 
-       for (FedBy::iterator f = fed_by.begin(); f != fed_by.end(); ++f) {
+       for (FedBy::const_iterator f = fed_by.begin(); f != fed_by.end(); ++f) {
                boost::shared_ptr<Route> sr = f->r.lock();
 
                if (sr && (sr.get() == this)) {
@@ -3127,6 +3230,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 +3298,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 +3316,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 +3336,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 */
@@ -3284,18 +3395,21 @@ Route::set_latency_compensation (framecnt_t longest_session_latency)
 }
 
 Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr<Route> r)
-       : AutomationControl (r->session(), Evoral::Parameter (SoloAutomation),
-                            boost::shared_ptr<AutomationList>(), name)
+       : AutomationControl (r->session(),
+                            Evoral::Parameter (SoloAutomation),
+                            ParameterDescriptor(Evoral::Parameter (SoloAutomation)),
+                            boost::shared_ptr<AutomationList>(), name)
        , _route (r)
 {
        boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloAutomation)));
+       gl->set_interpolation(Evoral::ControlList::Discrete);
        set_list (gl);
 }
 
 void
 Route::SoloControllable::set_value (double val)
 {
-       bool bval = ((val >= 0.5f) ? true: false);
+       const bool bval = ((val >= 0.5) ? true : false);
 
        boost::shared_ptr<RouteList> rl (new RouteList);
 
@@ -3329,39 +3443,64 @@ Route::SoloControllable::get_value () const
 }
 
 Route::MuteControllable::MuteControllable (std::string name, boost::shared_ptr<Route> r)
-       : AutomationControl (r->session(), Evoral::Parameter (MuteAutomation),
-                            boost::shared_ptr<AutomationList>(), name)
+       : AutomationControl (r->session(),
+                            Evoral::Parameter (MuteAutomation),
+                            ParameterDescriptor (Evoral::Parameter (MuteAutomation)),
+                            boost::shared_ptr<AutomationList>(),
+                            name)
        , _route (r)
 {
        boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(MuteAutomation)));
+       gl->set_interpolation(Evoral::ControlList::Discrete);
        set_list (gl);
 }
 
 void
-Route::MuteControllable::set_value (double val)
+Route::MuteControllable::set_superficial_value(bool muted)
 {
-       bool bval = ((val >= 0.5f) ? true: false);
+       /* Note we can not use AutomationControl::set_value here since it will emit
+          Changed(), but the value will not be correct to the observer. */
 
-       boost::shared_ptr<RouteList> rl (new RouteList);
+       bool to_list = _list && ((AutomationList*)_list.get())->automation_write();
+
+       Control::set_double (muted, _session.transport_frame(), to_list);
+}
+
+void
+Route::MuteControllable::set_value (double val)
+{
+       const bool bval = ((val >= 0.5) ? true : false);
 
        boost::shared_ptr<Route> r = _route.lock ();
        if (!r) {
                return;
        }
 
-       rl->push_back (r);
-       _session.set_mute (rl, bval);
+       if (_list && ((AutomationList*)_list.get())->automation_playback()) {
+               // Playing back automation, set route mute directly
+               r->set_mute (bval, this);
+       } else {
+               // Set from user, queue mute event
+               boost::shared_ptr<RouteList> rl (new RouteList);
+               rl->push_back (r);
+               _session.set_mute (rl, bval, Session::rt_cleanup);
+       }
+
+       // Set superficial/automation value to drive controller (and possibly record)
+       set_superficial_value(bval);
 }
 
 double
 Route::MuteControllable::get_value () const
 {
-       boost::shared_ptr<Route> r = _route.lock ();
-       if (!r) {
-               return 0;
+       if (_list && ((AutomationList*)_list.get())->automation_playback()) {
+               // Playing back automation, get the value from the list
+               return AutomationControl::get_value();
        }
 
-       return r->muted() ? 1.0f : 0.0f;
+       // Not playing back automation, get the actual route mute value
+       boost::shared_ptr<Route> r = _route.lock ();
+       return (r && r->muted()) ? 1.0 : 0.0;
 }
 
 void
@@ -3471,14 +3610,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 +3742,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;
@@ -3620,7 +3763,7 @@ Route::set_active (bool yn, void* src)
 void
 Route::meter ()
 {
-       Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK);
+       Glib::Threads::RWLock::ReaderLock rm (_processor_lock);
 
        assert (_meter);
 
@@ -3675,7 +3818,7 @@ Route::get_control (const Evoral::Parameter& param)
 
                /* maybe one of our processors does or ... */
 
-               Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK);
+               Glib::Threads::RWLock::ReaderLock rm (_processor_lock);
                for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                        if ((c = boost::dynamic_pointer_cast<AutomationControl>((*i)->control (param))) != 0) {
                                break;
@@ -3953,7 +4096,7 @@ Route::setup_invisible_processors ()
                ++amp;
        }
 
-       assert (amp != _processors.end ());
+       assert (amp != new_processors.end ());
 
        /* and the processor after the amp */
 
@@ -4045,6 +4188,12 @@ Route::setup_invisible_processors ()
                }
        }
 
+#if 0 // not used - just yet
+       if (!is_master() && !is_monitor() && !is_auditioner()) {
+               new_processors.push_front (_delayline);
+       }
+#endif
+
        /* MONITOR CONTROL */
 
        if (_monitor_control && is_monitor ()) {
@@ -4174,7 +4323,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 +4350,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);