aboutsummaryrefslogtreecommitdiff
path: root/cyclone/sickle/matrix.c
diff options
context:
space:
mode:
Diffstat (limited to 'cyclone/sickle/matrix.c')
-rw-r--r--cyclone/sickle/matrix.c563
1 files changed, 563 insertions, 0 deletions
diff --git a/cyclone/sickle/matrix.c b/cyclone/sickle/matrix.c
new file mode 100644
index 0000000..a0772dc
--- /dev/null
+++ b/cyclone/sickle/matrix.c
@@ -0,0 +1,563 @@
+/* Copyright (c) 2005 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 "common/loud.h"
+#include "common/fitter.h"
+#include "unstable/fragile.h"
+#include "sickle/sic.h"
+
+#ifdef KRZYSZCZ
+#define MATRIX_DEBUG
+#endif
+
+#define MATRIX_DEFGAIN 0. /* CHECKED */
+#define MATRIX_DEFRAMP 0. /* CHECKED */
+
+#define MATRIX_GAINEPSILON 1e-20f
+#define MATRIX_MINRAMP .001 /* LATER rethink */
+
+typedef struct _matrix
+{
+ t_sic x_sic;
+ int x_ninlets;
+ int x_noutlets;
+ int x_nblock;
+ int x_maxblock;
+ t_float **x_ivecs;
+ t_float **x_ovecs;
+ t_float **x_osums;
+ int x_ncells;
+ int *x_cells;
+ t_outlet *x_dumpout;
+ /* The following fields are specific to nonbinary mode, i.e. we keep them
+ unallocated in binary mode. This is CHECKED to be incompatible: c74
+ always accepts (and reports) gains and ramps, although they are actually
+ meaningless in binary mode, and switching modes is not supported. */
+ float x_defgain;
+ float *x_gains; /* target gains */
+ float x_deframp;
+ float *x_ramps;
+ float x_ksr;
+ float *x_coefs; /* current coefs */
+ float *x_incrs;
+ float *x_bigincrs;
+ int *x_remains;
+} t_matrix;
+
+typedef void (*t_matrix_cellfn)(t_matrix *x, int indx, int ondx,
+ int onoff, float gain);
+
+static t_class *matrix_class;
+static t_symbol *matrixps_matrixtilde;
+
+/* called only in nonbinary mode; LATER deal with changing nblock/ksr */
+static void matrix_retarget(t_matrix *x, int cellndx)
+{
+ float target = (x->x_cells[cellndx] ? x->x_gains[cellndx] : 0.);
+ if (x->x_ramps[cellndx] < MATRIX_MINRAMP)
+ {
+ x->x_coefs[cellndx] = target;
+ x->x_remains[cellndx] = 0;
+ }
+ else
+ {
+ x->x_remains[cellndx] =
+ x->x_ramps[cellndx] * x->x_ksr + 0.5; /* LATER rethink */
+ x->x_incrs[cellndx] =
+ (target - x->x_coefs[cellndx]) / (float)x->x_remains[cellndx];
+ x->x_bigincrs[cellndx] = x->x_nblock * x->x_incrs[cellndx];
+ }
+}
+
+static void matrix_float(t_matrix *x, t_float f)
+{
+ loud_nomethod((t_pd *)x, &s_float); /* CHECKED */
+}
+
+static void matrix_list(t_matrix *x, t_symbol *s, int ac, t_atom *av)
+{
+ int indx, ondx, cellndx, onoff;
+ float gain;
+ if (ac < 3)
+ return; /* CHECKED list silently ignored if ac < 3 */
+ /* CHECKED floats silently clipped, symbols converted to 0 */
+ indx = (av->a_type == A_FLOAT ? (int)av->a_w.w_float : 0);
+ if (indx < 0 || indx >= x->x_ninlets)
+ { /* CHECKED */
+ loud_error((t_pd *)x, "invalid inlet number %d", indx);
+ return;
+ }
+ ac--; av++;
+ /* CHECKED floats silently clipped, symbols converted to 0 */
+ ondx = (av->a_type == A_FLOAT ? (int)av->a_w.w_float : 0);
+ if (ondx < 0 || ondx >= x->x_noutlets)
+ { /* CHECKED */
+ loud_error((t_pd *)x, "invalid outlet number %d", ondx);
+ return;
+ }
+ cellndx = indx * x->x_noutlets + ondx;
+ ac--; av++;
+ /* CHECKED negative gain used in nonbinary mode, accepted as 1 in binary */
+ gain = (av->a_type == A_FLOAT ? av->a_w.w_float : 0.);
+ onoff = (gain < -MATRIX_GAINEPSILON || gain > MATRIX_GAINEPSILON);
+ x->x_cells[cellndx] = onoff;
+ if (x->x_gains)
+ {
+ if (onoff) /* CHECKME */
+ x->x_gains[cellndx] = gain;
+ ac--; av++;
+ if (ac)
+ {
+ float ramp = (av->a_type == A_FLOAT ? av->a_w.w_float : 0.);
+ x->x_ramps[cellndx] = (ramp < MATRIX_MINRAMP ? 0. : ramp);
+ }
+ matrix_retarget(x, cellndx);
+ }
+}
+
+static void matrix_clear(t_matrix *x)
+{
+ int i;
+ for (i = 0; i < x->x_ncells; i++)
+ x->x_cells[i] = 0;
+}
+
+/* CHECKED c74's refman and help patch are wrong about int pairs --
+ the actual syntax is "[dis]connect indx ondx1 [ondx2 [ondx3..." */
+static void matrix_connect(t_matrix *x, t_symbol *s, int ac, t_atom *av)
+{
+ int onoff = (s == gensym("connect")), indx, celloffset;
+ if (ac < 2)
+ return; /* CHECKED */
+ /* CHECKED floats silently clipped, symbols converted to 0 */
+ indx = (av->a_type == A_FLOAT ? (int)av->a_w.w_float : 0);
+ if (indx < 0 || indx >= x->x_ninlets)
+ { /* CHECKED */
+ loud_error((t_pd *)x, "invalid inlet number %d", indx);
+ return;
+ }
+ celloffset = indx * x->x_noutlets;
+ ac--; av++;
+ while (ac)
+ {
+ /* CHECKED floats silently clipped, symbols converted to 0 */
+ int cellndx, ondx = (av->a_type == A_FLOAT ? (int)av->a_w.w_float : 0);
+ if (ondx < 0 || ondx >= x->x_noutlets)
+ { /* CHECKED */
+ loud_error((t_pd *)x, "invalid outlet number %d", ondx);
+ return;
+ }
+ cellndx = celloffset + ondx;
+ x->x_cells[cellndx] = onoff;
+ if (x->x_gains)
+ matrix_retarget(x, cellndx);
+ ac--; av++;
+ }
+}
+
+/* CHECKED active ramps are not retargeted */
+static void matrix_ramp(t_matrix *x, t_floatarg f)
+{
+ if (x->x_ramps)
+ {
+ int i;
+ x->x_deframp = (f < MATRIX_MINRAMP ? 0. : f);
+ /* CHECKED cell-specific ramps are lost */
+ for (i = 0; i < x->x_ncells; i++)
+ x->x_ramps[i] = x->x_deframp;
+ }
+}
+
+static t_int *matrix01_perform(t_int *w)
+{
+ t_matrix *x = (t_matrix *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float **ivecs = x->x_ivecs;
+ t_float **ovecs = x->x_ovecs;
+ t_float **osums = x->x_osums;
+ int *cellp = x->x_cells;
+ int indx = x->x_ninlets;
+ while (indx--)
+ {
+ t_float *ivec = *ivecs++;
+ t_float **ovecp = osums;
+ int ondx = x->x_noutlets;
+ while (ondx--)
+ {
+ if (*cellp++)
+ {
+ t_float *in = ivec;
+ t_float *out = *ovecp;
+ int sndx = nblock;
+ while (sndx--)
+ *out++ += *in++;
+ }
+ ovecp++;
+ }
+ }
+ osums = x->x_osums;
+ indx = x->x_noutlets;
+ while (indx--)
+ {
+ t_float *in = *osums++;
+ t_float *out = *ovecs++;
+ int sndx = nblock;
+ while (sndx--)
+ {
+ *out++ = *in;
+ *in++ = 0.;
+ }
+ }
+ return (w + 3);
+}
+
+static t_int *matrixnb_perform(t_int *w)
+{
+ t_matrix *x = (t_matrix *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float **ivecs = x->x_ivecs;
+ t_float **ovecs = x->x_ovecs;
+ t_float **osums = x->x_osums;
+ int *cellp = x->x_cells;
+ float *gainp = x->x_gains;
+ float *coefp = x->x_coefs;
+ float *incrp = x->x_incrs;
+ float *bigincrp = x->x_bigincrs;
+ int *nleftp = x->x_remains;
+ int indx = x->x_ninlets;
+ while (indx--)
+ {
+ t_float *ivec = *ivecs++;
+ t_float **ovecp = osums;
+ int ondx = x->x_noutlets;
+ while (ondx--)
+ {
+ t_float *in = ivec;
+ t_float *out = *ovecp;
+ float nleft = *nleftp;
+ int sndx = nblock;
+ if (nleft >= nblock)
+ {
+ float coef = *coefp;
+ float incr = *incrp;
+ if ((*nleftp -= nblock) == 0)
+ *coefp = (*cellp ? *gainp : 0.);
+ else
+ *coefp += *bigincrp;
+ while (sndx--)
+ *out++ += *in++ * coef, coef += incr;
+ }
+ else if (nleft > 0)
+ {
+ float coef = *coefp;
+ float incr = *incrp;
+ sndx -= nleft;
+ do
+ *out++ += *in++ * coef, coef += incr;
+ while (--nleft);
+ if (*cellp)
+ {
+ coef = *coefp = *gainp;
+ while (sndx--)
+ *out++ += *in++ * coef;
+ }
+ else *coefp = 0.;
+ *nleftp = 0;
+ }
+ else if (*cellp)
+ {
+ float coef = *coefp;
+ while (sndx--)
+ *out++ += *in++ * coef;
+ }
+ cellp++;
+ ovecp++;
+ gainp++;
+ coefp++;
+ incrp++;
+ bigincrp++;
+ nleftp++;
+ }
+ }
+ osums = x->x_osums;
+ indx = x->x_noutlets;
+ while (indx--)
+ {
+ t_float *in = *osums++;
+ t_float *out = *ovecs++;
+ int sndx = nblock;
+ while (sndx--)
+ {
+ *out++ = *in;
+ *in++ = 0.;
+ }
+ }
+ return (w + 3);
+}
+
+static void matrix_dsp(t_matrix *x, t_signal **sp)
+{
+ int i, nblock = sp[0]->s_n;
+ t_float **vecp = x->x_ivecs;
+ t_signal **sigp = sp;
+ for (i = 0; i < x->x_ninlets; i++)
+ *vecp++ = (*sigp++)->s_vec;
+ vecp = x->x_ovecs;
+ for (i = 0; i < x->x_noutlets; i++)
+ *vecp++ = (*sigp++)->s_vec;
+ if (nblock != x->x_nblock)
+ {
+ if (nblock > x->x_maxblock)
+ {
+ size_t oldsize = x->x_maxblock * sizeof(*x->x_osums[i]),
+ newsize = nblock * sizeof(*x->x_osums[i]);
+ for (i = 0; i < x->x_noutlets; i++)
+ x->x_osums[i] = resizebytes(x->x_osums[i], oldsize, newsize);
+ x->x_maxblock = nblock;
+ }
+ x->x_nblock = nblock;
+ }
+ if (x->x_gains)
+ {
+ x->x_ksr = sp[0]->s_sr * .001;
+ dsp_add(matrixnb_perform, 2, x, nblock);
+ }
+ else dsp_add(matrix01_perform, 2, x, nblock);
+}
+
+static void matrix_cellout(t_matrix *x, int indx, int ondx,
+ int onoff, float gain)
+{
+ t_atom atout[3];
+ SETFLOAT(&atout[0], (t_float)indx);
+ SETFLOAT(&atout[1], (t_float)ondx);
+ if (onoff)
+ SETFLOAT(&atout[2], gain);
+ else
+ SETFLOAT(&atout[2], 0.);
+ outlet_list(x->x_dumpout, &s_list, 3, atout);
+}
+
+static void matrix_cellprint(t_matrix *x, int indx, int ondx,
+ int onoff, float gain)
+{
+ post("%d %d %g", indx, ondx, (onoff ? gain : 0.));
+}
+
+#ifdef MATRIX_DEBUG
+static void matrix_celldebug(t_matrix *x, int indx, int ondx,
+ int onoff, float gain)
+{
+ loudbug_post("%d %d %g", indx, ondx, gain);
+}
+#endif
+
+static void matrix_report(t_matrix *x, float *gains, float defgain,
+ t_matrix_cellfn cellfn)
+{
+ if (gains)
+ {
+ int *cellp = x->x_cells;
+ float *gp = gains;
+ int indx, ondx;
+ for (indx = 0; indx < x->x_ninlets; indx++)
+ for (ondx = 0; ondx < x->x_noutlets; ondx++, cellp++, gp++)
+ /* CHECKED all cells are printed */
+ (*cellfn)(x, indx, ondx, *cellp, *gp);
+ }
+ else /* CHECKED incompatible: gains confusingly printed in binary mode */
+ {
+ int *cellp = x->x_cells;
+ int indx, ondx;
+ for (indx = 0; indx < x->x_ninlets; indx++)
+ for (ondx = 0; ondx < x->x_noutlets; ondx++, cellp++)
+ /* CHECKED all cells are printed */
+ (*cellfn)(x, indx, ondx, *cellp, defgain);
+ }
+}
+
+static void matrix_dump(t_matrix *x)
+{
+ matrix_report(x, x->x_coefs, 1., matrix_cellout);
+}
+
+static void matrix_dumptarget(t_matrix *x)
+{
+ matrix_report(x, x->x_gains, 1., matrix_cellout);
+}
+
+static void matrix_print(t_matrix *x)
+{
+ /* CHECKED same output as 'dump' -> [matrix~] -> [print] */
+ matrix_report(x, x->x_coefs, 1., matrix_cellprint);
+}
+
+#ifdef MATRIX_DEBUG
+static void matrix_debugramps(t_matrix *x)
+{
+ matrix_report(x, x->x_ramps, 0., matrix_celldebug);
+}
+
+static void matrix_debugsums(t_matrix *x)
+{
+ int i;
+ loudbug_startpost("nblock %d (max %d), vectors:",
+ x->x_nblock, x->x_maxblock);
+ for (i = 0; i < x->x_noutlets; i++)
+ loudbug_startpost(" %x", (int)x->x_osums[i]);
+ loudbug_endpost();
+}
+
+static void matrix_debug(t_matrix *x, t_symbol *s)
+{
+ if (s == gensym("ramps"))
+ matrix_debugramps(x);
+ else if (s == gensym("sums"))
+ matrix_debugsums(x);
+ else
+ {
+ matrix_debugramps(x);
+ matrix_debugsums(x);
+ }
+}
+#endif
+
+static void matrix_free(t_matrix *x)
+{
+ if (x->x_ivecs)
+ freebytes(x->x_ivecs, x->x_ninlets * sizeof(*x->x_ivecs));
+ if (x->x_ovecs)
+ freebytes(x->x_ovecs, x->x_noutlets * sizeof(*x->x_ovecs));
+ if (x->x_osums)
+ {
+ int i;
+ for (i = 0; i < x->x_noutlets; i++)
+ freebytes(x->x_osums[i], x->x_maxblock * sizeof(*x->x_osums[i]));
+ freebytes(x->x_osums, x->x_noutlets * sizeof(*x->x_osums));
+ }
+ if (x->x_cells)
+ freebytes(x->x_cells, x->x_ncells * sizeof(*x->x_cells));
+ if (x->x_gains)
+ freebytes(x->x_gains, x->x_ncells * sizeof(*x->x_gains));
+ if (x->x_ramps)
+ freebytes(x->x_ramps, x->x_ncells * sizeof(*x->x_ramps));
+ if (x->x_coefs)
+ freebytes(x->x_coefs, x->x_ncells * sizeof(*x->x_coefs));
+ if (x->x_incrs)
+ freebytes(x->x_incrs, x->x_ncells * sizeof(*x->x_incrs));
+ if (x->x_bigincrs)
+ freebytes(x->x_bigincrs, x->x_ncells * sizeof(*x->x_bigincrs));
+ if (x->x_remains)
+ freebytes(x->x_remains, x->x_ncells * sizeof(*x->x_remains));
+}
+
+static void *matrix_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_pd *z;
+ if (!fittermax_get() &&
+ (z = fragile_class_mutate(matrixps_matrixtilde,
+ (t_newmethod)matrix_new, ac, av)))
+ return (z);
+ else if (ac < 2)
+ {
+ loud_error(0, "bad creation arguments for class '%s'",
+ matrixps_matrixtilde->s_name);
+ loud_errand(0, "missing number of %s", (ac ? "outlets" : "inlets"));
+ return (0); /* CHECKED */
+ }
+ else
+ {
+ t_matrix *x = (t_matrix *)pd_new(matrix_class);
+ int i;
+ if (av[0].a_type == A_FLOAT)
+ {
+ if ((x->x_ninlets = (int)av[0].a_w.w_float) < 1)
+ x->x_ninlets = 1;
+ }
+ else x->x_ninlets = 1; /* CHECKED */
+ if (av[1].a_type == A_FLOAT)
+ {
+ if ((x->x_noutlets = (int)av[1].a_w.w_float) < 1)
+ x->x_noutlets = 1;
+ }
+ else x->x_noutlets = 1; /* CHECKED */
+ x->x_ncells = x->x_ninlets * x->x_noutlets;
+ x->x_ivecs = getbytes(x->x_ninlets * sizeof(*x->x_ivecs));
+ x->x_ovecs = getbytes(x->x_noutlets * sizeof(*x->x_ovecs));
+ x->x_nblock = x->x_maxblock = sys_getblksize();
+ x->x_osums = getbytes(x->x_noutlets * sizeof(*x->x_osums));
+ for (i = 0; i < x->x_noutlets; i++)
+ x->x_osums[i] = getbytes(x->x_maxblock * sizeof(*x->x_osums[i]));
+ x->x_cells = getbytes(x->x_ncells * sizeof(*x->x_cells));
+ matrix_clear(x);
+ if (ac >= 3)
+ {
+ if (av[2].a_type == A_FLOAT)
+ x->x_defgain = av[2].a_w.w_float;
+ else
+ x->x_defgain = MATRIX_DEFGAIN;
+ x->x_gains = getbytes(x->x_ncells * sizeof(*x->x_gains));
+ for (i = 0; i < x->x_ncells; i++)
+ x->x_gains[i] = x->x_defgain;
+ x->x_ramps = getbytes(x->x_ncells * sizeof(*x->x_ramps));
+ matrix_ramp(x, MATRIX_DEFRAMP);
+ x->x_coefs = getbytes(x->x_ncells * sizeof(*x->x_coefs));
+ for (i = 0; i < x->x_ncells; i++)
+ x->x_coefs[i] = 0.;
+ x->x_ksr = sys_getsr() * .001;
+ x->x_incrs = getbytes(x->x_ncells * sizeof(*x->x_incrs));
+ x->x_bigincrs = getbytes(x->x_ncells * sizeof(*x->x_bigincrs));
+ x->x_remains = getbytes(x->x_ncells * sizeof(*x->x_remains));
+ for (i = 0; i < x->x_ncells; i++)
+ x->x_remains[i] = 0;
+ }
+ else
+ {
+ x->x_gains = 0;
+ x->x_ramps = 0;
+ x->x_coefs = 0;
+ x->x_incrs = 0;
+ x->x_bigincrs = 0;
+ x->x_remains = 0;
+ }
+ for (i = 1; i < x->x_ninlets; i++)
+ sic_newinlet((t_sic *)x, 0.);
+ for (i = 0; i < x->x_noutlets; i++)
+ outlet_new((t_object *)x, &s_signal);
+ x->x_dumpout = outlet_new((t_object *)x, &s_list);
+ return (x);
+ }
+}
+
+void matrix_tilde_setup(void)
+{
+ matrixps_matrixtilde = gensym("matrix~");
+ matrix_class = class_new(matrixps_matrixtilde,
+ (t_newmethod)matrix_new,
+ (t_method)matrix_free,
+ sizeof(t_matrix), 0, A_GIMME, 0);
+ fragile_class_raise(matrixps_matrixtilde, (t_newmethod)matrix_new);
+ sic_setup(matrix_class, matrix_dsp, matrix_float);
+ class_addlist(matrix_class, matrix_list);
+ class_addmethod(matrix_class, (t_method)matrix_clear,
+ gensym("clear"), 0);
+ class_addmethod(matrix_class, (t_method)matrix_connect,
+ gensym("connect"), A_GIMME, 0);
+ class_addmethod(matrix_class, (t_method)matrix_connect,
+ gensym("disconnect"), A_GIMME, 0);
+ class_addmethod(matrix_class, (t_method)matrix_ramp,
+ gensym("ramp"), A_FLOAT, 0);
+ class_addmethod(matrix_class, (t_method)matrix_dump,
+ gensym("dump"), 0);
+ class_addmethod(matrix_class, (t_method)matrix_dumptarget,
+ gensym("dumptarget"), 0);
+ class_addmethod(matrix_class, (t_method)matrix_print,
+ gensym("print"), 0);
+#ifdef MATRIX_DEBUG
+ class_addmethod(matrix_class, (t_method)matrix_debug,
+ gensym("debug"), A_DEFSYM, 0);
+#endif
+ fitter_setup(matrix_class, 0);
+}