independent panning for external sends
[ardour.git] / libs / ardour / route.cc
index 99da5ea63a6988598190022f60b1689cdcfbea60..a036c8feb078a7191d2aaf750fa9b1b789ab5799 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "ardour/amp.h"
 #include "ardour/audio_buffer.h"
+#include "ardour/audio_port.h"
 #include "ardour/audioengine.h"
 #include "ardour/buffer.h"
 #include "ardour/buffer_set.h"
 #include "ardour/internal_return.h"
 #include "ardour/internal_send.h"
 #include "ardour/meter.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"
@@ -66,7 +70,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)
@@ -80,6 +84,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _flags (flg)
        , _pending_declick (true)
        , _meter_point (MeterPostFader)
+       , _meter_type (MeterPeak)
        , _self_solo (false)
        , _soloed_by_others_upstream (0)
        , _soloed_by_others_downstream (0)
@@ -92,11 +97,17 @@ 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)
        , _in_configure_processors (false)
+       , _initial_io_setup (false)
        , _custom_meter_position_noted (false)
        , _last_custom_meter_was_at_end (false)
 {
+       if (is_master()) {
+               _meter_type = MeterK20;
+       }
        processor_max_streams.reset();
 }
 
@@ -129,6 +140,7 @@ Route::init ()
        _input->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::input_port_count_changing, this, _1));
 
        _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2));
+       _output->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::output_port_count_changing, this, _1));
 
        /* add amp processor  */
 
@@ -139,7 +151,8 @@ Route::init ()
           they will be added to _processors by setup_invisible_processors ()
        */
 
-       _meter.reset (new PeakMeter (_session));
+       _meter.reset (new PeakMeter (_session, _name));
+       _meter->set_owner (this);
        _meter->set_display_to_user (false);
        _meter->activate ();
 
@@ -158,7 +171,7 @@ Route::init ()
                _monitor_control->activate ();
        }
 
-       if (is_master() || is_monitor() || is_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                _mute_master->set_solo_ignore (true);
        }
 
@@ -167,8 +180,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);
        }
 
@@ -202,12 +214,13 @@ Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
        if (Config->get_remote_model() != UserOrdered) {
                return;
        }
-       
-       if (id < 1) {
-               error << _("Remote Control ID's start at one, not zero") << endmsg;
-               return;
-       }
 
+       set_remote_control_id_internal (id, notify_class_listeners);
+}
+
+void
+Route::set_remote_control_id_internal (uint32_t id, bool notify_class_listeners)
+{
        /* force IDs for master/monitor busses and prevent 
           any other route from accidentally getting these IDs
           (i.e. legacy sessions)
@@ -221,6 +234,10 @@ Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
                id = MonitorBusRemoteControlID;
        }
 
+       if (id < 1) {
+               return;
+       }
+
        /* don't allow it to collide */
 
        if (!is_master () && !is_monitor() && 
@@ -253,54 +270,21 @@ 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_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                /* hard-coded remote IDs, or no remote ID */
                return;
        }
@@ -322,18 +306,18 @@ Route::set_remote_control_id_from_order_key (RouteSortOrderKey key, uint32_t rid
 }
 
 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 ();
 }
@@ -435,7 +419,8 @@ 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);
+       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) {
@@ -449,8 +434,8 @@ Route::process_output_buffers (BufferSet& bufs,
           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);
 
+       _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
 
        /* -------------------------------------------------------------------------------------------
           GLOBAL DECLICK (for transport changes etc.)
@@ -531,11 +516,10 @@ Route::process_output_buffers (BufferSet& bufs,
                        if (bufs.count() != (*i)->input_streams()) {
                                DEBUG_TRACE (
                                        DEBUG::Processors, string_compose (
-                                               "%1 bufs = %2 input for %3 = %4\n",
+                                               "input port mismatch %1 bufs = %2 input for %3 = %4\n",
                                                _name, bufs.count(), (*i)->name(), (*i)->input_streams()
                                                )
                                        );
-                               continue;
                        }
                }
 #endif
@@ -556,39 +540,26 @@ Route::n_process_buffers ()
 }
 
 void
-Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+Route::monitor_run (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
 {
-       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+       assert (is_monitor());
+       BufferSet& bufs (_session.get_route_buffers (n_process_buffers()));
+       passthru (bufs, start_frame, end_frame, nframes, declick);
+}
 
+void
+Route::passthru (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+{
        _silent = false;
 
-       assert (bufs.available() >= input_streams());
-
-       if (_input->n_ports() == ChanCount::ZERO) {
-               silence_unlocked (nframes);
-       }
-
-       bufs.set_count (input_streams());
-
        if (is_monitor() && _session.listening() && !_session.is_auditioning()) {
 
                /* control/monitor bus ignores input ports when something is
                   feeding the listen "stream". data will "arrive" into the
                   route from the intreturn processor element.
                */
-               bufs.silence (nframes, 0);
-
-       } else {
 
-               for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-
-                       BufferSet::iterator o = bufs.begin(*t);
-                       PortSet& ports (_input->ports());
-
-                       for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) {
-                               o->read_from (i->get_buffer(nframes), nframes);
-                       }
-               }
+               bufs.silence (nframes, 0);
        }
 
        write_out_of_band_data (bufs, start_frame, end_frame, nframes);
