summaryrefslogtreecommitdiff
path: root/libs/ardour/route.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/route.cc')
-rw-r--r--libs/ardour/route.cc367
1 files changed, 197 insertions, 170 deletions
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 36b0a6bf68..0b6c3c48ca 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -38,6 +38,8 @@
#include "ardour/configuration.h"
#include "ardour/cycle_timer.h"
#include "ardour/dB.h"
+#include "ardour/internal_send.h"
+#include "ardour/internal_return.h"
#include "ardour/ladspa_plugin.h"
#include "ardour/meter.h"
#include "ardour/mix.h"
@@ -73,6 +75,24 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
{
init ();
+
+ /* add standard processors other than amp (added by ::init()) */
+
+ _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);
+
+ /* now that we have _meter, its safe to connect to this */
+
+ _meter_connection = Metering::connect (mem_fun (*this, &Route::meter));
}
Route::Route (Session& sess, const XMLNode& node, DataType default_type)
@@ -83,7 +103,12 @@ Route::Route (Session& sess, const XMLNode& node, DataType default_type)
, _default_type (default_type)
{
init ();
+
_set_state (node, false);
+
+ /* now that we have _meter, its safe to connect to this */
+
+ _meter_connection = Metering::connect (mem_fun (*this, &Route::meter));
}
void
@@ -123,20 +148,10 @@ Route::init ()
_input->changed.connect (mem_fun (this, &Route::input_change_handler));
_output->changed.connect (mem_fun (this, &Route::output_change_handler));
- /* add standard processors */
+ /* add amp processor */
_amp.reset (new Amp (_session, _mute_master));
add_processor (_amp, PostFader);
-
- _meter.reset (new PeakMeter (_session));
- add_processor (_meter, PreFader);
-
- _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
- add_processor (_main_outs, PostFader);
-
- /* now we can meter */
-
- _meter_connection = Metering::connect (mem_fun (*this, &Route::meter));
}
Route::~Route ()
@@ -316,7 +331,7 @@ Route::process_output_buffers (BufferSet& bufs,
switch (Config->get_monitoring_model()) {
case HardwareMonitoring:
case ExternalMonitoring:
- monitor = record_enabled() && (_session.config.get_auto_input() || _session.actively_recording());
+ monitor = !record_enabled() || (_session.config.get_auto_input() && !_session.actively_recording());
break;
default:
monitor = true;
@@ -327,13 +342,13 @@ Route::process_output_buffers (BufferSet& bufs,
}
/* 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 */
+ /* tell main outs what to do about monitoring */
_main_outs->no_outs_cuz_we_no_monitor (!monitor);
+
/* -------------------------------------------------------------------------------------------
GLOBAL DECLICK (for transport changes etc.)
----------------------------------------------------------------------------------------- */
@@ -520,25 +535,16 @@ Route::muted() const
return _mute_master->muted ();
}
-#if DEFINE_IF_YOU_NEED_THIS
static void
dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs)
{
cerr << name << " {" << endl;
for (list<boost::shared_ptr<Processor> >::const_iterator p = procs.begin();
p != procs.end(); ++p) {
- cerr << "\t" << (*p)->name() << endl;
+ cerr << "\t" << (*p)->name() << " ID = " << (*p)->id() << endl;
}
cerr << "}" << endl;
}
-#endif
-
-Route::ProcessorList::iterator
-Route::prefader_iterator()
-{
- Glib::RWLock::ReaderLock lm (_processor_lock);
- return find (_processors.begin(), _processors.end(), _amp);
-}
int
Route::add_processor (boost::shared_ptr<Processor> processor, Placement placement, ProcessorStreams* err)
@@ -615,6 +621,8 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
loc = iter;
}
+ cerr << "Adding " << processor->name() << " @ " << processor << endl;
+
_processors.insert (loc, processor);
// Set up processor list channels. This will set processor->[input|output]_streams(),
@@ -626,6 +634,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
--ploc;
_processors.erase(ploc);
configure_processors_unlocked (0); // it worked before we tried to add it ...
+ cerr << "configure failed\n";
return -1;
}
@@ -660,6 +669,7 @@ bool
Route::add_processor_from_xml (const XMLNode& node, Placement placement)
{
ProcessorList::iterator loc;
+
if (placement == PreFader) {
/* generic pre-fader: insert immediately before the amp */
loc = find(_processors.begin(), _processors.end(), _amp);
@@ -699,7 +709,6 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter
cerr << _name << " : got processor type " << prop->value() << endl;
boost::shared_ptr<Processor> processor;
- bool have_insert = false;
if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" ||
@@ -707,7 +716,6 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter
prop->value() == "audiounit") {
processor.reset (new PluginInsert(_session, node));
- have_insert = true;
} else if (prop->value() == "port") {
@@ -716,32 +724,66 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter
} else if (prop->value() == "send") {
processor.reset (new Send (_session, _mute_master, node));
- have_insert = true;
-
+
} else if (prop->value() == "meter") {
+ if (_meter) {
+ if (_meter->set_state (node)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ _meter.reset (new PeakMeter (_session, node));
processor = _meter;
- processor->set_state (node);
} else if (prop->value() == "amp") {
+
+ /* amp always exists */
processor = _amp;
- processor->set_state (node);
+ if (processor->set_state (node)) {
+ return false;
+ } else {
+ /* never any reason to add it */
+ return true;
+ }
} else if (prop->value() == "listen" || prop->value() == "deliver") {
/* XXX need to generalize */
- processor = _control_outs;
- processor->set_state (node);
+ } 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)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ _intreturn.reset (new InternalReturn (_session, node));
+ processor = _intreturn;
+
} else if (prop->value() == "main-outs") {
+ if (_main_outs) {
+ if (_main_outs->set_state (node)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ _main_outs.reset (new Delivery (_session, _output, _mute_master, node));
processor = _main_outs;
- processor->set_state (node);
} else {
-
error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
}
@@ -997,31 +1039,6 @@ Route::ab_plugins (bool forward)
}
-/* Figure out the streams that will feed into PreFader */
-ChanCount
-Route::pre_fader_streams() const
-{
- boost::shared_ptr<Processor> processor;
-
- /* Find the last pre-fader redirect that isn't a send; sends don't affect the number
- * of streams. */
- for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
- if ((*i) == _amp) {
- break;
- }
- if (boost::dynamic_pointer_cast<Send> (*i) == 0) {
- processor = *i;
- }
- }
-
- if (processor) {
- return processor->output_streams();
- } else {
- return _input->n_ports ();
- }
-}
-
-
/** Remove processors with a given placement.
* @param p Placement of processors to remove.
*/
@@ -1195,7 +1212,11 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
ChanCount out;
list< pair<ChanCount,ChanCount> > configuration;
uint32_t index = 0;
+
+ cerr << "Processor check with " << _processors.size() << endl;
+
for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++index) {
+ cerr << "Checking out " << (*p)->name() << " type = " << endl;
if ((*p)->can_support_io_configuration(in, out)) {
configuration.push_back(make_pair(in, out));
in = out;
@@ -1488,6 +1509,34 @@ Route::_set_state (const XMLNode& node, bool call_base)
} else {
_flags = Flag (0);
}
+
+ /* add all processors (except amp, which is always present) */
+
+ nlist = node.children();
+ 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);
+ } else if (prop->value() == "Output") {
+ _output->set_state (*child);
+ }
+ }
+
+ if (child->name() == X_("Processor")) {
+ processor_state.add_child_copy (*child);
+ }
+ }
+
+ set_processor_state (processor_state);
if ((prop = node.property (X_("phase-invert"))) != 0) {
set_phase_invert (prop->value()=="yes"?true:false);
@@ -1555,32 +1604,6 @@ Route::_set_state (const XMLNode& node, bool call_base)
}
}
- nlist = node.children();
- 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);
- } else if (prop->value() == "Output") {
- _output->set_state (*child);
- }
- }
-
- if (child->name() == X_("Processor")) {
- processor_state.add_child_copy (*child);
- }
- }
-
- set_processor_state (processor_state);
-
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
@@ -1642,21 +1665,30 @@ Route::set_processor_state (const XMLNode& node)
{
const XMLNodeList &nlist = node.children();
XMLNodeConstIterator niter;
- bool has_meter_processor = false; // legacy sessions don't
ProcessorList::iterator i, o;
- cerr << _name << " _set_processor_states\n";
+ dump_processors ("set processor states", _processors);
// Iterate through existing processors, remove those which are not in the state list
+
for (i = _processors.begin(); i != _processors.end(); ) {
+
+ /* leave amp alone, always */
+
+ if ((*i) == _amp) {
+ ++i;
+ continue;
+ }
+
ProcessorList::iterator tmp = i;
++tmp;
bool processorInStateList = false;
-
+
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
XMLProperty* id_prop = (*niter)->property(X_("id"));
+ cerr << "\tchecking " << id_prop->value() << endl;
if (id_prop && (*i)->id() == id_prop->value()) {
processorInStateList = true;
break;
@@ -1672,26 +1704,24 @@ Route::set_processor_state (const XMLNode& node)
// Iterate through state list and make sure all processors are on the track and in the correct order,
// set the state of existing processors according to the new state on the same go
+
i = _processors.begin();
for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) {
XMLProperty* prop = (*niter)->property ("type");
- if (prop && prop->value() == "meter") {
- has_meter_processor = true;
- }
-
o = i;
- if (prop->value() != "meter" && prop->value() != "amp" && prop->value() != "main-outs") {
-
- // Check whether the next processor in the list
-
+ // 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;
+ break;
}
++o;
@@ -1700,6 +1730,7 @@ Route::set_processor_state (const XMLNode& node)
// If the processor (*niter) is not on the route,
// create it and move it to the correct location
+
if (o == _processors.end()) {
if (add_processor_from_xml (**niter, i)) {
@@ -1708,10 +1739,11 @@ Route::set_processor_state (const XMLNode& node)
cerr << "Error restoring route: unable to restore processor" << endl;
}
- // Otherwise, the processor already exists; just
- // ensure it is at the location provided in the XML state
} else {
+ // Otherwise, the processor already exists; just
+ // ensure it is at the location provided in the XML state
+
if (i != o) {
boost::shared_ptr<Processor> tmp = (*o);
_processors.erase (o); // remove the old copy
@@ -1719,6 +1751,8 @@ Route::set_processor_state (const XMLNode& node)
--i; // move iterator to the correct processor
}
+ // and make it (just) so
+
(*i)->set_state (**niter);
}
}
@@ -1727,10 +1761,6 @@ Route::set_processor_state (const XMLNode& node)
the XML state represents a working signal route.
*/
- if (!has_meter_processor) {
- set_meter_point (_meter_point, NULL);
- }
-
processors_changed ();
}
@@ -1772,33 +1802,38 @@ Route::silence (nframes_t nframes)
}
}
-boost::shared_ptr<Delivery>
-Route::add_listener (boost::shared_ptr<IO> io, const string& listen_name)
+BufferSet*
+Route::get_return_buffer () const
{
- string name = _name;
- name += '[';
- name += listen_name;
- name += ']';
-
- boost::shared_ptr<Delivery> listener (new Delivery (_session, _mute_master, name, Delivery::Listen));
-
- /* As an IO, our control outs need as many IO outputs as we have outputs
- * (we track the changes in ::output_change_handler()).
- * As a processor, the listener is an identity processor
- * (i.e. it does not modify its input buffers whatsoever)
- */
-
- if (listener->output()->ensure_io (n_outputs(), true, this)) {
- return boost::shared_ptr<Delivery>();
+ 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->get_buffers ();
+ }
}
- add_processor (listener, PostFader);
+ return 0;
+}
- return listener;
+void
+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 ();
+ }
+ }
}
int
-Route::listen_via (boost::shared_ptr<IO> io, const string& listen_name)
+Route::listen_via (boost::shared_ptr<Route> route, const string& listen_name)
{
vector<string> ports;
vector<string>::const_iterator i;
@@ -1807,71 +1842,58 @@ Route::listen_via (boost::shared_ptr<IO> io, const string& listen_name)
Glib::RWLock::ReaderLock rm (_processor_lock);
for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
- boost::shared_ptr<const Delivery> d = boost::dynamic_pointer_cast<const Delivery>(*x);
+ boost::shared_ptr<const InternalSend> d = boost::dynamic_pointer_cast<const InternalSend>(*x);
- if (d && d->output() == io) {
+ if (d && d->target_route() == route) {
/* already listening via the specified IO: do nothing */
return 0;
}
}
}
-
- uint32_t ni = io->n_ports().n_total();
-
- for (uint32_t n = 0; n < ni; ++n) {
- ports.push_back (io->nth (n)->name());
- }
-
- if (ports.empty()) {
- return 0;
- }
- boost::shared_ptr<Delivery> listen_point = add_listener (io, listen_name);
-
- /* XXX hack for now .... until we can generalize listen points */
+ boost::shared_ptr<InternalSend> listener;
- _control_outs = listen_point;
+ try {
+ listener.reset (new InternalSend (_session, _mute_master, route));
- /* now connect to the named ports */
-
- ni = listen_point->output()->n_ports().n_total();
- size_t psize = ports.size();
+ } catch (failed_constructor& err) {
- for (size_t n = 0; n < ni; ++n) {
- if (listen_point->output()->connect (listen_point->output()->nth (n), ports[n % psize], this)) {
- error << string_compose (_("could not connect %1 to %2"),
- listen_point->output()->nth (n)->name(), ports[n % psize]) << endmsg;
- return -1;
- }
+ return -1;
}
+ add_processor (listener, PreFader);
return 0;
}
void
-Route::drop_listen (boost::shared_ptr<IO> io)
+Route::drop_listen (boost::shared_ptr<Route> route)
{
ProcessorStreams err;
ProcessorList::iterator tmp;
- Glib::RWLock::ReaderLock rm (_processor_lock);
+ Glib::RWLock::ReaderLock rl(_processor_lock);
+ rl.acquire ();
+ again:
for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ) {
- tmp = x;
- ++tmp;
-
- boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery>(*x);
+ boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
- if (d && d->output() == io) {
- /* already listening via the specified IO: do nothing */
+ if (d && d->target_route() == route) {
+ rl.release ();
remove_processor (*x, &err);
-
+ rl.acquire ();
+
+ /* list could have been demolished while we dropped the lock
+ so start over.
+ */
+
+ goto again;
}
-
- x = tmp;
}
+
+ rl.release ();
}
void
@@ -1939,25 +1961,30 @@ Route::set_comment (string cmt, void *src)
}
bool
-Route::feeds (boost::shared_ptr<IO> other)
+Route::feeds (boost::shared_ptr<Route> other)
{
- if (_output->connected_to (other)) {
+ // cerr << _name << endl;
+
+ if (_output->connected_to (other->input())) {
+ // cerr << "\tdirect FEEDS " << other->name() << endl;
return true;
}
- /* check IOProcessors which may also interconnect Routes */
-
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->output() && iop->output()->connected_to (other)) {
+ if (iop->feeds (other)) {
+ // cerr << "\tIOP " << iop->name() << " feeds " << other->name() << endl;
return true;
+ } else {
+ // cerr << "\tIOP " << iop->name() << " does NOT feeds " << other->name() << endl;
}
}
}
+ // cerr << "\tdoes NOT FEED " << other->name() << endl;
return false;
}
@@ -2418,15 +2445,15 @@ Route::set_name (const string& str)
}
boost::shared_ptr<Send>
-Route::send_for (boost::shared_ptr<const IO> target) const
+Route::internal_send_for (boost::shared_ptr<const Route> target) const
{
Glib::RWLock::ReaderLock lm (_processor_lock);
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
- boost::shared_ptr<Send> send;
+ boost::shared_ptr<InternalSend> send;
- if ((send = boost::dynamic_pointer_cast<Send>(*i)) != 0) {
- if (send->output()->connected_to (target)) {
+ if ((send = boost::dynamic_pointer_cast<InternalSend>(*i)) != 0) {
+ if (send->target_route() == target) {
return send;
}
}