aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--test/cyclone/a-mix2.pd41
-rw-r--r--test/cyclone/curve-test.pd89
-rw-r--r--test/cyclone/lores-test.pd78
-rw-r--r--test/cyclone/mstosamps-test.pd23
-rw-r--r--test/cyclone/mtr-test.pd85
-rw-r--r--test/cyclone/onepole-test.pd63
-rw-r--r--test/cyclone/pink-test.pd55
-rw-r--r--test/cyclone/poke-test.pd58
-rw-r--r--test/cyclone/pong-test.pd17
-rw-r--r--test/cyclone/reson-test.pd73
-rw-r--r--test/cyclone/svf-test.pd81
-rw-r--r--test/cyclone/zerox-test.pd33
23 files changed, 2162 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 */
+}
diff --git a/test/cyclone/a-mix2.pd b/test/cyclone/a-mix2.pd
new file mode 100644
index 0000000..31ba6b2
--- /dev/null
+++ b/test/cyclone/a-mix2.pd
@@ -0,0 +1,41 @@
+#N canvas 26 52 303 333 12;
+#X obj 128 272 *~ 0;
+#X obj 171 272 *~ 0;
+#X obj 202 230 dbtorms;
+#X obj 17 248 hsl 80 15 0 90 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 0;
+#X obj 121 230 dbtorms;
+#X msg 203 194 90;
+#X msg 65 194 90;
+#X msg 142 194 0;
+#X msg 14 194 0;
+#X obj 14 128 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 129 128 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 142 156 sel 1;
+#X obj 52 31 inlet~;
+#X obj 171 31 inlet~;
+#X obj 171 299 outlet~;
+#X obj 242 33 vsl 15 80 0 90 0 0 empty empty empty 0 -8 0 8 -262144
+-1 -1 0 0;
+#X connect 0 0 14 0;
+#X connect 1 0 14 0;
+#X connect 2 0 1 1;
+#X connect 3 0 4 0;
+#X connect 4 0 0 1;
+#X connect 5 0 15 0;
+#X connect 6 0 3 0;
+#X connect 7 0 15 0;
+#X connect 8 0 3 0;
+#X connect 9 0 8 0;
+#X connect 9 0 7 0;
+#X connect 10 0 11 0;
+#X connect 11 0 7 0;
+#X connect 11 0 6 0;
+#X connect 11 1 5 0;
+#X connect 11 1 8 0;
+#X connect 12 0 0 0;
+#X connect 13 0 1 0;
+#X connect 15 0 2 0;
+#X coords 0 0 1 1 150 100 1;
diff --git a/test/cyclone/curve-test.pd b/test/cyclone/curve-test.pd
new file mode 100644
index 0000000..dd1f325
--- /dev/null
+++ b/test/cyclone/curve-test.pd
@@ -0,0 +1,89 @@
+#N canvas 52 64 618 381 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array t 133000 float 0;
+#X coords 0 1000 132999 -1000 200 140 1;
+#X restore 373 92 graph;
+#X obj 23 261 tabwrite~ t;
+#X msg 277 291 clear;
+#X msg 212 291 clear;
+#X floatatom 206 230 5 0 0 0 - - -;
+#X obj 46 291 delay~ 4096 4096;
+#X obj 23 135 curve~;
+#X obj 206 196 Snapshot~ 100;
+#X floatatom 23 22 5 0 0 0 - - -;
+#X obj 23 64 t 0 b;
+#X obj 46 330 capture~ f;
+#X msg 23 96 0 \, 1000 100 \$1;
+#X obj 277 330 capture~ f 2206;
+#N canvas 47 16 654 382 curves 0;
+#X obj 31 351 outlet;
+#X obj 31 17 inlet;
+#X msg 31 86 0 \, 1000 1000 0.5 0 1000 0.5 1000 1000 0;
+#X msg 62 146 1000 \, 0 1000 1 1000 1000 1 0 1000 0;
+#X msg 88 209 0 \, 1000 1000 0.9 0 0 0 -500 1000 0.8 0 0 0 1000 1000
+0.7;
+#X msg 105 278 0 \, 1000 1000 0.1 0 0 0 -500 1000 0.2 0 0 0 1000 1000
+0.3;
+#X obj 31 49 sel 1 -1 2 -2 3 -3 4 -4;
+#X msg 73 311 0 \, 1000 1000 -0.1 0 0 0 -500 1000 -0.2 0 0 0 1000 1000
+-0.3;
+#X msg 94 243 0 \, 1000 1000 -0.9 0 0 0 -500 1000 -0.8 0 0 0 1000 1000
+-0.7;
+#X msg 80 174 1000 \, 0 1000 -1 1000 1000 -1 0 1000 0;
+#X msg 47 117 0 \, 1000 1000 -0.5 0 1000 -0.5 1000 1000 0;
+#X connect 1 0 6 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 2 0;
+#X connect 6 1 10 0;
+#X connect 6 2 3 0;
+#X connect 6 3 9 0;
+#X connect 6 4 4 0;
+#X connect 6 5 8 0;
+#X connect 6 6 5 0;
+#X connect 6 7 7 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X restore 237 96 pd curves;
+#X obj 237 64 t 0 b;
+#X msg 107 22 1;
+#X msg 151 22 -1;
+#X msg 193 22 2;
+#X msg 237 22 -2;
+#X msg 282 22 3;
+#X msg 368 22 4;
+#X msg 326 22 -3;
+#X msg 412 22 -4;
+#X obj 72 200 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X connect 2 0 12 0;
+#X connect 3 0 10 0;
+#X connect 5 0 10 0;
+#X connect 6 0 1 0;
+#X connect 6 0 5 0;
+#X connect 6 0 7 0;
+#X connect 6 0 12 0;
+#X connect 6 1 3 0;
+#X connect 6 1 23 0;
+#X connect 7 0 4 0;
+#X connect 8 0 9 0;
+#X connect 9 0 11 0;
+#X connect 9 1 1 0;
+#X connect 9 1 2 0;
+#X connect 11 0 6 0;
+#X connect 13 0 6 0;
+#X connect 14 0 13 0;
+#X connect 14 1 1 0;
+#X connect 14 1 2 0;
+#X connect 15 0 14 0;
+#X connect 16 0 14 0;
+#X connect 17 0 14 0;
+#X connect 18 0 14 0;
+#X connect 19 0 14 0;
+#X connect 20 0 14 0;
+#X connect 21 0 14 0;
+#X connect 22 0 14 0;
diff --git a/test/cyclone/lores-test.pd b/test/cyclone/lores-test.pd
new file mode 100644
index 0000000..545d2ff
--- /dev/null
+++ b/test/cyclone/lores-test.pd
@@ -0,0 +1,78 @@
+#N canvas 189 10 584 487 12;
+#X obj 39 18 noise~;
+#X obj 144 435 dac~;
+#X floatatom 308 111 5 0 0 0 - - -;
+#X obj 391 143 *~ 10;
+#X obj 391 172 +~ 0;
+#X floatatom 479 114 5 0 0 0 - - -;
+#X floatatom 391 82 5 0 0 0 - - -;
+#X obj 159 303 a-mix2;
+#X obj 38 82 a-mix2;
+#X obj 349 18 loadbang;
+#X msg 479 58 0;
+#X msg 308 82 1000;
+#X obj 391 114 osc~ 4;
+#X msg 522 58 1000;
+#X msg 243 82 5000;
+#X msg 514 82 10000;
+#X msg 354 58 13;
+#X msg 397 58 4;
+#X obj 323 268 lores~;
+#X obj 92 268 vcf~;
+#X floatatom 123 236 5 0 0 0 - - -;
+#X floatatom 310 160 5 0 0 0 - - -;
+#X obj 248 211 - 1;
+#X obj 248 240 t b 0;
+#X obj 196 211 / -1;
+#X obj 196 182 * -0.001;
+#X obj 323 303 *~ 0.1;
+#N canvas 217 47 350 257 pulse 0;
+#X obj 144 176 train~ 10 0.1;
+#X obj 145 21 inlet;
+#X obj 144 206 outlet~;
+#X obj 144 146 /;
+#X obj 145 51 t b 0;
+#X msg 123 96 1000;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 4 1 3 1;
+#X connect 5 0 3 0;
+#X restore 133 50 pd pulse;
+#X floatatom 133 18 5 0 0 0 - - -;
+#X connect 0 0 8 0;
+#X connect 2 0 4 1;
+#X connect 2 0 25 0;
+#X connect 3 0 4 0;
+#X connect 4 0 18 1;
+#X connect 4 0 19 1;
+#X connect 5 0 3 1;
+#X connect 6 0 12 0;
+#X connect 7 0 1 0;
+#X connect 7 0 1 1;
+#X connect 8 0 18 0;
+#X connect 8 0 19 0;
+#X connect 9 0 11 0;
+#X connect 9 0 10 0;
+#X connect 10 0 5 0;
+#X connect 11 0 2 0;
+#X connect 12 0 3 0;
+#X connect 13 0 5 0;
+#X connect 14 0 2 0;
+#X connect 15 0 5 0;
+#X connect 16 0 6 0;
+#X connect 17 0 6 0;
+#X connect 18 0 26 0;
+#X connect 19 0 7 0;
+#X connect 20 0 19 2;
+#X connect 21 0 18 2;
+#X connect 21 0 22 0;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 23 1 24 1;
+#X connect 24 0 20 0;
+#X connect 25 0 24 0;
+#X connect 26 0 7 1;
+#X connect 27 0 8 1;
+#X connect 28 0 27 0;
diff --git a/test/cyclone/mstosamps-test.pd b/test/cyclone/mstosamps-test.pd
new file mode 100644
index 0000000..67f23cd
--- /dev/null
+++ b/test/cyclone/mstosamps-test.pd
@@ -0,0 +1,23 @@
+#N canvas 0 0 450 300 12;
+#X obj 160 72 mstosamps~;
+#X floatatom 160 39 5 0 0 0 - - -;
+#X obj 245 143 sampstoms~;
+#X floatatom 330 180 5 0 0 0 - - -;
+#X floatatom 245 110 5 0 0 0 - - -;
+#X obj 244 212 Snapshot~ 100;
+#X floatatom 244 246 5 0 0 0 - - -;
+#X obj 98 143 Snapshot~ 100;
+#X floatatom 98 180 5 0 0 0 - - -;
+#X floatatom 41 39 5 0 0 0 - - -;
+#X obj 41 72 sig~;
+#X connect 0 0 7 0;
+#X connect 0 0 2 0;
+#X connect 0 1 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 2 1 3 0;
+#X connect 4 0 2 0;
+#X connect 5 0 6 0;
+#X connect 7 0 8 0;
+#X connect 9 0 10 0;
+#X connect 10 0 0 0;
diff --git a/test/cyclone/mtr-test.pd b/test/cyclone/mtr-test.pd
new file mode 100644
index 0000000..6d40842
--- /dev/null
+++ b/test/cyclone/mtr-test.pd
@@ -0,0 +1,85 @@
+#N canvas 80 56 592 383 12;
+#X obj 150 267 mtr 7 ________;
+#X msg 125 81 write;
+#X msg 21 17 record;
+#X obj 232 142 hsl 128 15 0 127 0 0 empty hs1 empty -2 -6 64 8 -262144
+-1 -1 0 1;
+#X obj 167 337 s hs1;
+#X obj 249 173 hsl 128 15 0 127 0 0 empty hs2 empty -2 -6 64 8 -262144
+-1 -1 0 1;
+#X obj 184 302 s hs2;
+#X msg 52 48 play;
+#X msg 416 159 record;
+#X msg 430 192 play;
+#X msg 446 227 write;
+#X obj 271 227 testmess 100;
+#X obj 271 204 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 107 48 stop;
+#X msg 490 192 stop;
+#X msg 92 17 record 6;
+#X msg 142 109 write test.mtr;
+#X msg 23 183 first 0;
+#X msg 21 81 play 0 6;
+#X msg 423 267 write test1.mtr;
+#X msg 26 267 read;
+#X msg 27 302 read test.mtr;
+#X msg 189 17 rewind;
+#X msg 25 218 debug;
+#X obj 26 337 print stamp;
+#X obj 271 302 print tr7;
+#X obj 362 109 print tr1;
+#X obj 322 17 r hs1;
+#X obj 322 44 spigot;
+#X msg 389 44 0;
+#X obj 322 71 t b a;
+#X msg 260 17 next;
+#X msg 389 17 1;
+#X obj 260 44 t a b;
+#X obj 445 44 spigot;
+#X msg 512 44 0;
+#X obj 445 71 t b a;
+#X msg 512 17 1;
+#X obj 485 109 print tr2;
+#X obj 445 17 r hs2;
+#X connect 0 0 24 0;
+#X connect 0 1 4 0;
+#X connect 0 2 6 0;
+#X connect 0 7 25 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 1;
+#X connect 5 0 0 2;
+#X connect 7 0 0 0;
+#X connect 8 0 0 2;
+#X connect 9 0 0 2;
+#X connect 10 0 0 2;
+#X connect 11 0 0 7;
+#X connect 12 0 11 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 2;
+#X connect 15 0 0 0;
+#X connect 16 0 0 0;
+#X connect 17 0 0 0;
+#X connect 18 0 0 0;
+#X connect 19 0 0 2;
+#X connect 20 0 0 0;
+#X connect 21 0 0 0;
+#X connect 22 0 0 0;
+#X connect 23 0 0 0;
+#X connect 27 0 28 0;
+#X connect 28 0 30 0;
+#X connect 29 0 28 1;
+#X connect 30 0 29 0;
+#X connect 30 1 26 0;
+#X connect 31 0 33 0;
+#X connect 32 0 28 1;
+#X connect 33 0 0 0;
+#X connect 33 1 32 0;
+#X connect 33 1 37 0;
+#X connect 34 0 36 0;
+#X connect 35 0 34 1;
+#X connect 36 0 35 0;
+#X connect 36 1 38 0;
+#X connect 37 0 34 1;
+#X connect 39 0 34 0;
diff --git a/test/cyclone/onepole-test.pd b/test/cyclone/onepole-test.pd
new file mode 100644
index 0000000..4165e6c
--- /dev/null
+++ b/test/cyclone/onepole-test.pd
@@ -0,0 +1,63 @@
+#N canvas 274 148 584 417 12;
+#X obj 39 16 noise~;
+#X obj 144 376 dac~;
+#X floatatom 308 112 5 0 0 0 - - -;
+#X obj 92 209 lop~;
+#X obj 323 209 onepole~;
+#X obj 391 145 *~ 10;
+#X obj 391 175 +~ 0;
+#X floatatom 479 115 5 0 0 0 - - -;
+#X floatatom 391 82 5 0 0 0 - - -;
+#X obj 159 244 a-mix2;
+#X obj 38 82 a-mix2;
+#X obj 349 16 loadbang;
+#X obj 141 209 Snapshot~ 2;
+#X msg 479 58 0;
+#X msg 308 82 1000;
+#X obj 391 115 osc~ 4;
+#X msg 522 58 1000;
+#X msg 243 82 5000;
+#X msg 514 82 10000;
+#X msg 354 58 13;
+#X msg 397 58 4;
+#N canvas 217 47 350 257 pulse 0;
+#X obj 144 176 train~ 10 0.1;
+#X obj 145 21 inlet;
+#X obj 144 206 outlet~;
+#X obj 144 146 /;
+#X obj 145 51 t b 0;
+#X msg 123 96 1000;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 4 1 3 1;
+#X connect 5 0 3 0;
+#X restore 133 50 pd pulse;
+#X floatatom 133 16 5 0 0 0 - - -;
+#X connect 0 0 10 0;
+#X connect 2 0 6 1;
+#X connect 3 0 9 0;
+#X connect 4 0 9 1;
+#X connect 5 0 6 0;
+#X connect 6 0 4 1;
+#X connect 6 0 12 0;
+#X connect 7 0 5 1;
+#X connect 8 0 15 0;
+#X connect 9 0 1 0;
+#X connect 9 0 1 1;
+#X connect 10 0 3 0;
+#X connect 10 0 4 0;
+#X connect 11 0 14 0;
+#X connect 11 0 13 0;
+#X connect 12 0 3 1;
+#X connect 13 0 7 0;
+#X connect 14 0 2 0;
+#X connect 15 0 5 0;
+#X connect 16 0 7 0;
+#X connect 17 0 2 0;
+#X connect 18 0 7 0;
+#X connect 19 0 8 0;
+#X connect 20 0 8 0;
+#X connect 21 0 10 1;
+#X connect 22 0 21 0;
diff --git a/test/cyclone/pink-test.pd b/test/cyclone/pink-test.pd
new file mode 100644
index 0000000..b1f4fdf
--- /dev/null
+++ b/test/cyclone/pink-test.pd
@@ -0,0 +1,55 @@
+#N canvas 114 365 411 405 12;
+#X obj 27 23 pink~;
+#X obj 146 212 Scope~ 249 177 256 3 128 -1 1 0 0 0 0 102 255 51 135
+135 135 0;
+#N canvas 540 253 607 486 spectrum 1;
+#X obj 24 233 Scope~ 562 220 2 3 512 0 512 0 0 0 0 102 255 51 135 135
+135 0;
+#X obj 136 117 cartopol~;
+#X obj 136 73 rfft~;
+#X obj 380 25 block~ 1024;
+#X obj 24 159 vectral~ 1024;
+#X obj 24 25 count~ 0 1024 1 1;
+#X floatatom 73 73 5 0 0 0 - - -;
+#X msg 172 159 slide 10 10;
+#X msg 92 193 range 0 512 \, 2 \, bufsize 512;
+#X obj 226 25 inlet~;
+#X obj 24 117 *~ 0.55;
+#X obj 226 73 *~ 1;
+#X floatatom 295 25 5 0 0 0 - - -;
+#X connect 1 0 4 2;
+#X connect 2 0 1 0;
+#X connect 2 1 1 1;
+#X connect 4 0 0 0;
+#X connect 5 0 4 1;
+#X connect 5 0 10 0;
+#X connect 6 0 10 1;
+#X connect 7 0 4 0;
+#X connect 8 0 0 0;
+#X connect 9 0 11 0;
+#X connect 10 0 4 0;
+#X connect 11 0 2 0;
+#X connect 12 0 11 1;
+#X restore 27 369 pd spectrum;
+#X obj 52 274 osc~ 1000;
+#X floatatom 52 241 5 0 0 0 - - -;
+#X floatatom 84 306 5 0 0 0 - - -;
+#X obj 53 337 *~ 0;
+#X obj 101 65 minmax~;
+#X obj 101 95 Snapshot~ 100;
+#X obj 231 95 Snapshot~ 100;
+#X floatatom 101 125 5 0 0 0 - - -;
+#X floatatom 231 125 5 0 0 0 - - -;
+#X msg 101 35 reset;
+#X connect 0 0 1 0;
+#X connect 0 0 2 0;
+#X connect 0 0 7 0;
+#X connect 3 0 6 0;
+#X connect 4 0 3 0;
+#X connect 5 0 6 1;
+#X connect 6 0 2 0;
+#X connect 7 0 8 0;
+#X connect 7 1 9 0;
+#X connect 8 0 10 0;
+#X connect 9 0 11 0;
+#X connect 12 0 7 0;
diff --git a/test/cyclone/poke-test.pd b/test/cyclone/poke-test.pd
new file mode 100644
index 0000000..ec92e81
--- /dev/null
+++ b/test/cyclone/poke-test.pd
@@ -0,0 +1,58 @@
+#N canvas 334 79 638 463 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array 0-t 20000 float 0;
+#X coords 0 1 19999 -1 200 140 1;
+#X restore 59 17 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array 1-t 20000 float 0;
+#X coords 0 1 19999 -1 200 140 1;
+#X restore 326 17 graph;
+#X msg 279 259 1;
+#X msg 279 295 2;
+#X msg 279 331 3;
+#X msg 279 224 0;
+#X obj 150 384 poke~ t 1;
+#X obj 65 217 Uzi;
+#X obj 65 247 counter;
+#X msg 65 187 1000;
+#X obj 65 313 % 1000;
+#X obj 65 277 t 0 0;
+#X obj 65 349 / 1000;
+#X msg 122 217 set 0;
+#X floatatom 150 281 5 0 0 0 - - -;
+#X floatatom 188 317 5 0 0 0 - - -;
+#X floatatom 392 199 5 0 0 0 - - -;
+#X floatatom 392 270 5 0 0 0 - - -;
+#X obj 392 234 peek~ t 1;
+#X obj 432 349 sig~;
+#X floatatom 432 322 5 0 0 0 - - -;
+#X obj 505 349 sig~;
+#X floatatom 505 322 5 0 0 0 - - -;
+#X msg 373 349 bang;
+#X obj 432 379 poke~ t 2;
+#X floatatom 504 199 5 0 0 0 - - -;
+#X floatatom 504 270 5 0 0 0 - - -;
+#X obj 504 234 peek~ t 2;
+#X connect 2 0 6 2;
+#X connect 3 0 6 2;
+#X connect 4 0 6 2;
+#X connect 5 0 6 2;
+#X connect 7 0 8 0;
+#X connect 8 0 11 0;
+#X connect 9 0 7 0;
+#X connect 10 0 12 0;
+#X connect 11 0 10 0;
+#X connect 11 1 6 1;
+#X connect 12 0 6 0;
+#X connect 13 0 8 0;
+#X connect 14 0 6 0;
+#X connect 15 0 6 1;
+#X connect 16 0 18 0;
+#X connect 18 0 17 0;
+#X connect 19 0 24 0;
+#X connect 20 0 19 0;
+#X connect 21 0 24 1;
+#X connect 22 0 21 0;
+#X connect 23 0 24 0;
+#X connect 25 0 27 0;
+#X connect 27 0 26 0;
diff --git a/test/cyclone/pong-test.pd b/test/cyclone/pong-test.pd
new file mode 100644
index 0000000..2a5e97a
--- /dev/null
+++ b/test/cyclone/pong-test.pd
@@ -0,0 +1,17 @@
+#N canvas 0 0 450 300 12;
+#X obj 143 147 pong~;
+#X obj 143 194 Snapshot~ 100;
+#X floatatom 143 229 5 0 0 0 - - -;
+#X floatatom 143 36 5 0 0 0 - - -;
+#X floatatom 163 69 5 0 0 0 - - -;
+#X floatatom 183 99 5 0 0 0 - - -;
+#X msg 46 99 mode \$1;
+#X obj 46 69 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 1;
+#X connect 5 0 0 2;
+#X connect 6 0 0 0;
+#X connect 7 0 6 0;
diff --git a/test/cyclone/reson-test.pd b/test/cyclone/reson-test.pd
new file mode 100644
index 0000000..2f5267e
--- /dev/null
+++ b/test/cyclone/reson-test.pd
@@ -0,0 +1,73 @@
+#N canvas 274 148 584 487 12;
+#X obj 39 19 noise~;
+#X obj 144 435 dac~;
+#X floatatom 308 117 5 0 0 0 - - -;
+#X obj 391 149 *~ 10;
+#X obj 391 181 +~ 0;
+#X floatatom 479 117 5 0 0 0 - - -;
+#X floatatom 391 85 5 0 0 0 - - -;
+#X obj 159 300 a-mix2;
+#X obj 38 92 a-mix2;
+#X obj 348 19 loadbang;
+#X msg 479 58 0;
+#X msg 308 85 1000;
+#X obj 391 117 osc~ 4;
+#X msg 522 58 1000;
+#X msg 243 85 5000;
+#X msg 354 58 13;
+#X msg 397 58 4;
+#X obj 38 265 vcf~;
+#X floatatom 216 186 5 0 0 0 - - -;
+#X obj 346 265 reson~ 1;
+#X obj 37 300 *~ 0.25;
+#X obj 346 300 *~ 0.25;
+#X msg 522 92 4000;
+#X floatatom 216 255 5 0 0 0 - - -;
+#X floatatom 419 218 5 0 0 0 - - -;
+#N canvas 217 47 350 257 pulse 0;
+#X obj 144 176 train~ 10 0.1;
+#X obj 145 21 inlet;
+#X obj 144 206 outlet~;
+#X obj 144 146 /;
+#X obj 145 51 t b 0;
+#X msg 123 96 1000;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 4 1 3 1;
+#X connect 5 0 3 0;
+#X restore 133 50 pd pulse;
+#X floatatom 133 19 5 0 0 0 - - -;
+#X connect 0 0 8 0;
+#X connect 2 0 4 1;
+#X connect 3 0 4 0;
+#X connect 4 0 19 2;
+#X connect 4 0 17 1;
+#X connect 5 0 3 1;
+#X connect 6 0 12 0;
+#X connect 7 0 1 0;
+#X connect 7 0 1 1;
+#X connect 8 0 17 0;
+#X connect 8 0 19 0;
+#X connect 9 0 11 0;
+#X connect 9 0 10 0;
+#X connect 10 0 5 0;
+#X connect 11 0 2 0;
+#X connect 12 0 3 0;
+#X connect 13 0 5 0;
+#X connect 14 0 2 0;
+#X connect 15 0 6 0;
+#X connect 16 0 6 0;
+#X connect 17 0 20 0;
+#X connect 18 0 19 3;
+#X connect 18 0 17 2;
+#X connect 19 0 21 0;
+#X connect 20 0 7 0;
+#X connect 21 0 7 1;
+#X connect 22 0 5 0;
+#X connect 23 0 21 1;
+#X connect 23 0 20 1;
+#X connect 24 0 19 1;
+#X connect 25 0 8 1;
+#X connect 26 0 25 0;
diff --git a/test/cyclone/svf-test.pd b/test/cyclone/svf-test.pd
new file mode 100644
index 0000000..d110efe
--- /dev/null
+++ b/test/cyclone/svf-test.pd
@@ -0,0 +1,81 @@
+#N canvas 197 96 582 543 12;
+#X obj 38 21 noise~;
+#X obj 77 504 dac~;
+#X floatatom 307 110 5 0 0 0 - - -;
+#X obj 390 142 *~ 10;
+#X obj 390 176 +~ 0;
+#X floatatom 478 110 5 0 0 0 - - -;
+#X floatatom 390 78 5 0 0 0 - - -;
+#X obj 53 277 a-mix2;
+#X obj 37 85 a-mix2;
+#X obj 348 21 loadbang;
+#X msg 478 50 0;
+#X msg 307 78 1000;
+#X obj 390 110 osc~ 4;
+#X msg 521 50 1000;
+#X msg 242 78 5000;
+#X msg 353 50 13;
+#X msg 396 50 4;
+#X floatatom 246 176 5 0 0 0 - - -;
+#X obj 53 245 *~ 0.25;
+#X obj 139 245 *~ 0.25;
+#X msg 521 85 4000;
+#X floatatom 410 250 5 0 0 0 - - -;
+#X obj 215 212 svf~;
+#X obj 235 277 a-mix2;
+#X obj 235 245 *~ 0.25;
+#X obj 321 245 *~ 0.25;
+#X obj 91 391 a-mix2;
+#N canvas 217 47 350 257 pulse 0;
+#X obj 144 176 train~ 10 0.1;
+#X obj 145 21 inlet;
+#X obj 144 206 outlet~;
+#X obj 144 146 /;
+#X obj 145 51 t b 0;
+#X msg 123 96 1000;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 4 1 3 1;
+#X connect 5 0 3 0;
+#X restore 133 50 pd pulse;
+#X floatatom 133 21 5 0 0 0 - - -;
+#X msg 435 50 689;
+#X connect 0 0 8 0;
+#X connect 2 0 4 1;
+#X connect 3 0 4 0;
+#X connect 4 0 22 1;
+#X connect 5 0 3 1;
+#X connect 6 0 12 0;
+#X connect 7 0 26 0;
+#X connect 8 0 22 0;
+#X connect 9 0 11 0;
+#X connect 9 0 10 0;
+#X connect 10 0 5 0;
+#X connect 11 0 2 0;
+#X connect 12 0 3 0;
+#X connect 13 0 5 0;
+#X connect 14 0 2 0;
+#X connect 15 0 6 0;
+#X connect 16 0 6 0;
+#X connect 17 0 22 2;
+#X connect 18 0 7 0;
+#X connect 19 0 7 1;
+#X connect 20 0 5 0;
+#X connect 21 0 19 1;
+#X connect 21 0 18 1;
+#X connect 21 0 24 1;
+#X connect 21 0 25 1;
+#X connect 22 0 18 0;
+#X connect 22 1 19 0;
+#X connect 22 2 24 0;
+#X connect 22 3 25 0;
+#X connect 23 0 26 1;
+#X connect 24 0 23 0;
+#X connect 25 0 23 1;
+#X connect 26 0 1 0;
+#X connect 26 0 1 1;
+#X connect 27 0 8 1;
+#X connect 28 0 27 0;
+#X connect 29 0 6 0;
diff --git a/test/cyclone/zerox-test.pd b/test/cyclone/zerox-test.pd
new file mode 100644
index 0000000..f579242
--- /dev/null
+++ b/test/cyclone/zerox-test.pd
@@ -0,0 +1,33 @@
+#N canvas 235 256 580 405 12;
+#X obj 88 184 zerox~;
+#X msg 154 149 set \$1;
+#X floatatom 154 120 5 0 0 0 - - -;
+#X obj 89 84 cycle~ 1;
+#X floatatom 89 55 5 0 0 0 - - -;
+#X obj 225 219 Snapshot~ 100;
+#X floatatom 225 251 5 0 0 0 - - -;
+#X obj 88 219 Snapshot~ 100;
+#X floatatom 88 251 5 0 0 0 - - -;
+#X obj 48 313 capture~ f 512;
+#X msg 88 280 clear;
+#X obj 409 184 zerox~;
+#X obj 459 219 edge~;
+#X obj 409 256 counter;
+#X floatatom 409 288 5 0 0 0 - - -;
+#X msg 376 219 set 0;
+#X floatatom 409 149 5 0 0 0 - - -;
+#X connect 0 0 7 0;
+#X connect 0 0 9 0;
+#X connect 0 1 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 5 0 6 0;
+#X connect 7 0 8 0;
+#X connect 10 0 9 0;
+#X connect 11 1 12 0;
+#X connect 12 0 13 0;
+#X connect 13 0 14 0;
+#X connect 15 0 13 0;
+#X connect 16 0 11 0;