@@ -598,7 +569,7 @@ Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes
 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()));
+       BufferSet& bufs (_session.get_route_buffers (n_process_buffers(), true));
 
        bufs.set_count (_input->n_ports());
        write_out_of_band_data (bufs, start_frame, end_frame, nframes);
@@ -661,6 +632,7 @@ void
 Route::set_solo (bool yn, void *src)
 {
        if (_solo_safe) {
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change due to solo-safe\n", name()));
                return;
        }
 
@@ -669,6 +641,9 @@ Route::set_solo (bool yn, void *src)
                return;
        }
 
+       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set solo => %2, src: %3 grp ? %4 currently self-soloed ? %5\n", 
+                                                 name(), yn, src, (src == _route_group), self_soloed()));
+
        if (self_soloed() != yn) {
                set_self_solo (yn);
                set_mute_master_solo ();
@@ -680,6 +655,7 @@ Route::set_solo (bool yn, void *src)
 void
 Route::set_self_solo (bool yn)
 {
+       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set SELF solo => %2\n", name(), yn));
        _self_solo = yn;
 }
 
@@ -687,9 +663,13 @@ void
 Route::mod_solo_by_others_upstream (int32_t delta)
 {
        if (_solo_safe) {
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo-by-upstream due to solo-safe\n", name()));
                return;
        }
 
+       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-upstream by %2, current up = %3 down = %4\n", 
+                                                 name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
+
        uint32_t old_sbu = _soloed_by_others_upstream;
 
        if (delta < 0) {
@@ -743,9 +723,13 @@ void
 Route::mod_solo_by_others_downstream (int32_t delta)
 {
        if (_solo_safe) {
+               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo-by-downstream due to solo safe\n", name()));
                return;
        }
 
+       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-downstream by %2, current up = %3 down = %4\n", 
+                                                 name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
+
        if (delta < 0) {
                if (_soloed_by_others_downstream >= (uint32_t) abs (delta)) {
                        _soloed_by_others_downstream += delta;
@@ -771,7 +755,7 @@ Route::set_mute_master_solo ()
 void
 Route::set_solo_isolated (bool yn, void *src)
 {
-       if (is_master() || is_monitor() || is_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                return;
        }
 
@@ -785,7 +769,7 @@ Route::set_solo_isolated (bool yn, void *src)
        boost::shared_ptr<RouteList> routes = _session.get_routes ();
        for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
 
-               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_hidden()) {
+               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
                        continue;
                }
 
@@ -958,11 +942,12 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
        DEBUG_TRACE (DEBUG::Processors, string_compose (
                             "%1 adding processor %2\n", name(), processor->name()));
 
-       if (!_session.engine().connected() || !processor) {
+       if (!AudioEngine::instance()->connected() || !processor) {
                return 1;
        }
 
        {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
@@ -998,13 +983,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 ...
@@ -1070,7 +1054,7 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
 
                                if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                                prop->value() == "lv2" ||
-                                               prop->value() == "vst" ||
+                                               prop->value() == "windows-vst" ||
                                                prop->value() == "lxvst" ||
                                                prop->value() == "audiounit") {
 
@@ -1085,7 +1069,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 {
 
@@ -1132,6 +1117,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);
 
@@ -1148,13 +1134,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 ...
@@ -1330,6 +1317,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;
@@ -1374,11 +1362,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,6 +1398,10 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
        processor_max_streams.reset();
 
        {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK);
+               if (need_process_lock) {
+                       lx.acquire();
+               }
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
@@ -1454,22 +1442,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;
@@ -1484,6 +1461,9 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                                }
                        }
                }
+               if (need_process_lock) {
+                       lx.release();
+               }
        }
 
        reset_instrument_info ();
@@ -1506,6 +1486,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);
 
@@ -1552,16 +1533,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;
 
@@ -1590,11 +1568,65 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
        return 0;
 }
 
+void
+Route::set_custom_panner_uri (std::string const panner_uri)
+{
+       if (_in_configure_processors) {
+               DEBUG_TRACE (DEBUG::Panning, string_compose (_("Route::set_custom_panner_uri '%1' -- called while in_configure_processors\n"), name()));
+               return;
+       }
+
+       if (!_main_outs->panner_shell()->set_user_selected_panner_uri(panner_uri)) {
+               DEBUG_TRACE (DEBUG::Panning, string_compose (_("Route::set_custom_panner_uri '%1 '%2' -- no change needed\n"), name(), panner_uri));
+               /* no change needed */
+               return;
+       }
+
+       DEBUG_TRACE (DEBUG::Panning, string_compose (_("Route::set_custom_panner_uri '%1 '%2' -- reconfigure I/O\n"), name(), panner_uri));
+
+       /* reconfigure I/O -- re-initialize panner modules */
+       {
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+
+               for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p) {
+                       boost::shared_ptr<Delivery> dl;
+                       boost::shared_ptr<Panner> panner;
+                       if ((dl = boost::dynamic_pointer_cast<Delivery> (*p)) == 0) {
+                               continue;
+                       }
+                       if (!dl->panner_shell()) {
+                               continue;
+                       }
+                       if (!(panner = dl->panner_shell()->panner())) {
+                               continue;
+                       }
+                       /* _main_outs has already been set before the loop.
+                        * Ignore the return status here. It need reconfiguration */
+                       if (dl->panner_shell() != _main_outs->panner_shell()) {
+                               if (!dl->panner_shell()->set_user_selected_panner_uri(panner_uri)) {
+                                       continue;
+                               }
+                       }
+
+                       ChanCount in = panner->in();
+                       ChanCount out = panner->out();
+                       dl->panner_shell()->configure_io(in, out);
+                       dl->panner_shell()->pannable()->set_panner(dl->panner_shell()->panner());
+               }
+       }
+
+       processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+       _session.set_dirty ();
+}
+
 void
 Route::reset_instrument_info ()
 {
        boost::shared_ptr<Processor> instr = the_instrument();
-       _instrument_info.set_internal_instrument (instr);
+       if (instr) {
+               _instrument_info.set_internal_instrument (instr);
+       }
 }
 
 /** Caller must hold process lock */
@@ -1602,7 +1634,6 @@ int
 Route::configure_processors (ProcessorStreams* err)
 {
        assert (!AudioEngine::instance()->process_lock().trylock());
-
        if (!_in_configure_processors) {
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                return configure_processors_unlocked (err);
@@ -1640,7 +1671,8 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
 
                if (boost::dynamic_pointer_cast<UnknownProcessor> (*p)) {
                        DEBUG_TRACE (DEBUG::Processors, "--- CONFIGURE ABORTED due to unknown processor.\n");
-                       break;
+                       DEBUG_TRACE (DEBUG::Processors, "}\n");
+                       return list<pair<ChanCount, ChanCount> > ();
                }
 
                if ((*p)->can_support_io_configuration(in, out)) {
@@ -1690,6 +1722,9 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
        }
 
        ChanCount out;
+       bool seen_mains_out = false;
+       processor_out_streams = _input->n_ports();
+       processor_max_streams.reset();
 
        list< pair<ChanCount,ChanCount> >::iterator c = configuration.begin();
        for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++c) {
@@ -1702,8 +1737,21 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
                processor_max_streams = ChanCount::max(processor_max_streams, c->first);
                processor_max_streams = ChanCount::max(processor_max_streams, c->second);
                out = c->second;
+
+               if (boost::dynamic_pointer_cast<Delivery> (*p)
+                               && boost::dynamic_pointer_cast<Delivery> (*p)->role() == Delivery::Main) {
+                       /* main delivery will increase port count to match input.
+                        * the Delivery::Main is usually the last processor - followed only by
+                        * 'MeterOutput'.
+                        */
+                       seen_mains_out = true;
+               }
+               if (!seen_mains_out) {
+                       processor_out_streams = out;
+               }
        }
 
+
        if (_meter) {
                _meter->reset_max_channels (processor_max_streams);
        }
@@ -1756,6 +1804,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);
 
@@ -1817,13 +1866,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;
                }
        }
 
