fix other potential crashes with non-existing plugins and presets caused by indiscrim...
[ardour.git] / libs / ardour / route.cc
index 2112336d8b040541b876cf5cbc4de2b7f5937d84..1a90553be2f80ebd4089597968beb515b595bf6b 100644 (file)
@@ -66,7 +66,6 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-uint32_t Route::order_key_cnt = 0;
 PBD::Signal1<void,RouteSortOrderKey> Route::SyncOrderKeys;
 PBD::Signal0<void> Route::RemoteControlIDChange;
 
@@ -169,7 +168,7 @@ Route::init ()
 
        {
                /* run a configure so that the invisible processors get set up */
-               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                configure_processors (0);
        }
 
@@ -189,14 +188,12 @@ Route::~Route ()
           be half-destroyed by now
        */
 
-       Glib::RWLock::WriterLock lm (_processor_lock);
+       Glib::Threads::RWLock::WriterLock lm (_processor_lock);
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->drop_references ();
        }
 
        _processors.clear ();
-
-       delete _remote_control_id;
 }
 
 void
@@ -205,12 +202,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)
@@ -224,6 +222,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() && 
@@ -232,11 +234,9 @@ Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
        }
 
        if (id != remote_control_id()) {
-               if (!_remote_control_id) {
-                       _remote_control_id = new uint32_t;
-               }
-               *_remote_control_id = id;
+               _remote_control_id = id;
                RemoteControlIDChanged ();
+
                if (notify_class_listeners) {
                        RemoteControlIDChange ();
                }
@@ -246,16 +246,6 @@ Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
 uint32_t
 Route::remote_control_id() const
 {
-       switch (Config->get_remote_model()) {
-       case UserOrdered:
-               if (_remote_control_id) {
-                       return *_remote_control_id;
-               }
-               break;
-       default:
-               break;
-       }
-
        if (is_master()) {
                return MasterBusRemoteControlID;
        } 
@@ -264,16 +254,7 @@ Route::remote_control_id() const
                return MonitorBusRemoteControlID;
        }
 
-       /* order keys are zero-based, remote control ID's are one-based
-        */
-
-       switch (Config->get_remote_model()) {
-       case EditorOrdered:
-               return order_key (EditorSort) + 1;
-       case MixerOrdered:
-       default:
-               return order_key (MixerSort) + 1;
-       }
+       return _remote_control_id;
 }
 
 bool
@@ -297,6 +278,10 @@ Route::order_key (RouteSortOrderKey key) const
 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()) {
@@ -305,27 +290,57 @@ Route::sync_order_keys (RouteSortOrderKey base)
 
        for (OrderKeys::iterator k = order_keys.begin(); k != order_keys.end(); ++k) {
 
-               if (k->first == MixerSort && (is_master() || is_monitor())) {
-                       /* don't sync the mixer sort keys for master/monitor,
-                        * since they are not part of the normal ordering.
-                        */
-                        
-                       continue;
-               }
-               
                if (k->first != base) {
+                       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 set key for %2 to %3 from %4\n",
+                                                                      name(),
+                                                                      enum_2_string (k->first),
+                                                                      i->second,
+                                                                      enum_2_string (base)));
+                                                                      
                        k->second = i->second;
                }
        }
 }
 
