Prepare API to resample session to engine when SR mismatches

This commit is contained in:
Robin Gareus 2022-09-20 23:51:52 +02:00
parent f76e63fd89
commit 3ca0f4e43d
No known key found for this signature in database
GPG key ID: A090BCE02CF57F04
6 changed files with 69 additions and 20 deletions

View file

@ -140,7 +140,8 @@ public:
static PBD::Signal0<void> PortDrop;
static PBD::Signal0<void> PortSignalDrop;
static void set_speed_ratio (double s);
static void set_varispeed_ratio (double s); //< varispeed playback
static bool set_engine_ratio (double session, double engine); //< SR mismatch
static void set_cycle_samplecnt (pframes_t n);
static samplecnt_t port_offset() { return _global_port_buffer_offset; }
@ -158,11 +159,13 @@ public:
static pframes_t cycle_nframes () { return _cycle_nframes; }
static double speed_ratio () { return _speed_ratio; }
static double engine_ratio () { return _engine_ratio; }
static double resample_ratio () { return _resample_ratio; } // == _speed_ratio * _engine_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);
static bool setup_resampler (uint32_t q = 17);
protected:
@ -179,6 +182,8 @@ protected:
LatencyRange _private_capture_latency;
static double _speed_ratio;
static double _engine_ratio;
static double _resample_ratio; // = _speed_ratio * _engine_ratio (cached)
private:
std::string _name; ///< port short name

View file

@ -128,6 +128,9 @@ public:
uint32_t port_name_size () const;
std::string my_name () const;
size_t total_port_count () const { return _ports.reader ()->size (); }
size_t session_port_count () const;
#ifndef NDEBUG
void list_cycle_ports () const;
void list_all_ports () const;

View file

@ -234,7 +234,7 @@ AudioEngine::process_callback (pframes_t nframes)
{
TimerRAII tr (dsp_stats[ProcessCallback]);
Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
Port::set_speed_ratio (1.0);
Port::set_varispeed_ratio (1.0);
PT_TIMING_REF;
PT_TIMING_CHECK (1);
@ -490,7 +490,7 @@ AudioEngine::process_callback (pframes_t nframes)
*/
double catch_speed = tmm.pre_process_transport_masters (nframes, sample_time_at_cycle_start());
catch_speed = _session->plan_master_strategy (nframes, tmm.get_current_speed_in_process_context(), tmm.get_current_position_in_process_context(), catch_speed);
Port::set_speed_ratio (catch_speed);
Port::set_varispeed_ratio (catch_speed);
DEBUG_TRACE (DEBUG::Slave, string_compose ("transport master (current=%1) gives speed %2 (ports using %3)\n", tmm.current() ? tmm.current()->name() : string("[]"), catch_speed, Port::speed_ratio()));
#if 0 // USE FOR DEBUG ONLY

View file

@ -123,7 +123,7 @@ MidiPort::get_midi_buffer (pframes_t nframes)
continue;
}
timestamp = floor (timestamp * _speed_ratio);
timestamp = floor (timestamp * resample_ratio ());
/* check that the event is in the acceptable time range */
if ((timestamp < (_global_port_buffer_offset)) ||
@ -241,7 +241,7 @@ MidiPort::resolve_notes (void* port_buffer, MidiBuffer::TimeType when)
for (uint8_t channel = 0; channel <= 0xF; channel++) {
uint8_t ev[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), MIDI_CTL_SUSTAIN, 0 };
pframes_t tme = floor (when / _speed_ratio);
pframes_t tme = floor (when / resample_ratio ());
/* we need to send all notes off AND turn the
* sustain/damper pedal off to handle synths
@ -282,7 +282,7 @@ MidiPort::flush_buffers (pframes_t nframes)
port_buffer = port_engine.get_buffer (_port_handle, nframes);
}
double speed_ratio = (flags () & TransportGenerator) ? 1.0 : _speed_ratio;
double speed_ratio = (flags () & TransportGenerator) ? 1.0 : resample_ratio ();
for (MidiBuffer::iterator i = _buffer->begin(); i != _buffer->end(); ++i) {

View file

@ -46,6 +46,8 @@ bool Port::_connecting_blocked = false;
pframes_t Port::_global_port_buffer_offset = 0;
pframes_t Port::_cycle_nframes = 0;
double Port::_speed_ratio = 1.0;
double Port::_engine_ratio = 1.0;
double Port::_resample_ratio = 1.0;
std::string Port::state_node_name = X_("Port");
uint32_t Port::_resampler_quality = 17;
uint32_t Port::_resampler_latency = 16; // = _resampler_quality - 1;
@ -706,20 +708,19 @@ Port::set_state (const XMLNode& node, int)
return 0;
}
/* static */ void
/* static */ bool
Port::setup_resampler (uint32_t q)
{
/* configure at application start (Ardour::init) */
static bool setup_done = false;
if (setup_done) {
return;
if (port_manager && port_manager->session_port_count() > 0) {
return false;
}
setup_done = true;
if (q == 0) {
/* no vari-speed */
_resampler_quality = 0;
_resampler_latency = 0;
return;
return true;
}
// range constrained in VMResampler::setup
if (q < 8) {
@ -730,22 +731,49 @@ Port::setup_resampler (uint32_t q)
}
_resampler_quality = q;
_resampler_latency = q - 1;
return true;
}
/*static*/ bool
Port::set_engine_ratio (double session_rate, double engine_rate)
{
bool rv = true;
if (session_rate > 0 && engine_rate > 0 && can_varispeed ()) {
_engine_ratio = session_rate / engine_rate;
} else {
_engine_ratio = 1.0;
rv = false;
}
/* constrain range to provide for additional vari-speed.
* but do allow 384000 / 44100 = 8.7
*/
if (_engine_ratio < 0.11 || _engine_ratio > 9) {
_engine_ratio = 1.0;
rv = false;
}
/* apply constraints, and calc _resample_ratio */
set_varispeed_ratio (_speed_ratio);
return rv;
}
/*static*/ void
Port::set_speed_ratio (double s) {
Port::set_varispeed_ratio (double s) {
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)));
_speed_ratio = std::min (16.0, std::max (0.02, fabs (s * _engine_ratio))) / _engine_ratio;
_speed_ratio = std::min ((double) Config->get_max_transport_speed(), _speed_ratio);
}
/* cache overall speed */
_resample_ratio = _speed_ratio * _engine_ratio;
}
/*static*/ void
Port::set_cycle_samplecnt (pframes_t n)
{
_cycle_nframes = floor (n * _speed_ratio);
_cycle_nframes = floor (n * resample_ratio ());
}