@@ -1868,28 +1913,14 @@ Route::state(bool full_state)
        node->add_property("denormal-protection", _denormal_protection?"yes":"no");
        node->add_property("meter-point", enum_2_string (_meter_point));
 
+       node->add_property("meter-type", enum_2_string (_meter_type));
+
        if (_route_group) {
                node->add_property("route-group", _route_group->name());
        }
 
-       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);
@@ -1932,7 +1963,7 @@ Route::state(bool full_state)
                        boost::shared_ptr<InternalSend> is;
 
                        if ((is = boost::dynamic_pointer_cast<InternalSend> (*i)) != 0) {
-                               if (is->role() == Delivery::Aux || is->role() == Delivery::Listen) {
+                               if (is->role() == Delivery::Listen) {
                                        continue;
                                }
                        }
@@ -1979,6 +2010,7 @@ Route::set_state (const XMLNode& node, int version)
        }
 
        set_id (node);
+       _initial_io_setup = true;
 
        if ((prop = node.property (X_("flags"))) != 0) {
                _flags = Flag (string_2_enum (prop->value(), _flags));
@@ -1986,7 +2018,7 @@ Route::set_state (const XMLNode& node, int version)
                _flags = Flag (0);
        }
 
-       if (is_master() || is_monitor() || is_hidden()) {
+       if (is_master() || is_monitor() || is_auditioner()) {
                _mute_master->set_solo_ignore (true);
        }
 
@@ -2025,7 +2057,6 @@ Route::set_state (const XMLNode& node, int version)
                        processor_state.add_child_copy (*child);
                }
 
