From aa226b246007d71fd2e3c9ddf8e83d9c85df3317 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Thu, 20 Jan 2011 21:26:47 +0000 Subject: [PATCH] Add biquad high-pass and low-pass IIR filters. Signed-off-by: Mans Rullgard (cherry picked from commit fcdf0a43cd267c1d4193aa172b024f35903c286e) --- libavcodec/iirfilter.c | 50 ++++++++++++++++++++++++++++++++++++++++++ libavcodec/iirfilter.h | 1 + 2 files changed, 51 insertions(+) diff --git a/libavcodec/iirfilter.c b/libavcodec/iirfilter.c index c0ac947289..085482032b 100644 --- a/libavcodec/iirfilter.c +++ b/libavcodec/iirfilter.c @@ -112,6 +112,51 @@ static int butterworth_init_coeffs(void *avc, struct FFIIRFilterCoeffs *c, return 0; } +static int biquad_init_coeffs(void *avc, struct FFIIRFilterCoeffs *c, + enum IIRFilterMode filt_mode, int order, + float cutoff_ratio, float stopband) +{ + double cos_w0, sin_w0; + double a0, x0, x1; + + if (filt_mode != FF_FILTER_MODE_HIGHPASS && + filt_mode != FF_FILTER_MODE_LOWPASS) { + av_log(avc, AV_LOG_ERROR, "Biquad filter currently only supports " + "high-pass and low-pass filter modes\n"); + return -1; + } + if (order != 2) { + av_log(avc, AV_LOG_ERROR, "Biquad filter must have order of 2\n"); + return -1; + } + + cos_w0 = cos(M_PI * cutoff_ratio); + sin_w0 = sin(M_PI * cutoff_ratio); + + a0 = 1.0 + (sin_w0 / 2.0); + + if (filt_mode == FF_FILTER_MODE_HIGHPASS) { + c->gain = ((1.0 + cos_w0) / 2.0) / a0; + x0 = (-(1.0 + cos_w0)) / a0; + x1 = ((1.0 + cos_w0) / 2.0) / a0; + } else { // FF_FILTER_MODE_LOWPASS + c->gain = ((1.0 - cos_w0) / 2.0) / a0; + x0 = (1.0 - cos_w0) / a0; + x1 = ((1.0 - cos_w0) / 2.0) / a0; + } + c->cy[0] = (2.0 * cos_w0) / a0; + c->cy[1] = (-1.0 + (sin_w0 / 2.0)) / a0; + + // divide by gain to make the x coeffs integers. + // during filtering, the delay state will include the gain multiplication + c->cx[0] = lrintf(x0 / c->gain); + c->cx[1] = lrintf(x1 / c->gain); + c->cy[0] /= c->gain; + c->cy[1] /= c->gain; + + return 0; +} + av_cold struct FFIIRFilterCoeffs* ff_iir_filter_init_coeffs(void *avc, enum IIRFilterType filt_type, enum IIRFilterMode filt_mode, @@ -136,6 +181,11 @@ av_cold struct FFIIRFilterCoeffs* ff_iir_filter_init_coeffs(void *avc, stopband)) { goto init_fail; } + } else if (filt_type == FF_FILTER_TYPE_BIQUAD) { + if (biquad_init_coeffs(avc, c, filt_mode, order, cutoff_ratio, + stopband)) { + goto init_fail; + } } else { av_log(avc, AV_LOG_ERROR, "filter type is not currently implemented\n"); goto init_fail; diff --git a/libavcodec/iirfilter.h b/libavcodec/iirfilter.h index 13e1598e39..c2484e23d3 100644 --- a/libavcodec/iirfilter.h +++ b/libavcodec/iirfilter.h @@ -34,6 +34,7 @@ struct FFIIRFilterState; enum IIRFilterType{ FF_FILTER_TYPE_BESSEL, + FF_FILTER_TYPE_BIQUAD, FF_FILTER_TYPE_BUTTERWORTH, FF_FILTER_TYPE_CHEBYSHEV, FF_FILTER_TYPE_ELLIPTIC,