View file

@ -552,6 +552,19 @@ PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlag
return _backend->get_ports (port_name_pattern, type, flags, s);
}
size_t
PortManager::session_port_count () const
{
size_t cnt = 0;
for (auto const& p : *_ports.reader ()) {
if (p.second->flags () & TransportSyncPort) {
continue;
}
++cnt;
}
return cnt;
}
void
PortManager::port_registration_failure (const std::string& portname)
{
@ -1230,7 +1243,7 @@ PortManager::cycle_start (pframes_t nframes, Session* s)
if (s) {
tl = s->rt_tasklist ();
}
if (tl && fabs (Port::speed_ratio ()) != 1.0) {
if (tl && fabs (Port::resample_ratio ()) != 1.0) {
for (Ports::iterator p = _cycle_ports->begin (); p != _cycle_ports->end (); ++p) {
if (!(p->second->flags () & TransportSyncPort)) {
tl->push_back (boost::bind (&Port::cycle_start, p->second, nframes));
@ -1256,7 +1269,7 @@ PortManager::cycle_end (pframes_t nframes, Session* s)
if (s) {
tl = s->rt_tasklist ();
}
if (tl && fabs (Port::speed_ratio ()) != 1.0) {
if (tl && fabs (Port::resample_ratio ()) != 1.0) {
for (Ports::iterator p = _cycle_ports->begin (); p != _cycle_ports->end (); ++p) {
if (!(p->second->flags () & TransportSyncPort)) {
tl->push_back (boost::bind (&Port::cycle_end, p->second, nframes));
@ -1274,7 +1287,7 @@ PortManager::cycle_end (pframes_t nframes, Session* s)
for (Ports::iterator p = _cycle_ports->begin (); p != _cycle_ports->end (); ++p) {
/* AudioEngine::split_cycle flushes buffers until Port::port_offset.
* Now only flush remaining events (after Port::port_offset) */
p->second->flush_buffers (nframes * Port::speed_ratio () - Port::port_offset ());
p->second->flush_buffers (nframes * Port::resample_ratio () - Port::port_offset ());
}
_cycle_ports.reset ();
@ -1374,7 +1387,7 @@ PortManager::cycle_end_fade_out (gain_t base_gain, gain_t gain_step, pframes_t n
if (s) {
tl = s->rt_tasklist ();
}
if (tl && fabs (Port::speed_ratio ()) != 1.0) {
if (tl && fabs (Port::resample_ratio ()) != 1.0) {
for (Ports::iterator p = _cycle_ports->begin (); p != _cycle_ports->end (); ++p) {
if (!(p->second->flags () & TransportSyncPort)) {
tl->push_back (boost::bind (&Port::cycle_end, p->second, nframes));