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.4 2000/11/07 09:51:43 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 void IIR_reset(IIR_state *s){
50 memset(s->z_A,0,sizeof(float)*s->stages*2);
53 float IIR_filter(IIR_state *s,float in){
54 int stages=s->stages,i;
57 float *zA=s->z_A+s->ring;
60 for(i=0;i<stages;i++){
61 newA+= s->coeff_A[i] * zA[i];
62 newB+= s->coeff_B[i] * zA[i];
64 newB+=newA*s->coeff_B[stages];
66 zA[0]=zA[stages]=newA;
67 if(++s->ring>=stages)s->ring=0;
72 /* this assumes the symmetrical structure of the feed-forward stage of
73 a Chebyshev bandpass to save multiplies */
74 float IIR_filter_ChebBand(IIR_state *s,float in){
75 int stages=s->stages,i;
78 float *zA=s->z_A+s->ring;
82 newA+= s->coeff_A[0] * zA[0];
83 for(i=1;i<(stages>>1);i++){
84 newA+= s->coeff_A[i] * zA[i];
85 newB+= s->coeff_B[i] * (zA[i]-zA[stages-i]);
87 newB+= s->coeff_B[i] * zA[i];
89 newA+= s->coeff_A[i] * zA[i];
93 zA[0]=zA[stages]=newA;
94 if(++s->ring>=stages)s->ring=0;
101 /* z^-stage, z^-stage+1... */
102 static float cheb_bandpass_B[]={-1.,0.,5.,0.,-10.,0.,10.,0.,-5.,0.,1};
103 static float cheb_bandpass_A[]={-0.6665900311,
114 static float data[128]={
244 /* comparison test code from http://www-users.cs.york.ac.uk/~fisher/mkfilter/
245 (the above page kicks ass, BTW)*/
249 #define GAIN 4.599477515e+02
251 static float xv[NZEROS+1], yv[NPOLES+1];
253 static float filterloop(float next){
254 xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; xv[4] = xv[5];
255 xv[5] = xv[6]; xv[6] = xv[7]; xv[7] = xv[8]; xv[8] = xv[9]; xv[9] = xv[10];
256 xv[10] = next / GAIN;
257 yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; yv[4] = yv[5];
258 yv[5] = yv[6]; yv[6] = yv[7]; yv[7] = yv[8]; yv[8] = yv[9]; yv[9] = yv[10];
259 yv[10] = (xv[10] - xv[0]) + 5 * (xv[2] - xv[8]) + 10 * (xv[6] - xv[4])
260 + ( -0.6665900311 * yv[0]) + ( 1.0070146601 * yv[1])
261 + ( -3.1262875409 * yv[2]) + ( 3.5017171569 * yv[3])
262 + ( -6.2779211945 * yv[4]) + ( 5.2966481740 * yv[5])
263 + ( -6.7570216587 * yv[6]) + ( 4.0760335768 * yv[7])
264 + ( -3.9134284363 * yv[8]) + ( 1.3997338886 * yv[9]);
271 /* run the pregenerated Chebyshev filter, then our own distillation
272 through the generic and specialized code */
273 float *work=_ogg_malloc(128*sizeof(float));
277 for(i=0;i<128;i++)work[i]=filterloop(data[i]);
279 FILE *out=fopen("IIR_ref.m","w");
280 for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);
284 IIR_init(&iir,NPOLES,GAIN,cheb_bandpass_A,cheb_bandpass_B);
285 for(i=0;i<128;i++)work[i]=IIR_filter(&iir,data[i]);
287 FILE *out=fopen("IIR_gen.m","w");
288 for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);
293 IIR_init(&iir,NPOLES,GAIN,cheb_bandpass_A,cheb_bandpass_B);
294 for(i=0;i<128;i++)work[i]=IIR_filter_ChebBand(&iir,data[i]);
296 FILE *out=fopen("IIR_cheb.m","w");
297 for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);