-
                if (child->name() == X_("Pannable")) {
                        if (_pannable) {
                                _pannable->set_state (*child, version);
@@ -2043,8 +2074,17 @@ Route::set_state (const XMLNode& node, int version)
                }
        }
 
+       if ((prop = node.property (X_("meter-type"))) != 0) {
+               _meter_type = MeterType (string_2_enum (prop->value (), _meter_type));
+       }
+
+       _initial_io_setup = false;
+
        set_processor_state (processor_state);
 
+       // this looks up the internal instrument in processors
+       reset_instrument_info();
+
        if ((prop = node.property ("self-solo")) != 0) {
                set_self_solo (string_is_affirmative (prop->value()));
        }
@@ -2081,7 +2121,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;
 
@@ -2099,17 +2143,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);
                                }
                        }
 
@@ -2162,7 +2200,7 @@ Route::set_state (const XMLNode& node, int version)
                        if ((prop = child->property (X_("id"))) != 0) {
                                int32_t x;
                                sscanf (prop->value().c_str(), "%d", &x);
-                               set_remote_control_id (x);
+                               set_remote_control_id_internal (x);
                        }
 
                } else if (child->name() == X_("MuteMaster")) {
@@ -2200,6 +2238,10 @@ Route::set_state_2X (const XMLNode& node, int version)
                _flags = Flag (0);
        }
 
+       if (is_master() || is_monitor() || is_auditioner()) {
+               _mute_master->set_solo_ignore (true);
+       }
+
        if ((prop = node.property (X_("phase-invert"))) != 0) {
                boost::dynamic_bitset<> p (_input->n_ports().n_audio ());
                if (string_is_affirmative (prop->value ())) {
@@ -2306,17 +2348,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);
                                }
                        }
 
@@ -2423,7 +2459,7 @@ Route::set_state_2X (const XMLNode& node, int version)
                        if ((prop = child->property (X_("id"))) != 0) {
                                int32_t x;
                                sscanf (prop->value().c_str(), "%d", &x);
-                               set_remote_control_id (x);
+                               set_remote_control_id_internal (x);
                        }
 
                }
