+ Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
+ Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+ ProcessorState pstate (this);
+
+ apply_processor_order (new_order);
+
+ if (configure_processors_unlocked (err, &lm)) {
+ pstate.restore ();
+ return -1;
+ }
+
+ lm.release();
+ lx.release();
+
+ processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+ set_processor_positions ();
+
+ } else {
+ DEBUG_TRACE (DEBUG::Processors, "Queue clickless processor re-order.\n");
+ Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+
+ // _pending_processor_order is protected by _processor_lock
+ _pending_processor_order = new_order;
+ g_atomic_int_set (&_pending_process_reorder, 1);
+ }
+
+ return 0;
+}
+
+bool
+Route::add_remove_sidechain (boost::shared_ptr<Processor> proc, bool add)
+{
+ boost::shared_ptr<PluginInsert> pi;
+ if ((pi = boost::dynamic_pointer_cast<PluginInsert>(proc)) == 0) {
+ return false;
+ }
+
+ if (pi->has_sidechain () == add) {
+ return true; // ?? call failed, but result is as expected.
+ }
+
+ {
+ Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+ ProcessorList::iterator i = find (_processors.begin(), _processors.end(), proc);
+ if (i == _processors.end ()) {
+ return false;
+ }
+ }
+
+ {
+ Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); // take before Writerlock to avoid deadlock
+ Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+ PBD::Unwinder<bool> uw (_in_sidechain_setup, true);
+
+ lx.release (); // IO::add_port() and ~IO takes process lock - XXX check if this is safe
+ if (add) {
+ if (!pi->add_sidechain ()) {
+ return false;
+ }
+ } else {
+ if (!pi->del_sidechain ()) {
+ return false;
+ }
+ }
+
+ lx.acquire ();
+ list<pair<ChanCount, ChanCount> > c = try_configure_processors_unlocked (n_inputs (), 0);
+ lx.release ();
+
+ if (c.empty()) {
+ if (add) {
+ pi->del_sidechain ();
+ } else {
+ pi->add_sidechain ();
+ // TODO restore side-chain's state.
+ }
+ return false;
+ }
+ lx.acquire ();
+ configure_processors_unlocked (0, &lm);
+ }
+
+ if (pi->has_sidechain ()) {
+ pi->sidechain_input ()->changed.connect_same_thread (*this, boost::bind (&Route::sidechain_change_handler, this, _1, _2));
+ }
+
+ processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+ _session.set_dirty ();
+ return true;
+}
+
+bool
+Route::plugin_preset_output (boost::shared_ptr<Processor> proc, ChanCount outs)
+{
+ boost::shared_ptr<PluginInsert> pi;
+ if ((pi = boost::dynamic_pointer_cast<PluginInsert>(proc)) == 0) {
+ return false;
+ }
+
+ {
+ Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+ ProcessorList::iterator i = find (_processors.begin(), _processors.end(), proc);
+ if (i == _processors.end ()) {
+ return false;
+ }
+ }
+
+ {
+ Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
+ Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+
+ const ChanCount& old (pi->preset_out ());
+ if (!pi->set_preset_out (outs)) {
+ return true; // no change, OK
+ }
+
+ list<pair<ChanCount, ChanCount> > c = try_configure_processors_unlocked (n_inputs (), 0);
+ if (c.empty()) {
+ /* not possible */
+ pi->set_preset_out (old);
+ return false;
+ }
+ configure_processors_unlocked (0, &lm);
+ }
+
+ processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+ _session.set_dirty ();
+ return true;
+}
+
+bool
+Route::reset_plugin_insert (boost::shared_ptr<Processor> proc)
+{
+ ChanCount unused;
+ return customize_plugin_insert (proc, 0, unused, unused);
+}
+
+bool
+Route::customize_plugin_insert (boost::shared_ptr<Processor> proc, uint32_t count, ChanCount outs, ChanCount sinks)
+{
+ boost::shared_ptr<PluginInsert> pi;
+ if ((pi = boost::dynamic_pointer_cast<PluginInsert>(proc)) == 0) {
+ return false;
+ }
+
+ {
+ Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+ ProcessorList::iterator i = find (_processors.begin(), _processors.end(), proc);
+ if (i == _processors.end ()) {
+ return false;
+ }
+ }
+
+ {
+ Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
+ Glib::Threads::RWLock::WriterLock lm (_processor_lock);
+
+ bool old_cust = pi->custom_cfg ();
+ uint32_t old_cnt = pi->get_count ();
+ ChanCount old_chan = pi->output_streams ();
+ ChanCount old_sinks = pi->natural_input_streams ();
+
+ if (count == 0) {
+ pi->set_custom_cfg (false);
+ } else {
+ pi->set_custom_cfg (true);
+ pi->set_count (count);
+ pi->set_outputs (outs);
+ pi->set_sinks (sinks);
+ }
+
+ list<pair<ChanCount, ChanCount> > c = try_configure_processors_unlocked (n_inputs (), 0);
+ if (c.empty()) {
+ /* not possible */
+
+ pi->set_count (old_cnt);
+ pi->set_sinks (old_sinks);
+ pi->set_outputs (old_chan);
+ pi->set_custom_cfg (old_cust);
+
+ return false;
+ }
+ configure_processors_unlocked (0, &lm);
+ }
+
+ processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+ _session.set_dirty ();
+ return true;
+}