diff options
Diffstat (limited to 'libs/ardour/route.cc')
-rw-r--r-- | libs/ardour/route.cc | 533 |
1 files changed, 282 insertions, 251 deletions
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 931ae9a996..db06368371 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -20,6 +20,7 @@ #include <cmath> #include <fstream> #include <cassert> +#include <algorithm> #include <sigc++/bind.h> #include "pbd/xml++.h" @@ -35,7 +36,6 @@ #include "ardour/buffer.h" #include "ardour/buffer_set.h" #include "ardour/configuration.h" -#include "ardour/control_outputs.h" #include "ardour/cycle_timer.h" #include "ardour/dB.h" #include "ardour/ladspa_plugin.h" @@ -64,7 +64,7 @@ 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) + DataType default_type, ChanCount in, ChanCount out) : IO (sess, name, default_type, in, ChanCount::INFINITE, out, ChanCount::INFINITE) , _flags (flg) , _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl)) @@ -73,6 +73,7 @@ Route::Route (Session& sess, string name, Flag flg, _configured_inputs = in; _configured_outputs = out; init (); + } Route::Route (Session& sess, const XMLNode& node, DataType default_type) @@ -123,11 +124,19 @@ 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: amp, meter, main outs */ + + /* 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, NULL); - add_processor (_meter, NULL); + add_processor (_amp); + add_processor (_meter); + + _main_outs.reset (new Delivery (_session, this, _name, Delivery::Main)); + ProcessorList::iterator i = _processors.end(); + add_processor (_main_outs, 0, &i); } Route::~Route () @@ -294,8 +303,8 @@ Route::set_gain (gain_t val, void *src) */ void Route::process_output_buffers (BufferSet& bufs, - nframes_t start_frame, nframes_t end_frame, nframes_t nframes, - bool with_processors, int declick) + sframes_t start_frame, sframes_t end_frame, nframes_t nframes, + bool with_processors, int declick) { ProcessorList::iterator i; bool mute_declick_applied = false; @@ -345,9 +354,8 @@ Route::process_output_buffers (BufferSet& bufs, || Config->get_monitoring_model() == SoftwareMonitoring); // mute at the amp if... - _amp->apply_mute( - !_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader, - mute_gain, dmg); + _amp->apply_mute (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader, + mute_gain, dmg); _amp->set_gain (_gain, dg); @@ -356,17 +364,32 @@ Route::process_output_buffers (BufferSet& bufs, SET UP CONTROL OUTPUTS ----------------------------------------------------------------------------------------- */ - boost::shared_ptr<ControlOutputs> co = _control_outs; + boost::shared_ptr<Delivery> co = _control_outs; if (co) { // deliver control outputs unless we're ... - co->deliver (!( - dsg == 0 || // muted by solo of another track - (dmg == 0 && _mute_affects_control_outs) || // or muted by mute of this track - !recording_without_monitoring )); // or rec-enabled w/o s/w monitoring + bool self_mute = ((dmg == 0 && _mute_affects_control_outs) || // or muted by mute of this track + !recording_without_monitoring); // or rec-enabled w/o s/w monitoring + bool other_mute = (dsg == 0); // muted by solo of another track + + co->set_self_mute (self_mute); + co->set_nonself_mute (other_mute); } - /* ------------------------------------------------------------------------------------------- + SET UP MAIN OUTPUT STAGE + ----------------------------------------------------------------------------------------- */ + + bool solo_audible = dsg > 0; + bool mute_audible = dmg > 0 || !_mute_affects_main_outs; + + bool silent_anyway = (_gain == 0 && !_amp->apply_gain_automation()); + bool muted_by_other_solo = (!solo_audible && (Config->get_solo_model() != SoloBus)); + bool muted_by_self = !mute_audible; + + _main_outs->set_nonself_mute (recording_without_monitoring || muted_by_other_solo || silent_anyway); + _main_outs->set_self_mute (muted_by_self); + + /* ------------------------------------------------------------------------------------------- GLOBAL DECLICK (for transport changes etc.) ----------------------------------------------------------------------------------------- */ @@ -413,33 +436,23 @@ Route::process_output_buffers (BufferSet& bufs, } } - /* ------------------------------------------------------------------------------------------- - PROCESSORS (including Amp (fader) and Meter) + and go .... ----------------------------------------------------------------------------------------- */ - if (with_processors) { - Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK); - if (rm.locked()) { - //if (!bufs.is_silent()) { - for (i = _processors.begin(); i != _processors.end(); ++i) { - bufs.set_count(ChanCount::max(bufs.count(), (*i)->input_streams())); - (*i)->run_in_place (bufs, start_frame, end_frame, nframes); - bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams())); - } - /*} else { - for (i = _processors.begin(); i != _processors.end(); ++i) { - (*i)->silence (nframes); - bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams())); - } - }*/ - } + Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK); + + if (rm.locked()) { + for (i = _processors.begin(); i != _processors.end(); ++i) { + bufs.set_count(ChanCount::max(bufs.count(), (*i)->input_streams())); + (*i)->run_in_place (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())); } } - /* ------------------------------------------------------------------------------------------- POST-FADER MUTING @@ -450,64 +463,11 @@ Route::process_output_buffers (BufferSet& bufs, mute_gain = dmg; mute_declick_applied = true; } + if (mute_gain == 0.0f && dmg == 0.0f) { bufs.is_silent(true); } - - /* ------------------------------------------------------------------------------------------- - MAIN OUTPUT STAGE - ----------------------------------------------------------------------------------------- */ - - bool solo_audible = dsg > 0; - bool mute_audible = dmg > 0 || !_mute_affects_main_outs; - - if (n_outputs().get(_default_type) == 0) { - - /* relax */ - - } else if (recording_without_monitoring) { - - IO::silence (nframes); - - } else { - - if ( // we're silent anyway - (_gain == 0 && !_amp->apply_gain_automation()) || - - // or muted by solo of another track, but not using control outs for solo - (!solo_audible && (Config->get_solo_model() != SoloBus)) || - - // or muted by mute of this track - !mute_audible - ) { - - /* don't use Route::silence() here, because that causes - all outputs (sends, port processors, etc. to be silent). - */ - IO::silence (nframes); - - } else { - - deliver_output(bufs, start_frame, end_frame, nframes); - - } - - } - - /* ------------------------------------------------------------------------------------------- - POST-FADER METERING - ----------------------------------------------------------------------------------------- */ - - /* TODO: Processor-list-ification needs to go further for this to be cleanly possible... - if (meter && (_meter_point == MeterPostFader)) { - if ((_gain == 0 && !apply_gain_automation) || dmg == 0) { - _meter->reset(); - } else { - _meter->run_in_place(output_buffers(), start_frame, end_frame, nframes); - } - }*/ - // at this point we've reached the desired mute gain regardless mute_gain = dmg; } @@ -527,7 +487,7 @@ Route::setup_peak_meters() } void -Route::passthru (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick) +Route::passthru (sframes_t start_frame, sframes_t end_frame, nframes_t nframes, int declick) { BufferSet& bufs = _session.get_scratch_buffers(n_process_buffers()); @@ -539,7 +499,7 @@ Route::passthru (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, } void -Route::passthru_silence (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick) +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); } @@ -643,13 +603,26 @@ dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& p cerr << "}" << endl; } + +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 +{ + return _amp->sort_key(); +} + /** 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, Placement placement) +Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err, ProcessorList::iterator* iter) { ChanCount old_pms = processor_max_streams; @@ -657,6 +630,10 @@ 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; + { Glib::RWLock::WriterLock lm (_processor_lock); @@ -665,8 +642,8 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), processor); - if (processor == _amp || processor == _meter) { - // Ensure only one amp and one meter are in the list at any time + 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 @@ -687,17 +664,21 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* } } - // Use position given by user if (iter) { + // Use position given by user loc = *iter; - - // Insert immediately before the amp - } else if (placement == PreFader) { - loc = find(_processors.begin(), _processors.end(), _amp); - - // Insert at end } else { - loc = _processors.end(); + 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 @@ -715,11 +696,12 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* // Set up processor list channels. This will set processor->[input|output]_streams(), // configure redirect ports properly, etc. if (configure_processors_unlocked (err)) { - dump_processors(_name, _processors); + dump_processors(_name + "bad config", _processors); ProcessorList::iterator ploc = loc; --ploc; _processors.erase(ploc); configure_processors_unlocked (0); // it worked before we tried to add it ... + cerr << "Bad IO config\n"; return -1; } @@ -733,8 +715,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* } // Ensure peak vector sizes before the plugin is activated - ChanCount potential_max_streams = ChanCount::max( - processor->input_streams(), processor->output_streams()); + ChanCount potential_max_streams = ChanCount::max (processor->input_streams(), processor->output_streams()); _meter->configure_io (potential_max_streams, potential_max_streams); @@ -749,15 +730,14 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* reset_panner (); } - dump_processors (_name, _processors); + dump_processors (_name + " added one", _processors); processors_changed (); /* EMIT SIGNAL */ - return 0; } int -Route::add_processors (const ProcessorList& others, ProcessorStreams* err, Placement placement) +Route::add_processors (const ProcessorList& others, ProcessorStreams* err, uint32_t first_sort_key) { /* NOTE: this is intended to be used ONLY when copying processors from another Route. Hence the subtle @@ -773,10 +753,26 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err, Place { 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); + } for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) { @@ -800,11 +796,7 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err, Place // Ensure peak vector sizes before the plugin is activated _meter->configure_io (potential_max_streams, potential_max_streams); - - ProcessorList::iterator loc = (placement == PreFader) - ? find(_processors.begin(), _processors.end(), _amp) - : _processors.end(); - + _processors.insert (loc, *i); if (configure_processors_unlocked (err)) { @@ -824,7 +816,7 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err, Place reset_panner (); } - dump_processors (_name, _processors); + dump_processors (_name + " added several", _processors); processors_changed (); /* EMIT SIGNAL */ return 0; @@ -1003,7 +995,8 @@ Route::clear_processors (Placement p) { Glib::RWLock::WriterLock lm (_processor_lock); ProcessorList new_list; - + ProcessorStreams err; + ProcessorList::iterator amp_loc = find(_processors.begin(), _processors.end(), _amp); if (p == PreFader) { // Get rid of PreFader processors @@ -1027,9 +1020,9 @@ Route::clear_processors (Placement p) } _processors = new_list; + configure_processors_unlocked (&err); // this can't fail } - /* FIXME: can't see how this test can ever fire */ if (processor_max_streams != old_pms) { reset_panner (); } @@ -1046,7 +1039,9 @@ Route::clear_processors (Placement p) int Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err) { - if (processor == _amp || processor == _meter) { + /* these can never be removed */ + + if (processor == _amp || processor == _meter || processor == _main_outs) { return 0; } @@ -1063,18 +1058,13 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream ProcessorList::iterator i; bool removed = false; - for (i = _processors.begin(); i != _processors.end(); ++i) { + for (i = _processors.begin(); i != _processors.end(); ) { if (*i == processor) { - ProcessorList::iterator tmp; - /* move along, see failure case for configure_processors() where we may need to reprocessor the processor. */ - tmp = i; - ++tmp; - /* stop redirects that send signals to JACK ports from causing noise as a result of no longer being run. @@ -1086,12 +1076,13 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream redirect->io()->disconnect_inputs (this); redirect->io()->disconnect_outputs (this); } - - _processors.erase (i); - - i = tmp; + + i = _processors.erase (i); removed = true; break; + + } else { + ++i; } _user_latency = 0; @@ -1130,7 +1121,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream processor->drop_references (); - dump_processors (_name, _processors); + dump_processors (_name + " removed one", _processors); processors_changed (); /* EMIT SIGNAL */ return 0; @@ -1252,17 +1243,11 @@ Route::all_processors_active (Placement p, bool state) _session.set_dirty (); } -struct ProcessorSorter { - bool operator() (boost::shared_ptr<const Processor> a, boost::shared_ptr<const Processor> b) { - return a->sort_key() < b->sort_key(); - } -}; - int Route::sort_processors (ProcessorStreams* err) { { - ProcessorSorter comparator; + ProcessorSortByKey comparator; Glib::RWLock::WriterLock lm (_processor_lock); ChanCount old_pms = processor_max_streams; @@ -1270,6 +1255,8 @@ Route::sort_processors (ProcessorStreams* err) ProcessorList as_it_was_before = _processors; + dump_processors (_name + " PRESORT", _processors); + _processors.sort (comparator); if (configure_processors_unlocked (err)) { @@ -1279,6 +1266,7 @@ Route::sort_processors (ProcessorStreams* err) } } + dump_processors (_name + " sorted", _processors); reset_panner (); processors_changed (); /* EMIT SIGNAL */ @@ -1356,12 +1344,6 @@ Route::state(bool full_state) remote_control_node->add_property (X_("id"), buf); node->add_child_nocopy (*remote_control_node); - if (_control_outs) { - XMLNode* cnode = new XMLNode (X_("ControlOuts")); - cnode->add_child_nocopy (_control_outs->io()->state (full_state)); - node->add_child_nocopy (*cnode); - } - if (_comment.length()) { XMLNode *cmt = node->add_child ("Comment"); cmt->add_content (_comment); @@ -1517,7 +1499,17 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator* ite } 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; @@ -1712,27 +1704,8 @@ Route::_set_state (const XMLNode& node, bool call_base) } } else if (child->name() == X_("ControlOuts")) { - - string coutname = _name; - coutname += _("[control]"); - _control_outs = boost::shared_ptr<ControlOutputs> ( - new ControlOutputs (_session, new IO (_session, coutname))); - - /* fix up the control out name in the XML before setting it. - Otherwise track templates don't work because the control - outs end up with the stored template name, rather than - the new name of the track based on the template. - */ - - XMLProperty* prop = (*child->children().begin())->property ("name"); - if (prop) { - prop->set_value (coutname); - } - - _control_outs->io()->set_state (**(child->children().begin())); - _control_outs->set_sort_key (_meter->sort_key() + 1); - add_processor (_control_outs, 0); + /* ignore this - deprecated */ } else if (child->name() == X_("Comment")) { @@ -1779,7 +1752,6 @@ void Route::_set_processor_states(const XMLNodeList &nlist) { XMLNodeConstIterator niter; - char buf[64]; ProcessorList::iterator i, o; @@ -1790,21 +1762,12 @@ Route::_set_processor_states(const XMLNodeList &nlist) bool processorInStateList = false; - (*i)->id().print (buf, sizeof (buf)); - for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - // legacy sessions (IOProcessor as a child of Processor, both is-a IO) - XMLNode* ioproc_node = (*niter)->child(X_("IOProcessor")); - if (ioproc_node && strncmp(buf, ioproc_node->child(X_("IO"))->property(X_("id"))->value().c_str(), sizeof(buf)) == 0) { + XMLProperty* id_prop = (*niter)->property(X_("id")); + if (id_prop && (*i)->id() == id_prop->value()) { processorInStateList = true; break; - } else { - XMLProperty* id_prop = (*niter)->property(X_("id")); - if (id_prop && strncmp(buf, id_prop->value().c_str(), sizeof(buf)) == 0) { - processorInStateList = true; - } - break; } } @@ -1815,56 +1778,53 @@ Route::_set_processor_states(const XMLNodeList &nlist) i = tmp; } - Placement placement = PreFader; - // 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) { - // Check whether the next processor in the list + for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) { + + XMLProperty* prop = (*niter)->property ("type"); + o = i; - while (o != _processors.end()) { - (*o)->id().print (buf, sizeof (buf)); - XMLNode* ioproc_node = (*niter)->child(X_("IOProcessor")); - if (ioproc_node && strncmp(buf, ioproc_node->child(X_("IO"))->property(X_("id"))->value().c_str(), sizeof(buf)) == 0) { - break; - } else { + if (prop->value() != "meter" && prop->value() != "amp" && prop->value() != "main-outs") { + + // Check whether the next processor in the list + + while (o != _processors.end()) { XMLProperty* id_prop = (*niter)->property(X_("id")); - if (id_prop && strncmp(buf, id_prop->value().c_str(), sizeof(buf)) == 0) { + if (id_prop && (*o)->id() == id_prop->value()) { break; } + + ++o; } - - ++o; } // 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)) { --i; // move iterator to the newly inserted processor } else { cerr << "Error restoring route: unable to restore processor" << endl; } - // Otherwise, we found the processor (*niter) on the route, + // Otherwise, the processor already exists; just // ensure it is at the location provided in the XML state } else { if (i != o) { boost::shared_ptr<Processor> tmp = (*o); - _processors.erase(o); // remove the old copy - _processors.insert(i, tmp); // insert the processor at the correct location + 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 } - (*i)->set_state((**niter)); - } - - if (*i == _amp) { - placement = PostFader; + (*i)->set_state (**niter); } } } @@ -1882,22 +1842,19 @@ Route::silence (nframes_t nframes) if (!_silent) { IO::silence (nframes); - - if (_control_outs) { - _control_outs->io()->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; + if (!_active && (pi = boost::dynamic_pointer_cast<PluginInsert> (*i)) != 0) { // skip plugins, they don't need anything when we're not active continue; } - + (*i)->silence (nframes); } @@ -1910,53 +1867,110 @@ Route::silence (nframes_t nframes) } } -int -Route::set_control_outs (const vector<string>& ports) +boost::shared_ptr<Delivery> +Route::add_listener (boost::shared_ptr<IO> io, const string& listen_name) { - vector<string>::const_iterator i; - - if (is_control() || is_master()) { - /* no control outs for these two special busses */ - return 0; - } + string name = _name; + name += '['; + name += listen_name; + name += ']'; - if (ports.empty()) { - return 0; - } - - string coutname = _name; - coutname += _("[control]"); - - IO* out_io = new IO (_session, coutname); - boost::shared_ptr<ControlOutputs> out_proc(new ControlOutputs (_session, out_io)); + boost::shared_ptr<Delivery> listener (new Delivery (_session, 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 control outs is an identity processor + * As a processor, the listener is an identity processor * (i.e. it does not modify its input buffers whatsoever) */ - if (out_io->ensure_io (ChanCount::ZERO, n_outputs(), true, this)) { - return -1; + + if (listener->io()->ensure_io (ChanCount::ZERO, n_outputs(), true, this)) { + return boost::shared_ptr<Delivery>(); } + + listener->set_sort_key (_meter->sort_key() + 1); + add_processor (listener, NULL); + + return listener; +} + +int +Route::listen_via (boost::shared_ptr<IO> io, const string& listen_name) +{ + vector<string> ports; + vector<string>::const_iterator i; + + { + 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); + + if (d && d->io() == io) { + /* already listening via the specified IO: do nothing */ + return 0; + } + } + } + + uint32_t ni = io->n_inputs().n_total(); + + for (uint32_t n = 0; n < ni; ++n) { + ports.push_back (io->input(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 */ + + _control_outs = listen_point; /* now connect to the named ports */ - for (size_t n = 0; n < n_outputs().n_total(); ++n) { - if (out_io->connect_output (out_io->output (n), ports[n % ports.size()], this)) { + ni = listen_point->io()->n_outputs().n_total(); + size_t psize = ports.size(); + + for (size_t n = 0; n < ni; ++n) { + if (listen_point->io()->connect_output (listen_point->io()->output (n), ports[n % psize], this)) { error << string_compose (_("could not connect %1 to %2"), - out_io->output(n)->name(), ports[n]) << endmsg; + listen_point->io()->output(n)->name(), ports[n % psize]) << endmsg; return -1; } } - _control_outs = out_proc; - _control_outs->set_sort_key (_meter->sort_key() + 1); - add_processor (_control_outs, NULL); - + return 0; } void +Route::drop_listen (boost::shared_ptr<IO> io) +{ + ProcessorStreams err; + ProcessorList::iterator tmp; + + Glib::RWLock::ReaderLock rm (_processor_lock); + + for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ) { + + tmp = x; + ++tmp; + + boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery>(*x); + + if (d && d->io() == io) { + /* already listening via the specified IO: do nothing */ + remove_processor (*x, &err); + + } + + x = tmp; + } +} + +void Route::set_edit_group (RouteGroup *eg, void *src) { @@ -2041,33 +2055,17 @@ Route::feeds (boost::shared_ptr<Route> other) for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); r++) { - boost::shared_ptr<IOProcessor> redirect = boost::dynamic_pointer_cast<IOProcessor>(*r); - - if ( ! redirect) + boost::shared_ptr<IOProcessor> proc = boost::dynamic_pointer_cast<IOProcessor>(*r); + + if (!proc) { continue; - - // TODO: support internal redirects here - - no = redirect->io()->n_outputs().n_total(); - - for (i = 0; i < no; ++i) { - for (j = 0; j < ni; ++j) { - if (redirect->io()->output(i)->connected_to (other->input (j)->name())) { - return true; - } - } } - } - - /* check for control room outputs which may also interconnect Routes */ - - if (_control_outs) { - - no = _control_outs->io()->n_outputs().n_total(); + + no = proc->io()->n_outputs().n_total(); for (i = 0; i < no; ++i) { for (j = 0; j < ni; ++j) { - if (_control_outs->io()->output(i)->connected_to (other->input (j)->name())) { + if (proc->io()->output(i)->connected_to (other->input (j)->name())) { return true; } } @@ -2185,7 +2183,7 @@ Route::pans_required () const } int -Route::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, +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) { @@ -2236,7 +2234,7 @@ Route::check_initial_delay (nframes_t nframes, nframes_t& transport_frame) } int -Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int declick, +Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, bool can_record, bool rec_monitors_input) { { @@ -2282,7 +2280,7 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int } int -Route::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_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); @@ -2602,3 +2600,36 @@ Route::save_as_template (const string& path, const string& name) tree.set_root (&node); return tree.write (path.c_str()); } + + +bool +Route::set_name (const string& str) +{ + bool ret; + string ioproc_name; + + if ((ret = IO::set_name (str)) == true) { + Glib::RWLock::ReaderLock lm (_processor_lock); + + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + + /* rename all delivery objects to reflect our new name */ + + boost::shared_ptr<Delivery> dp = boost::dynamic_pointer_cast<Delivery> (*i); + + if (dp) { + string dp_name = str; + dp_name += '['; + dp_name += "XXX FIX ME XXX"; + dp_name += ']'; + + if (!dp->set_name (dp_name)) { + ret = false; + } + } + } + + } + + return ret; +} |