aboutsummaryrefslogtreecommitdiff
path: root/cyclone/sickle/svf.c
diff options
context:
space:
mode:
Diffstat (limited to 'cyclone/sickle/svf.c')
-rw-r--r--cyclone/sickle/svf.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/cyclone/sickle/svf.c b/cyclone/sickle/svf.c
new file mode 100644
index 0000000..900a78c
--- /dev/null
+++ b/cyclone/sickle/svf.c
@@ -0,0 +1,169 @@
+/* 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. */
+
+/* Based on Chamberlin's prototype from "Musical Applications of
+ Microprocessors" (csound's svfilter). Slightly distorted,
+ no upsampling. */
+
+/* CHECKED scalar case: input preserved (not coefs) after changing mode */
+/* 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 cosf cos
+#endif
+
+#define SVF_HZ 0
+#define SVF_LINEAR 1
+#define SVF_RADIANS 2
+#define SVF_DRIVE .0001
+#define SVF_QSTRETCH 1.2 /* CHECKED */
+#define SVF_MINR 0. /* CHECKME */
+#define SVF_MAXR 1.2 /* CHECKME */
+#define SVF_MINOMEGA 0. /* CHECKME */
+#define SVF_MAXOMEGA (SHARED_PI * .5) /* CHECKME */
+
+typedef struct _svf
+{
+ t_sic x_sic;
+ int x_mode;
+ float x_srcoef;
+ float x_band;
+ float x_low;
+} t_svf;
+
+static t_class *svf_class;
+
+static t_symbol *ps_hz;
+static t_symbol *ps_linear;
+static t_symbol *ps_radians;
+
+static void svf_clear(t_svf *x)
+{
+ x->x_band = x->x_low = 0.;
+}
+
+static void svf_hz(t_svf *x)
+{
+ x->x_mode = SVF_HZ;
+}
+
+static void svf_linear(t_svf *x)
+{
+ x->x_mode = SVF_LINEAR;
+}
+
+static void svf_radians(t_svf *x)
+{
+ x->x_mode = SVF_RADIANS;
+}
+
+/* LATER make ready for optional audio-rate modulation
+ (separate scalar case routines, use sic_makecostable(), etc.) */
+static t_int *svf_perform(t_int *w)
+{
+ t_svf *x = (t_svf *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *xin = (t_float *)(w[3]);
+ t_float fin0 = *(t_float *)(w[4]);
+ t_float rin0 = *(t_float *)(w[5]);
+ t_float *lout = (t_float *)(w[6]);
+ t_float *hout = (t_float *)(w[7]);
+ t_float *bout = (t_float *)(w[8]);
+ t_float *nout = (t_float *)(w[9]);
+ float band = x->x_band;
+ float low = x->x_low;
+ /* CHECKME sampled once per block */
+ float c1, c2;
+ float r = (1. - rin0) * SVF_QSTRETCH; /* CHECKED */
+ if (r < SVF_MINR)
+ r = SVF_MINR;
+ else if (r > SVF_MAXR)
+ r = SVF_MAXR;
+ c2 = r * r;
+ if (x->x_mode == SVF_HZ)
+ {
+ float omega = fin0 * x->x_srcoef;
+ if (omega < SVF_MINOMEGA)
+ omega = SVF_MINOMEGA;
+ else if (omega > SVF_MAXOMEGA)
+ omega = SVF_MAXOMEGA;
+ c1 = sinf(omega);
+ /* CHECKED irs slightly drift apart at high omega, LATER investigate */
+ }
+ else if (x->x_mode == SVF_LINEAR)
+ c1 = sinf(fin0 * (SHARED_PI * .5)); /* CHECKME actual range of fin0 */
+ else
+ c1 = fin0; /* CHECKME range */
+ while (nblock--)
+ {
+ float high, xn = *xin++;
+ *lout++ = low = low + c1 * band;
+ *hout++ = high = xn - low - c2 * band;
+ *bout++ = band = c1 * high + band;
+ *nout++ = low + high;
+ band -= band * band * band * SVF_DRIVE;
+ }
+ /* LATER rethink */
+ x->x_band = (PD_BADFLOAT(band) ? 0. : band);
+ x->x_low = (PD_BADFLOAT(low) ? 0. : low);
+ return (w + 10);
+}
+
+static void svf_dsp(t_svf *x, t_signal **sp)
+{
+ x->x_srcoef = SHARED_2PI / sp[0]->s_sr;
+ svf_clear(x);
+ dsp_add(svf_perform, 9, 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, sp[5]->s_vec, sp[6]->s_vec);
+}
+
+static void *svf_new(t_symbol *s, t_floatarg f1, t_floatarg f2)
+{
+ t_svf *x = (t_svf *)pd_new(svf_class);
+ x->x_srcoef = SHARED_PI / sys_getsr();
+ sic_newinlet((t_sic *)x, f1);
+ sic_newinlet((t_sic *)x, f2);
+ outlet_new((t_object *)x, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ svf_clear(x);
+ if (s == ps_linear)
+ x->x_mode = SVF_LINEAR;
+ else if (s == ps_radians)
+ x->x_mode = SVF_RADIANS;
+ else
+ {
+ x->x_mode = SVF_HZ;
+ if (s && s != &s_ && s != ps_hz && s != gensym("Hz"))
+ {
+ /* CHECKED no warning */
+ }
+ }
+ return (x);
+}
+
+void svf_tilde_setup(void)
+{
+ ps_hz = gensym("hz");
+ ps_linear = gensym("linear");
+ ps_radians = gensym("radians");
+ svf_class = class_new(gensym("svf~"),
+ (t_newmethod)svf_new, 0,
+ sizeof(t_svf), 0,
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFSYM, 0);
+ sic_setup(svf_class, svf_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(svf_class, (t_method)svf_clear, gensym("clear"), 0);
+ class_addmethod(svf_class, (t_method)svf_hz, ps_hz, 0);
+ class_addmethod(svf_class, (t_method)svf_hz, gensym("Hz"), 0);
+ class_addmethod(svf_class, (t_method)svf_linear, ps_linear, 0);
+ class_addmethod(svf_class, (t_method)svf_radians, ps_radians, 0);
+}