1 //
2 //	Combined-filter based filter-running code.
3 //
4 //        Copyright (c) 2002-2003 Jim Peters <http://uazu.net/>.  This
5 //        file is released under the GNU Lesser General Public License
6 //        (LGPL) version 2.1 as published by the Free Software
7 //        Foundation.  See the file COPYING_LIB for details, or visit
8 //        <http://www.fsf.org/licenses/licenses.html>.
9 //
10 //	Convolves all the filters into a single IIR/FIR pair, and runs
11 //	that directly through static code.  Compiled with GCC -O6 on
12 //	ix86 this is surprisingly fast -- at worst half the speed of
13 //	assembler code, at best matching it.  The downside of
14 //	convolving all the sub-filters together like this is loss of
15 //	accuracy and instability in some kinds of filters, especially
16 //	high-order ones.  The one big advantage of this approach is
17 //	that the code is easy to understand.
18 //
19 
20 #ifndef FIDCOMBINED_H
21 #define FIDCOMBINED_H
22 
23 typedef struct Run {
24    int magic;		// Magic: 0x64966325
25    double *fir;         // FIR parameters
26    int n_fir;           // Number of FIR parameters
27    double *iir;         // IIR parameters
28    int n_iir;           // Number of IIR parameters
29    int n_buf;           // Number of entries in buffer
30    FidFilter *filt;	// Combined filter
31 } Run;
32 
33 typedef struct RunBuf {
34    Run *run;
35    double buf[0];
36 } RunBuf;
37 
38 static double
filter_step(void * rb,double val)39 filter_step(void *rb, double val) {
40    Run *rr= ((RunBuf*)rb)->run;
41    double *buf= ((RunBuf*)rb)->buf;
42    int a;
43 
44    // Shift the whole internal array up one
45    memmove(buf+1, buf, (rr->n_buf-1)*sizeof(buf[0]));
46 
47    // Do IIR
48    for (a= 1; a<rr->n_iir; a++) val -= rr->iir[a] * buf[a];
49    buf[0]= val;
50 
51    // Do FIR
52    val= 0;
53    for (a= 0; a<rr->n_fir; a++) val += rr->fir[a] * buf[a];
54 
55    return val;
56 }
57 
58 
59 //
60 //	Create an instance of a filter, ready to run.  This returns a
61 //	void* handle, and a function to call to execute the filter.
62 //	Working buffers for the filter instances must be allocated
63 //	separately using fid_run_newbuf().  This allows many
64 //	simultaneous instances of the filter to be run.
65 //
66 //	The returned handle must be released using fid_run_free().
67 //
68 
69 void *
fid_run_new(FidFilter * filt,double (** funcpp)(void *,double))70 fid_run_new(FidFilter *filt, double (**funcpp)(void *,double)) {
71    Run *rr= ALLOC(Run);
72    FidFilter *ff;
73 
74    rr->magic= 0x64966325;
75    rr->filt= fid_flatten(filt);
76 
77    ff= rr->filt;
78    if (ff->typ != 'I') goto bad;
79    rr->n_iir= ff->len;
80    rr->iir= ff->val;
81    ff= FFNEXT(ff);
82    if (ff->typ != 'F') goto bad;
83    rr->n_fir= ff->len;
84    rr->fir= ff->val;
85    ff= FFNEXT(ff);
86    if (ff->len) goto bad;
87 
88    rr->n_buf= rr->n_fir > rr->n_iir ? rr->n_fir : rr->n_iir;
89 
90    *funcpp= filter_step;
91 
92    return rr;
93 
94  bad:
95    error("Internal error: fid_run_new() expecting IIR+FIR in flattened filter");
96    return 0;
97 }
98 
99 //
100 //	Create a new instance of the given filter
101 //
102 
103 void *
fid_run_newbuf(void * run)104 fid_run_newbuf(void *run) {
105    Run *rr= run;
106    RunBuf *rb;
107 
108    if (rr->magic != 0x64966325)
109       error("Bad handle passed to fid_run_newbuf()");
110 
111    rb= Alloc(sizeof(RunBuf) + rr->n_buf * sizeof(double));
112    rb->run= run;
113    // rb->buf[] already zerod
114 
115    return rb;
116 }
117 
118 //
119 //	Reinitialise an instance ready to start afresh
120 //
121 
122 void
fid_run_zapbuf(void * buf)123 fid_run_zapbuf(void *buf) {
124    RunBuf *rb;
125    Run *rr= rb->run;
126    memset(rb->buf, 0, rr->n_buf * sizeof(double));
127 }
128 
129 //
130 //	Delete an instance
131 //
132 
133 void
fid_run_freebuf(void * runbuf)134 fid_run_freebuf(void *runbuf) {
135    free(runbuf);
136 }
137 
138 //
139 //	Delete the filter
140 //
141 
142 void
fid_run_free(void * run)143 fid_run_free(void *run) {
144    Run *rr= run;
145    free(rr->filt);
146    free(rr);
147 }
148 
149 // END //
150 #endif
151 
152