independent panning for external sends
[ardour.git] / libs / ardour / route.cc
index d48fbeff9686dafc9944aef03132a4ce81659f4a..a036c8feb078a7191d2aaf750fa9b1b789ab5799 100644 (file)
@@ -51,6 +51,7 @@
 #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 +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)
@@ -96,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();
 }
 
@@ -133,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  */
 
@@ -144,6 +152,7 @@ Route::init ()
        */
 
        _meter.reset (new PeakMeter (_session, _name));
+       _meter->set_owner (this);
        _meter->set_display_to_user (false);
        _meter->activate ();
 
@@ -171,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);
        }
 
@@ -262,52 +270,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
-{
-       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)
+Route::order_key () const
 {
-       /* 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 */
@@ -331,18 +306,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 ();
 }
@@ -444,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) {
@@ -540,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
@@ -568,7 +543,7 @@ void
 Route::monitor_run (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
 {
        assert (is_monitor());
-       BufferSet& bufs (_session.get_scratch_buffers (n_process_buffers()));
+       BufferSet& bufs (_session.get_route_buffers (n_process_buffers()));
        passthru (bufs, start_frame, end_frame, nframes, declick);
 }
 
@@ -594,7 +569,7 @@ Route::passthru (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame,
 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);
@@ -967,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);
 
@@ -1007,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 ...
@@ -1094,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 {
 
@@ -1141,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);
 
@@ -1157,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 ...
@@ -1339,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;
@@ -1383,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();
@@ -1423,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);
 
@@ -1463,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;
@@ -1493,6 +1461,9 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                                }
                        }
                }
+               if (need_process_lock) {
+                       lx.release();
+               }
        }
 
        reset_instrument_info ();
@@ -1515,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);
 
@@ -1561,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;
 
@@ -1599,6 +1568,58 @@ 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 ()
 {
@@ -1613,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);
@@ -1651,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)) {
@@ -1701,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) {
@@ -1713,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);
        }
@@ -1767,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);
 
@@ -1828,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;
                }
        }
 
@@ -1885,24 +1919,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);
@@ -1992,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));
@@ -2059,6 +2078,8 @@ Route::set_state (const XMLNode& node, int version)
                _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
@@ -2100,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;
 
@@ -2118,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);
                                }
                        }
 
@@ -2329,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);
                                }
                        }
 
@@ -2535,7 +2548,8 @@ 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" ||
@@ -2551,34 +2565,17 @@ 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;
                                        continue;
                                }
 
-                               if (boost::dynamic_pointer_cast<PluginInsert>(processor)) {     
-                                       cerr << "Working on plugin processor state for " << processor->name() << endl;
-#ifndef NO_PLUGIN_STATE
-                                       cerr << "plugin state allowed\n";
-                                       if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
-                                               /* This processor could not be configured.  Turn it into a UnknownProcessor */
-                                               processor.reset (new UnknownProcessor (_session, **niter));
-                                       }
-#else
-                                       cerr << "plugin state dis-allowed\n";
-                                       /* plugin, with NO_PLUGIN_STATE defined
-                                        * =>::set_state() not allowed. Do not
-                                        * display a message here - things will
-                                        * get too verbose.
-                                        */
-#endif
-                               } else {
-                                       if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
-                                               /* This processor could not be configured.  Turn it into a UnknownProcessor */
-                                               processor.reset (new UnknownProcessor (_session, **niter));
-                                       }
+                               if (processor->set_state (**niter, Stateful::current_state_version) != 0) {
+                                       /* This processor could not be configured.  Turn it into a UnknownProcessor */
+                                       processor.reset (new UnknownProcessor (_session, **niter));
                                }
 
                                /* we have to note the monitor send here, otherwise a new one will be created
@@ -2600,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;
@@ -2717,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) {
@@ -2757,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);
@@ -2957,6 +2957,9 @@ 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 
@@ -3031,7 +3034,7 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
                */
        }
 
-       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+       BufferSet& bufs = _session.get_route_buffers (n_process_buffers());
 
        fill_buffers_with_input (bufs, _input, nframes);
 
@@ -3070,7 +3073,7 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in
 
        _silent = false;
 
-       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+       BufferSet& bufs = _session.get_route_buffers (n_process_buffers());
 
        fill_buffers_with_input (bufs, _input, nframes);
 
@@ -3181,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;
                }
        }
 
@@ -3207,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);
 
        }
 
@@ -3769,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
 {
@@ -3792,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
@@ -3807,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);
                        
@@ -3872,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;
@@ -4148,7 +4158,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 ();
 }
 
@@ -4176,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) {