From e863a7dbc926b9ef327af792f79ecd45ccbcf46a Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Mon, 23 May 2022 15:42:16 +0200 Subject: [PATCH] Allow to configure vari-speed resampler quality This also allows to disable the resampler, effectively disabling varispeed support, for the benefit of adding no additional latency. By default 2 * 16 samples latency are added, due to port-resampler, this is not desirable if Ardour is used as mixer only. --- libs/ardour/ardour/port.h | 8 ++- libs/ardour/ardour/rc_configuration_vars.h | 3 + libs/ardour/audio_port.cc | 2 +- libs/ardour/disk_writer.cc | 4 +- libs/ardour/globals.cc | 2 + libs/ardour/port.cc | 67 ++++++++++++---------- 6 files changed, 52 insertions(+), 34 deletions(-) diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h index eaaed6c16d..020a9bf66e 100644 --- a/libs/ardour/ardour/port.h +++ b/libs/ardour/ardour/port.h @@ -158,7 +158,11 @@ public: static pframes_t cycle_nframes () { return _cycle_nframes; } static double speed_ratio () { return _speed_ratio; } + static uint32_t resampler_quality () { return _resampler_quality; } + static uint32_t resampler_latency () { return _resampler_latency; } + static bool can_varispeed () { return _resampler_latency > 0; } + static void setup_resampler (uint32_t q = 17); protected: @@ -175,7 +179,6 @@ protected: LatencyRange _private_capture_latency; static double _speed_ratio; - static const uint32_t _resampler_quality; /* also latency of the resampler */ private: std::string _name; ///< port short name @@ -188,6 +191,9 @@ private: */ std::set _connections; + static uint32_t _resampler_quality; // 8 <= q <= 96 + static uint32_t _resampler_latency; // = _resampler_quality - 1 + void port_connected_or_disconnected (boost::weak_ptr, boost::weak_ptr, bool); void signal_drop (); void session_global_drop (); diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index 6c408f9801..5591361010 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -40,6 +40,9 @@ CONFIG_VARIABLE (AutoConnectOption, output_auto_connect, "output-auto-connect", CONFIG_VARIABLE (AutoConnectOption, input_auto_connect, "input-auto-connect", AutoConnectPhysical) CONFIG_VARIABLE (bool, strict_io, "strict-io", true) +/* 0: off, no varispeed, q: 8..96 */ +CONFIG_VARIABLE (uint32_t, port_resampler_quality, "port-resampler-quality,", 17) + /* Connect all physical inputs to a dummy port, this makes raw input data available. * `jack_port_get_buffer (jack_port_by_name (c, "system:capture_1") , n_samples);` * nees to work for input-monitoring (recorder page). diff --git a/libs/ardour/audio_port.cc b/libs/ardour/audio_port.cc index c096cd37fb..3dc3d4e970 100644 --- a/libs/ardour/audio_port.cc +++ b/libs/ardour/audio_port.cc @@ -42,7 +42,7 @@ AudioPort::AudioPort (const std::string& name, PortFlags flags) , _data (0) { assert (name.find_first_of (':') == string::npos); - _src.setup (_resampler_quality); + _src.setup (resampler_quality ()); _src.set_rrfilt (10); } diff --git a/libs/ardour/disk_writer.cc b/libs/ardour/disk_writer.cc index c2d59cf1be..03d00d122a 100644 --- a/libs/ardour/disk_writer.cc +++ b/libs/ardour/disk_writer.cc @@ -699,9 +699,9 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp } if (_xrun_flag) { - /* There still are `Port::resampler_quality () -1` samples in the resampler + /* There still are `Port::resampler_latency ()` samples in the resampler * buffer from before the xrun. */ - _xruns.push_back (_capture_captured + Port::resampler_quality () - 1); + _xruns.push_back (_capture_captured + Port::resampler_latency ()); } _capture_captured += rec_nframes; diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 89d2eba15e..f82a6bff75 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -613,6 +613,8 @@ ARDOUR::init (bool try_optimization, const char* localedir, bool with_gui) } #endif + Port::setup_resampler (Config->get_port_resampler_quality ()); + setup_hardware_optimization (try_optimization); if (Config->get_cpu_dma_latency () >= 0) { diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index d87c417938..410886d4a3 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -47,7 +47,8 @@ pframes_t Port::_global_port_buffer_offset = 0; pframes_t Port::_cycle_nframes = 0; double Port::_speed_ratio = 1.0; std::string Port::state_node_name = X_("Port"); -const uint32_t Port::_resampler_quality = 17; +uint32_t Port::_resampler_quality = 17; +uint32_t Port::_resampler_latency = 16; // = _resampler_quality - 1; /* a handy define to shorten what would otherwise be a needlessly verbose * repeated phrase @@ -388,13 +389,9 @@ Port::set_public_latency_range (LatencyRange const& range, bool playback) const if (_port_handle) { LatencyRange r (range); if (externally_connected () && 0 == (_flags & TransportSyncPort) && sends_output () == playback) { -#if 0 - r.min *= _speed_ratio; - r.max *= _speed_ratio; -#endif if (type () == DataType::AUDIO) { - r.min += (_resampler_quality - 1); - r.max += (_resampler_quality - 1); + r.min += (_resampler_latency); + r.max += (_resampler_latency); } } port_engine.set_latency_range (_port_handle, playback, r); @@ -449,19 +446,6 @@ Port::public_latency_range (bool playback) const if (_port_handle) { 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; -#endif -#if 0 - /* use value as set by set_public_latency_range */ - if (type () == DataType::AUDIO) { - r.min += (_resampler_quality - 1); - r.max += (_resampler_quality - 1); - } -#endif - } DEBUG_TRACE (DEBUG::LatencyIO, string_compose ( "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n", @@ -493,8 +477,8 @@ Port::collect_latency_from_backend (LatencyRange& range, bool playback) const if (!AudioEngine::instance()->port_is_mine (*c)) { if (externally_connected () && 0 == (_flags & TransportSyncPort) && sends_output () == playback) { if (type () == DataType::AUDIO) { - lr.min += (_resampler_quality - 1); - lr.max += (_resampler_quality - 1); + lr.min += (_resampler_latency); + lr.max += (_resampler_latency); } } } @@ -542,13 +526,9 @@ 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) && sends_output () == playback) { -#if 0 - lr.min /= _speed_ratio; - lr.max /= _speed_ratio; -#endif if (type () == DataType::AUDIO) { - lr.min += (_resampler_quality - 1); - lr.max += (_resampler_quality - 1); + lr.min += (_resampler_latency); + lr.max += (_resampler_latency); } } @@ -726,13 +706,40 @@ Port::set_state (const XMLNode& node, int) return 0; } +/* static */ void +Port::setup_resampler (uint32_t q) +{ + /* configure at application start (Ardour::init) */ + static bool setup_done = false; + if (setup_done) { + return; + } + setup_done = true; + if (q == 0) { + /* no vari-speed */ + _resampler_quality = 0; + _resampler_latency = 0; + return; + } + // range constrained in VMResampler::setup + if (q < 8) { + q = 8; + } + if (q > 96) { + q = 96; + } + _resampler_quality = q; + _resampler_latency = q - 1; +} + + /*static*/ void Port::set_speed_ratio (double s) { - /* see VMResampler::set_rratio() for min/max range */ - if (s == 0.0) { + if (s == 0.0 || !can_varispeed ()) { /* no resampling when stopped */ _speed_ratio = 1.0; } else { + /* see VMResampler::set_rratio() for min/max range */ _speed_ratio = std::min ((double) Config->get_max_transport_speed(), std::max (0.02, fabs (s))); } }