aboutsummaryrefslogtreecommitdiff
path: root/cyclone
diff options
context:
space:
mode:
Diffstat (limited to 'cyclone')
-rw-r--r--cyclone/sickle/curve.c462
-rw-r--r--cyclone/sickle/curve.gp9
-rw-r--r--cyclone/sickle/lores.c109
-rw-r--r--cyclone/sickle/mstosamps.c55
-rw-r--r--cyclone/sickle/onepole.c151
-rw-r--r--cyclone/sickle/pink.c100
-rw-r--r--cyclone/sickle/poke.c155
-rw-r--r--cyclone/sickle/reson.c123
-rw-r--r--cyclone/sickle/sampstoms.c55
-rw-r--r--cyclone/sickle/svf.c169
-rw-r--r--cyclone/sickle/zerox.c78
11 files changed, 1466 insertions, 0 deletions
diff --git a/cyclone/sickle/curve.c b/cyclone/sickle/curve.c
new file mode 100644
index 0000000..e6bade1
--- /dev/null
+++ b/cyclone/sickle/curve.c
@@ -0,0 +1,462 @@
+/* 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. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "common/grow.h"
+#include "common/loud.h"
+#include "sickle/sic.h"
+
+//#define CURVE_DEBUG
+
+/* CHECKED apparently c74's formula was not very carefully tuned. It has 5%
+ deviation from the straight line for ccinput=0 (ccinput is user's curve
+ control parameter, <0..1>) at half-domain, range=1. It generates nans for
+ ccinput > .995.
+
+ The formula below generates curves with < .000004% deviation and no nans.
+
+ Problem: find a function f : ccinput -> cc, such that the curves will bend
+ in a semi-linear way over the ccinput's range of 0..1. The curve function
+ is then g(x, p) = (exp(f(p) * x) - 1) / (exp(f(p)) - 1), where x is curve's
+ domain, and p is ccinput. If, for example, the points g(0.5, p) are to make
+ a semi-linear pattern, then the solution is a function f that minimizes
+ the integral of the error function e(p) = sqr(((1-p)/2)-g(.5, p)) over 0..1.
+ Until someone does this analytically, we are left with a lame formula, which
+ has been tweaked and tested in gnuplot: f(p) = h(p) / (1 - h(p)), where
+ h(p) = (((p + 1e-20) * 1.2) ** .41) * .91. The file curve.gp, in the
+ sickle's source directory, may come handy, in case there is anyone, who
+ fancy tweaking it even further.
+
+ To implement this, start from these equations:
+ bb * mm ^ npoints = bb + 1
+ (bb ^ 2) * (mm ^ npoints) = ((exp(ff/2) - 1) / (exp(ff) - 1)) ^ 2
+
+ and calculate:
+ hh = pow(((ccinput + c1) * c2), c3) * c4
+ ff = hh / (1 - hh)
+ eff = exp(ff) - 1
+ gh = (exp(ff * .5) - 1) / eff
+ bb = gh * (gh / (1 - (gh + gh)))
+ mm = ((exp(ff * (1/npoints)) - 1) / (eff * bb)) + 1
+
+ The loop is:
+ for (vv = bb, i = 0; i < n; vv *= mm, i++)
+ result = (vv - bb) * (y1 - y0) + y0
+ where y0, y1 are start and destination values
+*/
+
+#define CURVE_C1 1e-20
+#define CURVE_C2 1.2
+#define CURVE_C3 0.41
+#define CURVE_C4 0.91
+
+#define CURVE_MINCCINPUT -1.
+#define CURVE_MAXCCINPUT 1.
+
+#define CURVE_INISIZE 64 /* LATER rethink */
+#define CURVE_MAXSIZE 64
+
+typedef struct _curveseg
+{
+ float s_target;
+ float s_delta;
+ int s_npoints;
+ float s_ccinput;
+ double s_bb;
+ double s_mm;
+} t_curveseg;
+
+typedef struct _curve
+{
+ t_sic x_sic;
+ float x_value;
+ float x_ccinput;
+ float x_target;
+ float x_delta;
+ int x_deltaset;
+ double x_vv;
+ double x_bb;
+ double x_mm;
+ float x_y0;
+ float x_dy;
+ float x_ksr;
+ int x_nleft;
+ int x_retarget;
+ int x_size; /* as allocated */
+ int x_nsegs; /* as used */
+ t_curveseg *x_curseg;
+ t_curveseg *x_segs;
+ t_curveseg x_segini[CURVE_INISIZE];
+ t_clock *x_clock;
+ t_outlet *x_bangout;
+#ifdef CURVE_DEBUG
+ int dbg_nretargets;
+ int dbg_exitpoint;
+ int dbg_npoints;
+#endif
+} t_curve;
+
+static t_class *curve_class;
+static double curve_coef;
+
+static void curve_cc(t_curve *x, t_curveseg *segp, float f)
+{
+ int npoints = segp->s_delta * x->x_ksr + 0.5; /* LATER rethink */
+ segp->s_ccinput = f;
+ if (npoints > 0)
+ {
+ double hh, ff, eff, gh;
+ segp->s_npoints = npoints;
+ if (f < 0)
+ {
+ if (f < CURVE_MINCCINPUT)
+ f = CURVE_MINCCINPUT;
+ hh = pow(((CURVE_C1 - f) * CURVE_C2), CURVE_C3) * CURVE_C4;
+ ff = hh / (1. - hh);
+ eff = exp(ff) - 1.;
+ gh = (exp(ff * .5) - 1.) / eff;
+ segp->s_bb = gh * (gh / (1. - (gh + gh)));
+ segp->s_mm = 1. / (((exp(ff * (1. / (double)npoints)) - 1.) /
+ (eff * segp->s_bb)) + 1.);
+ }
+ else
+ {
+ if (f > CURVE_MAXCCINPUT)
+ f = CURVE_MAXCCINPUT;
+ hh = pow(((f + CURVE_C1) * CURVE_C2), CURVE_C3) * CURVE_C4;
+ ff = hh / (1. - hh);
+ eff = exp(ff) - 1.;
+ gh = (exp(ff * .5) - 1.) / eff;
+ segp->s_bb = gh * (gh / (1. - (gh + gh)));
+ segp->s_mm = ((exp(ff * (1. / (double)npoints)) - 1.) /
+ (eff * segp->s_bb)) + 1.;
+ }
+ }
+ else
+ {
+ segp->s_npoints = 0;
+ segp->s_bb = segp->s_mm = 1.;
+ }
+#ifdef CURVE_DEBUG
+ post("%g %g %g %g",
+ segp->s_target, segp->s_delta, segp->s_bb, segp->s_mm);
+#endif
+}
+
+static void curve_tick(t_curve *x)
+{
+ outlet_bang(x->x_bangout);
+#ifdef CURVE_DEBUG
+ post("exit point %d, after %d retarget calls",
+ x->dbg_exitpoint, x->dbg_nretargets);
+ post("at value %g, after last %d npoints, with bb %g, mm %g",
+ x->x_value, x->dbg_npoints, x->x_bb, x->x_mm);
+ x->dbg_nretargets = x->dbg_exitpoint = x->dbg_npoints = 0;
+#endif
+}
+
+static t_int *curve_perform(t_int *w)
+{
+ t_curve *x = (t_curve *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int nblock = (int)(w[3]);
+ int nxfer = x->x_nleft;
+ float curval = x->x_value;
+ double vv = x->x_vv;
+ double bb = x->x_bb;
+ double mm = x->x_mm;
+ float dy = x->x_dy;
+ float y0 = x->x_y0;
+ if (PD_BADFLOAT(curval)) /* LATER rethink */
+ curval = x->x_value = 0;
+retarget:
+ if (x->x_retarget)
+ {
+ float target = x->x_curseg->s_target;
+ float delta = x->x_curseg->s_delta;
+ int npoints = x->x_curseg->s_npoints;
+ mm = x->x_curseg->s_mm;
+ if (x->x_curseg->s_ccinput < 0)
+ {
+ bb = x->x_curseg->s_bb + 1.;
+ dy = x->x_value - target;
+ }
+ else
+ {
+ bb = x->x_curseg->s_bb;
+ dy = target - x->x_value;
+ }
+#ifdef CURVE_DEBUG
+ x->dbg_nretargets++;
+#endif
+ x->x_nsegs--;
+ x->x_curseg++;
+ while (npoints <= 0)
+ {
+ curval = x->x_value = target;
+ if (x->x_nsegs)
+ {
+ target = x->x_curseg->s_target;
+ delta = x->x_curseg->s_delta;
+ npoints = x->x_curseg->s_npoints;
+ mm = x->x_curseg->s_mm;
+ if (x->x_curseg->s_ccinput < 0)
+ {
+ bb = x->x_curseg->s_bb + 1.;
+ dy = x->x_value - target;
+ }
+ else
+ {
+ bb = x->x_curseg->s_bb;
+ dy = target - x->x_value;
+ }
+ x->x_nsegs--;
+ x->x_curseg++;
+ }
+ else
+ {
+ while (nblock--) *out++ = curval;
+ x->x_nleft = 0;
+#ifdef CURVE_DEBUG
+ x->dbg_exitpoint = 1;
+#endif
+ clock_delay(x->x_clock, 0);
+ x->x_retarget = 0;
+ return (w + 4);
+ }
+ }
+ nxfer = x->x_nleft = npoints;
+ x->x_vv = vv = bb;
+ x->x_bb = bb;
+ x->x_mm = mm;
+ x->x_dy = dy;
+ x->x_y0 = y0 = x->x_value;
+ x->x_target = target;
+ x->x_retarget = 0;
+#ifdef CURVE_DEBUG
+ x->dbg_npoints = npoints;
+#endif
+ }
+ if (nxfer >= nblock)
+ {
+ int silly = ((x->x_nleft -= nblock) == 0); /* LATER rethink */
+ while (nblock--)
+ {
+ *out++ = curval = (vv - bb) * dy + y0;
+ vv *= mm;
+ }
+ if (silly)
+ {
+ if (x->x_nsegs) x->x_retarget = 1;
+ else
+ {
+#ifdef CURVE_DEBUG
+ x->dbg_exitpoint = 2;
+#endif
+ clock_delay(x->x_clock, 0);
+ }
+ x->x_value = x->x_target;
+ }
+ else
+ {
+ x->x_value = curval;
+ x->x_vv = vv;
+ }
+ }
+ else if (nxfer > 0)
+ {
+ nblock -= nxfer;
+ do
+ *out++ = (vv - bb) * dy + y0, vv *= mm;
+ while (--nxfer);
+ curval = x->x_value = x->x_target;
+ if (x->x_nsegs)
+ {
+ x->x_retarget = 1;
+ goto retarget;
+ }
+ else
+ {
+ while (nblock--) *out++ = curval;
+ x->x_nleft = 0;
+#ifdef CURVE_DEBUG
+ x->dbg_exitpoint = 3;
+#endif
+ clock_delay(x->x_clock, 0);
+ }
+ }
+ else while (nblock--) *out++ = curval;
+ return (w + 4);
+}
+
+static void curve_float(t_curve *x, t_float f)
+{
+ if (x->x_deltaset)
+ {
+ x->x_deltaset = 0;
+ x->x_target = f;
+ x->x_nsegs = 1;
+ x->x_curseg = x->x_segs;
+ x->x_curseg->s_target = f;
+ x->x_curseg->s_delta = x->x_delta;
+#ifdef CURVE_DEBUG
+ startpost("single segment: ");
+#endif
+ curve_cc(x, x->x_curseg, x->x_ccinput);
+ x->x_retarget = 1;
+ }
+ else
+ {
+ x->x_value = x->x_target = f;
+ x->x_nsegs = 0;
+ x->x_curseg = 0;
+ x->x_nleft = 0;
+ x->x_retarget = 0;
+ }
+}
+
+/* CHECKED delta is not persistent, but ccinput is */
+static void curve_ft1(t_curve *x, t_floatarg f)
+{
+ x->x_delta = f;
+ x->x_deltaset = (f > 0);
+}
+
+static void curve_list(t_curve *x, t_symbol *s, int ac, t_atom *av)
+{
+ int natoms, nsegs, odd;
+ t_atom *ap;
+ t_curveseg *segp;
+ for (natoms = 0, ap = av; natoms < ac; natoms++, ap++)
+ {
+ if (ap->a_type != A_FLOAT)
+ {
+ loud_messarg((t_pd *)x, &s_list); /* CHECKED */
+ return; /* CHECKED */
+ }
+ }
+ if (!natoms)
+ return; /* CHECKED */
+ odd = natoms % 3;
+ nsegs = natoms / 3;
+ if (odd) nsegs++;
+ if (nsegs > x->x_size)
+ {
+ int ns = nsegs;
+ x->x_segs = grow_nodata(&ns, &x->x_size, x->x_segs,
+ CURVE_INISIZE, x->x_segini,
+ sizeof(*x->x_segs));
+ if (ns < nsegs)
+ {
+ natoms = ns * 3;
+ nsegs = ns;
+ odd = 0;
+ }
+ }
+ x->x_nsegs = nsegs;
+#ifdef CURVE_DEBUG
+ post("%d segments:", x->x_nsegs);
+#endif
+ segp = x->x_segs;
+ if (odd) nsegs--;
+ while (nsegs--)
+ {
+ segp->s_target = av++->a_w.w_float;
+ segp->s_delta = av++->a_w.w_float;
+ curve_cc(x, segp, av++->a_w.w_float);
+ segp++;
+ }
+ if (odd)
+ {
+ segp->s_target = av->a_w.w_float;
+ if (odd > 1)
+ segp->s_delta = av[1].a_w.w_float;
+ else
+ segp->s_delta = 0;
+ curve_cc(x, segp, 0.);
+ }
+ x->x_deltaset = 0;
+ x->x_target = x->x_segs->s_target;
+ x->x_curseg = x->x_segs;
+ x->x_retarget = 1;
+}
+
+/* CHECKED no stop, pity... */
+#if 0
+static void curve_stop(t_curve *x)
+{
+ x->x_target = x->x_value;
+ x->x_nleft = 0;
+ x->x_retarget = 0;
+ x->x_nsegs = 0;
+ x->x_curseg = 0;
+}
+#endif
+
+static void curve_dsp(t_curve *x, t_signal **sp)
+{
+ float ksr = sp[0]->s_sr * 0.001;
+ if (ksr != x->x_ksr)
+ {
+ int nsegs = x->x_nsegs;
+ t_curveseg *segp = x->x_segs;
+ x->x_ksr = ksr;
+ while (nsegs--)
+ {
+ curve_cc(x, segp, segp->s_ccinput);
+ segp++;
+ }
+ }
+ dsp_add(curve_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void curve_free(t_curve *x)
+{
+ if (x->x_segs != x->x_segini)
+ freebytes(x->x_segs, x->x_size * sizeof(*x->x_segs));
+ if (x->x_clock) clock_free(x->x_clock);
+}
+
+static void *curve_new(t_floatarg f1, t_floatarg f2)
+{
+ static int initialized = 0;
+ t_curve *x = (t_curve *)pd_new(curve_class);
+ if (!initialized)
+ {
+ curve_coef = CURVE_C2 / exp(CURVE_C3);
+ initialized = 1;
+ }
+ x->x_value = x->x_target = f1;
+ x->x_ccinput = f2;
+ x->x_deltaset = 0;
+ x->x_ksr = sys_getsr() * 0.001;
+ x->x_nleft = 0;
+ x->x_retarget = 0;
+ x->x_size = CURVE_INISIZE;
+ x->x_nsegs = 0;
+ x->x_segs = x->x_segini;
+ x->x_curseg = 0;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ floatinlet_new((t_object *)x, &x->x_ccinput);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_bangout = outlet_new((t_object *)x, &s_bang);
+ x->x_clock = clock_new(x, (t_method)curve_tick);
+ return (x);
+}
+
+void curve_tilde_setup(void)
+{
+ curve_class = class_new(gensym("curve~"),
+ (t_newmethod)curve_new,
+ (t_method)curve_free,
+ sizeof(t_curve), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ sic_setup(curve_class, curve_dsp, SIC_NOMAINSIGNALIN);
+ class_addfloat(curve_class, curve_float);
+ class_addlist(curve_class, curve_list);
+ class_addmethod(curve_class, (t_method)curve_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/curve.gp b/cyclone/sickle/curve.gp
new file mode 100644
index 0000000..be5dacb
--- /dev/null
+++ b/cyclone/sickle/curve.gp
@@ -0,0 +1,9 @@
+h(p) = (((p + 1e-20) * 1.2) ** .41) * .91
+f(p) = h(p) / (1 - h(p))
+g(x, p) = (exp(f(p) * x) - 1) / (exp(f(p)) - 1)
+splot [0:1] [0:1] g(x, y)
+pause -1
+plot [0:1] g(.25, x), g(.5, x), g(.75, x)
+pause -1
+plot [0:1] g(x, 0), g(x, .25), g(x, .5), g(x, .75), g(x, 1)
+print g(.5, 0)
diff --git a/cyclone/sickle/lores.c b/cyclone/sickle/lores.c
new file mode 100644
index 0000000..9449947
--- /dev/null
+++ b/cyclone/sickle/lores.c
@@ -0,0 +1,109 @@
+/* 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. */
+
+/* The general two-pole resonator (csound's lp2). For a nice analysis
+ see section 9.1.3 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
+
+/* CHECKME negative resonance */
+/* CHECKME max resonance, esp. at low freqs (watch out, gain not normalized) */
+#define LORES_MAXRESONANCE (1. - 1e-20)
+#define LORES_MINOMEGA .0001 /* CHECKME */
+#define LORES_MAXOMEGA SHARED_PI /* CHECKME */
+
+typedef struct _lores
+{
+ t_sic x_sic;
+ float x_srcoef;
+ float x_ynm1;
+ float x_ynm2;
+} t_lores;
+
+static t_class *lores_class;
+
+static void lores_clear(t_lores *x)
+{
+ 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 *lores_perform(t_int *w)
+{
+ t_lores *x = (t_lores *)(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 *out = (t_float *)(w[6]);
+ float ynm1 = x->x_ynm1;
+ float ynm2 = x->x_ynm2;
+ /* CHECKME sampled once per block */
+ float omega = fin0 * x->x_srcoef;
+ float radius, c1, c2, b0;
+ if (omega < LORES_MINOMEGA)
+ omega = LORES_MINOMEGA;
+ else if (omega > LORES_MAXOMEGA)
+ omega = LORES_MAXOMEGA;
+ if (rin0 > LORES_MAXRESONANCE)
+ rin0 = LORES_MAXRESONANCE;
+ /* radius = pow(base, rin0 - 1), which maps rin0 of 0..1 to radius
+ of 1/base..1, where base=exp(.125), and 1/base=.882496902585 */
+ radius = expf(rin0 * .125) * .882496902585;
+ c1 = 2. * radius * cos(omega);
+ c2 = radius * radius;
+ b0 = 1. - c1 + c2;
+ while (nblock--)
+ {
+ float yn;
+ *out++ = yn = b0 * *xin++ + c1 * ynm1 - c2 * ynm2;
+ ynm2 = ynm1;
+ ynm1 = yn;
+ }
+ /* LATER rethink */
+ x->x_ynm1 = (PD_BADFLOAT(ynm1) ? 0. : ynm1);
+ x->x_ynm2 = (PD_BADFLOAT(ynm2) ? 0. : ynm2);
+ return (w + 7);
+}
+
+static void lores_dsp(t_lores *x, t_signal **sp)
+{
+ x->x_srcoef = SHARED_2PI / sp[0]->s_sr;
+ lores_clear(x);
+ dsp_add(lores_perform, 6, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec);
+}
+
+static void *lores_new(t_floatarg f1, t_floatarg f2)
+{
+ t_lores *x = (t_lores *)pd_new(lores_class);
+ x->x_srcoef = SHARED_2PI / sys_getsr();
+ sic_newinlet((t_sic *)x, f1);
+ sic_newinlet((t_sic *)x, f2);
+ outlet_new((t_object *)x, &s_signal);
+ lores_clear(x);
+ return (x);
+}
+
+void lores_tilde_setup(void)
+{
+ lores_class = class_new(gensym("lores~"),
+ (t_newmethod)lores_new, 0,
+ sizeof(t_lores), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ sic_setup(lores_class, lores_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(lores_class, (t_method)lores_clear, gensym("clear"), 0);
+}
diff --git a/cyclone/sickle/mstosamps.c b/cyclone/sickle/mstosamps.c
new file mode 100644
index 0000000..37b2cc5
--- /dev/null
+++ b/cyclone/sickle/mstosamps.c
@@ -0,0 +1,55 @@
+/* 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. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _mstosamps
+{
+ t_sic x_sic;
+ float x_ksr;
+ t_outlet *x_floatout;
+} t_mstosamps;
+
+static t_class *mstosamps_class;
+
+static void mstosamps_float(t_mstosamps *x, t_float f)
+{
+ outlet_float(x->x_floatout, f * x->x_ksr);
+}
+
+static t_int *mstosamps_perform(t_int *w)
+{
+ t_mstosamps *x = (t_mstosamps *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ float ksr = x->x_ksr;
+ while (nblock--) *out++ = *in++ * ksr;
+ return (w + 5);
+}
+
+static void mstosamps_dsp(t_mstosamps *x, t_signal **sp)
+{
+ x->x_ksr = sp[0]->s_sr * .001;
+ dsp_add(mstosamps_perform, 4, x,
+ sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *mstosamps_new(void)
+{
+ t_mstosamps *x = (t_mstosamps *)pd_new(mstosamps_class);
+ x->x_ksr = sys_getsr() * .001; /* LATER rethink */
+ outlet_new((t_object *)x, &s_signal);
+ x->x_floatout = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void mstosamps_tilde_setup(void)
+{
+ mstosamps_class = class_new(gensym("mstosamps~"),
+ (t_newmethod)mstosamps_new, 0,
+ sizeof(t_mstosamps), 0, 0);
+ sic_setup(mstosamps_class, mstosamps_dsp, mstosamps_float);
+}
diff --git a/cyclone/sickle/onepole.c b/cyclone/sickle/onepole.c
new file mode 100644
index 0000000..f06b581
--- /dev/null
+++ b/cyclone/sickle/onepole.c
@@ -0,0 +1,151 @@
+/* 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 is Pd's lop~ with signal-controlled cutoff. */
+
+/* CHECKED scalar case: input preserved (not coefs) after changing mode */
+/* CHECKME if creation arg (or a default) 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 sinf sin
+#endif
+
+#define ONEPOLE_HZ 0
+#define ONEPOLE_LINEAR 1
+#define ONEPOLE_RADIANS 2
+#define ONEPOLE_MINB0 .0001 /* CHECKED 1st term of ir for b0=0 */
+#define ONEPOLE_MAXB0 .99 /* CHECKED 1st term of ir for b0=1 */
+#define ONEPOLE_MINOMEGA 0. /* CHECKME */
+#define ONEPOLE_MAXOMEGA (SHARED_PI * .5) /* CHECKME */
+
+typedef struct _onepole
+{
+ t_sic x_sic;
+ int x_mode;
+ float x_srcoef;
+ float x_ynm1;
+} t_onepole;
+
+static t_class *onepole_class;
+
+static t_symbol *ps_hz;
+static t_symbol *ps_linear;
+static t_symbol *ps_radians;
+
+static void onepole_clear(t_onepole *x)
+{
+ x->x_ynm1 = 0.;
+}
+
+static void onepole_hz(t_onepole *x)
+{
+ x->x_mode = ONEPOLE_HZ;
+}
+
+static void onepole_linear(t_onepole *x)
+{
+ x->x_mode = ONEPOLE_LINEAR;
+}
+
+static void onepole_radians(t_onepole *x)
+{
+ x->x_mode = ONEPOLE_RADIANS;
+}
+
+/* LATER make ready for optional audio-rate modulation
+ (separate scalar case routine, use sic_makecostable(), etc.) */
+static t_int *onepole_perform(t_int *w)
+{
+ t_onepole *x = (t_onepole *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *xin = (t_float *)(w[3]);
+ t_float fin0 = *(t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ int mode = x->x_mode;
+ float ynm1 = x->x_ynm1;
+ /* CHECKME sampled once per block */
+ float b0;
+ if (mode == ONEPOLE_HZ)
+ {
+ float omega = fin0 * x->x_srcoef;
+ if (omega < ONEPOLE_MINOMEGA)
+ omega = ONEPOLE_MINOMEGA;
+ else if (omega > ONEPOLE_MAXOMEGA)
+ omega = ONEPOLE_MAXOMEGA;
+ /* The actual solution for a half-power cutoff is:
+ b0 = sqrt(sqr(2-cos(omega))-1) + cos(omega) - 1.
+ The sin(omega) below is only slightly better approximation than
+ Miller's b0=omega, except for the two highest octaves (or so),
+ where it is much better (but far from good). */
+ b0 = sinf(omega);
+ }
+ else if (mode == ONEPOLE_LINEAR)
+ b0 = sinf(fin0 * (SHARED_PI * .5)); /* CHECKME actual range of fin0 */
+ else
+ b0 = fin0;
+ if (b0 < ONEPOLE_MINB0)
+ b0 = ONEPOLE_MINB0;
+ else if (b0 > ONEPOLE_MAXB0)
+ b0 = ONEPOLE_MAXB0;
+ /* b0 is the standard 1-|a1| (where |a1| is pole's radius),
+ specifically: a1=b0-1 => a1 in [-.9999 .. -.01] => lowpass (stable) */
+ while (nblock--)
+ *out++ = ynm1 = b0 * (*xin++ - ynm1) + ynm1;
+ x->x_ynm1 = (PD_BADFLOAT(ynm1) ? 0. : ynm1);
+ return (w + 6);
+}
+
+static void onepole_dsp(t_onepole *x, t_signal **sp)
+{
+ x->x_srcoef = SHARED_2PI / sp[0]->s_sr;
+ onepole_clear(x);
+ dsp_add(onepole_perform, 5, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *onepole_new(t_symbol *s, t_floatarg f)
+{
+ t_onepole *x = (t_onepole *)pd_new(onepole_class);
+ x->x_srcoef = SHARED_2PI / sys_getsr();
+ /* CHECKED no int-to-float conversion (any int bashed to 0.) */
+ sic_newinlet((t_sic *)x, f);
+ outlet_new((t_object *)x, &s_signal);
+ onepole_clear(x);
+ if (s == ps_linear)
+ x->x_mode = ONEPOLE_LINEAR;
+ else if (s == ps_radians)
+ x->x_mode = ONEPOLE_RADIANS;
+ else
+ {
+ x->x_mode = ONEPOLE_HZ;
+ if (s && s != &s_ && s != ps_hz && s != gensym("Hz"))
+ {
+ /* CHECKED no warning */
+ }
+ }
+ return (x);
+}
+
+void onepole_tilde_setup(void)
+{
+ ps_hz = gensym("hz");
+ ps_linear = gensym("linear");
+ ps_radians = gensym("radians");
+ onepole_class = class_new(gensym("onepole~"),
+ (t_newmethod)onepole_new, 0,
+ sizeof(t_onepole), 0,
+ A_DEFFLOAT, A_DEFSYM, 0);
+ sic_setup(onepole_class, onepole_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(onepole_class, (t_method)onepole_clear, gensym("clear"), 0);
+ class_addmethod(onepole_class, (t_method)onepole_hz, ps_hz, 0);
+ class_addmethod(onepole_class, (t_method)onepole_hz, gensym("Hz"), 0);
+ class_addmethod(onepole_class, (t_method)onepole_linear, ps_linear, 0);
+ class_addmethod(onepole_class, (t_method)onepole_radians, ps_radians, 0);
+}
diff --git a/cyclone/sickle/pink.c b/cyclone/sickle/pink.c
new file mode 100644
index 0000000..0ba71b2
--- /dev/null
+++ b/cyclone/sickle/pink.c
@@ -0,0 +1,100 @@
+/* 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. */
+
+/* Filter: Paul Kellet's from music-dsp. This is the most popular one,
+ used in jMax, Csound, etc. LATER compare to McCartney's (sc).
+ Rng: noise~ code from d_osc.c. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "sickle/sic.h"
+
+/* more like 0.085 in c74's */
+#define PINK_GAIN .105
+
+typedef struct _pink
+{
+ t_sic x_sic;
+ int x_state;
+ float x_b0;
+ float x_b1;
+ float x_b2;
+ float x_b3;
+ float x_b4;
+ float x_b5;
+ float x_b6;
+} t_pink;
+
+static t_class *pink_class;
+
+static void pink_float(t_pink *x, t_float f)
+{
+ loud_nomethod((t_pd *)x, &s_float); /* LATER rethink */
+}
+
+static t_int *pink_perform(t_int *w)
+{
+ t_pink *x = (t_pink *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int state = x->x_state;
+ float b0 = x->x_b0;
+ float b1 = x->x_b1;
+ float b2 = x->x_b2;
+ float b3 = x->x_b3;
+ float b4 = x->x_b4;
+ float b5 = x->x_b5;
+ float b6 = x->x_b6;
+ while (nblock--)
+ {
+ float white = ((float)((state & 0x7fffffff) - 0x40000000)) *
+ (float)(1.0 / 0x40000000);
+ state = state * 435898247 + 382842987;
+ b0 = 0.99886 * b0 + white * 0.0555179;
+ b1 = 0.99332 * b1 + white * 0.0750759;
+ b2 = 0.96900 * b2 + white * 0.1538520;
+ b3 = 0.86650 * b3 + white * 0.3104856;
+ b4 = 0.55000 * b4 + white * 0.5329522;
+ b5 = -0.7616 * b5 - white * 0.0168980;
+ *out++ = (b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362)
+ * PINK_GAIN;
+ b6 = white * 0.115926;
+ }
+ x->x_state = state;
+ x->x_b0 = b0;
+ x->x_b1 = b1;
+ x->x_b2 = b2;
+ x->x_b3 = b3;
+ x->x_b4 = b4;
+ x->x_b5 = b5;
+ x->x_b6 = b6;
+ return (w + 4);
+}
+
+static void pink_dsp(t_pink *x, t_signal **sp)
+{
+ dsp_add(pink_perform, 3, x, sp[1]->s_n, sp[1]->s_vec);
+}
+
+static void *pink_new(void)
+{
+ t_pink *x = (t_pink *)pd_new(pink_class);
+ /* borrowed from d_osc.c, LATER rethink */
+ static int init = 307;
+ x->x_state = (init *= 1319);
+ /* all coefs set to zero */
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void pink_tilde_setup(void)
+{
+ pink_class = class_new(gensym("pink~"),
+ (t_newmethod)pink_new, 0,
+ sizeof(t_pink), 0, 0);
+ /* dummy float method: we need signal in (for begin~), but neither
+ float-to-signal conversion, nor a float method (the only control
+ input is 'enable'). LATER rethink. */
+ sic_setup(pink_class, pink_dsp, pink_float);
+}
diff --git a/cyclone/sickle/poke.c b/cyclone/sickle/poke.c
new file mode 100644
index 0000000..d0fb22a
--- /dev/null
+++ b/cyclone/sickle/poke.c
@@ -0,0 +1,155 @@
+/* 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. */
+
+/* LATER: 'click' method */
+
+#include "m_pd.h"
+#include "unstable/fragile.h"
+#include "sickle/sic.h"
+#include "sickle/arsic.h"
+
+#define POKE_MAXCHANNELS 4 /* LATER implement arsic resizing feature */
+
+typedef struct _poke
+{
+ t_arsic x_arsic;
+ int x_maxchannels;
+ int x_effchannel; /* effective channel (clipped reqchannel) */
+ int x_reqchannel; /* requested channel */
+ t_sample *x_indexptr;
+ t_clock *x_clock;
+ double x_clocklasttick;
+ int x_clockset;
+} t_poke;
+
+static t_class *poke_class;
+
+static void poke_tick(t_poke *x)
+{
+ arsic_redraw((t_arsic *)x); /* LATER redraw only dirty channel(s!) */
+ x->x_clockset = 0;
+ x->x_clocklasttick = clock_getsystime();
+}
+
+static void poke_set(t_poke *x, t_symbol *s)
+{
+ arsic_setarray((t_arsic *)x, s, 1);
+}
+
+static void poke_bang(t_poke *x)
+{
+ arsic_redraw((t_arsic *)x);
+}
+
+/* CHECKED: index 0-based, negative values block input, overflowed are clipped.
+ LATER revisit: incompatibly, the code below is nop for any out-of-range index
+ (see also peek.c) */
+/* CHECKED: value never clipped, 'clip' not understood */
+/* CHECKED: no float-to-signal conversion. 'Float' message is ignored
+ when dsp is on -- whether a signal is connected to the left inlet, or not
+ (if not, current index is set to zero). Incompatible (revisit LATER) */
+static void poke_float(t_poke *x, t_float f)
+{
+ t_arsic *sic = (t_arsic *)x;
+ t_float *vp;
+ arsic_validate(sic, 0); /* LATER rethink (efficiency, and complaining) */
+ if (vp = sic->s_vectors[x->x_effchannel])
+ {
+ int ndx = (int)*x->x_indexptr;
+ if (ndx >= 0 && ndx < sic->s_vecsize)
+ {
+ double timesince;
+ vp[ndx] = f;
+ timesince = clock_gettimesince(x->x_clocklasttick);
+ if (timesince > 1000) poke_tick(x);
+ else if (!x->x_clockset)
+ {
+ clock_delay(x->x_clock, 1000 - timesince);
+ x->x_clockset = 1;
+ }
+ }
+ }
+}
+
+static void poke_ft2(t_poke *x, t_floatarg f)
+{
+ if ((x->x_reqchannel = (f > 1 ? (int)f - 1 : 0)) > x->x_maxchannels)
+ x->x_effchannel = x->x_maxchannels - 1;
+ else
+ x->x_effchannel = x->x_reqchannel;
+}
+
+static t_int *poke_perform(t_int *w)
+{
+ t_arsic *sic = (t_arsic *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ t_poke *x = (t_poke *)sic;
+ t_float *vp = sic->s_vectors[x->x_effchannel];
+ if (vp && sic->s_playable)
+ {
+ int vecsize = sic->s_vecsize;
+ while (nblock--)
+ {
+ t_float f = *in1++;
+ int ndx = (int)*in2++;
+ if (ndx >= 0 && ndx < vecsize)
+ vp[ndx] = f;
+ }
+ }
+ return (w + sic->s_nperfargs + 1);
+}
+
+static void poke_dsp(t_poke *x, t_signal **sp)
+{
+ arsic_dsp((t_arsic *)x, sp, poke_perform, 0);
+}
+
+static void poke_free(t_poke *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+ arsic_free((t_arsic *)x);
+}
+
+static void *poke_new(t_symbol *s, t_floatarg f)
+{
+ int ch = (f > 0 ? (int)f : 0);
+ t_poke *x = (t_poke *)arsic_new(poke_class, s,
+ (ch ? POKE_MAXCHANNELS : 0), 2, 0);
+ if (x)
+ {
+ t_inlet *in2;
+ if (ch > POKE_MAXCHANNELS)
+ ch = POKE_MAXCHANNELS;
+ x->x_maxchannels = (ch ? POKE_MAXCHANNELS : 1);
+ x->x_effchannel = x->x_reqchannel = (ch ? ch - 1 : 0);
+ /* CHECKED: no float-to-signal conversion.
+ Floats in 2nd inlet are ignored when dsp is on, but only if a signal
+ is connected to this inlet. Incompatible (revisit LATER). */
+ in2 = inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ x->x_indexptr = fragile_inlet_signalscalar(in2);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2"));
+ x->x_clock = clock_new(x, (t_method)poke_tick);
+ x->x_clocklasttick = clock_getsystime();
+ x->x_clockset = 0;
+ }
+ return (x);
+}
+
+void poke_tilde_setup(void)
+{
+ poke_class = class_new(gensym("poke~"),
+ (t_newmethod)poke_new,
+ (t_method)poke_free,
+ sizeof(t_poke), 0,
+ A_DEFSYM, A_DEFFLOAT, 0);
+ arsic_setup(poke_class, poke_dsp, poke_float);
+ class_addbang(poke_class, poke_bang); /* LATER rethink */
+ class_addfloat(poke_class, poke_float);
+ class_addmethod(poke_class, (t_method)poke_set,
+ gensym("set"), A_SYMBOL, 0);
+ class_addmethod(poke_class, (t_method)poke_ft2,
+ gensym("ft2"), A_FLOAT, 0);
+}
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);
+}
diff --git a/cyclone/sickle/sampstoms.c b/cyclone/sickle/sampstoms.c
new file mode 100644
index 0000000..36b686c
--- /dev/null
+++ b/cyclone/sickle/sampstoms.c
@@ -0,0 +1,55 @@
+/* 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. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _sampstoms
+{
+ t_sic x_sic;
+ float x_rcpksr;
+ t_outlet *x_floatout;
+} t_sampstoms;
+
+static t_class *sampstoms_class;
+
+static void sampstoms_float(t_sampstoms *x, t_float f)
+{
+ outlet_float(x->x_floatout, f * x->x_rcpksr);
+}
+
+static t_int *sampstoms_perform(t_int *w)
+{
+ t_sampstoms *x = (t_sampstoms *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ float rcpksr = x->x_rcpksr;
+ while (nblock--) *out++ = *in++ * rcpksr;
+ return (w + 5);
+}
+
+static void sampstoms_dsp(t_sampstoms *x, t_signal **sp)
+{
+ x->x_rcpksr = 1000. / sp[0]->s_sr;
+ dsp_add(sampstoms_perform, 4, x,
+ sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *sampstoms_new(void)
+{
+ t_sampstoms *x = (t_sampstoms *)pd_new(sampstoms_class);
+ x->x_rcpksr = 1000. / sys_getsr(); /* LATER rethink */
+ outlet_new((t_object *)x, &s_signal);
+ x->x_floatout = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void sampstoms_tilde_setup(void)
+{
+ sampstoms_class = class_new(gensym("sampstoms~"),
+ (t_newmethod)sampstoms_new, 0,
+ sizeof(t_sampstoms), 0, 0);
+ sic_setup(sampstoms_class, sampstoms_dsp, sampstoms_float);
+}
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);
+}
diff --git a/cyclone/sickle/zerox.c b/cyclone/sickle/zerox.c
new file mode 100644
index 0000000..95b35d6
--- /dev/null
+++ b/cyclone/sickle/zerox.c
@@ -0,0 +1,78 @@
+/* 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. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#define ZEROX_DEFVOLUME 1.
+
+typedef struct _zerox
+{
+ t_sic x_sic;
+ t_float x_volume;
+ int x_lastsign;
+} t_zerox;
+
+static t_class *zerox_class;
+
+static void zerox_set(t_zerox *x, t_floatarg f)
+{
+ x->x_volume = f; /* CHECKED anything goes (including 0.) */
+}
+
+static t_int *zerox_perform(t_int *w)
+{
+ t_zerox *x = (t_zerox *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out1 = (t_float *)(w[4]);
+ t_float *out2 = (t_float *)(w[5]);
+ t_float volume = x->x_volume;
+ int lastsign = x->x_lastsign;
+ int i = nblock;
+ int count = 0;
+ t_float fcount;
+ while (i--)
+ {
+ /* CHECKED -1 -> 0 and 0 -> -1 are hits, 1 -> 0, 0 -> 1 are not */
+ int sign = (*in++ < 0 ? 1. : 0.); /* LATER read the sign bit */
+ if (sign != lastsign)
+ {
+ count++;
+ *out2++ = volume;
+ lastsign = sign;
+ }
+ else *out2++ = 0.;
+ }
+ fcount = (t_float)count;
+ while (nblock--) *out1++ = fcount;
+ x->x_lastsign = lastsign;
+ return (w + 6);
+}
+
+static void zerox_dsp(t_zerox *x, t_signal **sp)
+{
+ dsp_add(zerox_perform, 5, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *zerox_new(t_floatarg f)
+{
+ t_zerox *x = (t_zerox *)pd_new(zerox_class);
+ x->x_volume = (f == 0. ? ZEROX_DEFVOLUME : f);
+ x->x_lastsign = 0; /* CHECKED the very first sample hits if negative */
+ outlet_new((t_object *)x, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void zerox_tilde_setup(void)
+{
+ zerox_class = class_new(gensym("zerox~"),
+ (t_newmethod)zerox_new, 0,
+ sizeof(t_zerox), 0, A_DEFFLOAT, 0);
+ sic_setup(zerox_class, zerox_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(zerox_class, (t_method)zerox_set,
+ gensym("set"), A_FLOAT, 0); /* CHECKED arg obligatory */
+}