[pulseaudio-discuss] [PATCH 11/13] loopback: Don't change rate abruptly
Georg Chini
georg at chini.tk
Wed Feb 25 10:43:23 PST 2015
If a big latency difference forms (due to underrun or source/sink
switching), the controller has to change the rate by a big step. This may
be noticeable for a specially trained ear of a musician, so avoid it.
---
src/modules/module-loopback.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 6b48fc6..d22afb5 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -182,24 +182,35 @@ static void teardown(struct userdata *u) {
/* rate controller
* - maximum deviation from base rate is less than 1%
- * - can create audible artifacts by changing the rate too quickly
+ * - maximum rate step size is less than 2‰
* - deadband to handle error of latency measurement
*/
static uint32_t rate_controller(
- uint32_t base_rate,
+ uint32_t base_rate, uint32_t old_rate,
pa_usec_t adjust_time,
int32_t latency_difference_usec, pa_usec_t latency_error_usec) {
- uint32_t new_rate;
- double min_cycles;
+ uint32_t new_rate, new_rate_1, new_rate_2;
+ double min_cycles_1, min_cycles_2;
+
+ /* Calculate next rate that is not more than 2‰ away from the last rate */
+ min_cycles_1 = (double)abs(latency_difference_usec) / adjust_time / 0.002 + 1;
+ new_rate_1 = old_rate + base_rate * (double)latency_difference_usec / min_cycles_1 / adjust_time;
/* Calculate best rate to correct the current latency offset, limit at
* slightly below 1% difference from base_rate */
- min_cycles = (double)abs(latency_difference_usec) / adjust_time / 0.0095 + 1;
- new_rate = base_rate * (1.0 + (double)latency_difference_usec / min_cycles / adjust_time);
+ min_cycles_2 = (double)abs(latency_difference_usec) / adjust_time / 0.0095 + 1;
+ new_rate_2 = base_rate * (1.0 + (double)latency_difference_usec / min_cycles_2 / adjust_time);
+
+ /* Choose the rate that is nearer to base_rate */
+ if (abs(new_rate_1 - base_rate) < abs(new_rate_2 - base_rate))
+ new_rate = new_rate_1;
+ else
+ new_rate = new_rate_2;
- /* Adjust as good as physics allows (with some safety margin) */
- if (abs(latency_difference_usec) <= 2.5 * latency_error_usec + adjust_time / 2 / base_rate + 100)
+ /* Adjust as good as physics allows (with some safety margin)
+ * make sure the rate is near enough to the base rate before clipping */
+ if (abs(latency_difference_usec) <= 2.5 * latency_error_usec + adjust_time / 2 / base_rate + 100 && abs(old_rate - base_rate) < 0.002 * base_rate)
new_rate = base_rate;
return new_rate;
@@ -280,7 +291,7 @@ static void adjust_rates(struct userdata *u) {
u->source_sink_changed = false;
/* Calculate new rate */
- new_rate = rate_controller(base_rate, u->adjust_time, latency_difference, u->latency_error * final_latency);
+ new_rate = rate_controller(base_rate, old_rate, u->adjust_time, latency_difference, u->latency_error * final_latency);
/* Predictor */
u->next_latency = (corrected_latency * base_rate + (int32_t)(base_rate - new_rate) * (int64_t)u->adjust_time) / new_rate;
--
2.1.4
More information about the pulseaudio-discuss
mailing list