X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Froute.cc;h=fa4b3ce51d08a72f280bf2acad00e297d96b99bd;hb=4e4c75a34a694a91bac75e763f3f83c512d11b36;hp=38bed70dfa7bf7777d974a20ac11c736f3e8629c;hpb=ef92349187b61349d2d5182f49f700183901f59e;p=ardour.git diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 38bed70dfa..fa4b3ce51d 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -22,10 +22,10 @@ #include #include -#include #include "pbd/xml++.h" #include "pbd/enumwriter.h" #include "pbd/memento_command.h" +#include "pbd/stacktrace.h" #include "evoral/Curve.hpp" @@ -36,6 +36,7 @@ #include "ardour/buffer_set.h" #include "ardour/configuration.h" #include "ardour/cycle_timer.h" +#include "ardour/debug.h" #include "ardour/delivery.h" #include "ardour/dB.h" #include "ardour/internal_send.h" @@ -63,13 +64,15 @@ using namespace ARDOUR; using namespace PBD; uint32_t Route::order_key_cnt = 0; -sigc::signal Route::SyncOrderKeys; +PBD::Signal1 Route::SyncOrderKeys; +PBD::Signal0 Route::RemoteControlIDChange; Route::Route (Session& sess, string name, Flag flg, DataType default_type) : SessionObject (sess, name) , AutomatableControls (sess) , _flags (flg) , _solo_control (new SoloControllable (X_("solo"), *this)) + , _mute_control (new MuteControllable (X_("mute"), *this)) , _mute_master (new MuteMaster (sess, name)) , _default_type (default_type) @@ -79,7 +82,8 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) /* add standard processors other than amp (added by ::init()) */ _meter.reset (new PeakMeter (_session)); - add_processor (_meter, PreFader); + _meter->set_display_to_user (false); + add_processor (_meter, PostFader); if (_flags & ControlOut) { /* where we listen to tracks */ @@ -92,13 +96,14 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) /* now that we have _meter, its safe to connect to this */ - _meter_connection = Metering::connect (mem_fun (*this, &Route::meter)); + Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this))); } Route::Route (Session& sess, const XMLNode& node, DataType default_type) : SessionObject (sess, "toBeReset") , AutomatableControls (sess) , _solo_control (new SoloControllable (X_("solo"), *this)) + , _mute_control (new MuteControllable (X_("mute"), *this)) , _mute_master (new MuteMaster (sess, "toBeReset")) , _default_type (default_type) { @@ -108,17 +113,18 @@ Route::Route (Session& sess, const XMLNode& node, DataType default_type) /* now that we have _meter, its safe to connect to this */ - _meter_connection = Metering::connect (mem_fun (*this, &Route::meter)); + Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this))); } void Route::init () { - _solo_level = 0; - _solo_isolated = false; + _self_solo = false; + _soloed_by_others = 0; + _solo_isolated = 0; + _solo_safe = false; _active = true; processor_max_streams.reset(); - _solo_safe = false; _recordable = true; order_keys[N_("signal")] = order_key_cnt++; _silent = false; @@ -132,23 +138,24 @@ Route::init () _in_configure_processors = false; _mute_points = MuteMaster::AllPoints; - _route_group = 0; - _phase_invert = 0; _denormal_protection = false; /* add standard controls */ + _solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle)); + _mute_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle)); + add_control (_solo_control); - add_control (_mute_master); + add_control (_mute_control); /* input and output objects */ _input.reset (new IO (_session, _name, IO::Input, _default_type)); _output.reset (new IO (_session, _name, IO::Output, _default_type)); - _input->changed.connect (mem_fun (this, &Route::input_change_handler)); - _output->changed.connect (mem_fun (this, &Route::output_change_handler)); + _input->changed.connect_same_thread (*this, boost::bind (&Route::input_change_handler, this, _1, _2)); + _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2)); /* add amp processor */ @@ -158,18 +165,34 @@ Route::init () Route::~Route () { - Metering::disconnect (_meter_connection); + DEBUG_TRACE (DEBUG::Destruction, string_compose ("route %1 destructor\n", _name)); + + /* do this early so that we don't get incoming signals as we are going through destruction + */ - clear_processors (PreFader); - clear_processors (PostFader); + drop_connections (); + + /* don't use clear_processors here, as it depends on the session which may + be half-destroyed by now + */ + + Glib::RWLock::WriterLock lm (_processor_lock); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + (*i)->drop_references (); + } + + _processors.clear (); } void -Route::set_remote_control_id (uint32_t id) +Route::set_remote_control_id (uint32_t id, bool notify_class_listeners) { if (id != _remote_control_id) { _remote_control_id = id; RemoteControlIDChanged (); + if (notify_class_listeners) { + RemoteControlIDChange (); + } } } @@ -420,18 +443,16 @@ Route::process_output_buffers (BufferSet& bufs, if (rm.locked()) { for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + if (bufs.count() != (*i)->input_streams()) { cerr << _name << " bufs = " << bufs.count() << " input for " << (*i)->name() << " = " << (*i)->input_streams() << endl; } assert (bufs.count() == (*i)->input_streams()); - (*i)->run (bufs, start_frame, end_frame, nframes); - bufs.set_count (ChanCount::max(bufs.count(), (*i)->output_streams())); - } - if (!_processors.empty()) { - bufs.set_count (ChanCount::max (bufs.count(), _processors.back()->output_streams())); + (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back()); + bufs.set_count ((*i)->output_streams()); } } } @@ -518,10 +539,25 @@ Route::listening () const } } +void +Route::set_solo_safe (bool yn, void *src) +{ + if (_solo_safe != yn) { + _solo_safe = yn; + solo_safe_changed (src); + } +} + +bool +Route::solo_safe() const +{ + return _solo_safe; +} + void Route::set_solo (bool yn, void *src) { - if (_solo_safe || _solo_isolated) { + if (_solo_safe) { return; } @@ -530,50 +566,95 @@ Route::set_solo (bool yn, void *src) return; } - if (soloed() != yn) { - mod_solo_level (yn ? 1 : -1); + if (self_soloed() != yn) { + set_self_solo (yn); + set_delivery_solo (); solo_changed (src); /* EMIT SIGNAL */ _solo_control->Changed (); /* EMIT SIGNAL */ } } void -Route::mod_solo_level (int32_t delta) +Route::set_self_solo (bool yn) +{ + _self_solo = yn; +} + +void +Route::mod_solo_by_others (int32_t delta) { if (delta < 0) { - if (_solo_level >= (uint32_t) delta) { - _solo_level += delta; + if (_soloed_by_others >= (uint32_t) delta) { + _soloed_by_others += delta; } else { - _solo_level = 0; + _soloed_by_others = 0; } } else { - _solo_level += delta; + _soloed_by_others += delta; } - /* tell main outs what the solo situation is - */ + set_delivery_solo (); +} - _main_outs->set_solo_level (_solo_level); - _main_outs->set_solo_isolated (_solo_isolated); +void +Route::set_delivery_solo () +{ + /* tell all delivery processors what the solo situation is, so that they keep + delivering even though Session::soloing() is true and they were not + explicitly soloed. + */ + + Glib::RWLock::ReaderLock rm (_processor_lock); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + boost::shared_ptr d; + + if ((d = boost::dynamic_pointer_cast (*i)) != 0) { + d->set_solo_level (soloed ()); + d->set_solo_isolated (solo_isolated()); + } + } } void Route::set_solo_isolated (bool yn, void *src) { + if (is_master() || is_control() || is_hidden()) { + return; + } + if (_route_group && src != _route_group && _route_group->active_property (RouteGroup::Solo)) { _route_group->apply (&Route::set_solo_isolated, yn, _route_group); return; } + + /* forward propagate solo-isolate status to everything fed by this route, but not those via sends only */ - if (yn != _solo_isolated) { - _solo_isolated = yn; + boost::shared_ptr routes = _session.get_routes (); + for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { + bool sends_only; + bool does_feed = feeds (*i, &sends_only); + + if (does_feed && !sends_only) { + (*i)->set_solo_isolated (yn, (*i)->route_group()); + } + } - /* tell main outs what the solo situation is - */ + bool changed = false; - _main_outs->set_solo_level (_solo_level); - _main_outs->set_solo_isolated (_solo_isolated); + if (yn) { + if (_solo_isolated == 0) { + changed = true; + } + _solo_isolated++; + } else { + changed = (_solo_isolated == 1); + if (_solo_isolated > 0) { + _solo_isolated--; + } + } + if (changed) { + set_delivery_solo (); solo_isolated_changed (src); } } @@ -581,7 +662,7 @@ Route::set_solo_isolated (bool yn, void *src) bool Route::solo_isolated () const { - return _solo_isolated; + return _solo_isolated > 0; } void @@ -723,12 +804,13 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite // XXX: do we want to emit the signal here ? change call order. processor->activate (); } - processor->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false)); + + processor->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false)); _output->set_user_latency (0); } - processors_changed (); /* EMIT SIGNAL */ + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ return 0; } @@ -773,6 +855,7 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter } _meter.reset (new PeakMeter (_session, node)); + _meter->set_display_to_user (_meter_point == MeterCustom); processor = _meter; } else if (prop->value() == "amp") { @@ -821,12 +904,12 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter return false; } - if (iter == _processors.end() && processor->visible() && !_processors.empty()) { + if (iter == _processors.end() && processor->display_to_user() && !_processors.empty()) { /* check for invisible processors stacked at the end and leave them there */ ProcessorList::iterator p; p = _processors.end(); --p; - while (!(*p)->visible() && p != _processors.begin()) { + while (!(*p)->display_to_user() && p != _processors.begin()) { --p; } ++p; @@ -884,12 +967,12 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorLis return false; } - if (iter == _processors.end() && processor->visible() && !_processors.empty()) { + if (iter == _processors.end() && processor->display_to_user() && !_processors.empty()) { /* check for invisible processors stacked at the end and leave them there */ ProcessorList::iterator p; p = _processors.end(); --p; - while (!(*p)->visible() && p != _processors.begin()) { + while (!(*p)->display_to_user() && p != _processors.begin()) { --p; } ++p; @@ -940,8 +1023,6 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter { Glib::RWLock::WriterLock lm (_processor_lock); - ProcessorList::iterator existing_end = _processors.end(); - --existing_end; ChanCount potential_max_streams = ChanCount::max (_input->n_ports(), _output->n_ports()); @@ -967,22 +1048,25 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter } } - _processors.insert (iter, *i); + ProcessorList::iterator inserted = _processors.insert (iter, *i); + + if ((*i)->active()) { + (*i)->activate (); + } if (configure_processors_unlocked (err)) { - ++existing_end; - _processors.erase (existing_end, _processors.end()); + _processors.erase (inserted); configure_processors_unlocked (0); // it worked before we tried to add it ... return -1; } - (*i)->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false)); + (*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false)); } _output->set_user_latency (0); } - processors_changed (); /* EMIT SIGNAL */ + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ return 0; } @@ -1182,7 +1266,7 @@ Route::clear_processors (Placement p) processor_max_streams.reset(); _have_internal_generator = false; - processors_changed (); /* EMIT SIGNAL */ + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ if (!already_deleting) { _session.clear_deletion_in_progress(); @@ -1273,7 +1357,7 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream } processor->drop_references (); - processors_changed (); /* EMIT SIGNAL */ + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ return 0; } @@ -1365,7 +1449,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* (*i)->drop_references (); } - processors_changed (); /* EMIT SIGNAL */ + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ return 0; } @@ -1399,9 +1483,19 @@ Route::configure_processors_unlocked (ProcessorStreams* err) list< pair > configuration; uint32_t index = 0; + DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configure processors\n", _name)); +#ifndef NDEBUG + DEBUG_TRACE (DEBUG::Processors, "{\n"); + for (list >::const_iterator p = _processors.begin(); p != _processors.end(); ++p) { + DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1 ID = %2\n", (*p)->name(), (*p)->id())); + } + DEBUG_TRACE (DEBUG::Processors, "}\n"); +#endif + for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++index) { if ((*p)->can_support_io_configuration(in, out)) { + DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1in = %2 out = %3\n",(*p)->name(), in, out)); configuration.push_back(make_pair(in, out)); in = out; } else { @@ -1414,15 +1508,6 @@ Route::configure_processors_unlocked (ProcessorStreams* err) } } - /* Take the process lock so that if we add a processor which increases the required - number of scratch buffers, we create those scratch buffers before the process - thread has a chance to ask for them. - XXX: in an ideal world we'd perhaps use some RCU magic to avoid having to take - the lock here. - */ - - Glib::Mutex::Lock pl (_session.engine().process_lock ()); - // We can, so configure everything list< pair >::iterator c = configuration.begin(); for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++c) { @@ -1432,6 +1517,10 @@ Route::configure_processors_unlocked (ProcessorStreams* err) out = c->second; } + if (_meter) { + _meter->reset_max_channels (processor_max_streams); + } + /* make sure we have sufficient scratch buffers to cope with the new processor configuration */ _session.ensure_buffers (n_process_buffers ()); @@ -1524,7 +1613,7 @@ int Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err) { /* "new_order" is an ordered list of processors to be positioned according to "placement". - NOTE: all processors in "new_order" MUST be marked as visible. There maybe additional + NOTE: all processors in "new_order" MUST be marked as display_to_user(). There maybe additional processors in the current actual processor list that are hidden. Any visible processors in the current list but not in "new_order" will be assumed to be deleted. */ @@ -1563,7 +1652,7 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err } else { - if (!(*oiter)->visible()) { + if (!(*oiter)->display_to_user()) { as_it_will_be.push_back (*oiter); @@ -1595,7 +1684,7 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err } } - processors_changed (); /* EMIT SIGNAL */ + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ return 0; } @@ -1655,6 +1744,9 @@ Route::state(bool full_state) order_string += ':'; } node->add_property ("order-keys", order_string); + node->add_property ("self-solo", (_self_solo ? "yes" : "no")); + snprintf (buf, sizeof (buf), "%d", _soloed_by_others); + node->add_property ("soloed-by-others", buf); node->add_child_nocopy (_input->state (full_state)); node->add_child_nocopy (_output->state (full_state)); @@ -1748,9 +1840,13 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) set_processor_state (processor_state); - if ((prop = node.property ("solo_level")) != 0) { - _solo_level = 0; // needed for mod_solo_level() to work - mod_solo_level (atoi (prop->value())); + if ((prop = node.property ("self-solo")) != 0) { + set_self_solo (string_is_affirmative (prop->value())); + } + + if ((prop = node.property ("soloed-by-others")) != 0) { + _soloed_by_others = 0; // needed for mod_solo_by_others () to work + mod_solo_by_others (atoi (prop->value())); } if ((prop = node.property ("solo-isolated")) != 0) { @@ -1771,24 +1867,10 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) set_active (yn); } - if ((prop = node.property (X_("soloed"))) != 0) { - bool yn = string_is_affirmative (prop->value()); - - /* XXX force reset of solo status */ - - set_solo (yn, this); - } - if ((prop = node.property (X_("meter-point"))) != 0) { _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point)); - } - - if ((prop = node.property (X_("route-group"))) != 0) { - RouteGroup* route_group = _session.route_group_by_name(prop->value()); - if (route_group == 0) { - error << string_compose(_("Route %1: unknown route group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg; - } else { - set_route_group (route_group, this); + if (_meter) { + _meter->set_display_to_user (_meter_point == MeterCustom); } } @@ -1958,26 +2040,9 @@ Route::_set_state_2X (const XMLNode& node, int version) _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point)); } - /* XXX: if the route was in both a mix group and an edit group, it'll end up - just in the edit group. */ - - if ((prop = node.property (X_("mix-group"))) != 0) { - RouteGroup* route_group = _session.route_group_by_name(prop->value()); - if (route_group == 0) { - error << string_compose(_("Route %1: unknown route group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg; - } else { - set_route_group (route_group, this); - } - } - - if ((prop = node.property (X_("edit-group"))) != 0) { - RouteGroup* route_group = _session.route_group_by_name(prop->value()); - if (route_group == 0) { - error << string_compose(_("Route %1: unknown route group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg; - } else { - set_route_group (route_group, this); - } - } + /* do not carry over edit/mix groups from 2.X because (a) its hard (b) they + don't mean the same thing. + */ if ((prop = node.property (X_("order-keys"))) != 0) { @@ -2182,7 +2247,7 @@ Route::set_processor_state (const XMLNode& node) the XML state represents a working signal route. */ - processors_changed (); + processors_changed (RouteProcessorChange ()); } void @@ -2345,33 +2410,6 @@ Route::drop_listen (boost::shared_ptr route) } } -void -Route::set_route_group (RouteGroup *rg, void *src) -{ - if (rg == _route_group) { - return; - } - - if (_route_group) { - _route_group->remove (this); - } - - if ((_route_group = rg) != 0) { - _route_group->add (this); - } - - _session.set_dirty (); - route_group_changed (src); /* EMIT SIGNAL */ -} - -void -Route::drop_route_group (void *src) -{ - _route_group = 0; - _session.set_dirty (); - route_group_changed (src); /* EMIT SIGNAL */ -} - void Route::set_comment (string cmt, void *src) { @@ -2383,11 +2421,10 @@ Route::set_comment (string cmt, void *src) bool Route::feeds (boost::shared_ptr other, bool* only_send) { - // cerr << _name << endl; + DEBUG_TRACE (DEBUG::Graph, string_compose ("Feeds? %1\n", _name)); if (_output->connected_to (other->input())) { - // cerr << "\tdirect FEEDS " << other->name() << endl; - + DEBUG_TRACE (DEBUG::Graph, string_compose ("\tdirect FEEDS %2\n", other->name())); if (only_send) { *only_send = false; } @@ -2402,18 +2439,21 @@ Route::feeds (boost::shared_ptr other, bool* only_send) if ((iop = boost::dynamic_pointer_cast(*r)) != 0) { if (iop->feeds (other)) { - // cerr << "\tIOP " << iop->name() << " feeds " << other->name() << endl; + DEBUG_TRACE (DEBUG::Graph, string_compose ("\tIOP %1 does feed %2\n", iop->name(), other->name())); if (only_send) { *only_send = true; } return true; } else { - // cerr << "\tIOP " << iop->name() << " does NOT feeds " << other->name() << endl; + DEBUG_TRACE (DEBUG::Graph, string_compose ("\tIOP %1 does NOT feed %2\n", iop->name(), other->name())); } + } else { + DEBUG_TRACE (DEBUG::Graph, string_compose ("\tPROC %1 is not an IOP\n", (*r)->name())); } + } - // cerr << "\tdoes NOT FEED " << other->name() << endl; + DEBUG_TRACE (DEBUG::Graph, string_compose ("\tdoes NOT feed %1\n", other->name())); return false; } @@ -2616,30 +2656,73 @@ Route::flush_processors () void Route::set_meter_point (MeterPoint p, void *src) { - if (_meter_point != p) { - _meter_point = p; + /* CAN BE CALLED FROM PROCESS CONTEXT */ - // Move meter in the processors list - ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), _meter); - _processors.erase(loc); - switch (p) { - case MeterInput: - loc = _processors.begin(); - break; - case MeterPreFader: - loc = find(_processors.begin(), _processors.end(), _amp); - break; - case MeterPostFader: - loc = _processors.end(); - break; - } - _processors.insert(loc, _meter); + if (_meter_point == p) { + return; + } - meter_change (src); /* EMIT SIGNAL */ - processors_changed (); /* EMIT SIGNAL */ - _session.set_dirty (); + bool meter_was_visible_to_user = _meter->display_to_user (); + + { + Glib::RWLock::WriterLock lm (_processor_lock); + + if (p != MeterCustom) { + // Move meter in the processors list to reflect the new position + ProcessorList::iterator loc = find (_processors.begin(), _processors.end(), _meter); + _processors.erase(loc); + switch (p) { + case MeterInput: + loc = _processors.begin(); + break; + case MeterPreFader: + loc = find (_processors.begin(), _processors.end(), _amp); + break; + case MeterPostFader: + loc = _processors.end(); + break; + default: + break; + } + + ChanCount m_in; + + if (loc == _processors.begin()) { + m_in = _input->n_ports(); + } else { + ProcessorList::iterator before = loc; + --before; + m_in = (*before)->output_streams (); + } + + _meter->reflect_inputs (m_in); + + _processors.insert (loc, _meter); + + /* we do not need to reconfigure the processors, because the meter + (a) is always ready to handle processor_max_streams + (b) is always an N-in/N-out processor, and thus moving + it doesn't require any changes to the other processors. + */ + + _meter->set_display_to_user (false); + + } else { + + // just make it visible and let the user move it + + _meter->set_display_to_user (true); + } } + + _meter_point = p; + meter_change (src); /* EMIT SIGNAL */ + + bool const meter_visibly_changed = (_meter->display_to_user() != meter_was_visible_to_user); + + processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, meter_visibly_changed)); /* EMIT SIGNAL */ } + void Route::put_control_outs_at (Placement p) { @@ -2647,27 +2730,37 @@ Route::put_control_outs_at (Placement p) return; } - // Move meter in the processors list - ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), _control_outs); - _processors.erase(loc); + { + Glib::RWLock::WriterLock lm (_processor_lock); + ProcessorList as_it_was (_processors); + // Move meter in the processors list + ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), _control_outs); + _processors.erase(loc); + + switch (p) { + case PreFader: + loc = find(_processors.begin(), _processors.end(), _amp); + if (loc != _processors.begin()) { + --loc; + } + break; + case PostFader: + loc = find(_processors.begin(), _processors.end(), _amp); + assert (loc != _processors.end()); + loc++; + break; + } + + _processors.insert(loc, _control_outs); - switch (p) { - case PreFader: - loc = find(_processors.begin(), _processors.end(), _amp); - if (loc != _processors.begin()) { - --loc; + if (configure_processors_unlocked (0)) { + _processors = as_it_was; + configure_processors_unlocked (0); // it worked before we tried to add it ... + return; } - break; - case PostFader: - loc = find(_processors.begin(), _processors.end(), _amp); - assert (loc != _processors.end()); - loc++; - break; } - _processors.insert(loc, _control_outs); - - processors_changed (); /* EMIT SIGNAL */ + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ _session.set_dirty (); } @@ -2683,10 +2776,7 @@ Route::update_total_latency () } } -#undef DEBUG_LATENCY -#ifdef DEBUG_LATENCY - cerr << _name << ": internal redirect latency = " << own_latency << endl; -#endif + DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: internal redirect latency = %2\n", _name, own_latency)); _output->set_port_latency (own_latency); @@ -2707,10 +2797,7 @@ Route::update_total_latency () signal_latency_changed (); /* EMIT SIGNAL */ } -#ifdef DEBUG_LATENCY - cerr << _name << ": input latency = " << _input->signal_latency() << " total = " - << own_latency << endl; -#endif + DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: input latency = %2 total = %3\n", _name, _input->signal_latency(), own_latency)); return _output->effective_latency (); } @@ -2763,14 +2850,60 @@ void Route::SoloControllable::set_value (float val) { bool bval = ((val >= 0.5f) ? true: false); +# if 0 + this is how it should be done + + boost::shared_ptr rl (new RouteList); + rl->push_back (route); + if (Config->get_solo_control_is_listen_control()) { + _session.set_listen (rl, bval); + } else { + _session.set_solo (rl, bval); + } +#else route.set_solo (bval, this); +#endif } float Route::SoloControllable::get_value (void) const { - return route.soloed() ? 1.0f : 0.0f; + if (Config->get_solo_control_is_listen_control()) { + return route.listening() ? 1.0f : 0.0f; + } else { + return route.self_soloed() ? 1.0f : 0.0f; + } +} + +Route::MuteControllable::MuteControllable (std::string name, Route& r) + : AutomationControl (r.session(), Evoral::Parameter (MuteAutomation), + boost::shared_ptr(), name) + , route (r) +{ + boost::shared_ptr gl(new AutomationList(Evoral::Parameter(MuteAutomation))); + set_list (gl); +} + +void +Route::MuteControllable::set_value (float val) +{ + bool bval = ((val >= 0.5f) ? true: false); +# if 0 + this is how it should be done + + boost::shared_ptr rl (new RouteList); + rl->push_back (route); + _session.set_mute (rl, bval); +#else + route.set_mute (bval, this); +#endif +} + +float +Route::MuteControllable::get_value (void) const +{ + return route.muted() ? 1.0f : 0.0f; } void @@ -3025,3 +3158,40 @@ Route::get_control (const Evoral::Parameter& param) return c; } + +boost::shared_ptr +Route::nth_plugin (uint32_t n) +{ + Glib::RWLock::ReaderLock lm (_processor_lock); + ProcessorList::iterator i; + + for (i = _processors.begin(); i != _processors.end(); ++i) { + if (boost::dynamic_pointer_cast (*i)) { + if (n-- == 0) { + return *i; + } + } + } + + return boost::shared_ptr (); +} + +boost::shared_ptr +Route::nth_send (uint32_t n) +{ + Glib::RWLock::ReaderLock lm (_processor_lock); + ProcessorList::iterator i; + + for (i = _processors.begin(); i != _processors.end(); ++i) { + cerr << "check " << (*i)->name() << endl; + if (boost::dynamic_pointer_cast (*i)) { + if (n-- == 0) { + return *i; + } + } else { + cerr << "\tnot a send\n"; + } + } + + return boost::shared_ptr (); +}