diff options
Diffstat (limited to 'cyclone/sickle/reson.c')
-rw-r--r-- | cyclone/sickle/reson.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/cyclone/sickle/reson.c b/cyclone/sickle/reson.c new file mode 100644 index 0000000..b072b32 --- /dev/null +++ b/cyclone/sickle/reson.c @@ -0,0 +1,123 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* This filter (cmusic's nres and csound's resonr) originates from + CMJv6n4 article by Smith & Angell. See also section 9.6 of + ``Introduction to Digital Filters'' by Smith. */ + +/* CHECKME if creation args (or defaults) restored after signal disconnection */ + +#include <math.h> +#include "m_pd.h" +#include "shared.h" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define expf exp +#define cosf cos +#endif + +#define RESON_DEFQ .01 +#define RESON_MINQ 1e-20 /* CHECKME */ +#define RESON_MINOMEGA .0001 /* CHECKME */ +#define RESON_MAXOMEGA SHARED_PI /* CHECKME */ + +typedef struct _reson +{ + t_sic x_sic; + float x_srcoef; + float x_xnm1; + float x_xnm2; + float x_ynm1; + float x_ynm2; +} t_reson; + +static t_class *reson_class; + +static void reson_clear(t_reson *x) +{ + x->x_xnm1 = x->x_xnm2 = x->x_ynm1 = x->x_ynm2 = 0.; +} + +/* LATER make ready for optional audio-rate modulation + (separate scalar case routines, use sic_makecostable(), etc.) */ +static t_int *reson_perform(t_int *w) +{ + t_reson *x = (t_reson *)(w[1]); + int nblock = (int)(w[2]); + t_float *xin = (t_float *)(w[3]); + t_float *gin = (t_float *)(w[4]); + t_float fin0 = *(t_float *)(w[5]); + t_float qin0 = *(t_float *)(w[6]); + t_float *out = (t_float *)(w[7]); + float xnm1 = x->x_xnm1; + float xnm2 = x->x_xnm2; + float ynm1 = x->x_ynm1; + float ynm2 = x->x_ynm2; + /* CHECKME sampled once per block */ + float qinv = (qin0 > RESON_MINQ ? -1. / qin0 : (-1. / RESON_MINQ)); + float omega = fin0 * x->x_srcoef; + float radius, c1, c2, scale; + if (omega < RESON_MINOMEGA) + omega = RESON_MINOMEGA; + else if (omega > RESON_MAXOMEGA) + omega = RESON_MAXOMEGA; + radius = expf(omega * qinv); /* radius < 1 (because omega * qinv < 0) */ + c1 = 2. * radius * cosf(omega); + c2 = radius * radius; + scale = 1. - radius; + while (nblock--) + { + float yn, xn = *xin++; + /* CHECKED gain control */ + *out++ = yn = + *gin++ * scale * (xn - radius * xnm2) + c1 * ynm1 - c2 * ynm2; + xnm2 = xnm1; + xnm1 = xn; + ynm2 = ynm1; + ynm1 = yn; + } + x->x_xnm1 = xnm1; + x->x_xnm2 = xnm2; + /* LATER rethink */ + x->x_ynm1 = (PD_BADFLOAT(ynm1) ? 0. : ynm1); + x->x_ynm2 = (PD_BADFLOAT(ynm2) ? 0. : ynm2); + return (w + 8); +} + +static void reson_dsp(t_reson *x, t_signal **sp) +{ + x->x_srcoef = SHARED_2PI / sp[0]->s_sr; + reson_clear(x); + dsp_add(reson_perform, 7, x, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec, + sp[4]->s_vec); +} + +static void *reson_new(t_floatarg f1, t_floatarg f2, t_floatarg f3) +{ + t_reson *x = (t_reson *)pd_new(reson_class); + x->x_srcoef = SHARED_2PI / sys_getsr(); + if (f1 < 0.) f1 = 0.; + if (f2 < 0.) f2 = 0.; + if (f3 <= 0.) + f3 = RESON_DEFQ; /* CHECKED */ + sic_newinlet((t_sic *)x, f1); + sic_newinlet((t_sic *)x, f2); + sic_newinlet((t_sic *)x, f3); + outlet_new((t_object *)x, &s_signal); + reson_clear(x); + return (x); +} + +void reson_tilde_setup(void) +{ + reson_class = class_new(gensym("reson~"), + (t_newmethod)reson_new, 0, + sizeof(t_reson), 0, + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + sic_setup(reson_class, reson_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(reson_class, (t_method)reson_clear, gensym("clear"), 0); +} |