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.cc504
1 files changed, 297 insertions, 207 deletions
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 06b9308d35..67ff44a709 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -63,15 +63,12 @@ using namespace PBD;
uint32_t Route::order_key_cnt = 0;
sigc::signal<void,const char*> Route::SyncOrderKeys;
-Route::Route (Session& sess, string name, Flag flg,
- DataType default_type, ChanCount in, ChanCount out)
- : IO (sess, name, default_type, in, ChanCount::INFINITE, out, ChanCount::INFINITE)
+Route::Route (Session& sess, string name, Flag flg, DataType default_type)
+ : IO (sess, name, default_type)
, _flags (flg)
, _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl))
, _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
{
- _configured_inputs = in;
- _configured_outputs = out;
init ();
}
@@ -129,14 +126,11 @@ Route::init ()
/* amp & meter belong to IO but need to be added to our processor list */
- _amp->set_sort_key (0);
- _meter->set_sort_key (1);
- add_processor (_amp);
- add_processor (_meter);
+ add_processor (_amp, PostFader);
+ add_processor (_meter, PreFader);
_main_outs.reset (new Delivery (_session, this, _name, Delivery::Main));
- ProcessorList::iterator i = _processors.end();
- add_processor (_main_outs, 0, &i);
+ add_processor (_main_outs, PostFader);
}
Route::~Route ()
@@ -598,31 +592,59 @@ dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& p
cerr << name << " {" << endl;
for (list<boost::shared_ptr<Processor> >::const_iterator p = procs.begin();
p != procs.end(); ++p) {
- cerr << "\t" << (*p)->sort_key() << ": " << (*p)->name() << endl;
+ cerr << "\t" << (*p)->name() << endl;
}
cerr << "}" << endl;
}
+Route::ProcessorList::iterator
+Route::prefader_iterator()
+{
+ Glib::RWLock::ReaderLock lm (_processor_lock);
+ return find (_processors.begin(), _processors.end(), _amp);
+}
-struct ProcessorSortByKey {
- bool operator() (boost::shared_ptr<Processor> a, boost::shared_ptr<Processor> b) {
- return a->sort_key() < b->sort_key();
- }
-};
-
-uint32_t
-Route::fader_sort_key() const
+int
+Route::add_processor (boost::shared_ptr<Processor> processor, Placement placement, ProcessorStreams* err)
{
- return _amp->sort_key();
+ ProcessorList::iterator loc;
+
+ /* XXX this is not thread safe - we don't hold the lock across determining the iter
+ to add before and actually doing the insertion. dammit.
+ */
+
+ if (placement == PreFader) {
+ /* generic pre-fader: insert immediately before the amp */
+ loc = find(_processors.begin(), _processors.end(), _amp);
+ } else {
+ /* generic post-fader: insert at end */
+ loc = _processors.end();
+
+ if (processor->visible() && !_processors.empty()) {
+ /* check for invisible processors stacked at the end and leave them there */
+ ProcessorList::iterator p;
+ p = _processors.end();
+ --p;
+ cerr << "Let's check " << (*p)->name() << " vis ? " << (*p)->visible() << endl;
+ while (!(*p)->visible() && p != _processors.begin()) {
+ --p;
+ }
+ ++p;
+ loc = p;
+ }
+ }
+
+ return add_processor (processor, loc, err);
}
+
/** Add a processor to the route.
* If @a iter is not NULL, it must point to an iterator in _processors and the new
* processor will be inserted immediately before this location. Otherwise,
* @a position is used.
*/
int
-Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err, ProcessorList::iterator* iter)
+Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::iterator iter, ProcessorStreams* err)
{
ChanCount old_pms = processor_max_streams;
@@ -630,9 +652,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
return 1;
}
- cerr << "Adding a processor called " << processor->name() << " sk = " << processor->sort_key()
- << ((iter == 0) ? " NO given position " : " with given position")
- << endl;
+ cerr << "Adding a processor called " << processor->name() << endl;
{
Glib::RWLock::WriterLock lm (_processor_lock);
@@ -645,15 +665,10 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
if (processor == _amp || processor == _meter || processor == _main_outs) {
// Ensure only one of these are in the list at any time
if (loc != _processors.end()) {
- if (iter) {
- if (*iter == loc) { // Already in place, do nothing
- return 0;
- } else { // New position given, relocate
- _processors.erase(loc);
- }
- } else { // Insert at end
- _processors.erase(loc);
- loc = _processors.end();
+ if (iter == loc) { // Already in place, do nothing
+ return 0;
+ } else { // New position given, relocate
+ _processors.erase (loc);
}
}
@@ -662,41 +677,26 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
cerr << "ERROR: Processor added to route twice!" << endl;
return 1;
}
- }
- if (iter) {
- // Use position given by user
- loc = *iter;
- } else {
- if (processor->sort_key() == 0) {
- /* generic pre-fader: insert immediately before the amp */
- loc = find(_processors.begin(), _processors.end(), _amp);
- } else if (processor->sort_key() > _processors.size()) {
- /* generic post-fader: insert at end */
- loc = _processors.end();
- } else {
- /* find insert point */
- ProcessorSortByKey cmp;
- loc = upper_bound (_processors.begin(), _processors.end(), processor, cmp);
- }
- }
-
- // Update sort keys
- if (loc == _processors.end()) {
- processor->set_sort_key(_processors.size());
- } else {
- processor->set_sort_key((*loc)->sort_key());
- for (ProcessorList::iterator p = loc; p != _processors.end(); ++p) {
- (*p)->set_sort_key((*p)->sort_key() + 1);
- }
+ loc = iter;
}
- _processors.insert(loc, processor);
+ cerr << "Adding " << processor->name() << endl;
+
+ _processors.insert (loc, processor);
// Set up processor list channels. This will set processor->[input|output]_streams(),
// configure redirect ports properly, etc.
- if (configure_processors_unlocked (err)) {
+
+ ProcessorStreams rerr;
+
+ if (configure_processors_unlocked (&rerr)) {
+
dump_processors(_name + "bad config", _processors);
+ if (err) {
+ *err = rerr;
+ }
+ cerr << "Error at proc " << rerr.index << " with input of " << rerr.count << endl;
ProcessorList::iterator ploc = loc;
--ploc;
_processors.erase(ploc);
@@ -736,8 +736,146 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
return 0;
}
+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);
+ } else {
+ /* generic post-fader: insert at end */
+ loc = _processors.end();
+ }
+
+ return add_processor_from_xml (node, loc);
+}
+
+bool
+Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter)
+{
+ const XMLProperty *prop;
+
+ // legacy sessions use a different node name for sends
+ if (node.name() == "Send") {
+
+ try {
+ boost::shared_ptr<Send> send (new Send (_session, node));
+ add_processor (send, iter);
+ return true;
+ }
+
+ catch (failed_constructor &err) {
+ error << _("Send construction failed") << endmsg;
+ return false;
+ }
+
+ } else if (node.name() == "Processor") {
+
+ try {
+ if ((prop = node.property ("type")) != 0) {
+
+ boost::shared_ptr<Processor> processor;
+ bool have_insert = false;
+
+ if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
+ prop->value() == "lv2" ||
+ prop->value() == "vst" ||
+ prop->value() == "audiounit") {
+
+ processor.reset (new PluginInsert(_session, node));
+ have_insert = true;
+
+ } else if (prop->value() == "port") {
+
+ processor.reset (new PortInsert (_session, node));
+
+ } else if (prop->value() == "send") {
+
+ processor.reset (new Send (_session, node));
+ have_insert = true;
+
+ } else if (prop->value() == "meter") {
+
+ processor = _meter;
+
+ } else if (prop->value() == "amp") {
+
+ processor = _amp;
+
+ } else if (prop->value() == "listen" || prop->value() == "deliver") {
+
+ /* XXX need to generalize */
+
+ processor = _control_outs;
+
+ } else if (prop->value() == "main-outs") {
+
+ processor = _main_outs;
+
+ } else {
+
+ error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
+ }
+
+ if (iter == _processors.end() && processor->visible() && !_processors.empty()) {
+ /* check for invisible processors stacked at the end and leave them there */
+ ProcessorList::iterator p;
+ p = _processors.end();
+ --p;
+ cerr << "Let's check " << (*p)->name() << " vis ? " << (*p)->visible() << endl;
+ while (!(*p)->visible() && p != _processors.begin()) {
+ --p;
+ }
+ ++p;
+ iter = p;
+ }
+
+ return (add_processor (processor, iter) == 0);
+
+ } else {
+ error << _("Processor XML node has no type property") << endmsg;
+ }
+ }
+
+ catch (failed_constructor &err) {
+ warning << _("processor could not be created. Ignored.") << endmsg;
+ return false;
+ }
+ }
+ return false;
+}
+
int
-Route::add_processors (const ProcessorList& others, ProcessorStreams* err, uint32_t first_sort_key)
+Route::add_processors (const ProcessorList& others, Placement placement, ProcessorStreams* err)
+{
+ ProcessorList::iterator loc;
+ if (placement == PreFader) {
+ /* generic pre-fader: insert immediately before the amp */
+ loc = find(_processors.begin(), _processors.end(), _amp);
+ } else {
+ /* generic post-fader: insert at end */
+ loc = _processors.end();
+
+ if (!_processors.empty()) {
+ /* check for invisible processors stacked at the end and leave them there */
+ ProcessorList::iterator p;
+ p = _processors.end();
+ --p;
+ cerr << "Let's check " << (*p)->name() << " vis ? " << (*p)->visible() << endl;
+ while (!(*p)->visible() && p != _processors.begin()) {
+ --p;
+ }
+ ++p;
+ loc = p;
+ }
+ }
+
+ return add_processors (others, loc, err);
+}
+
+int
+Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter, ProcessorStreams* err)
{
/* NOTE: this is intended to be used ONLY when copying
processors from another Route. Hence the subtle
@@ -750,29 +888,16 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err, uint3
return 1;
}
+ if (others.empty()) {
+ return 0;
+ }
+
{
Glib::RWLock::WriterLock lm (_processor_lock);
-
- ProcessorList::iterator loc;
ProcessorList::iterator existing_end = _processors.end();
--existing_end;
- ChanCount potential_max_streams = ChanCount::max(input_minimum(), output_minimum());
-
- if (first_sort_key == 0) {
- /* generic pre-fader: insert immediately before the amp */
- cerr << "Add new procs at amp, sk = " << first_sort_key << endl;
- loc = find(_processors.begin(), _processors.end(), _amp);
- } else if (first_sort_key > _processors.size()) {
- /* generic post-fader: insert at end */
- cerr << "Add new procs at end, sk = " << first_sort_key << endl;
- loc = _processors.end();
- } else {
- /* find insert point */
- ProcessorSortByKey cmp;
- cerr << "Add new procs at sk = " << first_sort_key << endl;
- loc = upper_bound (_processors.begin(), _processors.end(), others.front(), cmp);
- }
+ ChanCount potential_max_streams = ChanCount::max (n_inputs(), n_outputs());
for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) {
@@ -797,7 +922,7 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err, uint3
// Ensure peak vector sizes before the plugin is activated
_meter->configure_io (potential_max_streams, potential_max_streams);
- _processors.insert (loc, *i);
+ _processors.insert (iter, *i);
if (configure_processors_unlocked (err)) {
++existing_end;
@@ -1150,16 +1275,18 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
_in_configure_processors = true;
// Check each processor in order to see if we can configure as requested
- ChanCount in = _configured_inputs;
+ ChanCount in = n_inputs();
ChanCount out;
list< pair<ChanCount,ChanCount> > configuration;
uint32_t index = 0;
for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++index) {
- (*p)->set_sort_key(index);
+ cerr << "Can " << (*p)->name() << " support in= " << in << " out= " << out;
if ((*p)->can_support_io_configuration(in, out)) {
+ cerr << " yes\n";
configuration.push_back(make_pair(in, out));
in = out;
} else {
+ cerr << " no\n";
if (err) {
err->index = index;
err->count = in;
@@ -1181,7 +1308,7 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
// Ensure route outputs match last processor's outputs
if (out != n_outputs()) {
- ensure_io(_configured_inputs, out, false, this);
+ ensure_io (n_inputs(), out, false, this);
}
_in_configure_processors = false;
@@ -1244,21 +1371,68 @@ Route::all_processors_active (Placement p, bool state)
}
int
-Route::sort_processors (ProcessorStreams* err)
+Route::reorder_processors (const ProcessorList& new_order, Placement placement, ProcessorStreams* err)
{
{
- ProcessorSortByKey comparator;
Glib::RWLock::WriterLock lm (_processor_lock);
ChanCount old_pms = processor_max_streams;
+ ProcessorList::iterator oiter;
+ ProcessorList::const_iterator niter;
+ ProcessorList as_it_was_before = _processors;
+ ProcessorList as_it_will_be;
+ ProcessorList::iterator start, end;
- /* the sweet power of C++ ... */
+ dump_processors (_name + " PreReorder", _processors);
+ placement_range (placement, start, end);
- ProcessorList as_it_was_before = _processors;
+ oiter = start;
+ niter = new_order.begin();
- dump_processors (_name + " PRESORT", _processors);
+ while (oiter != end && 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.
+
+ 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 == end) {
+
+ /* no more elements in the old list, so just stick the rest of
+ the new order onto the temp list.
+ */
+
+ as_it_will_be.insert (as_it_will_be.end(), niter, new_order.end());
+
+ } else {
+
+ if (!(*oiter)->visible()) {
+
+ as_it_will_be.push_back (*oiter);
+
+ } else {
+
+ /* visible processor: check that its in the new order */
+
+ if (find (new_order.begin(), new_order.end(), (*oiter)) == new_order.end()) {
+ /* deleted: do nothing */
+ } else {
+ /* ignore this one, and add the next item from the new order instead */
+ as_it_will_be.push_back (*niter);
+ ++niter;
+ }
+ }
+
+ /* now remove from old order - its taken care of no matter what */
+ oiter = _processors.erase (oiter);
+ }
+ }
+
+ _processors.insert (end, as_it_will_be.begin(), as_it_will_be.end());
+
+ dump_processors (_name + " PostReorder", _processors);
- _processors.sort (comparator);
-
if (configure_processors_unlocked (err)) {
_processors = as_it_was_before;
processor_max_streams = old_pms;
@@ -1267,6 +1441,7 @@ Route::sort_processors (ProcessorStreams* err)
}
dump_processors (_name + " sorted", _processors);
+ /* do we really need to do this every time? */
reset_panner ();
processors_changed (); /* EMIT SIGNAL */
@@ -1440,96 +1615,12 @@ Route::set_deferred_state ()
nlist = deferred_state->children();
- for (niter = nlist.begin(); niter != nlist.end(); ++niter){
- add_processor_from_xml (**niter);
- }
+ _set_processor_states (nlist);
delete deferred_state;
deferred_state = 0;
}
-bool
-Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator* iter)
-{
- const XMLProperty *prop;
-
- // legacy sessions use a different node name for sends
- if (node.name() == "Send") {
-
- try {
- boost::shared_ptr<Send> send (new Send (_session, node));
- add_processor (send, 0, iter);
- return true;
- }
-
- catch (failed_constructor &err) {
- error << _("Send construction failed") << endmsg;
- return false;
- }
-
- } else if (node.name() == "Processor") {
-
- try {
- if ((prop = node.property ("type")) != 0) {
-
- boost::shared_ptr<Processor> processor;
- bool have_insert = false;
-
- if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
- prop->value() == "lv2" ||
- prop->value() == "vst" ||
- prop->value() == "audiounit") {
-
- processor.reset (new PluginInsert(_session, node));
- have_insert = true;
-
- } else if (prop->value() == "port") {
-
- processor.reset (new PortInsert (_session, node));
-
- } else if (prop->value() == "send") {
-
- processor.reset (new Send (_session, node));
- have_insert = true;
-
- } else if (prop->value() == "meter") {
-
- processor = _meter;
-
- } else if (prop->value() == "amp") {
-
- processor = _amp;
-
- } else if (prop->value() == "listen" || prop->value() == "deliver") {
-
- /* XXX need to generalize */
-
- processor = _control_outs;
-
- } else if (prop->value() == "main-outs") {
-
- processor = _main_outs;
-
- } else {
-
- error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
- }
-
- return (add_processor (processor, 0, iter) == 0);
-
- } else {
- error << _("Processor XML node has no type property") << endmsg;
- }
- }
-
- catch (failed_constructor &err) {
- warning << _("processor could not be created. Ignored.") << endmsg;
- return false;
- }
- }
- return false;
-}
-
int
Route::set_state (const XMLNode& node)
{
@@ -1671,31 +1762,23 @@ Route::_set_state (const XMLNode& node, bool call_base)
}
}
- XMLNodeList processor_nodes;
- bool has_meter_processor = false; // legacy sessions don't
-
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
-
+
child = *niter;
if (child->name() == X_("Send") || child->name() == X_("Processor")) {
- processor_nodes.push_back(child);
- if ((prop = child->property (X_("type"))) != 0 && prop->value() == "meter") {
- has_meter_processor = true;
- }
+ deferred_state->add_child_copy (*child);
}
-
}
- _set_processor_states(processor_nodes);
- if (!has_meter_processor) {
- set_meter_point(_meter_point, NULL);
+ if (ports_legal) {
+ _set_processor_states (deferred_state->children());
+ delete deferred_state;
+ deferred_state = 0;
}
- processors_changed ();
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
- // All processors have been applied already
if (child->name() == X_("Automation")) {
@@ -1752,9 +1835,11 @@ void
Route::_set_processor_states(const XMLNodeList &nlist)
{
XMLNodeConstIterator niter;
-
+ bool has_meter_processor = false; // legacy sessions don't
ProcessorList::iterator i, o;
+ cerr << "Setting processor states with in = " << n_inputs() << endl;
+
// Iterate through existing processors, remove those which are not in the state list
for (i = _processors.begin(); i != _processors.end(); ) {
ProcessorList::iterator tmp = i;
@@ -1785,7 +1870,11 @@ Route::_set_processor_states(const XMLNodeList &nlist)
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") {
@@ -1806,7 +1895,7 @@ Route::_set_processor_states(const XMLNodeList &nlist)
// create it and move it to the correct location
if (o == _processors.end()) {
- if (add_processor_from_xml (**niter, &i)) {
+ if (add_processor_from_xml (**niter, i)) {
--i; // move iterator to the newly inserted processor
} else {
cerr << "Error restoring route: unable to restore processor" << endl;
@@ -1818,7 +1907,6 @@ Route::_set_processor_states(const XMLNodeList &nlist)
if (i != o) {
boost::shared_ptr<Processor> tmp = (*o);
- cerr << "move proc from state\n";
_processors.erase (o); // remove the old copy
_processors.insert (i, tmp); // insert the processor at the correct location
--i; // move iterator to the correct processor
@@ -1827,6 +1915,19 @@ Route::_set_processor_states(const XMLNodeList &nlist)
(*i)->set_state (**niter);
}
}
+
+ /* note: there is no configure_processors() call because we figure that
+ the XML state represents a working signal route.
+ */
+
+ if (!has_meter_processor) {
+ set_meter_point (_meter_point, NULL);
+ }
+
+ processors_changed ();
+
+
+
}
void
@@ -1887,8 +1988,7 @@ Route::add_listener (boost::shared_ptr<IO> io, const string& listen_name)
return boost::shared_ptr<Delivery>();
}
- listener->set_sort_key (_meter->sort_key() + 1);
- add_processor (listener, NULL);
+ add_processor (listener, PostFader);
return listener;
}
@@ -2360,16 +2460,6 @@ Route::set_meter_point (MeterPoint p, void *src)
}
_processors.insert(loc, _meter);
- // Update sort key
- if (loc == _processors.end()) {
- _meter->set_sort_key(_processors.size());
- } else {
- _meter->set_sort_key((*loc)->sort_key());
- for (ProcessorList::iterator p = loc; p != _processors.end(); ++p) {
- (*p)->set_sort_key((*p)->sort_key() + 1);
- }
- }
-
meter_change (src); /* EMIT SIGNAL */
processors_changed (); /* EMIT SIGNAL */
_session.set_dirty ();