/*
- Copyright (C) 2000 Paul Davis
+ Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <sigc++/bind.h>
#include "pbd/xml++.h"
#include "pbd/enumwriter.h"
-#include "pbd/stacktrace.h"
#include "pbd/memento_command.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"
, _solo_control (new SoloControllable (X_("solo"), *this))
, _mute_master (new MuteMaster (sess, name))
, _default_type (default_type)
-
+
{
init ();
-
+
/* add standard processors other than amp (added by ::init()) */
-
+
_meter.reset (new PeakMeter (_session));
+ _meter->set_display_to_user (_meter_point == MeterCustom);
add_processor (_meter, PreFader);
if (_flags & ControlOut) {
_intreturn.reset (new InternalReturn (_session));
add_processor (_intreturn, PreFader);
}
-
+
_main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
add_processor (_main_outs, PostFader);
{
init ();
- _set_state (node, false);
+ _set_state (node, Stateful::loading_state_version, false);
/* now that we have _meter, its safe to connect to this */
-
+
_meter_connection = Metering::connect (mem_fun (*this, &Route::meter));
}
void
Route::init ()
{
- _solo_level = 0;
+ _self_solo = false;
+ _soloed_by_others = 0;
_solo_isolated = false;
+ _solo_safe = false;
_active = true;
processor_max_streams.reset();
- _solo_safe = false;
_recordable = true;
order_keys[N_("signal")] = order_key_cnt++;
_silent = false;
_pending_declick = true;
_remote_control_id = 0;
_in_configure_processors = false;
-
+ _mute_points = MuteMaster::AllPoints;
+
_route_group = 0;
_phase_invert = 0;
add_control (_solo_control);
add_control (_mute_master);
-
+
/* input and output objects */
_input.reset (new IO (_session, _name, IO::Input, _default_type));
for (OrderKeys::iterator x = order_keys.begin(); x != order_keys.end(); ++x) {
x->second = n;
}
- }
+ }
_session.set_dirty ();
}
Route::set_gain (gain_t val, void *src)
{
if (src != 0 && _route_group && src != _route_group && _route_group->active_property (RouteGroup::Gain)) {
-
+
if (_route_group->is_relative()) {
gain_t usable_gain = _amp->gain();
if (usable_gain < 0.000001f) {
usable_gain = 0.000001f;
}
-
+
gain_t delta = val;
if (delta < 0.000001f) {
delta = 0.000001f;
return;
}
}
-
+
_route_group->apply (&Route::inc_gain, factor, _route_group);
} else {
-
+
_route_group->apply (&Route::set_gain, val, _route_group);
}
return;
- }
+ }
if (val == _amp->gain()) {
return;
/** Process this route for one (sub) cycle (process thread)
*
* @param bufs Scratch buffers to use for the signal path
- * @param start_frame Initial transport frame
+ * @param start_frame Initial transport frame
* @param end_frame Final transport frame
* @param nframes Number of frames to output (to ports)
*
/* figure out if we're going to use gain automation */
_amp->setup_gain_automation (start_frame, end_frame, nframes);
-
+
/* tell main outs what to do about monitoring */
_main_outs->no_outs_cuz_we_no_monitor (!monitor);
Amp::apply_gain (bufs, nframes, 0.0, 1.0);
} else if (declick < 0) {
Amp::apply_gain (bufs, nframes, 1.0, 0.0);
- }
+ }
_pending_declick = 0;
-
+
/* -------------------------------------------------------------------------------------------
DENORMAL CONTROL/PHASE INVERT
----------------------------------------------------------------------------------------- */
if (_phase_invert) {
-
+
int chn = 0;
if (_denormal_protection || Config->get_denormal_protection()) {
-
+
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
Sample* const sp = i->data();
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
Sample* const sp = i->data();
-
+
if (_phase_invert & chn) {
for (nframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] = -sp[nx];
}
- }
+ }
}
}
} else {
if (_denormal_protection || Config->get_denormal_protection()) {
-
+
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
Sample* const sp = i->data();
for (nframes_t nx = 0; nx < nframes; ++nx) {
}
}
- }
+ }
}
/* -------------------------------------------------------------------------------------------
if (rm.locked()) {
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- bufs.set_count (ChanCount::max(bufs.count(), (*i)->input_streams()));
+ 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()));
}
_silent = false;
assert (bufs.available() >= _input->n_ports());
-
+
if (_input->n_ports() == ChanCount::ZERO) {
silence (nframes);
}
-
+
bufs.set_count (_input->n_ports());
if (is_control() && _session.listening()) {
-
+
/* control/monitor bus ignores input ports when something is
feeding the listen "stream". data will "arrive" into the
route from the intreturn processor element.
*/
-
+
bufs.silence (nframes, 0);
} else {
-
+
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-
+
BufferSet::iterator o = bufs.begin(*t);
PortSet& ports (_input->ports());
-
+
for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) {
o->read_from (i->get_buffer(nframes), nframes);
}
}
}
+ write_out_of_band_data (bufs, start_frame, end_frame, nframes);
process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick);
}
void
Route::passthru_silence (sframes_t start_frame, sframes_t end_frame, nframes_t nframes, int declick)
{
- process_output_buffers (_session.get_silent_buffers (n_process_buffers()), start_frame, end_frame, nframes, true, declick);
+ BufferSet& bufs (_session.get_silent_buffers (n_process_buffers()));
+ bufs.set_count (_input->n_ports());
+ write_out_of_band_data (bufs, start_frame, end_frame, nframes);
+ process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick);
}
void
Route::set_listen (bool yn, void* src)
{
- if (_control_outs) {
+ if (_control_outs) {
if (yn != _control_outs->active()) {
if (yn) {
_control_outs->activate ();
}
}
+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::set_self_solo (bool yn)
+{
+ _self_solo = yn;
}
void
-Route::mod_solo_level (int32_t delta)
+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 ();
+}
+
+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.
+ */
- _main_outs->set_solo_level (_solo_level);
- _main_outs->set_solo_isolated (_solo_isolated);
+ 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
if (yn != _solo_isolated) {
_solo_isolated = yn;
-
- /* tell main outs what the solo situation is
- */
-
- _main_outs->set_solo_level (_solo_level);
- _main_outs->set_solo_isolated (_solo_isolated);
-
+ set_delivery_solo ();
solo_isolated_changed (src);
}
}
bool
-Route::solo_isolated () const
+Route::solo_isolated () const
{
return _solo_isolated;
}
+void
+Route::set_mute_points (MuteMaster::MutePoint mp)
+{
+ _mute_points = mp;
+ mute_points_changed (); /* EMIT SIGNAL */
+
+ if (_mute_master->muted()) {
+ _mute_master->mute_at (_mute_points);
+ mute_changed (this); /* EMIT SIGNAL */
+ }
+}
+
void
Route::set_mute (bool yn, void *src)
{
}
if (muted() != yn) {
- _mute_master->mute (yn);
- mute_changed (src);
+ if (yn) {
+ _mute_master->mute_at (_mute_points);
+ } else {
+ _mute_master->clear_mute ();
+ }
+
+ mute_changed (src); /* EMIT SIGNAL */
}
-}
+}
bool
-Route::muted() const
+Route::muted() const
{
return _mute_master->muted ();
}
// Set up processor list channels. This will set processor->[input|output]_streams(),
// configure redirect ports properly, etc.
-
if (configure_processors_unlocked (err)) {
ProcessorList::iterator ploc = loc;
cerr << "configure failed\n";
return -1;
}
-
+
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(processor)) != 0) {
-
+
if (pi->natural_input_streams() == ChanCount::ZERO) {
/* generator plugin */
_have_internal_generator = true;
}
-
+
+ }
+
+ if (_control_outs != processor) {
+ // XXX: do we want to emit the signal here ? change call order.
+ processor->activate ();
}
-
- // 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));
_output->set_user_latency (0);
}
-
+
processors_changed (); /* EMIT SIGNAL */
-
+
return 0;
}
if (node.name() != "Processor") {
return false;
}
-
+
try {
if ((prop = node.property ("type")) != 0) {
-
+
boost::shared_ptr<Processor> processor;
- if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
+ if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" ||
prop->value() == "vst" ||
prop->value() == "audiounit") {
-
+
processor.reset (new PluginInsert(_session, node));
-
+
} else if (prop->value() == "port") {
processor.reset (new PortInsert (_session, _mute_master, node));
-
+
} else if (prop->value() == "send") {
processor.reset (new Send (_session, _mute_master, node));
} else if (prop->value() == "meter") {
if (_meter) {
- if (_meter->set_state (node)) {
+ if (_meter->set_state (node, Stateful::loading_state_version)) {
return false;
} else {
return true;
}
}
- _meter.reset (new PeakMeter (_session, node));
+ _meter.reset (new PeakMeter (_session, node));
+ _meter->set_display_to_user (_meter_point == MeterCustom);
processor = _meter;
-
+
} else if (prop->value() == "amp") {
/* amp always exists */
-
+
processor = _amp;
- if (processor->set_state (node)) {
+ if (processor->set_state (node, Stateful::loading_state_version)) {
return false;
} else {
/* never any reason to add it */
return true;
}
-
- } else if (prop->value() == "listen" || prop->value() == "deliver") {
-
- /* XXX need to generalize */
} else if (prop->value() == "intsend") {
processor.reset (new InternalSend (_session, _mute_master, node));
} else if (prop->value() == "intreturn") {
-
+
if (_intreturn) {
- if (_intreturn->set_state (node)) {
+ if (_intreturn->set_state (node, Stateful::loading_state_version)) {
return false;
} else {
return true;
processor = _intreturn;
} else if (prop->value() == "main-outs") {
-
+
if (_main_outs) {
- if (_main_outs->set_state (node)) {
+ if (_main_outs->set_state (node, Stateful::loading_state_version)) {
return false;
} else {
return true;
} else {
error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
+ 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 (add_processor (processor, iter) == 0);
-
+
} else {
error << _("Processor XML node has no type property") << endmsg;
return false;
}
}
+
+bool
+Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorList::iterator iter)
+{
+ const XMLProperty *prop;
+
+ try {
+ boost::shared_ptr<Processor> processor;
+
+ if (node.name() == "Insert") {
+
+ if ((prop = node.property ("type")) != 0) {
+
+ if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
+ prop->value() == "lv2" ||
+ prop->value() == "vst" ||
+ prop->value() == "audiounit") {
+
+ processor.reset (new PluginInsert (_session, node));
+
+ } else {
+
+ processor.reset (new PortInsert (_session, _mute_master, node));
+ }
+
+ }
+
+ } else if (node.name() == "Send") {
+
+ processor.reset (new Send (_session, _mute_master, node, version));
+
+ } else {
+
+ error << string_compose(_("unknown Processor type \"%1\"; ignored"), node.name()) << endmsg;
+ return false;
+ }
+
+ 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)->display_to_user() && p != _processors.begin()) {
+ --p;
+ }
+ ++p;
+ iter = p;
+ }
+
+ return (add_processor (processor, iter) == 0);
+ }
+
+ catch (failed_constructor &err) {
+ warning << _("processor could not be created. Ignored.") << endmsg;
+ return false;
+ }
+}
+
int
Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor> before, ProcessorStreams* err)
{
ChanCount potential_max_streams = ChanCount::max (_input->n_ports(), _output->n_ports());
for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) {
-
+
// Ensure meter only appears in the list once
if (*i == _meter) {
ProcessorList::iterator m = find(_processors.begin(), _processors.end(), *i);
_processors.erase(m);
}
}
-
+
boost::shared_ptr<PluginInsert> pi;
-
+
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
pi->set_count (1);
-
+
ChanCount m = max (pi->input_streams(), pi->output_streams());
if (m > potential_max_streams) {
}
_processors.insert (iter, *i);
-
+
if (configure_processors_unlocked (err)) {
++existing_end;
_processors.erase (existing_end, _processors.end());
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));
}
_output->set_user_latency (0);
}
-
+
processors_changed (); /* EMIT SIGNAL */
return 0;
Route::disable_processors (Placement p)
{
Glib::RWLock::ReaderLock lm (_processor_lock);
-
+
ProcessorList::iterator start, end;
placement_range(p, start, end);
-
+
for (ProcessorList::iterator i = start; i != end; ++i) {
(*i)->deactivate ();
}
_session.set_dirty ();
}
-/** Turn off all redirects
+/** Turn off all redirects
*/
void
Route::disable_processors ()
{
Glib::RWLock::ReaderLock lm (_processor_lock);
-
+
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->deactivate ();
}
-
+
_session.set_dirty ();
}
Route::disable_plugins (Placement p)
{
Glib::RWLock::ReaderLock lm (_processor_lock);
-
+
ProcessorList::iterator start, end;
placement_range(p, start, end);
-
+
for (ProcessorList::iterator i = start; i != end; ++i) {
if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
(*i)->deactivate ();
}
}
-
+
_session.set_dirty ();
}
Route::disable_plugins ()
{
Glib::RWLock::ReaderLock lm (_processor_lock);
-
+
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
(*i)->deactivate ();
}
}
-
+
_session.set_dirty ();
}
Route::ab_plugins (bool forward)
{
Glib::RWLock::ReaderLock lm (_processor_lock);
-
+
if (forward) {
/* forward = turn off all active redirects, and mark them so that the next time
}
}
}
-
+
_session.set_dirty ();
}
-
-
+
+
/** Remove processors with a given placement.
* @param p Placement of processors to remove.
*/
if (!_session.engine().connected()) {
return;
}
-
+
bool already_deleting = _session.deletion_in_progress();
if (!already_deleting) {
_session.set_deletion_in_progress();
}
if ((*i) == _amp || (*i) == _meter || (*i) == _main_outs) {
-
+
/* you can't remove these */
new_list.push_back (*i);
for (i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<PluginInsert> pi;
-
+
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
if (pi->is_generator()) {
_have_internal_generator = true;
as_we_were = _processors;
for (i = _processors.begin(); i != _processors.end(); ) {
-
+
processor = *i;
/* these can never be removed */
++i;
continue;
}
-
+
/* see if its in the list of processors to delete */
-
+
if (find (to_be_deleted.begin(), to_be_deleted.end(), processor) == to_be_deleted.end()) {
++i;
continue;
from causing noise as a result of no longer being
run.
*/
-
+
boost::shared_ptr<IOProcessor> iop;
-
+
if ((iop = boost::dynamic_pointer_cast<IOProcessor> (processor)) != 0) {
iop->disconnect ();
}
for (i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<PluginInsert> pi;
-
+
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
if (pi->is_generator()) {
_have_internal_generator = true;
ChanCount out;
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 {
return -1;
}
}
+
+ /* 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();
out = c->second;
}
- // Ensure route outputs match last processor's outputs
- if (out != _output->n_ports ()) {
- cerr << "For " << _name << " out/last mismatch - out = " << out << " vs. " << _output->n_ports() << endl;
- _output->ensure_io (out, false, this);
- }
+ /* make sure we have sufficient scratch buffers to cope with the new processor
+ configuration */
+ _session.ensure_buffers (n_process_buffers ());
_in_configure_processors = false;
return 0;
}
bool first_is_on = _processors.front()->active();
-
+
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (first_is_on) {
(*i)->deactivate ();
(*i)->activate ();
}
}
-
+
_session.set_dirty ();
}
}
}
}
-
+
_session.set_dirty ();
}
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.
*/
ProcessorList as_it_will_be;
oiter = _processors.begin();
- niter = new_order.begin();
+ niter = new_order.begin();
while (niter != new_order.end()) {
-
+
/* if the next processor in the old list is invisible (i.e. should not be in the new order)
- then append it to the temp list.
+ then append it to the temp list.
Otherwise, see if the next processor in the old list is in the new list. if not,
its been deleted. If its there, append it to the temp list.
if (oiter == _processors.end()) {
- /* no more elements in the old list, so just stick the rest of
+ /* no more elements in the old list, so just stick the rest of
the new order onto the temp list.
*/
break;
} else {
-
- if (!(*oiter)->visible()) {
+
+ if (!(*oiter)->display_to_user()) {
as_it_will_be.push_back (*oiter);
++niter;
}
}
-
+
/* now remove from old order - its taken care of no matter what */
oiter = _processors.erase (oiter);
}
-
+
}
_processors.insert (oiter, as_it_will_be.begin(), as_it_will_be.end());
_processors = as_it_was_before;
processor_max_streams = old_pms;
return -1;
- }
- }
+ }
+ }
processors_changed (); /* EMIT SIGNAL */
}
string order_string;
- OrderKeys::iterator x = order_keys.begin();
+ OrderKeys::iterator x = order_keys.begin();
while (x != order_keys.end()) {
order_string += string ((*x).first);
order_string += '=';
snprintf (buf, sizeof(buf), "%ld", (*x).second);
order_string += buf;
-
+
++x;
if (x == order_keys.end()) {
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));
if (_extra_xml){
node->add_child_copy (*_extra_xml);
}
-
+
return *node;
}
int
-Route::set_state (const XMLNode& node)
+Route::set_state (const XMLNode& node, int version)
{
- return _set_state (node, true);
+ return _set_state (node, version, true);
}
int
-Route::_set_state (const XMLNode& node, bool /*call_base*/)
+Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
{
+ if (version < 3000) {
+ return _set_state_2X (node, version);
+ }
XMLNodeList nlist;
XMLNodeConstIterator niter;
if ((prop = node.property (X_("name"))) != 0) {
Route::set_name (prop->value());
- }
+ }
if ((prop = node.property ("id")) != 0) {
_id = prop->value ();
XMLNode processor_state (X_("processor_state"));
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
-
+
child = *niter;
if (child->name() == IO::state_node_name) {
if ((prop = child->property (X_("direction"))) == 0) {
continue;
}
-
+
if (prop->value() == "Input") {
- _input->set_state (*child);
+ _input->set_state (*child, version);
} else if (prop->value() == "Output") {
- _output->set_state (*child);
+ _output->set_state (*child, version);
}
}
-
+
if (child->name() == X_("Processor")) {
processor_state.add_child_copy (*child);
}
}
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_solo_isolated (prop->value() == "yes", this);
+ set_solo_isolated (string_is_affirmative (prop->value()), this);
}
if ((prop = node.property (X_("phase-invert"))) != 0) {
- set_phase_invert (prop->value()=="yes"?true:false);
+ set_phase_invert (string_is_affirmative (prop->value()));
}
if ((prop = node.property (X_("denormal-protection"))) != 0) {
- set_denormal_protection (prop->value()=="yes"?true:false);
+ set_denormal_protection (string_is_affirmative (prop->value()));
}
-
+
if ((prop = node.property (X_("active"))) != 0) {
- bool yn = (prop->value() == "yes");
+ bool yn = string_is_affirmative (prop->value());
_active = !yn; // force switch
set_active (yn);
}
+ if ((prop = node.property (X_("meter-point"))) != 0) {
+ _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point));
+ if (_meter) {
+ _meter->set_display_to_user (_meter_point == MeterCustom);
+ }
+ }
+
+ 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 ((prop = node.property (X_("order-keys"))) != 0) {
+
+ long n;
+
+ string::size_type colon, equal;
+ string remaining = prop->value();
+
+ while (remaining.length()) {
+
+ if ((equal = remaining.find_first_of ('=')) == string::npos || equal == remaining.length()) {
+ error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
+ << endmsg;
+ } else {
+ if (sscanf (remaining.substr (equal+1).c_str(), "%ld", &n) != 1) {
+ error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
+ << endmsg;
+ } else {
+ set_order_key (remaining.substr (0, equal), n);
+ }
+ }
+
+ colon = remaining.find_first_of (':');
+
+ if (colon != string::npos) {
+ remaining = remaining.substr (colon+1);
+ } else {
+ break;
+ }
+ }
+ }
+
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter){
+ child = *niter;
+
+ if (child->name() == X_("Comment")) {
+
+ /* XXX this is a terrible API design in libxml++ */
+
+ XMLNode *cmt = *(child->children().begin());
+ _comment = cmt->content();
+
+ } else if (child->name() == X_("Extra")) {
+
+ _extra_xml = new XMLNode (*child);
+
+ } else if (child->name() == X_("Controllable") && (prop = child->property("name")) != 0) {
+
+ if (prop->value() == "solo") {
+ _solo_control->set_state (*child, version);
+ _session.add_controllable (_solo_control);
+ }
+
+ } else if (child->name() == X_("RemoteControl")) {
+ if ((prop = child->property (X_("id"))) != 0) {
+ int32_t x;
+ sscanf (prop->value().c_str(), "%d", &x);
+ set_remote_control_id (x);
+ }
+
+ } else if (child->name() == X_("MuteMaster")) {
+ _mute_master->set_state (*child, version);
+ }
+ }
+
+ return 0;
+}
+
+int
+Route::_set_state_2X (const XMLNode& node, int version)
+{
+ XMLNodeList nlist;
+ XMLNodeConstIterator niter;
+ XMLNode *child;
+ XMLPropertyList plist;
+ const XMLProperty *prop;
+
+ /* 2X things which still remain to be handled:
+ * default-type
+ * muted
+ * mute-affects-pre-fader
+ * mute-affects-post-fader
+ * mute-affects-control-outs
+ * mute-affects-main-outs
+ * automation
+ * controlouts
+ */
+
+ if (node.name() != "Route") {
+ error << string_compose(_("Bad node sent to Route::set_state() [%1]"), node.name()) << endmsg;
+ return -1;
+ }
+
+ if ((prop = node.property (X_("flags"))) != 0) {
+ _flags = Flag (string_2_enum (prop->value(), _flags));
+ } else {
+ _flags = Flag (0);
+ }
+
+ /* add standard processors */
+
+ _meter.reset (new PeakMeter (_session));
+ add_processor (_meter, PreFader);
+
+ if (_flags & ControlOut) {
+ /* where we listen to tracks */
+ _intreturn.reset (new InternalReturn (_session));
+ add_processor (_intreturn, PreFader);
+ }
+
+ _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
+ add_processor (_main_outs, PostFader);
+
+ /* IOs */
+
+ nlist = node.children ();
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+
+ child = *niter;
+
+ if (child->name() == IO::state_node_name) {
+
+ /* there is a note in IO::set_state_2X() about why we have to call
+ this directly.
+ */
+
+ _input->set_state_2X (*child, version, true);
+ _output->set_state_2X (*child, version, false);
+
+ if ((prop = child->property (X_("name"))) != 0) {
+ set_name (prop->value ());
+ }
+
+ if ((prop = child->property (X_("id"))) != 0) {
+ _id = prop->value ();
+ }
+
+ if ((prop = child->property (X_("active"))) != 0) {
+ bool yn = string_is_affirmative (prop->value());
+ _active = !yn; // force switch
+ set_active (yn);
+ }
+ }
+
+ /* XXX: panners? */
+ }
+
+ if ((prop = node.property (X_("phase-invert"))) != 0) {
+ set_phase_invert (string_is_affirmative (prop->value()));
+ }
+
+ if ((prop = node.property (X_("denormal-protection"))) != 0) {
+ set_denormal_protection (string_is_affirmative (prop->value()));
+ }
+
if ((prop = node.property (X_("soloed"))) != 0) {
- bool yn = (prop->value()=="yes");
+ bool yn = string_is_affirmative (prop->value());
/* XXX force reset of solo status */
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) {
+
+ /* 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;
if ((equal = remaining.find_first_of ('=')) == string::npos || equal == remaining.length()) {
error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
- << endmsg;
+ << endmsg;
} else {
if (sscanf (remaining.substr (equal+1).c_str(), "%ld", &n) != 1) {
error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
- << endmsg;
+ << endmsg;
} else {
set_order_key (remaining.substr (0, equal), n);
}
}
}
+ XMLNodeList redirect_nodes;
+
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter){
+
+ child = *niter;
+
+ if (child->name() == X_("Send") || child->name() == X_("Insert")) {
+ redirect_nodes.push_back(child);
+ }
+
+ }
+
+ set_processor_state_2X (redirect_nodes, version);
+
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
_extra_xml = new XMLNode (*child);
} else if (child->name() == X_("Controllable") && (prop = child->property("name")) != 0) {
-
+
if (prop->value() == "solo") {
- _solo_control->set_state (*child);
+ _solo_control->set_state (*child, version);
_session.add_controllable (_solo_control);
- }
+ }
} else if (child->name() == X_("RemoteControl")) {
if ((prop = child->property (X_("id"))) != 0) {
set_remote_control_id (x);
}
- } else if (child->name() == X_("MuteMaster")) {
- _mute_master->set_state (*child);
- }
+ }
}
return 0;
return *root;
}
+void
+Route::set_processor_state_2X (XMLNodeList const & nList, int version)
+{
+ /* We don't bother removing existing processors not in nList, as this
+ method will only be called when creating a Route from scratch, not
+ for undo purposes. Just put processors in at the appropriate place
+ in the list.
+ */
+
+ for (XMLNodeConstIterator i = nList.begin(); i != nList.end(); ++i) {
+ add_processor_from_xml_2X (**i, version, _processors.begin ());
+ }
+}
+
void
Route::set_processor_state (const XMLNode& node)
{
break;
}
}
-
+
if (!processorInStateList) {
remove_processor (*i);
}
i = _processors.begin();
for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) {
-
+
XMLProperty* prop = (*niter)->property ("type");
o = i;
// Check whether the next processor in the list is the right one,
// except for "amp" which is always there and may not have the
// old ID since it is always created anew in every Route
-
+
if (prop->value() != "amp") {
while (o != _processors.end()) {
XMLProperty* id_prop = (*niter)->property(X_("id"));
if (id_prop && (*o)->id() == id_prop->value()) {
break;
}
-
+
++o;
}
}
// and make it (just) so
- (*i)->set_state (**niter);
+ (*i)->set_state (**niter, Stateful::current_state_version);
}
}
if (!_silent) {
_output->silence (nframes);
-
- {
+
+ {
Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
-
+
if (lm.locked()) {
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<PluginInsert> pi;
// skip plugins, they don't need anything when we're not active
continue;
}
-
+
(*i)->silence (nframes);
}
}
}
}
-
+
}
-}
+}
void
Route::add_internal_return ()
Route::get_return_buffer () const
{
Glib::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);
-
+
if (d) {
BufferSet* bs = d->get_buffers ();
return bs;
}
}
-
+
return 0;
}
Route::release_return_buffer () const
{
Glib::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);
-
+
if (d) {
return d->release_buffers ();
}
{
Glib::RWLock::ReaderLock rm (_processor_lock);
-
+
for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ++x) {
boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
if (d && d->target_route() == route) {
-
+
/* if the target is the control outs, then make sure
we take note of which i-send is doing that.
*/
}
/* already listening via the specified IO: do nothing */
-
+
return 0;
}
}
}
-
+
boost::shared_ptr<InternalSend> listener;
try {
}
add_processor (listener, placement);
-
- return 0;
-}
+
+ return 0;
+}
void
Route::drop_listen (boost::shared_ptr<Route> route)
Glib::RWLock::ReaderLock rl(_processor_lock);
rl.acquire ();
-
+
again:
for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ) {
-
+
boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
-
+
if (d && d->target_route() == route) {
rl.release ();
remove_processor (*x, &err);
so start over.
*/
- goto again;
- }
+ goto again;
+ }
}
rl.release ();
}
bool
-Route::feeds (boost::shared_ptr<Route> other)
+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;
+ }
+
return true;
}
+
for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); r++) {
-
+
boost::shared_ptr<IOProcessor> iop;
-
+
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;
}
}
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-
+
if (Config->get_plugins_stop_with_transport() && can_flush_processors) {
(*i)->deactivate ();
(*i)->activate ();
}
-
+
(*i)->transport_stopped (now);
}
}
Route::output_change_handler (IOChange change, void * /*src*/)
{
if ((change & ConfigurationChanged)) {
-
+
/* XXX resize all listeners to match _main_outs? */
-
+
// configure_processors (0);
}
}
if (n_outputs().n_audio() < 2) {
return 0;
}
-
+
return max (n_inputs ().n_audio(), processor_max_streams.n_audio());
}
-int
-Route::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
+int
+Route::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
bool session_state_changing, bool /*can_record*/, bool /*rec_monitors_input*/)
{
if (n_outputs().n_total() == 0) {
nframes -= _roll_delay;
silence (_roll_delay);
- /* we've written _roll_delay of samples into the
+ /* we've written _roll_delay of samples into the
output ports, so make a note of that for
future reference.
*/
silence (nframes);
return 0;
}
-
+
nframes_t unused = 0;
if ((nframes = check_initial_delay (nframes, unused)) == 0) {
}
int
-Route::silent_roll (nframes_t nframes, sframes_t /*start_frame*/, sframes_t /*end_frame*/,
+Route::silent_roll (nframes_t nframes, sframes_t /*start_frame*/, sframes_t /*end_frame*/,
bool /*can_record*/, bool /*rec_monitors_input*/)
{
silence (nframes);
// FIXME: what about sends? - they don't return a signal back to ardour?
boost::shared_ptr<const PortInsert> pi;
-
+
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((pi = boost::dynamic_pointer_cast<const PortInsert>(*i)) != 0) {
for (PortSet::const_iterator port = pi->output()->ports().begin(); port != pi->output()->ports().end(); ++port) {
-
+
string port_name = port->name();
string client_name = port_name.substr (0, port_name.find(':'));
/* only say "yes" if the redirect is actually in use */
-
+
if (client_name != "ardour" && pi->active()) {
return true;
}
void
Route::set_meter_point (MeterPoint p, void *src)
{
- if (_meter_point != p) {
- _meter_point = p;
+ if (_meter_point == p) {
+ return;
+ }
- // 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();
+ {
+ Glib::RWLock::WriterLock lm (_processor_lock);
+ ProcessorList as_it_was (_processors);
+
+ 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;
+ }
+
+ _processors.insert(loc, _meter);
+
+ if (configure_processors_unlocked (0)) {
+ _processors = as_it_was;
+ configure_processors_unlocked (0); // it worked before we tried to add it ...
+ return;
+ }
+
+ _meter->set_display_to_user (false);
+
+ } else {
+
+ // just make it visible and let the user move it
+
+ _meter->set_display_to_user (true);
}
- _processors.insert(loc, _meter);
- meter_change (src); /* EMIT SIGNAL */
- processors_changed (); /* EMIT SIGNAL */
- _session.set_dirty ();
}
+
+ _meter_point = p;
+ meter_change (src); /* EMIT SIGNAL */
+ processors_changed (); /* EMIT SIGNAL */
+ _session.set_dirty ();
}
+
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 */
_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);
-
+
if (_output->user_latency() == 0) {
/* this (virtual) function is used for pure Routes,
port, not prerecorded material, and therefore we
have to take into account any input latency.
*/
-
+
own_latency += _input->signal_latency ();
}
_output->set_latency_delay (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::SoloControllable (std::string name, Route& r)
- : AutomationControl (r.session(), Evoral::Parameter (SoloAutomation),
+ : AutomationControl (r.session(), Evoral::Parameter (SoloAutomation),
boost::shared_ptr<AutomationList>(), name)
, route (r)
{
Route::SoloControllable::set_value (float val)
{
bool bval = ((val >= 0.5f) ? true: false);
-
+
route.set_solo (bval, this);
}
float
Route::SoloControllable::get_value (void) const
{
- return route.soloed() ? 1.0f : 0.0f;
+ return route.self_soloed() ? 1.0f : 0.0f;
}
-void
+void
Route::set_block_size (nframes_t nframes)
{
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->set_block_size (nframes);
}
- _session.ensure_buffers(processor_max_streams);
+
+ _session.ensure_buffers (n_process_buffers ());
}
void
{
Glib::RWLock::ReaderLock lm (redirect_lock);
for (RedirectList::iterator i = _redirects.begin (); i != _redirects.end (); ++i) {
-
+
set<uint32_t> a;
(*i)->what_has_automation (a);
-
+
for (set<uint32_t>::const_iterator j = a.begin (); j != a.end (); ++j) {
AutomationList & al = (*i)->automation_list (*j);
XMLNode &before = al.get_state ();
{
XMLNode& node (state (false));
XMLTree tree;
-
+
IO::set_name_in_state (*node.children().front(), name);
-
+
tree.set_root (&node);
return tree.write (path.c_str());
}
name = Route::ensure_track_or_route_name (str, _session);
SessionObject::set_name (name);
-
+
ret = (_input->set_name(name) && _output->set_name(name));
if (ret) {
-
+
Glib::RWLock::ReaderLock lm (_processor_lock);
-
+
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-
+
/* rename all I/O processors that have inputs or outputs */
boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor> (*i);
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<InternalSend> send;
-
+
if ((send = boost::dynamic_pointer_cast<InternalSend>(*i)) != 0) {
if (send->target_route() == target) {
return send;
}
}
}
-
+
return boost::shared_ptr<Send>();
}
{
Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
+ assert (_meter);
+
_meter->meter ();
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (!c) {
/* maybe one of our processors does or ... */
-
+
Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((c = boost::dynamic_pointer_cast<AutomationControl>((*i)->data().control (param))) != 0) {
}
}
}
-
+
if (!c) {
/* nobody does so we'll make a new one */