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