aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/filters/filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'Alc/filters/filter.c')
-rw-r--r--Alc/filters/filter.c53
1 files changed, 29 insertions, 24 deletions
diff --git a/Alc/filters/filter.c b/Alc/filters/filter.c
index 4d757be7..fe59977b 100644
--- a/Alc/filters/filter.c
+++ b/Alc/filters/filter.c
@@ -9,7 +9,7 @@
extern inline void BiquadState_clear(BiquadState *filter);
extern inline void BiquadState_copyParams(BiquadState *restrict dst, const BiquadState *restrict src);
-extern inline void BiquadState_processPassthru(BiquadState *filter, const ALfloat *restrict src, ALsizei numsamples);
+extern inline void BiquadState_processPassthru(BiquadState *filter, ALsizei numsamples);
extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope);
extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth);
@@ -96,38 +96,43 @@ void BiquadState_setParams(BiquadState *filter, BiquadType type, ALfloat gain, A
void BiquadState_processC(BiquadState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples)
{
- ALsizei i;
if(LIKELY(numsamples > 1))
{
- ALfloat x0 = filter->x[0];
- ALfloat x1 = filter->x[1];
- ALfloat y0 = filter->y[0];
- ALfloat y1 = filter->y[1];
+ const ALfloat a1 = filter->a1;
+ const ALfloat a2 = filter->a2;
+ const ALfloat b0 = filter->b0;
+ const ALfloat b1 = filter->b1;
+ const ALfloat b2 = filter->b2;
+ ALfloat z1 = filter->z1;
+ ALfloat z2 = filter->z2;
+ ALsizei i;
+ /* Processing loop is transposed direct form II. This requires less
+ * storage versus direct form I (only two delay components, instead of
+ * a four-sample history; the last two inputs and outputs), and works
+ * better for floating-point which favors summing similarly-sized
+ * values while being less bothered by overflow.
+ *
+ * See: http://www.earlevel.com/main/2003/02/28/biquads/
+ */
for(i = 0;i < numsamples;i++)
{
- dst[i] = filter->b0* src[i] +
- filter->b1*x0 + filter->b2*x1 -
- filter->a1*y0 - filter->a2*y1;
- y1 = y0; y0 = dst[i];
- x1 = x0; x0 = src[i];
+ ALfloat input = src[i];
+ ALfloat output = input*b0 + z1;
+ z1 = input*b1 - output*a1 + z2;
+ z2 = input*b2 - output*a2;
+ dst[i] = output;
}
- filter->x[0] = x0;
- filter->x[1] = x1;
- filter->y[0] = y0;
- filter->y[1] = y1;
+ filter->z1 = z1;
+ filter->z2 = z2;
}
else if(numsamples == 1)
{
- dst[0] = filter->b0 * src[0] +
- filter->b1 * filter->x[0] +
- filter->b2 * filter->x[1] -
- filter->a1 * filter->y[0] -
- filter->a2 * filter->y[1];
- filter->x[1] = filter->x[0];
- filter->x[0] = src[0];
- filter->y[1] = filter->y[0];
- filter->y[0] = dst[0];
+ ALfloat input = *src;
+ ALfloat output = input*filter->b0 + filter->z1;
+ filter->z1 = input*filter->b1 - output*filter->a1 + filter->z2;
+ filter->z2 = input*filter->b2 - output*filter->a2;
+ *dst = output;
}
}