From e02952a26c28876ea81440ee98e46f28483b91d6 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 26 Nov 2017 09:48:54 +0100 Subject: Sidechain latency compensation - part one This properly sets the port-latencies of PluginInsert owned ports as well as handles external sends (send-target playback latency). NB. This needs more work to ensure that Sidechain input port playback latency is set before the feeding send queries it the connected latency. Re-ordering process may change sidechain or external-send latencies, but since re-ordering does not change the route's latency, engine.update_latency() may not be called. --- libs/ardour/route.cc | 90 +++++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index c379158801..639a0e19bc 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -474,27 +474,6 @@ Route::process_output_buffers (BufferSet& bufs, } #endif - if (boost::dynamic_pointer_cast(*i) != 0) { - /* set potential sidechain ports, capture and playback latency. - * This effectively sets jack port latency which should include - * up/downstream latencies. - * - * However, the value is not used by Ardour (2017-09-20) and calling - * IO::latency() is expensive, so we punt. - * - * capture should be - * input()->latenct + latency, - * playback should be - * output->latency() + _signal_latency - latency - * - * Also see note below, _signal_latency may be smaller than latency - * if a plugin's latency increases while it's running. - */ - const samplecnt_t playback_latency = std::max ((samplecnt_t)0, _signal_latency - latency); - boost::dynamic_pointer_cast(*i)->set_sidechain_latency ( - /* input->latency() + */ latency, /* output->latency() + */ playback_latency); - } - bool re_inject_oob_data = false; if ((*i) == _disk_reader) { /* Well now, we've made it past the disk-writer and to the disk-reader. @@ -3989,6 +3968,9 @@ Route::update_signal_latency (bool apply_to_delayline) // here or in Session::* ? -> also zero send latencies, // and make sure that re-enabling a route updates things again... + samplecnt_t capt_lat_in = _input->connected_latency (false); + samplecnt_t play_lat_out = _output->connected_latency (true); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); samplecnt_t l_in = 0; @@ -3997,6 +3979,14 @@ Route::update_signal_latency (bool apply_to_delayline) if (boost::shared_ptr snd = boost::dynamic_pointer_cast (*i)) { snd->set_delay_in (l_out + _output->latency()); } + + if (boost::shared_ptr pi = boost::dynamic_pointer_cast (*i)) { + if (boost::shared_ptr pio = pi->sidechain_input ()) { + samplecnt_t lat = l_out + _output->latency(); + pio->set_private_port_latencies (lat, true); + pio->set_public_port_latencies (lat, true); + } + } (*i)->set_output_latency (l_out); if ((*i)->active ()) { l_out += (*i)->signal_latency (); @@ -4008,6 +3998,27 @@ Route::update_signal_latency (bool apply_to_delayline) _signal_latency = l_out; for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + + /* set sidechain, send and insert port latencies */ + if (boost::shared_ptr pi = boost::dynamic_pointer_cast (*i)) { + if (pi->input ()) { + /* propagate playback latency from output to input */ + pi->input ()->set_private_port_latencies (play_lat_out + l_in, true); + } + if (pi->output ()) { + /* propagate capture latency from input to output */ + pi->output ()->set_private_port_latencies (capt_lat_in + l_in, false); + } + + } else if (boost::shared_ptr snd = boost::dynamic_pointer_cast (*i)) { + if (snd->output ()) { + /* set capture latency */ + snd->output ()->set_private_port_latencies (capt_lat_in + l_in, false); + /* take send-target's playback latency into account */ + snd->set_delay_out (snd->output ()->connected_latency (true)); + } + } + (*i)->set_input_latency (l_in); (*i)->set_playback_offset (_signal_latency + _output->latency ()); (*i)->set_capture_offset (_input->latency ()); @@ -4590,6 +4601,7 @@ Route::set_private_port_latencies (bool playback) const */ for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { + if ((*i)->active ()) { own_latency += (*i)->signal_latency (); } @@ -4607,28 +4619,26 @@ Route::set_private_port_latencies (bool playback) const void Route::set_public_port_latencies (samplecnt_t value, bool playback) const { - /* this is called to set the JACK-visible port latencies, which take - latency compensation into account. - */ - - LatencyRange range; - - range.min = value; - range.max = value; - - { - const PortSet& ports (_input->ports()); - for (PortSet::const_iterator p = ports.begin(); p != ports.end(); ++p) { - p->set_public_latency_range (range, playback); + /* publish private latencies */ + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); + for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { + boost::shared_ptr iop = boost::dynamic_pointer_cast(*i); + if (!iop) { + continue; } - } - - { - const PortSet& ports (_output->ports()); - for (PortSet::const_iterator p = ports.begin(); p != ports.end(); ++p) { - p->set_public_latency_range (range, playback); + if (iop->input ()) { + iop->input ()->set_public_port_latencies (iop->input()->latency(), true); + } + if (iop->output ()) { + iop->output ()->set_public_port_latencies (iop->output()->latency(), false); } } + + /* this is called to set the JACK-visible port latencies, which take + * latency compensation into account. + */ + _input->set_public_port_latencies (value, playback); + _output->set_public_port_latencies (value, playback); } /** Put the invisible processors in the right place in _processors. -- cgit v1.2.3