+void
+Route::set_remote_control_id_from_order_key (RouteSortOrderKey /*key*/, uint32_t rid)
+{
+       if (is_master() || is_monitor() || is_hidden()) {
+               /* hard-coded remote IDs, or no remote ID */
+               return;
+       }
+
+       if (_remote_control_id != rid) {
+               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1: set edit-based RID to %2\n", name(), rid));
+               _remote_control_id = rid;
+               RemoteControlIDChanged (); /* EMIT SIGNAL (per-route) */
+       }
+
+       /* don't emit the class-level RID signal RemoteControlIDChange here,
+          leave that to the entity that changed the order key, so that we
+          don't get lots of emissions for no good reasons (e.g. when changing
+          all route order keys).
+
+          See Session::sync_remote_id_from_order_keys() for the (primary|only)
+          spot where that is emitted.
+       */
+}
+
 void
 Route::set_order_key (RouteSortOrderKey key, uint32_t n)
 {
-       if (order_keys.find (key) == order_keys.end() || order_keys[key] != n) {
-               order_keys[key] = n;
-               _session.set_dirty ();
+       OrderKeys::iterator i = order_keys.find (key);
+
+       if (i != order_keys.end() && i->second == n) {
+               return;
        }
+
+       order_keys[key] = n;
+
+       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 order key %2 set to %3\n",
+                                                      name(), enum_2_string (key), order_key (key)));
+
+       _session.set_dirty ();
 }
 
 string
@@ -651,6 +666,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;
        }
 
@@ -659,6 +675,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 ();
@@ -670,6 +689,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;
 }
 
@@ -677,9 +697,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) {
@@ -733,9 +757,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;
@@ -875,7 +903,7 @@ dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& p
 boost::shared_ptr<Processor>
 Route::before_processor_for_placement (Placement p)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        ProcessorList::iterator loc;
        
@@ -900,7 +928,7 @@ Route::before_processor_for_index (int index)
                return boost::shared_ptr<Processor> ();
        }
 
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        
        ProcessorList::iterator i = _processors.begin ();
        int j = 0;
@@ -953,7 +981,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
        }
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                boost::shared_ptr<PluginInsert> pi;
@@ -993,7 +1021,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
                // configure redirect ports properly, etc.
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
@@ -1011,7 +1039,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
 
                }
 
-               if (activation_allowed) {
+               if (activation_allowed && !_session.get_disable_all_loaded_plugins()) {
                        processor->activate ();
                }
 
@@ -1060,7 +1088,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") {
 
@@ -1122,7 +1150,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
        }
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) {
@@ -1144,7 +1172,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                        }
 
                        {
-                               Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                               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 ...
@@ -1195,7 +1223,7 @@ Route::placement_range(Placement p, ProcessorList::iterator& start, ProcessorLis
 void
 Route::disable_processors (Placement p)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        ProcessorList::iterator start, end;
        placement_range(p, start, end);
@@ -1212,7 +1240,7 @@ Route::disable_processors (Placement p)
 void
 Route::disable_processors ()
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->deactivate ();
@@ -1227,7 +1255,7 @@ Route::disable_processors ()
 void
 Route::disable_plugins (Placement p)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        ProcessorList::iterator start, end;
        placement_range(p, start, end);
@@ -1246,7 +1274,7 @@ Route::disable_plugins (Placement p)
 void
 Route::disable_plugins ()
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
@@ -1261,7 +1289,7 @@ Route::disable_plugins ()
 void
 Route::ab_plugins (bool forward)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        if (forward) {
 
@@ -1320,7 +1348,7 @@ Route::clear_processors (Placement p)
        }
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorList new_list;
                ProcessorStreams err;
                bool seen_amp = false;
@@ -1366,7 +1394,7 @@ Route::clear_processors (Placement p)
                _processors = new_list;
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                        configure_processors_unlocked (&err); // this can't fail
                }
        }
@@ -1404,7 +1432,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
        processor_max_streams.reset();
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                ProcessorList::iterator i;
@@ -1445,7 +1473,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                } 
 
                if (need_process_lock) {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
@@ -1496,7 +1524,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
        processor_max_streams.reset();
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                ProcessorList::iterator i;
@@ -1543,7 +1571,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
                _output->set_user_latency (0);
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
@@ -1584,7 +1612,9 @@ 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 */
@@ -1594,7 +1624,7 @@ Route::configure_processors (ProcessorStreams* err)
        assert (!AudioEngine::instance()->process_lock().trylock());
 
        if (!_in_configure_processors) {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                return configure_processors_unlocked (err);
        }
 
@@ -1610,7 +1640,7 @@ Route::input_streams () const
 list<pair<ChanCount, ChanCount> >
 Route::try_configure_processors (ChanCount in, ProcessorStreams* err)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        return try_configure_processors_unlocked (in, err);
 }
