On Wed, 2015-02-25 at 19:43 +0100, Georg Chini wrote: > For small values of latency_difference, this forms a classical > P-controller between the observed value of latency and the controlled > sample rate of the sink input. The coefficient aims for the full > correction of the observed difference to the next cycle - i.e. the > controller is tuned optimally according to > https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method > For higher latency values the controller limits the deviation from > the base rate to 0.95%. > --- > Â src/modules/module-loopback.c | 44 ++++++++++++++++++++++++------------------- > Â 1 file changed, 25 insertions(+), 19 deletions(-) > > diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c > index 3532728..372c3ed 100644 > --- a/src/modules/module-loopback.c > +++ b/src/modules/module-loopback.c > @@ -169,9 +169,30 @@ 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 > + * - exhibits hunting with USB or Bluetooth sources > + */ > +static uint32_t rate_controller( > +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â uint32_t base_rate, > +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_usec_t adjust_time, > +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int32_t latency_difference_usec) { > + > +Â Â Â Â uint32_t new_rate; > +Â Â Â Â double min_cycles; > + > +Â Â Â Â /* 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); > + > +Â Â Â Â return new_rate; > +} Sorry for being obtuse, but I don't follow what this simple bit of code is doing. You mentioned "P-controller" and the "Ziegler-Nichols method". I followed the Wikipedia link, and found that a P-controller is a very simple thing: u(t) = Kp * e(t) where u(t): the new control variable value (the new sink input rate) Kp: a tunable parameter (a magic number) e(t): the error value, i.e. the difference between the current process variable value and the target value (current latency minus configured latency) The Ziegler-Nichols method can be used to choose Kp. For a P-controller Kp is defined as Kp = 0.5 * Ku where Ku: a number that, when used in place of Kp, makes u(t) oscillate in a stable manner (A sidenote: I probably have understood something wrong, because Kp is a plain number, and u(t) and e(t) have different units, so there appears to be a unit mismatch. u(t) is a frequency and e(t) is a time amount.) Figuring out Ku seems to require having an initial calibration phase where various Ku values are tried and the oscillation of u(t) is measured. The code doesn't seem to do this. Could you explain how you have derived the formula in rate_controller()? -- Tanu