From f301e692a757ed0a38f37139f6288e7a86d3b718 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 8 Sep 2021 21:43:23 +0200 Subject: [PATCH] Expose compensated port-latency, fix ambig. latency detection Previously Ardour only announced processor latency. Routes that had additional latency to compensate for those have not published this delay. This is of no concern with internal backends, however with JACK, Ardour reported incorrect *individual* port-latencies of routes that perform PDC. Since public port latency now includes delay-compensation, some extra work is required to unset it before recalculating latency of paths that include external ports. --- libs/ardour/ardour/route.h | 2 +- libs/ardour/ardour/session.h | 1 + libs/ardour/port.cc | 16 ++++++---------- libs/ardour/route.cc | 28 ++++++++++++++++++++++----- libs/ardour/session.cc | 37 +++++++++++++++++++++++++++++++++++- 5 files changed, 67 insertions(+), 17 deletions(-) diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 9fd1630d1e..09441c038e 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -355,7 +355,7 @@ public: virtual void apply_latency_compensation (); samplecnt_t set_private_port_latencies (bool playback) const; - void set_public_port_latencies (samplecnt_t, bool playback) const; + void set_public_port_latencies (samplecnt_t, bool playback, bool with_latcomp) const; samplecnt_t signal_latency() const { return _signal_latency; } samplecnt_t playback_latency (bool incl_downstream = false) const; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 50610cf90e..1244a9ffdf 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -1432,6 +1432,7 @@ private: void remove_monitor_section (); void update_latency (bool playback); + void set_owned_port_public_latency (bool playback); bool update_route_latency (bool reverse, bool apply_to_delayline, bool* delayline_update_needed); void initialize_latencies (); void set_worst_output_latency (); diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index ee872ad125..25510a92ae 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -367,7 +367,7 @@ Port::set_public_latency_range (LatencyRange const& range, bool playback) const if (_port_handle) { LatencyRange r (range); - if (externally_connected () && 0 == (_flags & TransportSyncPort)) { + if (externally_connected () && 0 == (_flags & TransportSyncPort) && sends_output () == playback) { #if 0 r.min *= _speed_ratio; r.max *= _speed_ratio; @@ -399,10 +399,6 @@ Port::set_private_latency_range (LatencyRange& range, bool playback) _private_capture_latency.min, _private_capture_latency.max)); } - - /* push to public (port system) location so that everyone else can see it */ - - set_public_latency_range (range, playback); } const LatencyRange& @@ -426,14 +422,14 @@ Port::private_latency_range (bool playback) const } LatencyRange -Port::public_latency_range (bool /*playback*/) const +Port::public_latency_range (bool playback) const { /*Note: this method is no longer used. It exists purely for debugging reasons */ LatencyRange r; if (_port_handle) { - r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false); - if (externally_connected () && 0 == (_flags & TransportSyncPort)) { + r = port_engine.get_latency_range (_port_handle, playback); + if (externally_connected () && 0 == (_flags & TransportSyncPort) && sends_output () == playback) { #if 0 r.min /= _speed_ratio; r.max /= _speed_ratio; @@ -450,7 +446,7 @@ Port::public_latency_range (bool /*playback*/) const DEBUG_TRACE (DEBUG::LatencyIO, string_compose ( "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n", name(), r.min, r.max, - sends_output() ? "PLAYBACK" : "CAPTURE")); + playback ? "PLAYBACK" : "CAPTURE")); } return r; @@ -487,7 +483,7 @@ Port::get_connected_latency_range (LatencyRange& range, bool playback) const if (remote_port) { lr = port_engine.get_latency_range (remote_port, playback); - if (externally_connected () && 0 == (_flags & TransportSyncPort)) { + if (externally_connected () && 0 == (_flags & TransportSyncPort) && sends_output () == playback) { #if 0 lr.min /= _speed_ratio; lr.max /= _speed_ratio; diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 150019df94..092c8b72eb 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -4412,7 +4412,12 @@ Route::apply_latency_compensation () cout << "ROUTE " << name() << " delay for " << latcomp << " (c: " << latcomp_capt << ")" << endl; #endif - _delayline->set_delay (latcomp > 0 ? latcomp : 0); + if (_delayline->set_delay (latcomp > 0 ? latcomp : 0)) { + DEBUG_TRACE (DEBUG::LatencyRoute, string_compose ("%1: delay changed to %2\n", _name, latcomp)); + /* public port latency update is needed, + * Session::update_latency() calls this->set_public_port_latencies() + */ + } } void @@ -4975,7 +4980,7 @@ Route::set_private_port_latencies (bool playback) const } void -Route::set_public_port_latencies (samplecnt_t value, bool playback) const +Route::set_public_port_latencies (samplecnt_t value, bool playback, bool with_latcomp) const { /* publish private latencies */ Glib::Threads::RWLock::ReaderLock lm (_processor_lock); @@ -4985,9 +4990,10 @@ Route::set_public_port_latencies (samplecnt_t value, bool playback) const continue; } if (iop->input ()) { + assert (iop->input () != _input); // no delivery for Input iop->input ()->set_public_port_latencies (iop->input()->latency(), true); } - if (iop->output ()) { + if (iop->output () && iop->output () != _output) { iop->output ()->set_public_port_latencies (iop->output()->latency(), false); } } @@ -4995,8 +5001,20 @@ 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. */ - _input->set_public_port_latencies (value, playback); - _output->set_public_port_latencies (value, playback); + if (playback) { + _output->set_public_port_latencies (_output->latency (), playback); + if (_delayline && with_latcomp) { + value += _delayline->delay (); + } + _input->set_public_port_latencies (value, playback); + } else { + _input->set_public_port_latencies (_input->latency(), playback); + if (_delayline && with_latcomp) { + value += _delayline->delay (); + } + _output->set_public_port_latencies (value, playback); + } + } /** Put the invisible processors in the right place in _processors. diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index bc20361e2f..3486d01198 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -6675,6 +6675,21 @@ restart: return changed; } +void +Session::set_owned_port_public_latency (bool playback) +{ + /* special routes or IO or ports owned by the session */ + if (auditioner) { + samplecnt_t latency = auditioner->set_private_port_latencies (playback); + auditioner->set_public_port_latencies (latency, playback, true); + } + _click_io->set_public_port_latencies (_click_io->connected_latency (playback), playback); + + if (_midi_ports) { + _midi_ports->set_public_latency (playback); + } +} + void Session::update_latency (bool playback) { @@ -6744,10 +6759,18 @@ Session::update_latency (bool playback) reverse (r->begin(), r->end()); } for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + /* private port latency includes plugin and I/O delay, + * but no latency compensation delaylines. + */ samplecnt_t latency = (*i)->set_private_port_latencies (playback); - (*i)->set_public_port_latencies (latency, playback); + /* However we also need to reset the latency of connected external + * ports, since those includes latency compensation delaylines. + */ + (*i)->set_public_port_latencies (latency, playback, false); } + set_owned_port_public_latency (playback); + if (playback) { /* Processing needs to be blocked while re-configuring delaylines. * @@ -6773,6 +6796,18 @@ Session::update_latency (bool playback) update_route_latency (false, false, NULL); } + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + /* Publish port latency. This includes latency-compensation + * delaylines in the direction of signal flow. + */ + samplecnt_t latency = (*i)->set_private_port_latencies (playback); + (*i)->set_public_port_latencies (latency, playback, true); + } + + /* now handle non-route ports that we are responsible for */ + set_owned_port_public_latency (playback); + + DEBUG_TRACE (DEBUG::LatencyCompensation, "Engine latency callback: DONE\n"); LatencyUpdated (playback); /* EMIT SIGNAL */ }