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