From a0f8c026117d1bbe094894d614136efea4b65c97 Mon Sep 17 00:00:00 2001
From: "N.N." <krzyszcz@users.sourceforge.net>
Date: Thu, 14 Aug 2003 14:32:00 +0000
Subject: 10 new sickle classes

svn path=/trunk/externals/miXed/; revision=846
---
 cyclone/sickle/curve.c     | 462 +++++++++++++++++++++++++++++++++++++++++++++
 cyclone/sickle/curve.gp    |   9 +
 cyclone/sickle/lores.c     | 109 +++++++++++
 cyclone/sickle/mstosamps.c |  55 ++++++
 cyclone/sickle/onepole.c   | 151 +++++++++++++++
 cyclone/sickle/pink.c      | 100 ++++++++++
 cyclone/sickle/poke.c      | 155 +++++++++++++++
 cyclone/sickle/reson.c     | 123 ++++++++++++
 cyclone/sickle/sampstoms.c |  55 ++++++
 cyclone/sickle/svf.c       | 169 +++++++++++++++++
 cyclone/sickle/zerox.c     |  78 ++++++++
 11 files changed, 1466 insertions(+)
 create mode 100644 cyclone/sickle/curve.c
 create mode 100644 cyclone/sickle/curve.gp
 create mode 100644 cyclone/sickle/lores.c
 create mode 100644 cyclone/sickle/mstosamps.c
 create mode 100644 cyclone/sickle/onepole.c
 create mode 100644 cyclone/sickle/pink.c
 create mode 100644 cyclone/sickle/poke.c
 create mode 100644 cyclone/sickle/reson.c
 create mode 100644 cyclone/sickle/sampstoms.c
 create mode 100644 cyclone/sickle/svf.c
 create mode 100644 cyclone/sickle/zerox.c

(limited to 'cyclone/sickle')

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 */
+}
-- 
cgit v1.2.1