yading@10: /* yading@10: * IIR filter yading@10: * Copyright (c) 2008 Konstantin Shishkov yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * different IIR filters implementation yading@10: */ yading@10: yading@10: #include "iirfilter.h" yading@10: #include yading@10: #include "libavutil/common.h" yading@10: yading@10: /** yading@10: * IIR filter global parameters yading@10: */ yading@10: typedef struct FFIIRFilterCoeffs{ yading@10: int order; yading@10: float gain; yading@10: int *cx; yading@10: float *cy; yading@10: }FFIIRFilterCoeffs; yading@10: yading@10: /** yading@10: * IIR filter state yading@10: */ yading@10: typedef struct FFIIRFilterState{ yading@10: float x[1]; yading@10: }FFIIRFilterState; yading@10: yading@10: /// maximum supported filter order yading@10: #define MAXORDER 30 yading@10: yading@10: static int butterworth_init_coeffs(void *avc, struct FFIIRFilterCoeffs *c, yading@10: enum IIRFilterMode filt_mode, yading@10: int order, float cutoff_ratio, yading@10: float stopband) yading@10: { yading@10: int i, j; yading@10: double wa; yading@10: double p[MAXORDER + 1][2]; yading@10: yading@10: if (filt_mode != FF_FILTER_MODE_LOWPASS) { yading@10: av_log(avc, AV_LOG_ERROR, "Butterworth filter currently only supports " yading@10: "low-pass filter mode\n"); yading@10: return -1; yading@10: } yading@10: if (order & 1) { yading@10: av_log(avc, AV_LOG_ERROR, "Butterworth filter currently only supports " yading@10: "even filter orders\n"); yading@10: return -1; yading@10: } yading@10: yading@10: wa = 2 * tan(M_PI * 0.5 * cutoff_ratio); yading@10: yading@10: c->cx[0] = 1; yading@10: for(i = 1; i < (order >> 1) + 1; i++) yading@10: c->cx[i] = c->cx[i - 1] * (order - i + 1LL) / i; yading@10: yading@10: p[0][0] = 1.0; yading@10: p[0][1] = 0.0; yading@10: for(i = 1; i <= order; i++) yading@10: p[i][0] = p[i][1] = 0.0; yading@10: for(i = 0; i < order; i++){ yading@10: double zp[2]; yading@10: double th = (i + (order >> 1) + 0.5) * M_PI / order; yading@10: double a_re, a_im, c_re, c_im; yading@10: zp[0] = cos(th) * wa; yading@10: zp[1] = sin(th) * wa; yading@10: a_re = zp[0] + 2.0; yading@10: c_re = zp[0] - 2.0; yading@10: a_im = yading@10: c_im = zp[1]; yading@10: zp[0] = (a_re * c_re + a_im * c_im) / (c_re * c_re + c_im * c_im); yading@10: zp[1] = (a_im * c_re - a_re * c_im) / (c_re * c_re + c_im * c_im); yading@10: yading@10: for(j = order; j >= 1; j--) yading@10: { yading@10: a_re = p[j][0]; yading@10: a_im = p[j][1]; yading@10: p[j][0] = a_re*zp[0] - a_im*zp[1] + p[j-1][0]; yading@10: p[j][1] = a_re*zp[1] + a_im*zp[0] + p[j-1][1]; yading@10: } yading@10: a_re = p[0][0]*zp[0] - p[0][1]*zp[1]; yading@10: p[0][1] = p[0][0]*zp[1] + p[0][1]*zp[0]; yading@10: p[0][0] = a_re; yading@10: } yading@10: c->gain = p[order][0]; yading@10: for(i = 0; i < order; i++){ yading@10: c->gain += p[i][0]; yading@10: c->cy[i] = (-p[i][0] * p[order][0] + -p[i][1] * p[order][1]) / yading@10: (p[order][0] * p[order][0] + p[order][1] * p[order][1]); yading@10: } yading@10: c->gain /= 1 << order; yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static int biquad_init_coeffs(void *avc, struct FFIIRFilterCoeffs *c, yading@10: enum IIRFilterMode filt_mode, int order, yading@10: float cutoff_ratio, float stopband) yading@10: { yading@10: double cos_w0, sin_w0; yading@10: double a0, x0, x1; yading@10: yading@10: if (filt_mode != FF_FILTER_MODE_HIGHPASS && yading@10: filt_mode != FF_FILTER_MODE_LOWPASS) { yading@10: av_log(avc, AV_LOG_ERROR, "Biquad filter currently only supports " yading@10: "high-pass and low-pass filter modes\n"); yading@10: return -1; yading@10: } yading@10: if (order != 2) { yading@10: av_log(avc, AV_LOG_ERROR, "Biquad filter must have order of 2\n"); yading@10: return -1; yading@10: } yading@10: yading@10: cos_w0 = cos(M_PI * cutoff_ratio); yading@10: sin_w0 = sin(M_PI * cutoff_ratio); yading@10: yading@10: a0 = 1.0 + (sin_w0 / 2.0); yading@10: yading@10: if (filt_mode == FF_FILTER_MODE_HIGHPASS) { yading@10: c->gain = ((1.0 + cos_w0) / 2.0) / a0; yading@10: x0 = ((1.0 + cos_w0) / 2.0) / a0; yading@10: x1 = (-(1.0 + cos_w0)) / a0; yading@10: } else { // FF_FILTER_MODE_LOWPASS yading@10: c->gain = ((1.0 - cos_w0) / 2.0) / a0; yading@10: x0 = ((1.0 - cos_w0) / 2.0) / a0; yading@10: x1 = (1.0 - cos_w0) / a0; yading@10: } yading@10: c->cy[0] = (-1.0 + (sin_w0 / 2.0)) / a0; yading@10: c->cy[1] = (2.0 * cos_w0) / a0; yading@10: yading@10: // divide by gain to make the x coeffs integers. yading@10: // during filtering, the delay state will include the gain multiplication yading@10: c->cx[0] = lrintf(x0 / c->gain); yading@10: c->cx[1] = lrintf(x1 / c->gain); yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: av_cold struct FFIIRFilterCoeffs* ff_iir_filter_init_coeffs(void *avc, yading@10: enum IIRFilterType filt_type, yading@10: enum IIRFilterMode filt_mode, yading@10: int order, float cutoff_ratio, yading@10: float stopband, float ripple) yading@10: { yading@10: FFIIRFilterCoeffs *c; yading@10: int ret = 0; yading@10: yading@10: if (order <= 0 || order > MAXORDER || cutoff_ratio >= 1.0) yading@10: return NULL; yading@10: yading@10: FF_ALLOCZ_OR_GOTO(avc, c, sizeof(FFIIRFilterCoeffs), yading@10: init_fail); yading@10: FF_ALLOC_OR_GOTO (avc, c->cx, sizeof(c->cx[0]) * ((order >> 1) + 1), yading@10: init_fail); yading@10: FF_ALLOC_OR_GOTO (avc, c->cy, sizeof(c->cy[0]) * order, yading@10: init_fail); yading@10: c->order = order; yading@10: yading@10: switch (filt_type) { yading@10: case FF_FILTER_TYPE_BUTTERWORTH: yading@10: ret = butterworth_init_coeffs(avc, c, filt_mode, order, cutoff_ratio, yading@10: stopband); yading@10: break; yading@10: case FF_FILTER_TYPE_BIQUAD: yading@10: ret = biquad_init_coeffs(avc, c, filt_mode, order, cutoff_ratio, yading@10: stopband); yading@10: break; yading@10: default: yading@10: av_log(avc, AV_LOG_ERROR, "filter type is not currently implemented\n"); yading@10: goto init_fail; yading@10: } yading@10: yading@10: if (!ret) yading@10: return c; yading@10: yading@10: init_fail: yading@10: ff_iir_filter_free_coeffs(c); yading@10: return NULL; yading@10: } yading@10: yading@10: av_cold struct FFIIRFilterState* ff_iir_filter_init_state(int order) yading@10: { yading@10: FFIIRFilterState* s = av_mallocz(sizeof(FFIIRFilterState) + sizeof(s->x[0]) * (order - 1)); yading@10: return s; yading@10: } yading@10: yading@10: #define CONV_S16(dest, source) dest = av_clip_int16(lrintf(source)); yading@10: yading@10: #define CONV_FLT(dest, source) dest = source; yading@10: yading@10: #define FILTER_BW_O4_1(i0, i1, i2, i3, fmt) \ yading@10: in = *src0 * c->gain \ yading@10: + c->cy[0]*s->x[i0] + c->cy[1]*s->x[i1] \ yading@10: + c->cy[2]*s->x[i2] + c->cy[3]*s->x[i3]; \ yading@10: res = (s->x[i0] + in )*1 \ yading@10: + (s->x[i1] + s->x[i3])*4 \ yading@10: + s->x[i2] *6; \ yading@10: CONV_##fmt(*dst0, res) \ yading@10: s->x[i0] = in; \ yading@10: src0 += sstep; \ yading@10: dst0 += dstep; yading@10: yading@10: #define FILTER_BW_O4(type, fmt) { \ yading@10: int i; \ yading@10: const type *src0 = src; \ yading@10: type *dst0 = dst; \ yading@10: for (i = 0; i < size; i += 4) { \ yading@10: float in, res; \ yading@10: FILTER_BW_O4_1(0, 1, 2, 3, fmt); \ yading@10: FILTER_BW_O4_1(1, 2, 3, 0, fmt); \ yading@10: FILTER_BW_O4_1(2, 3, 0, 1, fmt); \ yading@10: FILTER_BW_O4_1(3, 0, 1, 2, fmt); \ yading@10: } \ yading@10: } yading@10: yading@10: #define FILTER_DIRECT_FORM_II(type, fmt) { \ yading@10: int i; \ yading@10: const type *src0 = src; \ yading@10: type *dst0 = dst; \ yading@10: for (i = 0; i < size; i++) { \ yading@10: int j; \ yading@10: float in, res; \ yading@10: in = *src0 * c->gain; \ yading@10: for(j = 0; j < c->order; j++) \ yading@10: in += c->cy[j] * s->x[j]; \ yading@10: res = s->x[0] + in + s->x[c->order >> 1] * c->cx[c->order >> 1]; \ yading@10: for(j = 1; j < c->order >> 1; j++) \ yading@10: res += (s->x[j] + s->x[c->order - j]) * c->cx[j]; \ yading@10: for(j = 0; j < c->order - 1; j++) \ yading@10: s->x[j] = s->x[j + 1]; \ yading@10: CONV_##fmt(*dst0, res) \ yading@10: s->x[c->order - 1] = in; \ yading@10: src0 += sstep; \ yading@10: dst0 += dstep; \ yading@10: } \ yading@10: } yading@10: yading@10: #define FILTER_O2(type, fmt) { \ yading@10: int i; \ yading@10: const type *src0 = src; \ yading@10: type *dst0 = dst; \ yading@10: for (i = 0; i < size; i++) { \ yading@10: float in = *src0 * c->gain + \ yading@10: s->x[0] * c->cy[0] + \ yading@10: s->x[1] * c->cy[1]; \ yading@10: CONV_##fmt(*dst0, s->x[0] + in + s->x[1] * c->cx[1]) \ yading@10: s->x[0] = s->x[1]; \ yading@10: s->x[1] = in; \ yading@10: src0 += sstep; \ yading@10: dst0 += dstep; \ yading@10: } \ yading@10: } yading@10: yading@10: void ff_iir_filter(const struct FFIIRFilterCoeffs *c, yading@10: struct FFIIRFilterState *s, int size, yading@10: const int16_t *src, int sstep, int16_t *dst, int dstep) yading@10: { yading@10: if (c->order == 2) { yading@10: FILTER_O2(int16_t, S16) yading@10: } else if (c->order == 4) { yading@10: FILTER_BW_O4(int16_t, S16) yading@10: } else { yading@10: FILTER_DIRECT_FORM_II(int16_t, S16) yading@10: } yading@10: } yading@10: yading@10: void ff_iir_filter_flt(const struct FFIIRFilterCoeffs *c, yading@10: struct FFIIRFilterState *s, int size, yading@10: const float *src, int sstep, float *dst, int dstep) yading@10: { yading@10: if (c->order == 2) { yading@10: FILTER_O2(float, FLT) yading@10: } else if (c->order == 4) { yading@10: FILTER_BW_O4(float, FLT) yading@10: } else { yading@10: FILTER_DIRECT_FORM_II(float, FLT) yading@10: } yading@10: } yading@10: yading@10: av_cold void ff_iir_filter_free_state(struct FFIIRFilterState *state) yading@10: { yading@10: av_free(state); yading@10: } yading@10: yading@10: av_cold void ff_iir_filter_free_coeffs(struct FFIIRFilterCoeffs *coeffs) yading@10: { yading@10: if(coeffs){ yading@10: av_free(coeffs->cx); yading@10: av_free(coeffs->cy); yading@10: } yading@10: av_free(coeffs); yading@10: } yading@10: yading@10: void ff_iir_filter_init(FFIIRFilterContext *f) { yading@10: f->filter_flt = ff_iir_filter_flt; yading@10: yading@10: if (HAVE_MIPSFPU) yading@10: ff_iir_filter_init_mips(f); yading@10: } yading@10: yading@10: #ifdef TEST yading@10: #include yading@10: yading@10: #define FILT_ORDER 4 yading@10: #define SIZE 1024 yading@10: int main(void) yading@10: { yading@10: struct FFIIRFilterCoeffs *fcoeffs = NULL; yading@10: struct FFIIRFilterState *fstate = NULL; yading@10: float cutoff_coeff = 0.4; yading@10: int16_t x[SIZE], y[SIZE]; yading@10: int i; yading@10: yading@10: fcoeffs = ff_iir_filter_init_coeffs(NULL, FF_FILTER_TYPE_BUTTERWORTH, yading@10: FF_FILTER_MODE_LOWPASS, FILT_ORDER, yading@10: cutoff_coeff, 0.0, 0.0); yading@10: fstate = ff_iir_filter_init_state(FILT_ORDER); yading@10: yading@10: for (i = 0; i < SIZE; i++) { yading@10: x[i] = lrint(0.75 * INT16_MAX * sin(0.5*M_PI*i*i/SIZE)); yading@10: } yading@10: yading@10: ff_iir_filter(fcoeffs, fstate, SIZE, x, 1, y, 1); yading@10: yading@10: for (i = 0; i < SIZE; i++) yading@10: printf("%6d %6d\n", x[i], y[i]); yading@10: yading@10: ff_iir_filter_free_coeffs(fcoeffs); yading@10: ff_iir_filter_free_state(fstate); yading@10: return 0; yading@10: } yading@10: #endif /* TEST */