1 /********************************************************************
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU LESSER/LIBRARY PUBLIC LICENSE, WHICH IS INCLUDED WITH *
6 * THIS SOURCE. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
9 * by Monty <monty@xiph.org> and the XIPHOPHORUS Company *
10 * http://www.xiph.org/ *
12 ********************************************************************
14 function: Direct Form I, II IIR filters, plus some specializations
15 last mod: $Id: iir.c,v 1.3 2000/11/06 00:07:00 xiphmont Exp $
17 ********************************************************************/
19 /* LPC is actually a degenerate case of form I/II filters, but we need
28 void IIR_init(IIR_state *s,int stages,float gain, float *A, float *B){
29 memset(s,0,sizeof(IIR_state));
32 s->coeff_A=_ogg_malloc(stages*sizeof(float));
33 s->coeff_B=_ogg_malloc((stages+1)*sizeof(float));
34 s->z_A=_ogg_calloc(stages*2,sizeof(float));
36 memcpy(s->coeff_A,A,stages*sizeof(float));
37 memcpy(s->coeff_B,B,(stages+1)*sizeof(float));
40 void IIR_clear(IIR_state *s){
45 memset(s,0,sizeof(IIR_state));
49 float IIR_filter(IIR_state *s,float in){
50 int stages=s->stages,i;
53 float *zA=s->z_A+s->ring;
56 for(i=0;i<stages;i++){
57 newA+= s->coeff_A[i] * zA[i];
58 newB+= s->coeff_B[i] * zA[i];
60 newB+=newA*s->coeff_B[stages];
62 zA[0]=zA[stages]=newA;
63 if(++s->ring>=stages)s->ring=0;
68 /* prevents ringing down to underflow */
69 void IIR_clamp(IIR_state *s,float thresh){
70 float *zA=s->z_A+s->ring;
72 for(i=0;i<s->stages;i++)
73 if(fabs(zA[i])>=thresh)break;
76 memset(s->z_A,0,sizeof(float)*s->stages*2);
79 /* this assumes the symmetrical structure of the feed-forward stage of
80 a Chebyshev bandpass to save multiplies */
81 float IIR_filter_ChebBand(IIR_state *s,float in){
82 int stages=s->stages,i;
85 float *zA=s->z_A+s->ring;
89 newA+= s->coeff_A[0] * zA[0];
90 for(i=1;i<(stages>>1);i++){
91 newA+= s->coeff_A[i] * zA[i];
92 newB+= s->coeff_B[i] * (zA[i]-zA[stages-i]);
94 newB+= s->coeff_B[i] * zA[i];
96 newA+= s->coeff_A[i] * zA[i];
100 zA[0]=zA[stages]=newA;
101 if(++s->ring>=stages)s->ring=0;
108 /* z^-stage, z^-stage+1... */
109 static float cheb_bandpass_B[]={-1.,0.,5.,0.,-10.,0.,10.,0.,-5.,0.,1};
110 static float cheb_bandpass_A[]={-0.6665900311,
121 static float data[128]={
251 /* comparison test code from http://www-users.cs.york.ac.uk/~fisher/mkfilter/
252 (the above page kicks ass, BTW)*/
256 #define GAIN 4.599477515e+02
258 static float xv[NZEROS+1], yv[NPOLES+1];
260 static float filterloop(float next){
261 xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; xv[4] = xv[5];
262 xv[5] = xv[6]; xv[6] = xv[7]; xv[7] = xv[8]; xv[8] = xv[9]; xv[9] = xv[10];
263 xv[10] = next / GAIN;
264 yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; yv[4] = yv[5];
265 yv[5] = yv[6]; yv[6] = yv[7]; yv[7] = yv[8]; yv[8] = yv[9]; yv[9] = yv[10];
266 yv[10] = (xv[10] - xv[0]) + 5 * (xv[2] - xv[8]) + 10 * (xv[6] - xv[4])
267 + ( -0.6665900311 * yv[0]) + ( 1.0070146601 * yv[1])
268 + ( -3.1262875409 * yv[2]) + ( 3.5017171569 * yv[3])
269 + ( -6.2779211945 * yv[4]) + ( 5.2966481740 * yv[5])
270 + ( -6.7570216587 * yv[6]) + ( 4.0760335768 * yv[7])
271 + ( -3.9134284363 * yv[8]) + ( 1.3997338886 * yv[9]);
278 /* run the pregenerated Chebyshev filter, then our own distillation
279 through the generic and specialized code */
280 float *work=_ogg_malloc(128*sizeof(float));
284 for(i=0;i<128;i++)work[i]=filterloop(data[i]);
286 FILE *out=fopen("IIR_ref.m","w");
287 for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);
291 IIR_init(&iir,NPOLES,GAIN,cheb_bandpass_A,cheb_bandpass_B);
292 for(i=0;i<128;i++)work[i]=IIR_filter(&iir,data[i]);
294 FILE *out=fopen("IIR_gen.m","w");
295 for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);
300 IIR_init(&iir,NPOLES,GAIN,cheb_bandpass_A,cheb_bandpass_B);
301 for(i=0;i<128;i++)work[i]=IIR_filter_ChebBand(&iir,data[i]);
303 FILE *out=fopen("IIR_cheb.m","w");
304 for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);