#include <cassert>
#include <algorithm>
-#include <sigc++/bind.h>
#include "pbd/xml++.h"
#include "pbd/enumwriter.h"
#include "pbd/memento_command.h"
+#include "pbd/stacktrace.h"
#include "evoral/Curve.hpp"
#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"
using namespace PBD;
uint32_t Route::order_key_cnt = 0;
-sigc::signal<void, string const &> Route::SyncOrderKeys;
+PBD::Signal1<void,string const&> Route::SyncOrderKeys;
+PBD::Signal0<void> 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)
/* 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 */
/* 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)
{
/* 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;
_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 */
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 ();
+ }
}
}
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());
}
}
}
}
}
+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;
}
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<Delivery> d;
+
+ if ((d = boost::dynamic_pointer_cast<Delivery> (*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<RouteList> 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);
}
}
bool
Route::solo_isolated () const
{
- return _solo_isolated;
+ return _solo_isolated > 0;
}
void
// 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;
}
}
_meter.reset (new PeakMeter (_session, node));
+ _meter->set_display_to_user (_meter_point == MeterCustom);
processor = _meter;
} else if (prop->value() == "amp") {
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;
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;
{
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());
}
}
- _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;
}
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();
}
processor->drop_references ();
- processors_changed (); /* EMIT SIGNAL */
+ processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
return 0;
}
(*i)->drop_references ();
}
- processors_changed (); /* EMIT SIGNAL */
+ processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
return 0;
}
list< pair<ChanCount,ChanCount> > 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<boost::shared_ptr<Processor> >::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 {
}
}
- /* 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<ChanCount,ChanCount> >::iterator c = configuration.begin();
for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++c) {
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 ());
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.
*/
} else {
- if (!(*oiter)->visible()) {
+ if (!(*oiter)->display_to_user()) {
as_it_will_be.push_back (*oiter);
}
}
- processors_changed (); /* EMIT SIGNAL */
+ processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
return 0;
}
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));
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) {
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);
}
}
_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) {
the XML state represents a working signal route.
*/
- processors_changed ();
+ processors_changed (RouteProcessorChange ());
}
void
}
}
-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)
{
bool
Route::feeds (boost::shared_ptr<Route> 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;
}
if ((iop = boost::dynamic_pointer_cast<IOProcessor>(*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;
}
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)
{
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 ();
}
}
}
-#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);
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 ();
}
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<RouteList> 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<AutomationList>(), name)
+ , route (r)
+{
+ boost::shared_ptr<AutomationList> 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<RouteList> 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
return c;
}
+
+boost::shared_ptr<Processor>
+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<PluginInsert> (*i)) {
+ if (n-- == 0) {
+ return *i;
+ }
+ }
+ }
+
+ return boost::shared_ptr<Processor> ();
+}
+
+boost::shared_ptr<Processor>
+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<Send> (*i)) {
+ if (n-- == 0) {
+ return *i;
+ }
+ } else {
+ cerr << "\tnot a send\n";
+ }
+ }
+
+ return boost::shared_ptr<Processor> ();
+}