@@ -2512,11 +2548,12 @@ 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)));
+                                       boost::shared_ptr<Pannable> sendpan (new Pannable (_session));
+                                       processor.reset (new InternalSend (_session, sendpan, _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() == "windows-vst" ||
                                           prop->value() == "lxvst" ||
                                           prop->value() == "audiounit") {
 
@@ -2528,7 +2565,8 @@ Route::set_processor_state (const XMLNode& node)
 
                                } else if (prop->value() == "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 {
                                        error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
@@ -2559,16 +2597,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;
@@ -2676,6 +2715,7 @@ 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) {
@@ -2716,7 +2756,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, route, Delivery::Aux));
                }
 
                add_processor (listener, before);
@@ -2866,7 +2907,7 @@ Route::direct_feeds_according_to_graph (boost::shared_ptr<Route> other, bool* vi
 
 /** Called from the (non-realtime) butler thread when the transport is stopped */
 void
-Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors)
+Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool /*did_locate*/, bool can_flush_processors)
 {
        framepos_t now = _session.transport_frame();
 
@@ -2916,12 +2957,17 @@ void
 Route::output_change_handler (IOChange change, void * /*src*/)
 {
        bool need_to_queue_solo_change = true;
+       if (_initial_io_setup) {
+               return;
+       }
 
        if ((change.type & IOChange::ConfigurationChanged)) {
                /* This is called with the process lock held if change 
                   contains ConfigurationChanged 
                */
                need_to_queue_solo_change = false;
+               configure_processors (0);
+               io_changed (); /* EMIT SIGNAL */
        }
 
        if (!_output->connected() && _soloed_by_others_downstream) {
@@ -2959,6 +3005,7 @@ int
 Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
 {
        Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+
        if (!lm.locked()) {
                return 0;
        }
@@ -2971,6 +3018,7 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
                silence_unlocked (nframes);
                return 0;
        }
+
        if (session_state_changing) {
                if (_session.transport_speed() != 0.0f) {
                        /* we're rolling but some state is changing (e.g. our diskstream contents)
@@ -2986,8 +3034,16 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
                */
        }
 
+       BufferSet& bufs = _session.get_route_buffers (n_process_buffers());
+
+       fill_buffers_with_input (bufs, _input, nframes);
+
+       if (_meter_point == MeterInput) {
+               _meter->run (bufs, start_frame, end_frame, nframes, true);
+       }
+
        _amp->apply_gain_automation (false);
-       passthru (start_frame, end_frame, nframes, 0);
+       passthru (bufs, start_frame, end_frame, nframes, 0);
 
        return 0;
 }
@@ -3017,7 +3073,15 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in
 
        _silent = false;
 
-       passthru (start_frame, end_frame, nframes, declick);
+       BufferSet& bufs = _session.get_route_buffers (n_process_buffers());
+
+       fill_buffers_with_input (bufs, _input, nframes);
+
+       if (_meter_point == MeterInput) {
+               _meter->run (bufs, start_frame, end_frame, nframes, true);
+       }
+
+       passthru (bufs, start_frame, end_frame, nframes, declick);
 
        return 0;
 }
@@ -3046,8 +3110,6 @@ Route::flush_processors ()
 void
 Route::set_meter_point (MeterPoint p, bool force)
 {
-       /* CAN BE CALLED FROM PROCESS CONTEXT */
-
        if (_meter_point == p && !force) {
                return;
        }
@@ -3122,17 +3184,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;
                }
        }
 
@@ -3148,10 +3207,7 @@ Route::add_export_point()
                _capturing_processor.reset (new CapturingProcessor (_session));
                _capturing_processor->activate ();
 
-               {
-                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-                       configure_processors (0);
-               }
+               configure_processors (0);
 
        }
 
@@ -3710,6 +3766,19 @@ Route::input_port_count_changing (ChanCount to)
        return false;
 }
 