@@ -1715,7 +1745,7 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
 void
 Route::all_visible_processors_active (bool state)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        if (_processors.empty()) {
                return;
@@ -1746,7 +1776,7 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
        */
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                ProcessorList::iterator oiter;
@@ -1808,7 +1838,7 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
                maybe_note_meter_position ();
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
@@ -1894,12 +1924,10 @@ Route::state(bool full_state)
        node->add_child_nocopy (_mute_control->get_state ());
        node->add_child_nocopy (_mute_master->get_state ());
 
-       if (_remote_control_id) {
-               XMLNode* remote_control_node = new XMLNode (X_("RemoteControl"));
-               snprintf (buf, sizeof (buf), "%d", *_remote_control_id);
-               remote_control_node->add_property (X_("id"), buf);
-               node->add_child_nocopy (*remote_control_node);
-       }
+       XMLNode* remote_control_node = new XMLNode (X_("RemoteControl"));
+       snprintf (buf, sizeof (buf), "%d", _remote_control_id);
+       remote_control_node->add_property (X_("id"), buf);
+       node->add_child_nocopy (*remote_control_node);
 
        if (_comment.length()) {
                XMLNode *cmt = node->add_child ("Comment");
@@ -1924,7 +1952,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;
                                }
                        }
@@ -2017,7 +2045,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);
@@ -2037,6 +2064,9 @@ Route::set_state (const XMLNode& node, int version)
 
        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()));
        }
@@ -2117,7 +2147,7 @@ Route::set_state (const XMLNode& node, int version)
 
        if ((prop = node.property (X_("processor-after-last-custom-meter"))) != 0) {
                PBD::ID id (prop->value ());
-               Glib::RWLock::ReaderLock lm (_processor_lock);
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
                ProcessorList::const_iterator i = _processors.begin ();
                while (i != _processors.end() && (*i)->id() != id) {
                        ++i;
@@ -2154,7 +2184,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")) {
@@ -2192,6 +2222,10 @@ Route::set_state_2X (const XMLNode& node, int version)
                _flags = Flag (0);
        }
 
+       if (is_master() || is_monitor() || is_hidden()) {
+               _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 ())) {
@@ -2305,7 +2339,7 @@ Route::set_state_2X (const XMLNode& node, int version)
                                        } else if (keyname == "editor") {
                                                sk = EditorSort;
                                        } else {
-                                               RouteSortOrderKey sk = (RouteSortOrderKey) string_2_enum (remaining.substr (0, equal), sk);
+                                               sk = (RouteSortOrderKey) string_2_enum (remaining.substr (0, equal), sk);
                                        }
 
                                        set_order_key (sk, n);
@@ -2415,7 +2449,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);
                        }
 
                }
@@ -2508,7 +2542,7 @@ Route::set_processor_state (const XMLNode& node)
 
                                } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                           prop->value() == "lv2" ||
-                                          prop->value() == "vst" ||
+                                          prop->value() == "windows-vst" ||
                                           prop->value() == "lxvst" ||
                                           prop->value() == "audiounit") {
 
@@ -2551,11 +2585,11 @@ Route::set_processor_state (const XMLNode& node)
        }
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                _processors = new_order;
 
                if (must_configure) {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                        configure_processors_unlocked (0);
                }
 
@@ -2589,7 +2623,7 @@ Route::curve_reallocate ()
 void
 Route::silence (framecnt_t nframes)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
        if (!lm.locked()) {
                return;
        }
