// // Combined-filter based filter-running code. // // Copyright (c) 2002-2003 Jim Peters . This // file is released under the GNU Lesser General Public License // (LGPL) version 2.1 as published by the Free Software // Foundation. See the file COPYING_LIB for details, or visit // . // // Convolves all the filters into a single IIR/FIR pair, and runs // that directly through static code. Compiled with GCC -O6 on // ix86 this is surprisingly fast -- at worst half the speed of // assembler code, at best matching it. The downside of // convolving all the sub-filters together like this is loss of // accuracy and instability in some kinds of filters, especially // high-order ones. The one big advantage of this approach is // that the code is easy to understand. // #ifndef FIDCOMBINED_H #define FIDCOMBINED_H typedef struct Run { int magic; // Magic: 0x64966325 double *fir; // FIR parameters int n_fir; // Number of FIR parameters double *iir; // IIR parameters int n_iir; // Number of IIR parameters int n_buf; // Number of entries in buffer FidFilter *filt; // Combined filter } Run; typedef struct RunBuf { Run *run; double buf[0]; } RunBuf; static double filter_step(void *rb, double val) { Run *rr= ((RunBuf*)rb)->run; double *buf= ((RunBuf*)rb)->buf; int a; // Shift the whole internal array up one memmove(buf+1, buf, (rr->n_buf-1)*sizeof(buf[0])); // Do IIR for (a= 1; an_iir; a++) val -= rr->iir[a] * buf[a]; buf[0]= val; // Do FIR val= 0; for (a= 0; an_fir; a++) val += rr->fir[a] * buf[a]; return val; } // // Create an instance of a filter, ready to run. This returns a // void* handle, and a function to call to execute the filter. // Working buffers for the filter instances must be allocated // separately using fid_run_newbuf(). This allows many // simultaneous instances of the filter to be run. // // The returned handle must be released using fid_run_free(). // void * fid_run_new(FidFilter *filt, double (**funcpp)(void *,double)) { Run *rr= ALLOC(Run); FidFilter *ff; rr->magic= 0x64966325; rr->filt= fid_flatten(filt); ff= rr->filt; if (ff->typ != 'I') goto bad; rr->n_iir= ff->len; rr->iir= ff->val; ff= FFNEXT(ff); if (ff->typ != 'F') goto bad; rr->n_fir= ff->len; rr->fir= ff->val; ff= FFNEXT(ff); if (ff->len) goto bad; rr->n_buf= rr->n_fir > rr->n_iir ? rr->n_fir : rr->n_iir; *funcpp= filter_step; return rr; bad: error("Internal error: fid_run_new() expecting IIR+FIR in flattened filter"); return 0; } // // Create a new instance of the given filter // void * fid_run_newbuf(void *run) { Run *rr= run; RunBuf *rb; if (rr->magic != 0x64966325) error("Bad handle passed to fid_run_newbuf()"); rb= Alloc(sizeof(RunBuf) + rr->n_buf * sizeof(double)); rb->run= run; // rb->buf[] already zerod return rb; } // // Reinitialise an instance ready to start afresh // void fid_run_zapbuf(void *buf) { RunBuf *rb; Run *rr= rb->run; memset(rb->buf, 0, rr->n_buf * sizeof(double)); } // // Delete an instance // void fid_run_freebuf(void *runbuf) { free(runbuf); } // // Delete the filter // void fid_run_free(void *run) { Run *rr= run; free(rr->filt); free(rr); } // END // #endif