diff options
author | Robin Gareus <robin@gareus.org> | 2015-03-05 01:33:13 +0100 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2015-03-05 01:59:59 +0100 |
commit | 782dd708751a78d7b944e826e41f0e6337818e98 (patch) | |
tree | a715735341a1434b041c1f61069ec3ae0ab16a18 /libs/backends/alsa | |
parent | 1acbd7c488956b9c48b343dded72dbfbcbb4f242 (diff) |
alsa: implement timing callback
Diffstat (limited to 'libs/backends/alsa')
-rw-r--r-- | libs/backends/alsa/alsa_audiobackend.cc | 38 | ||||
-rw-r--r-- | libs/backends/alsa/alsa_audiobackend.h | 3 |
2 files changed, 40 insertions, 1 deletions
diff --git a/libs/backends/alsa/alsa_audiobackend.cc b/libs/backends/alsa/alsa_audiobackend.cc index 8090ac8c9d..18de4dc0b8 100644 --- a/libs/backends/alsa/alsa_audiobackend.cc +++ b/libs/backends/alsa/alsa_audiobackend.cc @@ -50,6 +50,8 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info) , _freewheel (false) , _freewheeling (false) , _measure_latency (false) + , _last_process_start (0) + , _process_speed_samples_per_ms (0) , _audio_device("") , _midi_driver_option(_("None")) , _device_reservation(0) @@ -500,6 +502,13 @@ AlsaAudioBackend::_start (bool for_latency_measurement) _ports.clear(); } + /* reset internal state */ + _dsp_load = 0; + _freewheeling = false; + _freewheel = false; + _last_process_start = 0; + _process_speed_samples_per_ms = 0; + release_device(); assert(_rmidi_in.size() == 0); @@ -696,7 +705,25 @@ AlsaAudioBackend::sample_time_at_cycle_start () pframes_t AlsaAudioBackend::samples_since_cycle_start () { - return 0; + if (!_active || !_run || _freewheeling || _freewheel) { + return 0; + } + if (_last_process_start == 0 || _process_speed_samples_per_ms) { + return 0; + } + + const int64_t elapsed_time_us = _last_process_start - g_get_monotonic_time(); + const int64_t nomial_time = 1e6 * _samples_per_period / _samplerate; + + assert(elapsed_time_us >=0); + + /* linear extrapolation, using [low pass] filtered process-speed. */ + const pframes_t processed_samples = elapsed_time_us * _process_speed_samples_per_ms * 1e-3; + + if (processed_samples >= _samples_per_period) { + return _samples_per_period; + } + return processed_samples; } @@ -1465,6 +1492,8 @@ AlsaAudioBackend::main_process_thread () memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample)); } + /* call engine process callback */ + _last_process_start = g_get_monotonic_time(); if (engine.process_callback (_samples_per_period)) { _pcmi->pcm_stop (); _active = false; @@ -1504,6 +1533,12 @@ AlsaAudioBackend::main_process_thread () clock2 = g_get_monotonic_time(); const int64_t elapsed_time = clock2 - clock1; _dsp_load = elapsed_time / (float) nomial_time; + + const double ps = 1e3 * _samples_per_period / elapsed_time; + // low pass filter, The time-constant should really be + // 1.0 - e^(-2.0 * π * v / SR); + // with v = _samples_per_period / N, and SR = _samples_per_period; + _process_speed_samples_per_ms = _process_speed_samples_per_ms + .05 * (ps - _process_speed_samples_per_ms) + 1e-12; } if (xrun && (_pcmi->capt_xrun() > 0 || _pcmi->play_xrun() > 0)) { @@ -1539,6 +1574,7 @@ AlsaAudioBackend::main_process_thread () rm->sync_time (clock1); } + _last_process_start = -1; if (engine.process_callback (_samples_per_period)) { _pcmi->pcm_stop (); _active = false; diff --git a/libs/backends/alsa/alsa_audiobackend.h b/libs/backends/alsa/alsa_audiobackend.h index 3823db22ed..fe29caf166 100644 --- a/libs/backends/alsa/alsa_audiobackend.h +++ b/libs/backends/alsa/alsa_audiobackend.h @@ -305,6 +305,9 @@ class AlsaAudioBackend : public AudioBackend { bool _freewheeling; bool _measure_latency; + uint64_t _last_process_start; + double _process_speed_samples_per_ms; + static std::vector<std::string> _midi_options; static std::vector<AudioBackend::DeviceStatus> _audio_device_status; static std::vector<AudioBackend::DeviceStatus> _midi_device_status; |