@@ -2635,7 +2669,7 @@ Route::add_internal_return ()
 void
 Route::add_send_to_internal_return (InternalSend* send)
 {
-       Glib::RWLock::ReaderLock rm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock rm (_processor_lock);
 
        for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
                boost::shared_ptr<InternalReturn> d = boost::dynamic_pointer_cast<InternalReturn>(*x);
@@ -2649,7 +2683,7 @@ Route::add_send_to_internal_return (InternalSend* send)
 void
 Route::remove_send_from_internal_return (InternalSend* send)
 {
-       Glib::RWLock::ReaderLock rm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock rm (_processor_lock);
 
        for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
                boost::shared_ptr<InternalReturn> d = boost::dynamic_pointer_cast<InternalReturn>(*x);
@@ -2689,7 +2723,7 @@ Route::add_aux_send (boost::shared_ptr<Route> route, boost::shared_ptr<Processor
        assert (route != _session.monitor_out ());
 
        {
-               Glib::RWLock::ReaderLock rm (_processor_lock);
+               Glib::Threads::RWLock::ReaderLock rm (_processor_lock);
 
                for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ++x) {
 
@@ -2707,7 +2741,7 @@ Route::add_aux_send (boost::shared_ptr<Route> route, boost::shared_ptr<Processor
                boost::shared_ptr<InternalSend> listener;
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                        listener.reset (new InternalSend (_session, _pannable, _mute_master, route, Delivery::Aux));
                }
 
@@ -2727,7 +2761,7 @@ Route::remove_aux_or_listen (boost::shared_ptr<Route> route)
        ProcessorList::iterator tmp;
 
        {
-               Glib::RWLock::ReaderLock rl(_processor_lock);
+               Glib::Threads::RWLock::ReaderLock rl(_processor_lock);
 
                /* have to do this early because otherwise processor reconfig
                 * will put _monitor_send back in the list
@@ -2858,16 +2892,12 @@ 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();
 
        {
-               Glib::RWLock::ReaderLock lm (_processor_lock);
-
-               if (!did_locate) {
-                       automation_snapshot (now, true);
-               }
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
                Automatable::transport_stopped (now);
 
@@ -2954,7 +2984,7 @@ Route::pans_required () const
 int
 Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
        if (!lm.locked()) {
                return 0;
        }
@@ -2991,13 +3021,11 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
 int
 Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& /* need_butler */)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
        if (!lm.locked()) {
                return 0;
        }
 
-       automation_snapshot (_session.transport_frame(), false);
-
        if (n_outputs().n_total() == 0) {
                return 0;
        }
@@ -3034,7 +3062,7 @@ Route::flush_processors ()
           this is called from the RT audio thread.
        */
 
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->flush ();
@@ -3044,8 +3072,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;
        }
@@ -3053,7 +3079,7 @@ Route::set_meter_point (MeterPoint p, bool force)
        bool meter_was_visible_to_user = _meter->display_to_user ();
 
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
 
                maybe_note_meter_position ();
 
@@ -3120,11 +3146,11 @@ void
 Route::listen_position_changed ()
 {
        {
-               Glib::RWLock::WriterLock lm (_processor_lock);
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
                ProcessorState pstate (this);
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
                        if (configure_processors_unlocked (0)) {
                                pstate.restore ();
@@ -3147,7 +3173,7 @@ Route::add_export_point()
                _capturing_processor->activate ();
 
                {
-                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
                        configure_processors (0);
                }
 
@@ -3209,18 +3235,6 @@ Route::set_latency_compensation (framecnt_t longest_session_latency)
        }
 }
 
-void
-Route::automation_snapshot (framepos_t now, bool force)
-{
-       if (_pannable) {
-               _pannable->automation_snapshot (now, force);
-       }
-
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               (*i)->automation_snapshot (now, force);
-       }
-}
-
 Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr<Route> r)
        : AutomationControl (r->session(), Evoral::Parameter (SoloAutomation),
                             boost::shared_ptr<AutomationList>(), name)
@@ -3373,7 +3387,7 @@ Route::shift (framepos_t pos, framecnt_t frames)
 
        /* redirect automation */
        {
-               Glib::RWLock::ReaderLock lm (_processor_lock);
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
                for (ProcessorList::iterator i = _processors.begin (); i != _processors.end (); ++i) {
 
                        set<Evoral::Parameter> parameters = (*i)->what_can_be_automated();
@@ -3473,7 +3487,7 @@ Route::set_name_in_state (XMLNode& node, string const & name)
 boost::shared_ptr<Send>
 Route::internal_send_for (boost::shared_ptr<const Route> target) const
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
                boost::shared_ptr<InternalSend> send;
@@ -3551,13 +3565,14 @@ Route::set_active (bool yn, void* src)
                _input->set_active (yn);
                _output->set_active (yn);
                active_changed (); // EMIT SIGNAL
+               _session.set_dirty ();
        }
 }
 
 void
 Route::meter ()
 {
-       Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
+       Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK);
 
        assert (_meter);
 
@@ -3612,7 +3627,7 @@ Route::get_control (const Evoral::Parameter& param)
 
                /* maybe one of our processors does or ... */
 
-               Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
+               Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK);
                for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                        if ((c = boost::dynamic_pointer_cast<AutomationControl>((*i)->control (param))) != 0) {
                                break;
@@ -3634,7 +3649,7 @@ Route::get_control (const Evoral::Parameter& param)
 boost::shared_ptr<Processor>
 Route::nth_plugin (uint32_t n)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        ProcessorList::iterator i;
 
        for (i = _processors.begin(); i != _processors.end(); ++i) {
@@ -3651,7 +3666,7 @@ Route::nth_plugin (uint32_t n)
 boost::shared_ptr<Processor>
 Route::nth_send (uint32_t n)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        ProcessorList::iterator i;
 
        for (i = _processors.begin(); i != _processors.end(); ++i) {
@@ -3668,7 +3683,7 @@ Route::nth_send (uint32_t n)
 bool
 Route::has_io_processor_named (const string& name)
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        ProcessorList::iterator i;
 
        for (i = _processors.begin(); i != _processors.end(); ++i) {
@@ -3692,7 +3707,7 @@ Route::mute_points () const
 void
 Route::set_processor_positions ()
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
 
        bool had_amp = false;
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
@@ -3724,7 +3739,7 @@ Route::unknown_processors () const
 {
        list<string> p;
 
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<UnknownProcessor const> (*i)) {
                        p.push_back ((*i)->name ());
@@ -3849,7 +3864,7 @@ void
 Route::setup_invisible_processors ()
 {
 #ifndef NDEBUG
-       Glib::RWLock::WriterLock lm (_processor_lock, Glib::TRY_LOCK);
+       Glib::Threads::RWLock::WriterLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
        assert (!lm.locked ());
 #endif
 
@@ -4005,8 +4020,8 @@ Route::setup_invisible_processors ()
 void
 Route::unpan ()
 {
-       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-       Glib::RWLock::ReaderLock lp (_processor_lock);
+       Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+       Glib::Threads::RWLock::ReaderLock lp (_processor_lock);
 
        _pannable.reset ();
 
@@ -4050,7 +4065,7 @@ Route::maybe_note_meter_position ()
 boost::shared_ptr<Processor>
 Route::processor_by_id (PBD::ID id) const
 {
-       Glib::RWLock::ReaderLock lm (_processor_lock);
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if ((*i)->id() == id) {
                        return *i;
@@ -4098,7 +4113,13 @@ Route::has_external_redirects () const
 boost::shared_ptr<Processor>
 Route::the_instrument () const
 {
-       Glib::RWLock::WriterLock lm (_processor_lock);
+       Glib::Threads::RWLock::WriterLock 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 &&
@@ -4109,3 +4130,21 @@ Route::the_instrument () const
        }
        return boost::shared_ptr<Processor>();
 }
+
+
+
+void
+Route::non_realtime_locate (framepos_t pos)
+{
+       if (_pannable) {
+               _pannable->transport_located (pos);
+       }
+
+       {
+               Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+               
+               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+                       (*i)->transport_located (pos);
+               }
+       }
+}