Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin...
[kugel-rb.git] / apps / plugins / pdbox / PDa / extra / hlshelf.c
blob46190c9b7cf765f2cb55ed71f604a37c956a7cc6
1 /* (C) Guenter Geiger <geiger@epy.co.at> */
4 #include <m_pd.h>
5 #include <math.h>
7 #ifdef NT
8 #pragma warning( disable : 4244 )
9 #pragma warning( disable : 4305 )
10 #endif
12 /* ------------------------ hlshelf ----------------------------- */
15 #ifndef M_PI
16 #define M_PI 3.141593f
17 #endif
19 #define SRATE 44100.0
20 #define MAX_GAIN 120.0f
22 static t_class *hlshelf_class;
25 typedef struct _hlshelf
27 t_object x_obj;
28 float s_rate;
29 float s_gain0;
30 float s_gain1;
31 float s_gain2;
32 float s_ltransfq;
33 float s_htransfq;
34 float s_lradians;
35 float s_hradians;
36 } t_hlshelf;
39 int hlshelf_check_stability(t_float fb1,
40 t_float fb2,
41 t_float ff1,
42 t_float ff2,
43 t_float ff3)
45 float discriminant = fb1 * fb1 + 4 * fb2;
47 if (discriminant < 0) /* imaginary roots -- resonant filter */
49 /* they're conjugates so we just check that the product
50 is less than one */
51 if (fb2 >= -1.0f) goto stable;
53 else /* real roots */
55 /* check that the parabola 1 - fb1 x - fb2 x^2 has a
56 vertex between -1 and 1, and that it's nonnegative
57 at both ends, which implies both roots are in [1-,1]. */
58 if (fb1 <= 2.0f && fb1 >= -2.0f &&
59 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
60 goto stable;
62 return 0;
63 stable:
64 return 1;
68 void hlshelf_check(t_hlshelf *x)
71 if(x->s_gain0 - x->s_gain1 > MAX_GAIN) {
72 x->s_gain0 = x->s_gain1 + MAX_GAIN;
73 post("setting gain0 to %f",x->s_gain0);
77 if(x->s_gain1 > MAX_GAIN) {
78 x->s_gain1 = MAX_GAIN;
79 post("setting gain1 to %f",x->s_gain1);
82 if(x->s_gain2 - x->s_gain1 > MAX_GAIN) {
83 x->s_gain2 = x->s_gain1 + MAX_GAIN;
84 post("setting gain2 to %f",x->s_gain2);
87 /* constrain: 0 <= x->s_ltransfq < x->s_htransfq. */
88 x->s_ltransfq = (x->s_ltransfq < x->s_htransfq) ? x->s_ltransfq : x->s_htransfq - 0.5f;
90 if (x->s_ltransfq < 0) x->s_ltransfq = 0.0f;
92 x->s_lradians = M_PI * x->s_ltransfq / x->s_rate;
93 x->s_hradians= M_PI * (0.5f - (x->s_htransfq / x->s_rate));
98 void hlshelf_bang(t_hlshelf *x)
100 t_atom at[6];
101 float c0, c1, c2, d0, d1, d2; /* output coefs */
102 float a1, a2, b1, b2, g1, g2; /* temp coefs */
103 double xf;
105 hlshelf_check(x);
107 /* low shelf */
108 xf = 0.5 * 0.115129255 * (double)(x->s_gain0 - x->s_gain1); /* ln(10) / 20 = 0.115129255 */
109 if(xf < -200.) /* exp(x) -> 0 */
111 a1 = 1.0f;
112 b1 = -1.0f;
113 g1 = 0.0f;
115 else
117 double t = tan(x->s_lradians);
118 double e = exp(xf);
119 double r = t / e;
120 double kr = t * e;
122 a1 = (r - 1) / (r + 1);
123 b1 = (kr - 1) / (kr + 1);
124 g1 = (kr + 1) / (r + 1);
127 /* high shelf */
128 xf = 0.5 * 0.115129255 * (double)(x->s_gain2 - x->s_gain1); /* ln(10) / 20 = 0.115129255 */
129 if(xf < -200.) /* exp(x) -> 0 */
131 a2 = -1.0f;
132 b2 = 1.0f;
133 g2 = 0.0f;
135 else
137 double t = tan(x->s_hradians);
138 double e = exp(xf);
139 double r = t / e;
140 double kr = t * e;
142 a2 = (1 - r) / (1 + r);
143 b2 = (1 - kr) / (1 + kr);
144 g2 = (1 + kr) / (1 + r);
147 /* form product */
148 c0 = g1 * g2 * (float)(exp((double)(x->s_gain1) * 0.05f * 2.302585093f)); ;
149 c1 = a1 + a2;
150 c2 = a1 * a2;
151 d0 = 1.0f;
152 d1 = b1 + b2;
153 d2 = b1 * b2;
155 if (!hlshelf_check_stability(-c1/d0,-c2/d0,d0/d0,d1/d0,d2/d0)) {
156 post("hlshelf: filter unstable -> resetting");
157 c0=1.;c1=0.;c2=0.;
158 d0=1.;d1=0.;d2=0.;
161 SETFLOAT(at,-c1/d0);
162 SETFLOAT(at+1,-c2/d0);
163 SETFLOAT(at+2,d0/d0);
164 SETFLOAT(at+3,d1/d0);
165 SETFLOAT(at+4,d2/d0);
167 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
170 void hlshelf_float(t_hlshelf *x,t_floatarg f)
172 x->s_gain0 = f;
173 hlshelf_bang(x);
177 static void *hlshelf_new(t_symbol* s,t_int argc, t_atom* at)
179 t_hlshelf *x = (t_hlshelf *)pd_new(hlshelf_class);
180 t_float k0 = atom_getfloat(at);
181 t_float k1 = atom_getfloat(at+1);
182 t_float k2 = atom_getfloat(at+2);
183 t_float f1 = atom_getfloat(at+3);
184 t_float f2 = atom_getfloat(at+4);
187 f1 = atom_getfloat(at);
188 f2 = atom_getfloat(at);
190 if ((f1 == 0.0f && f2 == 0.0f) || f1 > f2){ /* all gains = 0db */
191 f1 = 150.0f;
192 f2 = 5000.0f;
195 if (f1 < 0) f1 = 0.0f;
196 if (f2 > SRATE) f2 = .5f*SRATE;
198 x->s_rate = SRATE; /* srate default */
199 x->s_gain0 = k0;
200 x->s_gain1 = k1;
201 x->s_gain2 = k2;
203 x->s_ltransfq = 0.0f;
204 x->s_htransfq = SRATE/2;
206 x->s_lradians = M_PI * x->s_ltransfq / x->s_rate;
207 x->s_hradians= M_PI * (0.5f - (x->s_htransfq / x->s_rate));
209 floatinlet_new(&x->x_obj, &x->s_gain1);
210 floatinlet_new(&x->x_obj, &x->s_gain2);
211 floatinlet_new(&x->x_obj, &x->s_ltransfq);
212 floatinlet_new(&x->x_obj, &x->s_htransfq);
213 outlet_new(&x->x_obj, &s_list);
215 return (x);
218 void hlshelf_setup(void)
220 hlshelf_class = class_new(gensym("hlshelf"), (t_newmethod)hlshelf_new, 0,
221 sizeof(t_hlshelf), 0, A_GIMME, 0);
222 class_addbang(hlshelf_class,hlshelf_bang);
223 class_addfloat(hlshelf_class,hlshelf_float);
227 /* (C) Guenter Geiger <geiger@epy.co.at> */
230 #include <m_pd.h>
231 #include <math.h>
233 #ifdef NT
234 #pragma warning( disable : 4244 )
235 #pragma warning( disable : 4305 )
236 #endif
238 /* ------------------------ hlshelf ----------------------------- */
241 #ifndef M_PI
242 #define M_PI 3.141593f
243 #endif
245 #define SRATE 44100.0
246 #define MAX_GAIN 120.0f
248 static t_class *hlshelf_class;
251 typedef struct _hlshelf
253 t_object x_obj;
254 float s_rate;
255 float s_gain0;
256 float s_gain1;
257 float s_gain2;
258 float s_ltransfq;
259 float s_htransfq;
260 float s_lradians;
261 float s_hradians;
262 } t_hlshelf;
265 int hlshelf_check_stability(t_float fb1,
266 t_float fb2,
267 t_float ff1,
268 t_float ff2,
269 t_float ff3)
271 float discriminant = fb1 * fb1 + 4 * fb2;
273 if (discriminant < 0) /* imaginary roots -- resonant filter */
275 /* they're conjugates so we just check that the product
276 is less than one */
277 if (fb2 >= -1.0f) goto stable;
279 else /* real roots */
281 /* check that the parabola 1 - fb1 x - fb2 x^2 has a
282 vertex between -1 and 1, and that it's nonnegative
283 at both ends, which implies both roots are in [1-,1]. */
284 if (fb1 <= 2.0f && fb1 >= -2.0f &&
285 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
286 goto stable;
288 return 0;
289 stable:
290 return 1;
294 void hlshelf_check(t_hlshelf *x)
297 if(x->s_gain0 - x->s_gain1 > MAX_GAIN) {
298 x->s_gain0 = x->s_gain1 + MAX_GAIN;
299 post("setting gain0 to %f",x->s_gain0);
303 if(x->s_gain1 > MAX_GAIN) {
304 x->s_gain1 = MAX_GAIN;
305 post("setting gain1 to %f",x->s_gain1);
308 if(x->s_gain2 - x->s_gain1 > MAX_GAIN) {
309 x->s_gain2 = x->s_gain1 + MAX_GAIN;
310 post("setting gain2 to %f",x->s_gain2);
313 /* constrain: 0 <= x->s_ltransfq < x->s_htransfq. */
314 x->s_ltransfq = (x->s_ltransfq < x->s_htransfq) ? x->s_ltransfq : x->s_htransfq - 0.5f;
316 if (x->s_ltransfq < 0) x->s_ltransfq = 0.0f;
318 x->s_lradians = M_PI * x->s_ltransfq / x->s_rate;
319 x->s_hradians= M_PI * (0.5f - (x->s_htransfq / x->s_rate));
324 void hlshelf_bang(t_hlshelf *x)
326 t_atom at[6];
327 float c0, c1, c2, d0, d1, d2; /* output coefs */
328 float a1, a2, b1, b2, g1, g2; /* temp coefs */
329 double xf;
331 hlshelf_check(x);
333 /* low shelf */
334 xf = 0.5 * 0.115129255 * (double)(x->s_gain0 - x->s_gain1); /* ln(10) / 20 = 0.115129255 */
335 if(xf < -200.) /* exp(x) -> 0 */
337 a1 = 1.0f;
338 b1 = -1.0f;
339 g1 = 0.0f;
341 else
343 double t = tan(x->s_lradians);
344 double e = exp(xf);
345 double r = t / e;
346 double kr = t * e;
348 a1 = (r - 1) / (r + 1);
349 b1 = (kr - 1) / (kr + 1);
350 g1 = (kr + 1) / (r + 1);
353 /* high shelf */
354 xf = 0.5 * 0.115129255 * (double)(x->s_gain2 - x->s_gain1); /* ln(10) / 20 = 0.115129255 */
355 if(xf < -200.) /* exp(x) -> 0 */
357 a2 = -1.0f;
358 b2 = 1.0f;
359 g2 = 0.0f;
361 else
363 double t = tan(x->s_hradians);
364 double e = exp(xf);
365 double r = t / e;
366 double kr = t * e;
368 a2 = (1 - r) / (1 + r);
369 b2 = (1 - kr) / (1 + kr);
370 g2 = (1 + kr) / (1 + r);
373 /* form product */
374 c0 = g1 * g2 * (float)(exp((double)(x->s_gain1) * 0.05f * 2.302585093f)); ;
375 c1 = a1 + a2;
376 c2 = a1 * a2;
377 d0 = 1.0f;
378 d1 = b1 + b2;
379 d2 = b1 * b2;
381 if (!hlshelf_check_stability(-c1/d0,-c2/d0,d0/d0,d1/d0,d2/d0)) {
382 post("hlshelf: filter unstable -> resetting");
383 c0=1.;c1=0.;c2=0.;
384 d0=1.;d1=0.;d2=0.;
387 SETFLOAT(at,-c1/d0);
388 SETFLOAT(at+1,-c2/d0);
389 SETFLOAT(at+2,d0/d0);
390 SETFLOAT(at+3,d1/d0);
391 SETFLOAT(at+4,d2/d0);
393 outlet_list(x->x_obj.ob_outlet,&s_list,5,at);
396 void hlshelf_float(t_hlshelf *x,t_floatarg f)
398 x->s_gain0 = f;
399 hlshelf_bang(x);
403 static void *hlshelf_new(t_symbol* s,t_int argc, t_atom* at)
405 t_hlshelf *x = (t_hlshelf *)pd_new(hlshelf_class);
406 t_float k0 = atom_getfloat(at);
407 t_float k1 = atom_getfloat(at+1);
408 t_float k2 = atom_getfloat(at+2);
409 t_float f1 = atom_getfloat(at+3);
410 t_float f2 = atom_getfloat(at+4);
413 f1 = atom_getfloat(at);
414 f2 = atom_getfloat(at);
416 if ((f1 == 0.0f && f2 == 0.0f) || f1 > f2){ /* all gains = 0db */
417 f1 = 150.0f;
418 f2 = 5000.0f;
421 if (f1 < 0) f1 = 0.0f;
422 if (f2 > SRATE) f2 = .5f*SRATE;
424 x->s_rate = SRATE; /* srate default */
425 x->s_gain0 = k0;
426 x->s_gain1 = k1;
427 x->s_gain2 = k2;
429 x->s_ltransfq = 0.0f;
430 x->s_htransfq = SRATE/2;
432 x->s_lradians = M_PI * x->s_ltransfq / x->s_rate;
433 x->s_hradians= M_PI * (0.5f - (x->s_htransfq / x->s_rate));
435 floatinlet_new(&x->x_obj, &x->s_gain1);
436 floatinlet_new(&x->x_obj, &x->s_gain2);
437 floatinlet_new(&x->x_obj, &x->s_ltransfq);
438 floatinlet_new(&x->x_obj, &x->s_htransfq);
439 outlet_new(&x->x_obj, &s_list);
441 return (x);
444 void hlshelf_setup(void)
446 hlshelf_class = class_new(gensym("hlshelf"), (t_newmethod)hlshelf_new, 0,
447 sizeof(t_hlshelf), 0, A_GIMME, 0);
448 class_addbang(hlshelf_class,hlshelf_bang);
449 class_addfloat(hlshelf_class,hlshelf_float);