# [pulseaudio-discuss] [PATCH 1-3/8] Summary for easier reviewing

Alexander E. Patrakov patrakov at gmail.com
Tue Mar 24 11:07:15 PDT 2015

```24.03.2015 14:29, David Henningsson wrote:
> This is a summary of patch 1, 2, 3 for easier reviewing, as requested by Alexander.

This time, there is even less dead code, and the formulas still produce
the same result as those published at
http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt (referenced below as
"their formula", "their version" and so on).

> +	} else if (cutoff > 0) {
> +		/* Compute biquad coefficients for lowpass filter */
> +		double d = sqrt(2);
Looks like their 1/Q

> +
> +		double theta = M_PI * cutoff;
Same as their w0

> +		double sn = 0.5 * d * sin(theta);
Same as their alpha

> +		double beta = 0.5 * (1 - sn) / (1 + sn);
> +		double gamma = (0.5 + beta) * cos(theta);
> +		double alpha = 0.25 * (0.5 + beta - gamma);
No exact equivalents in their terms. For the purpose of comparing the
formulas, it is useful to introduce K = 0.5 + beta, which obviously
simplifies down to 1 / (1 + sn). Then:

beta = K - 0.5
gamma = K * cos(theta)
alpha = 0.25 * K * (1 - cos(theta))

> +
> +		double b0 = 2 * alpha;
What matters is b0 / a0, with our a0 = 1.

Our version: 0.5 * K * (1 - cos(theta))

Their version: 0.5 * (1 - cos(theta)) / (1 + sn)

...which is the same.

> +		double b1 = 2 * 2 * alpha;
The comparison can be saved here, because this is the same as 2 * b0,
and b0 is already known to match.

> +		double b2 = 2 * alpha;
This is the same as b0, which is already known to match.

> +		double a1 = 2 * -gamma;
What matters is a1 / a0.

Our version: -2 * K * cos(theta), which, after substituting K = 1 / (1 +
sn), is exactly their result.

> +		double a2 = 2 * beta;
What matters is a2 / a0. In both our code and their cookbook, this is
quite obviously (1 - sn) / (1 + sn). Match!

> +
> +		set_coefficient(bq, b0, b1, b2, 1, a1, a2);
> +	} else {
> +		/* When cutoff is zero, nothing gets through the filter, so set
> +		 * coefficients up correctly.
> +		 */
> +		set_coefficient(bq, 0, 0, 0, 1, 0, 0);
> +	}
> +}
> +
> +{
> +	/* Limit cutoff to 0 to 1. */
> +	cutoff = PA_MIN(cutoff, 1.0);
> +	cutoff = PA_MAX(0.0, cutoff);
> +
> +	if (cutoff >= 1.0) {
> +		/* The z-transform is 0. */
> +		set_coefficient(bq, 0, 0, 0, 1, 0, 0);
> +	} else if (cutoff > 0) {
> +		/* Compute biquad coefficients for highpass filter */

And now compare with the lowpass filter. You'll see the differences for
edge cases (which are invalid for our purposes, are already eliminated
in lfe-filter.c and thus can be either dropped here or turned into
asserts), in the sign before gamma in the definition of alpha, and in
the sign of b1. So it may be a good idea to consider merging the two
functions together. But, this is just a nitpick.

> +void lr4_process_float32(struct lr4 *lr4, int samples, int channels, float *src, float *dest)

Yes, it was a good idea to remove in-place processing.

--
Alexander E. Patrakov
```