diff options
author | IOhannes m zmölnig <zmoelnig@users.sourceforge.net> | 2013-10-08 09:49:47 +0000 |
---|---|---|
committer | IOhannes m zmölnig <zmoelnig@users.sourceforge.net> | 2013-10-08 09:49:47 +0000 |
commit | 34f56d24a6292938be1a68dad590e51957d98697 (patch) | |
tree | f9391be52261f5f4ad11867612c06b6cc6edfb40 | |
parent | fc89459187380d862daf249c95ed389e3fb6c0d3 (diff) |
half biquad~
svn path=/trunk/externals/zexy/; revision=17213
-rw-r--r-- | src/doublepole~.c | 122 | ||||
-rw-r--r-- | src/z_zexy.c | 1 | ||||
-rw-r--r-- | src/z_zexy.h | 1 |
3 files changed, 124 insertions, 0 deletions
diff --git a/src/doublepole~.c b/src/doublepole~.c new file mode 100644 index 0000000..93a2a74 --- /dev/null +++ b/src/doublepole~.c @@ -0,0 +1,122 @@ +/* Copyright (c) 1997-1999 Miller Puckette. +* For information on usage and redistribution, and for a DISCLAIMER OF ALL +* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* "filters", both linear and nonlinear. +*/ +#include "m_pd.h" +#include <math.h> + +//* ---------------- doublepole~ - raw doublepole filter ----------------- */ + +typedef struct doublepolectl +{ + t_sample c_x1; + t_sample c_x2; + t_sample c_fb1; + t_sample c_fb2; +} t_doublepolectl; + +typedef struct sigdoublepole +{ + t_object x_obj; + t_float x_f; + t_doublepolectl x_cspace; + t_doublepolectl *x_ctl; +} t_sigdoublepole; + +static t_class *sigdoublepole_class = NULL; + +static void sigdoublepole_list(t_sigdoublepole *x, t_symbol *s, int argc, t_atom *argv); + +static void *sigdoublepole_new(t_symbol *s, int argc, t_atom *argv) +{ + t_sigdoublepole *x = (t_sigdoublepole *)pd_new(sigdoublepole_class); + outlet_new(&x->x_obj, &s_signal); + x->x_ctl = &x->x_cspace; + x->x_cspace.c_x1 = x->x_cspace.c_x2 = 0; + sigdoublepole_list(x, s, argc, argv); + x->x_f = 0; + return (x); +} + +static t_int *sigdoublepole_perform(t_int *w) +{ + t_sample *in = (t_sample *)(w[1]); + t_sample *out = (t_sample *)(w[2]); + t_doublepolectl *c = (t_doublepolectl *)(w[3]); + int n = (t_int)(w[4]); + int i; + t_sample last = c->c_x1; + t_sample prev = c->c_x2; + t_sample fb1 = c->c_fb1; + t_sample fb2 = c->c_fb2; + for (i = 0; i < n; i++) + { + t_sample output = *in++ + fb1 * last + fb2 * prev; + if (PD_BIGORSMALL(output)) + output = 0; + *out++ = output; + prev = last; + last = output; + } + c->c_x1 = last; + c->c_x2 = prev; + return (w+5); +} + +static void sigdoublepole_list(t_sigdoublepole *x, t_symbol *s, int argc, t_atom *argv) +{ + t_float fb1 = atom_getfloatarg(0, argc, argv); + t_float fb2 = atom_getfloatarg(1, argc, argv); + t_float discriminant = fb1 * fb1 + 4 * fb2; + t_doublepolectl *c = x->x_ctl; + if (discriminant < 0) /* imaginary roots -- resonant filter */ + { + /* they're conjugates so we just check that the product + is less than one */ + if (fb2 >= -1.0f) goto stable; + } + else /* real roots */ + { + /* check that the parabola 1 - fb1 x - fb2 x^2 has a + vertex between -1 and 1, and that it's nonnegative + at both ends, which implies both roots are in [1-,1]. */ + if (fb1 <= 2.0f && fb1 >= -2.0f && + 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0) + goto stable; + } + /* if unstable, just bash to zero */ + fb1 = fb2 = 0; +stable: + c->c_fb1 = fb1; + c->c_fb2 = fb2; +} + +static void sigdoublepole_set(t_sigdoublepole *x, t_symbol *s, int argc, t_atom *argv) +{ + t_doublepolectl *c = x->x_ctl; + c->c_x1 = atom_getfloatarg(0, argc, argv); + c->c_x2 = atom_getfloatarg(1, argc, argv); +} + +static void sigdoublepole_dsp(t_sigdoublepole *x, t_signal **sp) +{ + dsp_add(sigdoublepole_perform, 4, + sp[0]->s_vec, sp[1]->s_vec, + x->x_ctl, sp[0]->s_n); + +} + +void doublepole_tilde_setup(void) +{ + sigdoublepole_class = class_new(gensym("doublepole~"), (t_newmethod)sigdoublepole_new, + 0, sizeof(t_sigdoublepole), 0, A_GIMME, 0); + CLASS_MAINSIGNALIN(sigdoublepole_class, t_sigdoublepole, x_f); + class_addmethod(sigdoublepole_class, (t_method)sigdoublepole_dsp, gensym("dsp"), 0); + class_addlist(sigdoublepole_class, sigdoublepole_list); + class_addmethod(sigdoublepole_class, (t_method)sigdoublepole_set, gensym("set"), + A_GIMME, 0); + class_addmethod(sigdoublepole_class, (t_method)sigdoublepole_set, gensym("clear"), + A_GIMME, 0); +} diff --git a/src/z_zexy.c b/src/z_zexy.c index 4efc3d8..0a6c5b5 100644 --- a/src/z_zexy.c +++ b/src/z_zexy.c @@ -27,6 +27,7 @@ void z_zexy_setup(void) demultiplex_setup(); /* demultiplex */ dfreq_tilde_setup(); /* dfreq~ */ dirac_tilde_setup(); /* dirac~ */ + doublepole_tilde_setup(); /* doublepole~ */ drip_setup(); /* drip */ envrms_tilde_setup(); /* envrms~ */ fifop_setup(); /* fifop */ diff --git a/src/z_zexy.h b/src/z_zexy.h index 2699361..f8f6c55 100644 --- a/src/z_zexy.h +++ b/src/z_zexy.h @@ -25,6 +25,7 @@ void demultiplex_tilde_setup(void); /* demultiplex~ */ void demultiplex_setup(void); /* demultiplex */ void dfreq_tilde_setup(void); /* dfreq~ */ void dirac_tilde_setup(void); /* dirac~ */ +void doublepole_tilde_setup(void); /* doublepole~ */ void drip_setup(void); /* drip */ void envrms_tilde_setup(void); /* envrms~ */ void fifop_setup(void); /* fifop */ |