diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/intern/biquad~.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/intern/biquad~.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/intern/biquad~.c b/apps/plugins/pdbox/PDa/intern/biquad~.c new file mode 100644 index 0000000000..c37182a911 --- /dev/null +++ b/apps/plugins/pdbox/PDa/intern/biquad~.c | |||
@@ -0,0 +1,252 @@ | |||
1 | #include <m_pd.h> | ||
2 | #include <m_fixed.h> | ||
3 | |||
4 | typedef struct biquadctl | ||
5 | { | ||
6 | t_sample c_x1; | ||
7 | t_sample c_x2; | ||
8 | t_sample c_fb1; | ||
9 | t_sample c_fb2; | ||
10 | t_sample c_ff1; | ||
11 | t_sample c_ff2; | ||
12 | t_sample c_ff3; | ||
13 | } t_biquadctl; | ||
14 | |||
15 | typedef struct sigbiquad | ||
16 | { | ||
17 | t_object x_obj; | ||
18 | float x_f; | ||
19 | t_biquadctl x_cspace; | ||
20 | t_biquadctl *x_ctl; | ||
21 | } t_sigbiquad; | ||
22 | |||
23 | t_class *sigbiquad_class; | ||
24 | |||
25 | static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv); | ||
26 | |||
27 | static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv) | ||
28 | { | ||
29 | t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class); | ||
30 | outlet_new(&x->x_obj, gensym("signal")); | ||
31 | x->x_ctl = &x->x_cspace; | ||
32 | x->x_cspace.c_x1 = x->x_cspace.c_x2 = 0; | ||
33 | sigbiquad_list(x, s, argc, argv); | ||
34 | x->x_f = 0; | ||
35 | return (x); | ||
36 | } | ||
37 | |||
38 | static t_int *sigbiquad_perform(t_int *w) | ||
39 | { | ||
40 | t_sample *in = (t_sample *)(w[1]); | ||
41 | t_sample *out = (t_sample *)(w[2]); | ||
42 | t_biquadctl *c = (t_biquadctl *)(w[3]); | ||
43 | int n = (t_int)(w[4]); | ||
44 | int i; | ||
45 | t_sample last = c->c_x1; | ||
46 | t_sample prev = c->c_x2; | ||
47 | t_sample fb1 = c->c_fb1; | ||
48 | t_sample fb2 = c->c_fb2; | ||
49 | t_sample ff1 = c->c_ff1; | ||
50 | t_sample ff2 = c->c_ff2; | ||
51 | t_sample ff3 = c->c_ff3; | ||
52 | for (i = 0; i < n; i++) | ||
53 | { | ||
54 | t_sample output = *in++ + mult(fb1,last) + mult(fb2,prev); | ||
55 | if (PD_BADFLOAT(output)) | ||
56 | output = 0; | ||
57 | *out++ = mult(ff1,output) + mult(ff2,last) + mult(ff3,prev); | ||
58 | prev = last; | ||
59 | last = output; | ||
60 | } | ||
61 | c->c_x1 = last; | ||
62 | c->c_x2 = prev; | ||
63 | return (w+5); | ||
64 | } | ||
65 | |||
66 | static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv) | ||
67 | { | ||
68 | float fb1 = atom_getfloatarg(0, argc, argv); | ||
69 | float fb2 = atom_getfloatarg(1, argc, argv); | ||
70 | float ff1 = atom_getfloatarg(2, argc, argv); | ||
71 | float ff2 = atom_getfloatarg(3, argc, argv); | ||
72 | float ff3 = atom_getfloatarg(4, argc, argv); | ||
73 | float discriminant = fb1 * fb1 + 4 * fb2; | ||
74 | t_biquadctl *c = x->x_ctl; | ||
75 | if (discriminant < 0) /* imaginary roots -- resonant filter */ | ||
76 | { | ||
77 | /* they're conjugates so we just check that the product | ||
78 | is less than one */ | ||
79 | if (fb2 >= -1.0f) goto stable; | ||
80 | } | ||
81 | else /* real roots */ | ||
82 | { | ||
83 | /* check that the parabola 1 - fb1 x - fb2 x^2 has a | ||
84 | vertex between -1 and 1, and that it's nonnegative | ||
85 | at both ends, which implies both roots are in [1-,1]. */ | ||
86 | if (fb1 <= 2.0f && fb1 >= -2.0f && | ||
87 | 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0) | ||
88 | goto stable; | ||
89 | } | ||
90 | /* if unstable, just bash to zero */ | ||
91 | fb1 = fb2 = ff1 = ff2 = ff3 = 0; | ||
92 | stable: | ||
93 | c->c_fb1 = ftofix(fb1); | ||
94 | c->c_fb2 = ftofix(fb2); | ||
95 | c->c_ff1 = ftofix(ff1); | ||
96 | c->c_ff2 = ftofix(ff2); | ||
97 | c->c_ff3 = ftofix(ff3); | ||
98 | } | ||
99 | |||
100 | static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv) | ||
101 | { | ||
102 | t_biquadctl *c = x->x_ctl; | ||
103 | c->c_x1 = atom_getfloatarg(0, argc, argv); | ||
104 | c->c_x2 = atom_getfloatarg(1, argc, argv); | ||
105 | } | ||
106 | |||
107 | static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp) | ||
108 | { | ||
109 | dsp_add(sigbiquad_perform, 4, | ||
110 | sp[0]->s_vec, sp[1]->s_vec, | ||
111 | x->x_ctl, sp[0]->s_n); | ||
112 | |||
113 | } | ||
114 | |||
115 | void biquad_tilde_setup(void) | ||
116 | { | ||
117 | sigbiquad_class = class_new(gensym("biquad~"), (t_newmethod)sigbiquad_new, | ||
118 | 0, sizeof(t_sigbiquad), 0, A_GIMME, 0); | ||
119 | CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, x_f); | ||
120 | class_addmethod(sigbiquad_class, (t_method)sigbiquad_dsp, gensym("dsp"), 0); | ||
121 | class_addlist(sigbiquad_class, sigbiquad_list); | ||
122 | class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("set"), | ||
123 | A_GIMME, 0); | ||
124 | class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("clear"), | ||
125 | A_GIMME, 0); | ||
126 | } | ||
127 | #include <m_pd.h> | ||
128 | #include <m_fixed.h> | ||
129 | |||
130 | typedef struct biquadctl | ||
131 | { | ||
132 | t_sample c_x1; | ||
133 | t_sample c_x2; | ||
134 | t_sample c_fb1; | ||
135 | t_sample c_fb2; | ||
136 | t_sample c_ff1; | ||
137 | t_sample c_ff2; | ||
138 | t_sample c_ff3; | ||
139 | } t_biquadctl; | ||
140 | |||
141 | typedef struct sigbiquad | ||
142 | { | ||
143 | t_object x_obj; | ||
144 | float x_f; | ||
145 | t_biquadctl x_cspace; | ||
146 | t_biquadctl *x_ctl; | ||
147 | } t_sigbiquad; | ||
148 | |||
149 | t_class *sigbiquad_class; | ||
150 | |||
151 | static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv); | ||
152 | |||
153 | static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv) | ||
154 | { | ||
155 | t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class); | ||
156 | outlet_new(&x->x_obj, gensym("signal")); | ||
157 | x->x_ctl = &x->x_cspace; | ||
158 | x->x_cspace.c_x1 = x->x_cspace.c_x2 = 0; | ||
159 | sigbiquad_list(x, s, argc, argv); | ||
160 | x->x_f = 0; | ||
161 | return (x); | ||
162 | } | ||
163 | |||
164 | static t_int *sigbiquad_perform(t_int *w) | ||
165 | { | ||
166 | t_sample *in = (t_sample *)(w[1]); | ||
167 | t_sample *out = (t_sample *)(w[2]); | ||
168 | t_biquadctl *c = (t_biquadctl *)(w[3]); | ||
169 | int n = (t_int)(w[4]); | ||
170 | int i; | ||
171 | t_sample last = c->c_x1; | ||
172 | t_sample prev = c->c_x2; | ||
173 | t_sample fb1 = c->c_fb1; | ||
174 | t_sample fb2 = c->c_fb2; | ||
175 | t_sample ff1 = c->c_ff1; | ||
176 | t_sample ff2 = c->c_ff2; | ||
177 | t_sample ff3 = c->c_ff3; | ||
178 | for (i = 0; i < n; i++) | ||
179 | { | ||
180 | t_sample output = *in++ + mult(fb1,last) + mult(fb2,prev); | ||
181 | if (PD_BADFLOAT(output)) | ||
182 | output = 0; | ||
183 | *out++ = mult(ff1,output) + mult(ff2,last) + mult(ff3,prev); | ||
184 | prev = last; | ||
185 | last = output; | ||
186 | } | ||
187 | c->c_x1 = last; | ||
188 | c->c_x2 = prev; | ||
189 | return (w+5); | ||
190 | } | ||
191 | |||
192 | static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv) | ||
193 | { | ||
194 | float fb1 = atom_getfloatarg(0, argc, argv); | ||
195 | float fb2 = atom_getfloatarg(1, argc, argv); | ||
196 | float ff1 = atom_getfloatarg(2, argc, argv); | ||
197 | float ff2 = atom_getfloatarg(3, argc, argv); | ||
198 | float ff3 = atom_getfloatarg(4, argc, argv); | ||
199 | float discriminant = fb1 * fb1 + 4 * fb2; | ||
200 | t_biquadctl *c = x->x_ctl; | ||
201 | if (discriminant < 0) /* imaginary roots -- resonant filter */ | ||
202 | { | ||
203 | /* they're conjugates so we just check that the product | ||
204 | is less than one */ | ||
205 | if (fb2 >= -1.0f) goto stable; | ||
206 | } | ||
207 | else /* real roots */ | ||
208 | { | ||
209 | /* check that the parabola 1 - fb1 x - fb2 x^2 has a | ||
210 | vertex between -1 and 1, and that it's nonnegative | ||
211 | at both ends, which implies both roots are in [1-,1]. */ | ||
212 | if (fb1 <= 2.0f && fb1 >= -2.0f && | ||
213 | 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0) | ||
214 | goto stable; | ||
215 | } | ||
216 | /* if unstable, just bash to zero */ | ||
217 | fb1 = fb2 = ff1 = ff2 = ff3 = 0; | ||
218 | stable: | ||
219 | c->c_fb1 = ftofix(fb1); | ||
220 | c->c_fb2 = ftofix(fb2); | ||
221 | c->c_ff1 = ftofix(ff1); | ||
222 | c->c_ff2 = ftofix(ff2); | ||
223 | c->c_ff3 = ftofix(ff3); | ||
224 | } | ||
225 | |||
226 | static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv) | ||
227 | { | ||
228 | t_biquadctl *c = x->x_ctl; | ||
229 | c->c_x1 = atom_getfloatarg(0, argc, argv); | ||
230 | c->c_x2 = atom_getfloatarg(1, argc, argv); | ||
231 | } | ||
232 | |||
233 | static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp) | ||
234 | { | ||
235 | dsp_add(sigbiquad_perform, 4, | ||
236 | sp[0]->s_vec, sp[1]->s_vec, | ||
237 | x->x_ctl, sp[0]->s_n); | ||
238 | |||
239 | } | ||
240 | |||
241 | void biquad_tilde_setup(void) | ||
242 | { | ||
243 | sigbiquad_class = class_new(gensym("biquad~"), (t_newmethod)sigbiquad_new, | ||
244 | 0, sizeof(t_sigbiquad), 0, A_GIMME, 0); | ||
245 | CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, x_f); | ||
246 | class_addmethod(sigbiquad_class, (t_method)sigbiquad_dsp, gensym("dsp"), 0); | ||
247 | class_addlist(sigbiquad_class, sigbiquad_list); | ||
248 | class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("set"), | ||
249 | A_GIMME, 0); | ||
250 | class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("clear"), | ||
251 | A_GIMME, 0); | ||
252 | } | ||