+/** Called when there is a proposed change to the output port count */
+bool
+Route::output_port_count_changing (ChanCount to)
+{
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               if (processor_out_streams.get(*t) > to.get(*t)) {
+                       return true;
+               }
+       }
+       /* The change is ok */
+       return false;
+}
+
 list<string>
 Route::unknown_processors () const
 {
@@ -3733,13 +3802,13 @@ Route::update_port_latencies (PortSet& from, PortSet& to, bool playback, framecn
           universally true, but the alternative is way too corner-case to worry about.
        */
 
-       jack_latency_range_t all_connections;
+       LatencyRange all_connections;
 
        if (from.empty()) {
                all_connections.min = 0;
                all_connections.max = 0;
        } else {
-               all_connections.min = ~((jack_nframes_t) 0);
+               all_connections.min = ~((pframes_t) 0);
                all_connections.max = 0;
                
                /* iterate over all "from" ports and determine the latency range for all of their
@@ -3748,7 +3817,7 @@ Route::update_port_latencies (PortSet& from, PortSet& to, bool playback, framecn
                
                for (PortSet::iterator p = from.begin(); p != from.end(); ++p) {
                        
-                       jack_latency_range_t range;
+                       LatencyRange range;
                        
                        p->get_connected_latency_range (range, playback);
                        
@@ -3813,7 +3882,7 @@ Route::set_public_port_latencies (framecnt_t value, bool playback) const
           latency compensation into account.
        */
 
-       jack_latency_range_t range;
+       LatencyRange range;
 
        range.min = value;
        range.max = value;
@@ -4089,7 +4158,13 @@ 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 ();
+}
+
+boost::shared_ptr<Processor>
+Route::the_instrument_unlocked () const
+{
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<PluginInsert>(*i)) {
                        if ((*i)->input_streams().n_midi() > 0 &&
@@ -4101,6 +4176,8 @@ Route::the_instrument () const
        return boost::shared_ptr<Processor>();
 }
 
+
+
 void
 Route::non_realtime_locate (framepos_t pos)
 {
@@ -4109,6 +4186,7 @@ Route::non_realtime_locate (framepos_t pos)
        }
 
        {
+               //Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
                Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                
                for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
@@ -4116,3 +4194,93 @@ Route::non_realtime_locate (framepos_t pos)
                }
        }
 }
+
+void
+Route::fill_buffers_with_input (BufferSet& bufs, boost::shared_ptr<IO> io, pframes_t nframes)
+{
+       size_t n_buffers;
+       size_t i;
+       
+       /* MIDI 
+        *  
+        * We don't currently mix MIDI input together, so we don't need the
+        * complex logic of the audio case.
+        */
+
+       n_buffers = bufs.count().n_midi ();
+
+       for (i = 0; i < n_buffers; ++i) {
+
+               boost::shared_ptr<MidiPort> source_port = io->midi (i);
+               MidiBuffer& buf (bufs.get_midi (i));
+               
+               if (source_port) {
+                       buf.copy (source_port->get_midi_buffer(nframes));
+               } else {
+                       buf.silence (nframes);
+               }
+       }
+
+       /* AUDIO */
+
+       n_buffers = bufs.count().n_audio();
+
+       size_t n_ports = io->n_ports().n_audio();
+       float scaling = 1.0f;
+
+       if (n_ports > n_buffers) {
+               scaling = ((float) n_buffers) / n_ports;
+       }
+       
+       for (i = 0; i < n_ports; ++i) {
+               
+               /* if there are more ports than buffers, map them onto buffers
+                * in a round-robin fashion
+                */
+
+               boost::shared_ptr<AudioPort> source_port = io->audio (i);
+               AudioBuffer& buf (bufs.get_audio (i%n_buffers));
+                       
+
+               if (i < n_buffers) {
+                       
+                       /* first time through just copy a channel into
+                          the output buffer.
+                       */
+
+                       buf.read_from (source_port->get_audio_buffer (nframes), nframes);
+
+                       if (scaling != 1.0f) {
+                               buf.apply_gain (scaling, nframes);
+                       }
+                       
+               } else {
+                       
+                       /* on subsequent times around, merge data from
+                        * the port with what is already there 
+                        */
+
+                       if (scaling != 1.0f) {
+                               buf.accumulate_with_gain_from (source_port->get_audio_buffer (nframes), nframes, 0, scaling);
+                       } else {
+                               buf.accumulate_from (source_port->get_audio_buffer (nframes), nframes);
+                       }
+               }
+       }
+
+       /* silence any remaining buffers */
+
+       for (; i < n_buffers; ++i) {
+               AudioBuffer& buf (bufs.get_audio (i));
+               buf.silence (nframes);
+       }
+
+       /* establish the initial setup of the buffer set, reflecting what was
+          copied into it. unless, of course, we are the auditioner, in which
+          case nothing was fed into it from the inputs at all.
+       */
+
+       if (!is_auditioner()) {
+               bufs.set_count (io->n_ports());
+       }
+}