diff options
author | Justin Ruggles <justin.ruggles@gmail.com> | 2011-01-20 21:26:47 +0000 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2011-01-21 20:36:01 +0100 |
commit | aa226b246007d71fd2e3c9ddf8e83d9c85df3317 (patch) | |
tree | 59dd309eaea4ad352ab000ba26cb8eb8840cd98c | |
parent | 7f8c11b0052f1f34d8294865c3cb1ec002ebd58e (diff) | |
download | ffmpeg-aa226b246007d71fd2e3c9ddf8e83d9c85df3317.tar.gz |
Add biquad high-pass and low-pass IIR filters.
Signed-off-by: Mans Rullgard <mans@mansr.com>
(cherry picked from commit fcdf0a43cd267c1d4193aa172b024f35903c286e)
-rw-r--r-- | libavcodec/iirfilter.c | 50 | ||||
-rw-r--r-- | libavcodec/iirfilter.h | 1 |
2 files changed, 51 insertions, 0 deletions
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, |