mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-15 19:16:40 +01:00
Prepare API to resample session to engine when SR mismatches
This commit is contained in:
parent
f76e63fd89
commit
3ca0f4e43d
6 changed files with 69 additions and 20 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue