aboutsummaryrefslogtreecommitdiff
path: root/cyclone/hammer
diff options
context:
space:
mode:
Diffstat (limited to 'cyclone/hammer')
-rw-r--r--cyclone/hammer/Append.c207
-rw-r--r--cyclone/hammer/Borax.c177
-rw-r--r--cyclone/hammer/Bucket.c137
-rw-r--r--cyclone/hammer/Clip.c149
-rw-r--r--cyclone/hammer/Decode.c110
-rw-r--r--cyclone/hammer/Histo.c103
-rw-r--r--cyclone/hammer/Makefile3
-rw-r--r--cyclone/hammer/Makefile.objects14
-rw-r--r--cyclone/hammer/Makefile.sources80
-rw-r--r--cyclone/hammer/MouseState.c153
-rw-r--r--cyclone/hammer/Peak.c63
-rw-r--r--cyclone/hammer/TogEdge.c71
-rw-r--r--cyclone/hammer/Trough.c63
-rw-r--r--cyclone/hammer/Uzi.c108
-rw-r--r--cyclone/hammer/accum.c68
-rw-r--r--cyclone/hammer/acos.c48
-rw-r--r--cyclone/hammer/active.c55
-rw-r--r--cyclone/hammer/allhammers.c160
-rw-r--r--cyclone/hammer/anal.c108
-rw-r--r--cyclone/hammer/asin.c48
-rw-r--r--cyclone/hammer/bangbang.c73
-rw-r--r--cyclone/hammer/bondo.c394
-rw-r--r--cyclone/hammer/buddy.c253
-rw-r--r--cyclone/hammer/capture.c291
-rw-r--r--cyclone/hammer/cartopol.c44
-rw-r--r--cyclone/hammer/coll.c1597
-rw-r--r--cyclone/hammer/comment.c835
-rw-r--r--cyclone/hammer/cosh.c48
-rw-r--r--cyclone/hammer/counter.c399
-rw-r--r--cyclone/hammer/cycle.c153
-rw-r--r--cyclone/hammer/decide.c75
-rw-r--r--cyclone/hammer/drunk.c140
-rw-r--r--cyclone/hammer/flush.c79
-rw-r--r--cyclone/hammer/forward.c71
-rw-r--r--cyclone/hammer/fromsymbol.c88
-rw-r--r--cyclone/hammer/funbuff.c521
-rw-r--r--cyclone/hammer/funnel.c179
-rw-r--r--cyclone/hammer/gate.c147
-rw-r--r--cyclone/hammer/grab.c279
-rw-r--r--cyclone/hammer/hammer.c93
-rw-r--r--cyclone/hammer/iter.c112
-rw-r--r--cyclone/hammer/match.c216
-rw-r--r--cyclone/hammer/maximum.c88
-rw-r--r--cyclone/hammer/mean.c79
-rw-r--r--cyclone/hammer/midiflush.c102
-rw-r--r--cyclone/hammer/midiformat.c112
-rw-r--r--cyclone/hammer/midiparse.c132
-rw-r--r--cyclone/hammer/minimum.c88
-rw-r--r--cyclone/hammer/mousefilter.c70
-rw-r--r--cyclone/hammer/next.c58
-rw-r--r--cyclone/hammer/offer.c94
-rw-r--r--cyclone/hammer/onebang.c46
-rw-r--r--cyclone/hammer/past.c154
-rw-r--r--cyclone/hammer/pd-lib-notes.txt61
-rw-r--r--cyclone/hammer/poltocar.c44
-rw-r--r--cyclone/hammer/prepend.c258
-rw-r--r--cyclone/hammer/prob.c312
-rw-r--r--cyclone/hammer/pv.c457
-rw-r--r--cyclone/hammer/seq.c825
-rw-r--r--cyclone/hammer/sinh.c48
-rw-r--r--cyclone/hammer/speedlim.c173
-rw-r--r--cyclone/hammer/spell.c149
-rw-r--r--cyclone/hammer/split.c64
-rw-r--r--cyclone/hammer/spray.c93
-rw-r--r--cyclone/hammer/sprintf.c634
-rw-r--r--cyclone/hammer/substitute.c340
-rw-r--r--cyclone/hammer/sustain.c85
-rw-r--r--cyclone/hammer/switch.c152
-rw-r--r--cyclone/hammer/tanh.c48
-rw-r--r--cyclone/hammer/testmess.c245
-rw-r--r--cyclone/hammer/thresh.c134
-rw-r--r--cyclone/hammer/tosymbol.c184
-rw-r--r--cyclone/hammer/universal.c167
-rw-r--r--cyclone/hammer/urn.c148
-rw-r--r--cyclone/hammer/xbendin.c93
-rw-r--r--cyclone/hammer/xbendin2.c99
-rw-r--r--cyclone/hammer/xbendout.c54
-rw-r--r--cyclone/hammer/xbendout2.c60
-rw-r--r--cyclone/hammer/xnotein.c100
-rw-r--r--cyclone/hammer/xnoteout.c62
-rw-r--r--cyclone/hammer/zl.c982
81 files changed, 15106 insertions, 0 deletions
diff --git a/cyclone/hammer/Append.c b/cyclone/hammer/Append.c
new file mode 100644
index 0000000..19978c7
--- /dev/null
+++ b/cyclone/hammer/Append.c
@@ -0,0 +1,207 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/grow.h"
+
+#define APPEND_INISIZE 32 /* LATER rethink */
+#define APPEND_MAXSIZE 256
+
+typedef struct _append
+{
+ t_object x_ob;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ t_atom *x_message;
+ t_atom *x_messbuf;
+ t_atom x_messini[APPEND_INISIZE];
+ int x_entered;
+ int x_auxsize;
+ t_atom *x_auxbuf;
+} t_append;
+
+static t_class *append_class;
+
+/* Usually a preallocation method is used, except in special cases of:
+ 1) reentrant output request, or 2) an output request which would cause
+ resizing to more than MAXSIZE (no such limit for a 'set' message).
+ In both special cases, a temporary output buffer is allocated.
+ A separately preallocated output buffer is not used, thus avoiding
+ memcpying of the stored message (a small performance gain when the
+ preallocation method is chosen). Instead, self-invoked 'set'
+ messages are postponed, using an auxiliary buffer.
+*/
+
+/* Any Append's output goes through outlet_anything() -> typedmess() */
+
+static void append_setnatoms(t_append *x, int natoms)
+{
+ x->x_message = x->x_messbuf + x->x_size - natoms;
+ x->x_natoms = natoms;
+}
+
+static void append_anything(t_append *x, t_symbol *s, int ac, t_atom *av)
+{
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ int ntotal = x->x_natoms + ac;
+ t_atom *buf;
+ x->x_entered = 1;
+ if (prealloc && ntotal > x->x_size)
+ {
+ if (ntotal > APPEND_MAXSIZE)
+ prealloc = 0;
+ else
+ {
+ int nrequested = ntotal;
+ x->x_messbuf = grow_withtail(&nrequested, &x->x_natoms,
+ (char **)&x->x_message,
+ &x->x_size, x->x_messbuf,
+ APPEND_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ prealloc = (nrequested == ntotal);
+ }
+ }
+ if (prealloc)
+ {
+ buf = x->x_message - ac;
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ outlet_anything(((t_object *)x)->ob_outlet, s, ntotal, buf);
+ }
+ else
+ {
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ if (buf = getbytes(ntotal * sizeof(*buf)))
+ {
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ if (x->x_natoms)
+ memcpy(buf + ac, x->x_message, x->x_natoms * sizeof(*buf));
+ outlet_anything(((t_object *)x)->ob_outlet, s, ntotal, buf);
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+ }
+ if (!reentered)
+ {
+ x->x_entered = 0;
+ if (x->x_auxbuf)
+ {
+ if (x->x_auxsize <= x->x_size)
+ {
+ append_setnatoms(x, x->x_auxsize / 2);
+ memcpy(x->x_message, x->x_auxbuf + x->x_natoms,
+ x->x_natoms * sizeof(*x->x_message));
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ }
+ else
+ {
+ if (x->x_messbuf != x->x_messini)
+ freebytes(x->x_messbuf, x->x_size * sizeof(*x->x_messbuf));
+ x->x_size = x->x_auxsize;
+ x->x_messbuf = x->x_auxbuf;
+ append_setnatoms(x, x->x_auxsize / 2);
+ }
+ x->x_auxbuf = 0;
+ }
+ }
+}
+
+static void append_bang(t_append *x)
+{
+ /* CHECKED: a nop */
+}
+
+static void append_float(t_append *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ append_anything(x, &s_list, 1, &at); /* CHECKED: converted to list */
+}
+
+/* CHECKED: incompatible -- LATER consider converting to anything */
+static void append_symbol(t_append *x, t_symbol *s)
+{
+ t_atom at;
+ SETSYMBOL(&at, s);
+ append_anything(x, &s_symbol, 1, &at);
+}
+
+/* LATER gpointer */
+
+static void append_set(t_append *x, t_symbol *s, int ac, t_atom *av)
+{
+ int newsize = ac * 2;
+ if (newsize > 0)
+ {
+ if (x->x_entered)
+ {
+ if (x->x_auxbuf)
+ {
+ loud_warning((t_pd *)x, "\'set\' message overridden");
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ x->x_auxsize = 0;
+ }
+ if (x->x_auxbuf = getbytes(newsize * sizeof(*x->x_auxbuf)))
+ {
+ memcpy(x->x_auxbuf + ac, av, ac * sizeof(*x->x_auxbuf));
+ x->x_auxsize = newsize;
+ }
+ }
+ else
+ {
+ t_atom *ap;
+ if (newsize > x->x_size)
+ {
+ int sz = newsize;
+ x->x_messbuf = grow_nodata(&sz, &x->x_size, x->x_messbuf,
+ APPEND_INISIZE, x->x_messini,
+ sizeof(*x->x_messbuf));
+ if (sz != newsize)
+ ac = sz / 2; /* LATER rethink */
+ }
+ append_setnatoms(x, ac);
+ ap = x->x_message;
+ while (ac--) *ap++ = *av++;
+ }
+ }
+}
+
+static void append_free(t_append *x)
+{
+ if (x->x_messbuf != x->x_messini)
+ freebytes(x->x_messbuf, x->x_size * sizeof(*x->x_messbuf));
+}
+
+static void *append_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_append *x = (t_append *)pd_new(append_class);
+ x->x_size = APPEND_INISIZE;
+ x->x_natoms = 0;
+ x->x_messbuf = x->x_messini;
+ x->x_auxbuf = 0;
+ x->x_entered = 0;
+ outlet_new((t_object *)x, &s_anything);
+ append_setnatoms(x, 0);
+ append_set(x, 0, ac, av);
+ return (x);
+}
+
+void Append_setup(void)
+{
+ append_class = class_new(gensym("Append"),
+ (t_newmethod)append_new,
+ (t_method)append_free,
+ sizeof(t_append), 0,
+ A_GIMME, 0);
+ class_addbang(append_class, append_bang);
+ class_addfloat(append_class, append_float);
+ class_addsymbol(append_class, append_symbol);
+ class_addlist(append_class, append_anything); /* LATER rethink */
+ class_addanything(append_class, append_anything);
+ class_addmethod(append_class, (t_method)append_set,
+ gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/Borax.c b/cyclone/hammer/Borax.c
new file mode 100644
index 0000000..26e0ef8
--- /dev/null
+++ b/cyclone/hammer/Borax.c
@@ -0,0 +1,177 @@
+/* Copyright (c) 2002-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 first version of this code was written by Olaf Matthes.
+ It was entirely reimplemented in the hope of adapting it to the
+ cyclone's guidelines. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define BORAX_MAXVOICES 128 /* CHECKME */
+
+typedef struct _Borax_voice
+{
+ int v_index; /* free iff zero */
+ double v_onset;
+ int v_nonsets;
+} t_Borax_voice;
+
+typedef struct _Borax
+{
+ t_object x_ob;
+ int x_vel; /* CHECKME t_float controlled with floatinlet
+ (CHECKME the same in flush) */
+ double x_onset;
+ int x_nonsets;
+ int x_ndurs;
+ int x_ndtimes;
+ int x_minindex;
+ int x_indices[BORAX_MAXVOICES]; /* 0 (free) or 1 (used) */
+ int x_nvoices;
+ t_Borax_voice x_voices[BORAX_MAXVOICES];
+ t_outlet *x_voiceout;
+ t_outlet *x_nvoicesout;
+ t_outlet *x_pitchout;
+ t_outlet *x_velout;
+ t_outlet *x_ndursout;
+ t_outlet *x_durout;
+ t_outlet *x_ndtimesout;
+ t_outlet *x_dtimeout;
+} t_Borax;
+
+static t_class *Borax_class;
+
+static void Borax_delta(t_Borax *x)
+{
+ /* CHECKME first note */
+ float dtime = clock_gettimesince(x->x_onset); /* CHECKME */
+ outlet_float(x->x_dtimeout, dtime);
+ outlet_float(x->x_ndtimesout, ++x->x_ndtimes); /* CHECKME */
+}
+
+static void Borax_durout(t_Borax *x, int pitch)
+{
+ float dur = clock_gettimesince(x->x_voices[pitch].v_onset); /* CHECKME */
+ outlet_float(x->x_durout, dur);
+ outlet_float(x->x_ndursout, ++x->x_ndurs); /* CHECKME */
+}
+
+static void Borax_float(t_Borax *x, t_float f)
+{
+ int pitch;
+ if (loud_checkint((t_pd *)x, f, &pitch, &s_float)) /* CHECKME */
+ {
+ int index;
+ if (pitch < 0 || pitch >= BORAX_MAXVOICES)
+ {
+ /* CHECKME pitch range, complaints */
+ return;
+ }
+ index = x->x_voices[pitch].v_index;
+ if (x->x_vel)
+ {
+ if (index)
+ return; /* CHECKME */
+ x->x_indices[index = x->x_minindex] = 1;
+ while (x->x_indices[++x->x_minindex]);
+ index++; /* CHECKME one-based? */
+ Borax_delta(x);
+ x->x_onset = clock_getlogicaltime(); /* CHECKME (in delta?) */
+ x->x_voices[pitch].v_index = index;
+ x->x_voices[pitch].v_onset = x->x_onset;
+ x->x_voices[pitch].v_nonsets = ++x->x_nonsets;
+ x->x_nvoices++;
+ }
+ else
+ {
+ if (!index)
+ return; /* CHECKME */
+ index--;
+ x->x_indices[index] = 0;
+ if (index < x->x_minindex) x->x_minindex = index;
+ index++;
+ Borax_durout(x, pitch);
+ x->x_voices[pitch].v_index = 0;
+ x->x_nvoices--;
+ }
+ outlet_float(x->x_velout, x->x_vel);
+ outlet_float(x->x_pitchout, pitch);
+ outlet_float(x->x_nvoicesout, x->x_nvoices);
+ outlet_float(x->x_voiceout, index);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_voices[pitch].v_nonsets);
+ }
+}
+
+static void Borax_ft1(t_Borax *x, t_floatarg f)
+{
+ x->x_vel = (int)f; /* CHECKME */
+}
+
+static void Borax_reset(t_Borax *x)
+{
+ x->x_vel = 0;
+ x->x_onset = clock_getlogicaltime();
+ x->x_nonsets = x->x_ndurs = x->x_ndtimes = 0;
+ x->x_minindex = 0;
+ memset(x->x_indices, 0, sizeof(x->x_indices));
+ x->x_nvoices = 0;
+ memset(x->x_voices, 0, sizeof(x->x_voices));
+}
+
+static void Borax_bang2(t_Borax *x)
+{
+ int pitch;
+ for (pitch = 0; pitch < BORAX_MAXVOICES; pitch++)
+ {
+ if (x->x_voices[pitch].v_index)
+ {
+ /* CHECKME counters, etc. */
+ Borax_durout(x, pitch);
+ outlet_float(x->x_velout, 0);
+ outlet_float(x->x_pitchout, pitch);
+ outlet_float(x->x_nvoicesout, --x->x_nvoices);
+ outlet_float(x->x_voiceout, x->x_voices[pitch].v_index);
+ outlet_float(((t_object *)x)->ob_outlet,
+ x->x_voices[pitch].v_nonsets);
+ }
+ }
+ Borax_reset(x);
+}
+
+/* CHECKME flush in a destructor */
+
+static void *Borax_new(void)
+{
+ t_Borax *x = (t_Borax *)pd_new(Borax_class);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_bang, gensym("bang2"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_voiceout = outlet_new((t_object *)x, &s_float);
+ x->x_nvoicesout = outlet_new((t_object *)x, &s_float);
+ x->x_pitchout = outlet_new((t_object *)x, &s_float);
+ x->x_velout = outlet_new((t_object *)x, &s_float);
+ x->x_ndursout = outlet_new((t_object *)x, &s_float);
+ x->x_durout = outlet_new((t_object *)x, &s_float);
+ x->x_ndtimesout = outlet_new((t_object *)x, &s_float);
+ x->x_dtimeout = outlet_new((t_object *)x, &s_float);
+ Borax_reset(x);
+ return (x);
+}
+
+void Borax_setup(void)
+{
+ Borax_class = class_new(gensym("Borax"),
+ (t_newmethod)Borax_new, 0,
+ sizeof(t_Borax), 0, 0);
+ class_addfloat(Borax_class, Borax_float);
+ /* CHECKME list unfolding */
+ class_addmethod(Borax_class, (t_method)Borax_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(Borax_class, (t_method)Borax_bang2,
+ gensym("bang2"), 0);
+ class_addmethod(Borax_class, (t_method)Borax_delta,
+ gensym("delta"), 0);
+}
diff --git a/cyclone/hammer/Bucket.c b/cyclone/hammer/Bucket.c
new file mode 100644
index 0000000..036f836
--- /dev/null
+++ b/cyclone/hammer/Bucket.c
@@ -0,0 +1,137 @@
+/* Copyright (c) 2002-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 a modified version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+
+typedef struct _Bucket
+{
+ t_object x_ob;
+ int x_numbucks;
+ t_float *x_bucks; /* CHECKED: no limit */
+ t_outlet **x_outs;
+ short int x_frozen; /* 0 for thawed, 1 for frozen */
+ short int x_dir; /* 0 for L2R, 1 for R2L */
+} t_Bucket;
+
+static t_class *Bucket_class;
+
+static void Bucket_bang(t_Bucket *x)
+{
+ int i = x->x_numbucks;
+ /* CHECKED: outlets output in right-to-left order */
+ while (i--) outlet_float(x->x_outs[i], x->x_bucks[i]);
+}
+
+static void Bucket_float(t_Bucket *x, t_float val)
+{
+ int i;
+
+ if (!x->x_frozen)
+ Bucket_bang(x);
+ if (!x->x_dir)
+ {
+ for (i = x->x_numbucks - 1; i > 0; i--)
+ x->x_bucks[i] = x->x_bucks[i - 1];
+ x->x_bucks[0] = val;
+ }
+ else
+ {
+ for (i = 0; i < x->x_numbucks - 1; i++)
+ x->x_bucks[i] = x->x_bucks[i + 1];
+ x->x_bucks[x->x_numbucks - 1] = val;
+ }
+}
+
+static void Bucket_freeze(t_Bucket *x)
+{
+ x->x_frozen = 1;
+}
+
+static void Bucket_thaw(t_Bucket *x)
+{
+ x->x_frozen = 0;
+}
+
+static void Bucket_roll(t_Bucket *x)
+{
+ if (x->x_dir)
+ Bucket_float(x, x->x_bucks[0]);
+ else
+ Bucket_float(x, x->x_bucks[x->x_numbucks - 1]);
+}
+
+static void Bucket_rtol(t_Bucket *x)
+{
+ x->x_dir = 1;
+}
+
+static void Bucket_ltor(t_Bucket *x)
+{
+ x->x_dir = 0;
+}
+
+static void Bucket_set(t_Bucket *x, t_floatarg f)
+{
+ int i = x->x_numbucks;
+ while (i--) x->x_bucks[i] = f;
+ if (!x->x_frozen) /* CHECKED */
+ Bucket_bang(x);
+}
+
+static void Bucket_free(t_Bucket *x)
+{
+ if (x->x_bucks)
+ freebytes(x->x_bucks, x->x_numbucks * sizeof(*x->x_bucks));
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_numbucks * sizeof(*x->x_outs));
+}
+
+static void *Bucket_new(t_floatarg val)
+{
+ t_Bucket *x;
+ int i, nbucks = (int)val;
+ t_float *bucks;
+ t_outlet **outs;
+ if (nbucks < 1)
+ nbucks = 1;
+ if (!(bucks = (t_float *)getbytes(nbucks * sizeof(*bucks))))
+ return (0);
+ if (!(outs = (t_outlet **)getbytes(nbucks * sizeof(*outs))))
+ {
+ freebytes(bucks, nbucks * sizeof(*bucks));
+ return (0);
+ }
+ x = (t_Bucket *)pd_new(Bucket_class);
+ x->x_numbucks = nbucks;
+ x->x_bucks = bucks;
+ x->x_outs = outs;
+ x->x_frozen = 0;
+ x->x_dir = 0;
+ while (nbucks--) *outs++ = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void Bucket_setup(void)
+{
+ Bucket_class = class_new(gensym("Bucket"),
+ (t_newmethod)Bucket_new,
+ (t_method)Bucket_free,
+ sizeof(t_Bucket), 0, A_DEFFLOAT, 0);
+ class_addbang(Bucket_class, Bucket_bang);
+ class_addfloat(Bucket_class, Bucket_float);
+ class_addmethod(Bucket_class, (t_method)Bucket_freeze, gensym("freeze"), 0);
+ class_addmethod(Bucket_class, (t_method)Bucket_thaw, gensym("thaw"), 0);
+ class_addmethod(Bucket_class, (t_method)Bucket_ltor, gensym("L2R"), 0);
+ class_addmethod(Bucket_class, (t_method)Bucket_rtol, gensym("R2L"), 0);
+ /* CHECKED (refman error) roll has no argument */
+ class_addmethod(Bucket_class, (t_method)Bucket_roll, gensym("roll"), 0);
+ /* 3.5 additions */
+ class_addmethod(Bucket_class, (t_method)Bucket_set,
+ gensym("set"), A_FLOAT, 0);
+ class_addmethod(Bucket_class, (t_method)Bucket_ltor, gensym("l2r"), 0);
+ class_addmethod(Bucket_class, (t_method)Bucket_rtol, gensym("r2l"), 0);
+}
diff --git a/cyclone/hammer/Clip.c b/cyclone/hammer/Clip.c
new file mode 100644
index 0000000..a06d3a8
--- /dev/null
+++ b/cyclone/hammer/Clip.c
@@ -0,0 +1,149 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define CLIP_INISIZE 32 /* LATER rethink */
+#define CLIP_MAXSIZE 256
+
+typedef struct _clip
+{
+ t_object x_ob;
+ float x_f1;
+ float x_f2;
+ int x_size; /* as allocated */
+ t_atom *x_message;
+ t_atom x_messini[CLIP_INISIZE];
+ int x_entered;
+} t_clip;
+
+static t_class *clip_class;
+
+/* CHECKED case of f1 > f2: x <= f2 => f1, x > f2 => f2
+ (Pd implementation of clip has it the other way around) */
+static void clip_float(t_clip *x, t_float f)
+{
+ outlet_float(((t_object *)x)->ob_outlet,
+ (f > x->x_f2 ? x->x_f2 : (f < x->x_f1 ? x->x_f1 : f)));
+}
+
+static void clip_list(t_clip *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ int docopy = 0;
+ int i;
+ t_atom *ap;
+ t_float f1 = x->x_f1;
+ t_float f2 = x->x_f2;
+ for (i = 0, ap = av; i < ac; i++, ap++)
+ {
+ t_float f;
+ if (ap->a_type == A_FLOAT)
+ f = ap->a_w.w_float;
+ else
+ {
+ docopy = 1;
+ /* CHECKED: symbols inside lists are converted to zeros */
+ f = 0;
+ }
+ if (f < f1 || f > f2) docopy = 1;
+ }
+ if (docopy)
+ {
+ t_atom *buf;
+ t_atom *bp;
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ x->x_entered = 1;
+ if (prealloc && ac > x->x_size)
+ {
+ if (ac > CLIP_MAXSIZE)
+ prealloc = 0;
+ else
+ x->x_message = grow_nodata(&ac, &x->x_size, x->x_message,
+ CLIP_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ }
+ if (prealloc) buf = x->x_message;
+ else
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ buf = getbytes(ac * sizeof(*buf));
+ if (buf)
+ {
+ for (i = 0, ap = av, bp = buf; i < ac; i++, ap++, bp++)
+ {
+ t_float f = (ap->a_type == A_FLOAT ? ap->a_w.w_float : 0);
+ if (f < f1)
+ f = f1;
+ else if (f > f2)
+ f = f2;
+ SETFLOAT(bp, f);
+ }
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, buf);
+ if (buf != x->x_message)
+ freebytes(buf, ac * sizeof(*buf));
+ }
+ if (!reentered)
+ {
+ x->x_entered = 0;
+ }
+ }
+ else outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ }
+}
+
+static void clip_set(t_clip *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_f1 = 0;
+ x->x_f2 = 0;
+ if (ac) /* CHECKED: 'set' without arguments sets both values to 0 */
+ {
+ if (av->a_type == A_FLOAT) /* CHECKED: symbol is converted to 0 */
+ x->x_f1 = av->a_w.w_float;
+ av++;
+ if (--ac)
+ {
+ if (av->a_type == A_FLOAT)
+ x->x_f2 = av->a_w.w_float;
+ }
+ else x->x_f2 = x->x_f1; /* CHECKED */
+ }
+}
+
+static void clip_free(t_clip *x)
+{
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+}
+
+static void *clip_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_clip *x = (t_clip *)pd_new(clip_class);
+ x->x_f1 = 0;
+ x->x_f2 = 0;
+ x->x_size = CLIP_INISIZE;
+ x->x_message = x->x_messini;
+ x->x_entered = 0;
+ floatinlet_new((t_object *)x, &x->x_f1);
+ floatinlet_new((t_object *)x, &x->x_f2);
+ outlet_new(&x->x_ob, &s_anything);
+ clip_set(x, 0, ac, av);
+ return (x);
+}
+
+void Clip_setup(void)
+{
+ clip_class = class_new(gensym("Clip"),
+ (t_newmethod)clip_new,
+ (t_method)clip_free,
+ sizeof(t_clip), 0,
+ A_GIMME, 0);
+ class_addfloat(clip_class, clip_float);
+ class_addlist(clip_class, clip_list);
+ class_addmethod(clip_class, (t_method)clip_set,
+ gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/Decode.c b/cyclone/hammer/Decode.c
new file mode 100644
index 0000000..8317d7e
--- /dev/null
+++ b/cyclone/hammer/Decode.c
@@ -0,0 +1,110 @@
+/* Copyright (c) 2002-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 an entirely rewritten version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define DECODE_MAXOUTS 8 /* CHECKED (does it make any sense?) */
+#define DECODE_DEFOUTS 1
+
+typedef struct _Decode
+{
+ t_object x_ob;
+ int x_numouts;
+ int x_onout;
+ int x_allon; /* submaster switch */
+ int x_alloff; /* master switch */
+ t_outlet **x_outs;
+ t_outlet *x_outbuf[DECODE_MAXOUTS];
+} t_Decode;
+
+static t_class *Decode_class;
+
+/* CHECKED: all outlets deliver after any action */
+/* CHECKED: outlets output in right-to-left order */
+
+static void Decode_deliver(t_Decode *x)
+{
+ int i = x->x_numouts;
+ if (x->x_alloff)
+ while (i--) outlet_float(x->x_outs[i], 0);
+ else if (x->x_allon)
+ while (i--) outlet_float(x->x_outs[i], 1);
+ else
+ while (i--) outlet_float(x->x_outs[i], (i == x->x_onout ? 1 : 0));
+}
+
+static void Decode_float(t_Decode *x, t_floatarg f)
+{
+ int val = (int)f;
+ /* CHECKED: out-of-range input is clipped, not ignored */
+ if (val < 0)
+ val = 0;
+ else if (val >= x->x_numouts)
+ val = x->x_numouts - 1;
+ /* CHECKED: while in all-off mode, input is stored, not ignored */
+ x->x_onout = val;
+ Decode_deliver(x);
+}
+
+static void Decode_allon(t_Decode *x, t_floatarg f)
+{
+ x->x_allon = (f != 0);
+ Decode_deliver(x);
+}
+
+static void Decode_alloff(t_Decode *x, t_floatarg f)
+{
+ x->x_alloff = (f != 0);
+ Decode_deliver(x);
+}
+
+static void Decode_free(t_Decode *x)
+{
+ if (x->x_outs != x->x_outbuf)
+ freebytes(x->x_outs, x->x_numouts * sizeof(*x->x_outs));
+}
+
+static void *Decode_new(t_floatarg val)
+{
+ t_Decode *x;
+ int i, nouts = (int)val;
+ t_outlet **outs;
+ if (nouts < 1)
+ nouts = DECODE_DEFOUTS;
+ if (nouts > DECODE_MAXOUTS)
+ {
+ loud_incompatible_max(Decode_class, DECODE_MAXOUTS, "outlets");
+ if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
+ return (0);
+ }
+ else outs = 0;
+ x = (t_Decode *)pd_new(Decode_class);
+ x->x_numouts = nouts;
+ x->x_outs = (outs ? outs : x->x_outbuf);
+ x->x_onout = 0;
+ x->x_allon = 0;
+ x->x_alloff = 0;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2"));
+ for (i = 0; i < nouts; i++)
+ x->x_outs[i] = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void Decode_setup(void)
+{
+ Decode_class = class_new(gensym("Decode"),
+ (t_newmethod)Decode_new,
+ (t_method)Decode_free,
+ sizeof(t_Decode), 0, A_DEFFLOAT, 0);
+ class_addfloat(Decode_class, Decode_float);
+ class_addmethod(Decode_class, (t_method)Decode_allon,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(Decode_class, (t_method)Decode_alloff,
+ gensym("ft2"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/Histo.c b/cyclone/hammer/Histo.c
new file mode 100644
index 0000000..efb0deb
--- /dev/null
+++ b/cyclone/hammer/Histo.c
@@ -0,0 +1,103 @@
+/* Copyright (c) 2002-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 an entirely rewritten version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define HISTO_DEFSIZE 128
+
+typedef struct _Histo
+{
+ t_object x_ob;
+ int x_size;
+ unsigned *x_hist; /* LATER consider using 64 bits */
+ int x_lastinput;
+ t_outlet *x_countout;
+} t_Histo;
+
+static t_class *Histo_class;
+
+static void Histo_clear(t_Histo *x)
+{
+ int i = x->x_size;
+ while (i--) x->x_hist[i] = 0;
+ /* CHECKED: last input is kept */
+}
+
+static void Histo_doit(t_Histo *x, int val, int doincr)
+{
+ if (val >= 0 && val < x->x_size)
+ {
+ if (doincr)
+ {
+ /* CHECKED: only in-range numbers are stored */
+ x->x_lastinput = val;
+ x->x_hist[val]++;
+ }
+ outlet_float(x->x_countout, x->x_hist[val]);
+ /* CHECKED: out-of-range numbers are never passed thru */
+ outlet_float(((t_object *)x)->ob_outlet, val);
+ }
+}
+
+static void Histo_bang(t_Histo *x)
+{
+ Histo_doit(x, x->x_lastinput, 0);
+}
+
+static void Histo_float(t_Histo *x, t_floatarg f)
+{
+ int i;
+ if (loud_checkint((t_pd *)x, f, &i, &s_float)) /* CHECKED */
+ Histo_doit(x, i, 1);
+}
+
+static void Histo_ft1(t_Histo *x, t_floatarg f)
+{
+ /* CHECKED: floats are accepted in second inlet (truncated) */
+ Histo_doit(x, (int)f, 0);
+}
+
+static void Histo_free(t_Histo *x)
+{
+ if (x->x_hist)
+ freebytes(x->x_hist, x->x_size * sizeof(*x->x_hist));
+}
+
+static void *Histo_new(t_floatarg f)
+{
+ t_Histo *x;
+ int size = (int)f;
+ unsigned *hist;
+ if (size < 1) /* CHECKED: 1 is allowed */
+ size = HISTO_DEFSIZE;
+ if (!(hist = (unsigned *)getbytes(size * sizeof(*hist))))
+ return (0);
+ x = (t_Histo *)pd_new(Histo_class);
+ x->x_size = size;
+ x->x_hist = hist;
+ x->x_lastinput = 0;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_countout = outlet_new((t_object *)x, &s_float);
+ Histo_clear(x);
+ return (x);
+}
+
+void Histo_setup(void)
+{
+ Histo_class = class_new(gensym("Histo"),
+ (t_newmethod)Histo_new,
+ (t_method)Histo_free,
+ sizeof(t_Histo), 0, A_DEFFLOAT, 0);
+ class_addbang(Histo_class, Histo_bang);
+ class_addfloat(Histo_class, Histo_float);
+ class_addmethod(Histo_class, (t_method)Histo_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(Histo_class, (t_method)Histo_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/Makefile b/cyclone/hammer/Makefile
new file mode 100644
index 0000000..54383c3
--- /dev/null
+++ b/cyclone/hammer/Makefile
@@ -0,0 +1,3 @@
+ROOT_DIR = ../..
+redefault: allhammers.c default
+include $(ROOT_DIR)/Makefile.common
diff --git a/cyclone/hammer/Makefile.objects b/cyclone/hammer/Makefile.objects
new file mode 100644
index 0000000..0ac0a87
--- /dev/null
+++ b/cyclone/hammer/Makefile.objects
@@ -0,0 +1,14 @@
+SHARED_OBJECTS = \
+unstable/fragile.o \
+common/loud.o \
+common/grow.o \
+common/rand.o \
+common/vefl.o \
+common/sq.o \
+common/bifi.o \
+common/mifi.o \
+common/binport.o \
+common/port.o \
+hammer/file.o \
+hammer/gui.o \
+hammer/tree.o
diff --git a/cyclone/hammer/Makefile.sources b/cyclone/hammer/Makefile.sources
new file mode 100644
index 0000000..5df97f5
--- /dev/null
+++ b/cyclone/hammer/Makefile.sources
@@ -0,0 +1,80 @@
+CX_SOURCES = \
+hammer.c
+
+OTHER_SOURCES = \
+allhammers.c \
+testmess.c \
+accum.c \
+acos.c \
+active.c \
+anal.c \
+Append.c \
+asin.c \
+bangbang.c \
+bondo.c \
+Borax.c \
+Bucket.c \
+buddy.c \
+capture.c \
+cartopol.c \
+Clip.c \
+coll.c \
+comment.c \
+cosh.c \
+counter.c \
+cycle.c \
+decide.c \
+Decode.c \
+drunk.c \
+flush.c \
+forward.c \
+fromsymbol.c \
+funbuff.c \
+funnel.c \
+gate.c \
+grab.c \
+Histo.c \
+iter.c \
+match.c \
+maximum.c \
+mean.c \
+midiflush.c \
+midiformat.c \
+midiparse.c \
+minimum.c \
+mousefilter.c \
+MouseState.c \
+next.c \
+offer.c \
+onebang.c \
+past.c \
+Peak.c \
+poltocar.c \
+prepend.c \
+prob.c \
+pv.c \
+seq.c \
+sinh.c \
+speedlim.c \
+spell.c \
+split.c \
+spray.c \
+sprintf.c \
+substitute.c \
+sustain.c \
+switch.c \
+tanh.c \
+thresh.c \
+TogEdge.c \
+tosymbol.c \
+Trough.c \
+universal.c \
+urn.c \
+Uzi.c \
+xbendin.c \
+xbendin2.c \
+xbendout.c \
+xbendout2.c \
+xnotein.c \
+xnoteout.c \
+zl.c
diff --git a/cyclone/hammer/MouseState.c b/cyclone/hammer/MouseState.c
new file mode 100644
index 0000000..3b831bf
--- /dev/null
+++ b/cyclone/hammer/MouseState.c
@@ -0,0 +1,153 @@
+/* Copyright (c) 2002-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 "hammer/gui.h"
+
+typedef struct _MouseState
+{
+ t_object x_ob;
+ int x_ispolling;
+ int x_wasbanged;
+ int x_waszeroed;
+ int x_hlast;
+ int x_vlast;
+ int x_hzero;
+ int x_vzero;
+ t_outlet *x_hposout;
+ t_outlet *x_vposout;
+ t_outlet *x_hdiffout;
+ t_outlet *x_vdiffout;
+} t_MouseState;
+
+static t_class *MouseState_class;
+
+static void MouseState_anything(t_MouseState *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ /* dummy method, filtering out those messages from gui,
+ which are not handled explicitly */
+}
+
+static void MouseState_doup(t_MouseState *x, t_floatarg f)
+{
+ outlet_float(((t_object *)x)->ob_outlet, ((int)f ? 0 : 1));
+}
+
+static void MouseState_dobang(t_MouseState *x, t_floatarg f1, t_floatarg f2)
+{
+ if (x->x_wasbanged)
+ {
+ int h = (int)f1, v = (int)f2;
+ outlet_float(x->x_vdiffout, v - x->x_vlast);
+ outlet_float(x->x_hdiffout, h - x->x_hlast);
+ outlet_float(x->x_vposout, v - x->x_vzero);
+ outlet_float(x->x_hposout, h - x->x_hzero);
+ x->x_hlast = h;
+ x->x_vlast = v;
+ x->x_wasbanged = 0;
+ }
+}
+
+static void MouseState_dozero(t_MouseState *x, t_floatarg f1, t_floatarg f2)
+{
+ if (x->x_waszeroed)
+ {
+ int h = (int)f1, v = (int)f2;
+ x->x_hzero = h;
+ x->x_vzero = v;
+ x->x_waszeroed = 0;
+ }
+}
+
+static void MouseState_dopoll(t_MouseState *x, t_floatarg f1, t_floatarg f2)
+{
+ if (x->x_ispolling)
+ {
+ x->x_wasbanged = 1;
+ MouseState_dobang(x, f1, f2);
+ }
+}
+
+static void MouseState_bang(t_MouseState *x)
+{
+ hammergui_mousexy(gensym("_bang"));
+ x->x_wasbanged = 1;
+}
+
+static void MouseState_poll(t_MouseState *x)
+{
+ if (!x->x_ispolling)
+ {
+ x->x_ispolling = 1;
+ hammergui_startpolling((t_pd *)x);
+ }
+}
+
+static void MouseState_nopoll(t_MouseState *x)
+{
+ if (x->x_ispolling)
+ {
+ x->x_ispolling = 0;
+ hammergui_stoppolling((t_pd *)x);
+ }
+}
+
+static void MouseState_zero(t_MouseState *x)
+{
+ hammergui_mousexy(gensym("_zero"));
+ x->x_waszeroed = 1;
+}
+
+static void MouseState_reset(t_MouseState *x)
+{
+ x->x_hzero = x->x_vzero = 0;
+}
+
+static void MouseState_free(t_MouseState *x)
+{
+ MouseState_nopoll(x);
+ hammergui_unbindmouse((t_pd *)x);
+}
+
+static void *MouseState_new(void)
+{
+ t_MouseState *x = (t_MouseState *)pd_new(MouseState_class);
+ x->x_ispolling = x->x_wasbanged = x->x_waszeroed = 0;
+ outlet_new((t_object *)x, &s_float);
+ x->x_hposout = outlet_new((t_object *)x, &s_float);
+ x->x_vposout = outlet_new((t_object *)x, &s_float);
+ x->x_hdiffout = outlet_new((t_object *)x, &s_float);
+ x->x_vdiffout = outlet_new((t_object *)x, &s_float);
+ hammergui_bindmouse((t_pd *)x);
+ hammergui_willpoll();
+ MouseState_reset(x);
+ return (x);
+}
+
+void MouseState_setup(void)
+{
+ MouseState_class = class_new(gensym("MouseState"),
+ (t_newmethod)MouseState_new,
+ (t_method)MouseState_free,
+ sizeof(t_MouseState), 0, 0);
+ class_addanything(MouseState_class, MouseState_anything);
+ class_addmethod(MouseState_class, (t_method)MouseState_doup,
+ gensym("_up"), A_FLOAT, 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_dobang,
+ gensym("_bang"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_dozero,
+ gensym("_zero"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_dopoll,
+ gensym("_poll"), A_FLOAT, A_FLOAT, 0);
+ class_addbang(MouseState_class, MouseState_bang);
+ class_addmethod(MouseState_class, (t_method)MouseState_poll,
+ gensym("poll"), 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_nopoll,
+ gensym("nopoll"), 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_zero,
+ gensym("zero"), 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_reset,
+ gensym("reset"), 0);
+}
diff --git a/cyclone/hammer/Peak.c b/cyclone/hammer/Peak.c
new file mode 100644
index 0000000..6f7e30c
--- /dev/null
+++ b/cyclone/hammer/Peak.c
@@ -0,0 +1,63 @@
+/* Copyright (c) 2002-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"
+
+#define PEAK_INITIAL 0
+
+typedef struct _Peak
+{
+ t_object x_ob;
+ t_float x_value;
+ t_outlet *x_out2;
+ t_outlet *x_out3;
+} t_Peak;
+
+static t_class *Peak_class;
+
+static void Peak_bang(t_Peak *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void Peak_ft1(t_Peak *x, t_floatarg f)
+{
+ /* CHECKME loud_checkint */
+ outlet_float(x->x_out3, 0); /* CHECKME */
+ outlet_float(x->x_out2, 1);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = f);
+}
+
+static void Peak_float(t_Peak *x, t_float f)
+{
+ /* CHECKME loud_checkint */
+ if (f > x->x_value) Peak_ft1(x, f);
+ else
+ {
+ outlet_float(x->x_out3, 1);
+ outlet_float(x->x_out2, 0);
+ }
+}
+
+static void *Peak_new(t_floatarg f)
+{
+ t_Peak *x = (t_Peak *)pd_new(Peak_class);
+ x->x_value = PEAK_INITIAL;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_float);
+ x->x_out3 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void Peak_setup(void)
+{
+ Peak_class = class_new(gensym("Peak"),
+ (t_newmethod)Peak_new, 0,
+ sizeof(t_Peak), 0, 0);
+ class_addbang(Peak_class, Peak_bang);
+ class_addfloat(Peak_class, Peak_float);
+ class_addmethod(Peak_class, (t_method)Peak_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/TogEdge.c b/cyclone/hammer/TogEdge.c
new file mode 100644
index 0000000..79c26ec
--- /dev/null
+++ b/cyclone/hammer/TogEdge.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2002-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 "common/loud.h"
+
+typedef struct _TogEdge
+{
+ t_object x_ob;
+ int x_wason;
+ t_outlet *x_out1;
+} t_TogEdge;
+
+static t_class *TogEdge_class;
+
+static void TogEdge_bang(t_TogEdge *x)
+{
+ if (x->x_wason)
+ {
+ x->x_wason = 0;
+ outlet_bang(x->x_out1);
+ }
+ else
+ {
+ x->x_wason = 1;
+ outlet_bang(((t_object *)x)->ob_outlet);
+ }
+}
+
+static void TogEdge_float(t_TogEdge *x, t_float f)
+{
+ int i;
+ if (loud_checkint((t_pd *)x, f, &i, &s_float)) /* CHECKED */
+ {
+ if (x->x_wason)
+ {
+ if (!i)
+ {
+ x->x_wason = 0;
+ outlet_bang(x->x_out1);
+ }
+ }
+ else
+ {
+ if (i)
+ {
+ x->x_wason = 1;
+ outlet_bang(((t_object *)x)->ob_outlet);
+ }
+ }
+ }
+}
+
+static void *TogEdge_new(void)
+{
+ t_TogEdge *x = (t_TogEdge *)pd_new(TogEdge_class);
+ x->x_wason = 0; /* CHECKED */
+ outlet_new((t_object *)x, &s_bang);
+ x->x_out1 = outlet_new((t_object *)x, &s_bang);
+ return (x);
+}
+
+void TogEdge_setup(void)
+{
+ TogEdge_class = class_new(gensym("TogEdge"),
+ (t_newmethod)TogEdge_new, 0,
+ sizeof(t_TogEdge), 0, 0);
+ class_addbang(TogEdge_class, TogEdge_bang);
+ class_addfloat(TogEdge_class, TogEdge_float);
+}
diff --git a/cyclone/hammer/Trough.c b/cyclone/hammer/Trough.c
new file mode 100644
index 0000000..27b19ba
--- /dev/null
+++ b/cyclone/hammer/Trough.c
@@ -0,0 +1,63 @@
+/* Copyright (c) 2002-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"
+
+#define TROUGH_INITIAL 128 /* CHECKME */
+
+typedef struct _Trough
+{
+ t_object x_ob;
+ t_float x_value;
+ t_outlet *x_out2;
+ t_outlet *x_out3;
+} t_Trough;
+
+static t_class *Trough_class;
+
+static void Trough_bang(t_Trough *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void Trough_ft1(t_Trough *x, t_floatarg f)
+{
+ /* CHECKME loud_checkint */
+ outlet_float(x->x_out3, 0); /* CHECKME */
+ outlet_float(x->x_out2, 1);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = f);
+}
+
+static void Trough_float(t_Trough *x, t_float f)
+{
+ /* CHECKME loud_checkint */
+ if (f < x->x_value) Trough_ft1(x, f);
+ else
+ {
+ outlet_float(x->x_out3, 1);
+ outlet_float(x->x_out2, 0);
+ }
+}
+
+static void *Trough_new(t_floatarg f)
+{
+ t_Trough *x = (t_Trough *)pd_new(Trough_class);
+ x->x_value = TROUGH_INITIAL;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_float);
+ x->x_out3 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void Trough_setup(void)
+{
+ Trough_class = class_new(gensym("Trough"),
+ (t_newmethod)Trough_new, 0,
+ sizeof(t_Trough), 0, 0);
+ class_addbang(Trough_class, Trough_bang);
+ class_addfloat(Trough_class, Trough_float);
+ class_addmethod(Trough_class, (t_method)Trough_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/Uzi.c b/cyclone/hammer/Uzi.c
new file mode 100644
index 0000000..c773c6b
--- /dev/null
+++ b/cyclone/hammer/Uzi.c
@@ -0,0 +1,108 @@
+/* Copyright (c) 2002-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. */
+
+/* CHECKME negative 'nbangs' value set during run-time */
+
+#include "m_pd.h"
+
+typedef struct _Uzi
+{
+ t_object x_obj;
+ t_float x_nbangs;
+ int x_count;
+ int x_running;
+ t_outlet *x_out2;
+ t_outlet *x_out3;
+} t_Uzi;
+
+static t_class *Uzi_class;
+
+#define UZI_RUNNING 1
+#define UZI_PAUSED 2
+
+static void Uzi_dobang(t_Uzi *x)
+{
+ /* CHECKME reentrancy */
+ if (!x->x_running)
+ {
+ int count, nbangs = (int)x->x_nbangs;
+ x->x_running = UZI_RUNNING;
+ for (count = x->x_count + 1; count <= nbangs; count++)
+ {
+ outlet_float(x->x_out3, count);
+ outlet_bang(((t_object *)x)->ob_outlet);
+ if (x->x_running == UZI_PAUSED)
+ {
+ /* CHECKED: carry bang not sent, even if this is last bang */
+ x->x_count = count;
+ return;
+ }
+ }
+ /* CHECKED: carry bang sent also when there are no left-outlet bangs */
+ /* CHECKED: sent after left outlet, not before */
+ outlet_bang(x->x_out2);
+ x->x_count = 0;
+ x->x_running = 0;
+ }
+}
+
+static void Uzi_bang(t_Uzi *x)
+{
+ /* CHECKED: always restarts (when paused too) */
+ x->x_count = 0;
+ x->x_running = 0;
+ Uzi_dobang(x);
+}
+
+static void Uzi_float(t_Uzi *x, t_float f)
+{
+ /* CHECKED: always sets a new value and restarts (when paused too) */
+ x->x_nbangs = f;
+ Uzi_bang(x);
+}
+
+/* CHECKED: 'pause, resume' (but not just 'resume')
+ sends a carry bang when not running (a bug?) */
+static void Uzi_pause(t_Uzi *x)
+{
+ if (!x->x_running)
+ x->x_count = (int)x->x_nbangs; /* bug emulation? */
+ x->x_running = UZI_PAUSED;
+}
+
+static void Uzi_resume(t_Uzi *x)
+{
+ if (x->x_running == UZI_PAUSED)
+ {
+ x->x_running = 0;
+ Uzi_dobang(x);
+ }
+}
+
+static void *Uzi_new(t_floatarg f)
+{
+ t_Uzi *x = (t_Uzi *)pd_new(Uzi_class);
+ x->x_nbangs = (f > 1. ? f : 1.);
+ x->x_count = 0;
+ x->x_running = 0;
+ /* CHECKED: set when paused, but then 'resume' is blocked (a bug?) */
+ floatinlet_new((t_object *)x, &x->x_nbangs);
+ outlet_new((t_object *)x, &s_bang);
+ x->x_out2 = outlet_new((t_object *)x, &s_bang);
+ x->x_out3 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void Uzi_setup(void)
+{
+ Uzi_class = class_new(gensym("Uzi"),
+ (t_newmethod)Uzi_new, 0,
+ sizeof(t_Uzi), 0, A_DEFFLOAT, 0);
+ class_addbang(Uzi_class, Uzi_bang);
+ class_addfloat(Uzi_class, Uzi_float);
+ class_addmethod(Uzi_class, (t_method)Uzi_pause, gensym("pause"), 0);
+ class_addmethod(Uzi_class, (t_method)Uzi_pause, gensym("break"), 0);
+ class_addmethod(Uzi_class, (t_method)Uzi_resume, gensym("resume"), 0);
+ class_addmethod(Uzi_class, (t_method)Uzi_resume, gensym("continue"), 0);
+}
diff --git a/cyclone/hammer/accum.c b/cyclone/hammer/accum.c
new file mode 100644
index 0000000..d266fb3
--- /dev/null
+++ b/cyclone/hammer/accum.c
@@ -0,0 +1,68 @@
+/* Copyright (c) 2002-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 a slightly edited version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+
+typedef struct _accum
+{
+ t_object x_ob;
+ t_float x_total;
+} t_accum;
+
+static t_class *accum_class;
+
+static void accum_set(t_accum *x, t_floatarg val)
+{
+ x->x_total = val;
+}
+
+static void accum_bang(t_accum *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_total);
+}
+
+static void accum_float(t_accum *x, t_floatarg val)
+{
+ /* LATER reconsider int/float dilemma */
+ accum_set(x, val);
+ accum_bang(x);
+}
+
+static void accum_add(t_accum *x, t_floatarg val)
+{
+ /* LATER reconsider int/float dilemma */
+ x->x_total += val;
+}
+
+static void accum_mult(t_accum *x, t_floatarg val)
+{
+ x->x_total *= val;
+}
+
+static void *accum_new(t_floatarg val)
+{
+ t_accum *x = (t_accum *)pd_new(accum_class);
+ x->x_total = val;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2"));
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void accum_setup(void)
+{
+ accum_class = class_new(gensym("accum"), (t_newmethod)accum_new, 0,
+ sizeof(t_accum), 0, A_DEFFLOAT, 0);
+ class_addbang(accum_class, accum_bang);
+ class_addfloat(accum_class, accum_float);
+ class_addmethod(accum_class, (t_method)accum_add,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(accum_class, (t_method)accum_mult,
+ gensym("ft2"), A_FLOAT, 0);
+ class_addmethod(accum_class, (t_method)accum_set,
+ gensym("set"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/acos.c b/cyclone/hammer/acos.c
new file mode 100644
index 0000000..3f3abea
--- /dev/null
+++ b/cyclone/hammer/acos.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-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"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define acosf acos
+#endif
+
+typedef struct _acos
+{
+ t_object x_ob;
+ float x_value;
+} t_acos;
+
+static t_class *acos_class;
+
+static void acos_bang(t_acos *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void acos_float(t_acos *x, t_float f)
+{
+ if (f < -1.0) f = -1.0; else if (f > 1.0) f = 1.0; /* CHECKME */
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = acosf(f));
+}
+
+static void *acos_new(t_floatarg f)
+{
+ t_acos *x = (t_acos *)pd_new(acos_class);
+ if (f < -1.0) f = -1.0; else if (f > 1.0) f = 1.0; /* CHECKME */
+ x->x_value = acosf(f);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void acos_setup(void)
+{
+ acos_class = class_new(gensym("acos"),
+ (t_newmethod)acos_new, 0,
+ sizeof(t_acos), 0, A_DEFFLOAT, 0);
+ class_addbang(acos_class, acos_bang);
+ class_addfloat(acos_class, acos_float);
+}
diff --git a/cyclone/hammer/active.c b/cyclone/hammer/active.c
new file mode 100644
index 0000000..9d10f80
--- /dev/null
+++ b/cyclone/hammer/active.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2002-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 <stdio.h>
+#include "m_pd.h"
+#include "hammer/gui.h"
+
+typedef struct _active
+{
+ t_object x_ob;
+ t_symbol *x_cvname;
+ int x_on;
+} t_active;
+
+static t_class *active_class;
+
+static void active_dofocus(t_active *x, t_symbol *s, t_floatarg f)
+{
+ if ((int)f)
+ {
+ int on = (s == x->x_cvname);
+ if (on != x->x_on)
+ outlet_float(((t_object *)x)->ob_outlet, x->x_on = on);
+ }
+ else if (x->x_on && s == x->x_cvname)
+ outlet_float(((t_object *)x)->ob_outlet, x->x_on = 0);
+}
+
+static void active_free(t_active *x)
+{
+ hammergui_unbindfocus((t_pd *)x);
+}
+
+static void *active_new(void)
+{
+ t_active *x = (t_active *)pd_new(active_class);
+ char buf[32];
+ sprintf(buf, ".x%x.c", (int)canvas_getcurrent());
+ x->x_cvname = gensym(buf);
+ x->x_on = 0;
+ outlet_new((t_object *)x, &s_float);
+ hammergui_bindfocus((t_pd *)x);
+ return (x);
+}
+
+void active_setup(void)
+{
+ active_class = class_new(gensym("active"),
+ (t_newmethod)active_new,
+ (t_method)active_free,
+ sizeof(t_active), CLASS_NOINLET, 0);
+ class_addmethod(active_class, (t_method)active_dofocus,
+ gensym("_focus"), A_SYMBOL, A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/allhammers.c b/cyclone/hammer/allhammers.c
new file mode 100644
index 0000000..e6d8235
--- /dev/null
+++ b/cyclone/hammer/allhammers.c
@@ -0,0 +1,160 @@
+// Do not edit this file, run "make" instead.
+
+/* Copyright (c) 2002-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. */
+
+void accum_setup(void);
+void acos_setup(void);
+void active_setup(void);
+void anal_setup(void);
+void Append_setup(void);
+void asin_setup(void);
+void bangbang_setup(void);
+void bondo_setup(void);
+void Borax_setup(void);
+void Bucket_setup(void);
+void buddy_setup(void);
+void capture_setup(void);
+void cartopol_setup(void);
+void Clip_setup(void);
+void coll_setup(void);
+void comment_setup(void);
+void cosh_setup(void);
+void counter_setup(void);
+void cycle_setup(void);
+void decide_setup(void);
+void Decode_setup(void);
+void drunk_setup(void);
+void flush_setup(void);
+void forward_setup(void);
+void fromsymbol_setup(void);
+void funbuff_setup(void);
+void funnel_setup(void);
+void gate_setup(void);
+void grab_setup(void);
+void Histo_setup(void);
+void iter_setup(void);
+void match_setup(void);
+void maximum_setup(void);
+void mean_setup(void);
+void midiflush_setup(void);
+void midiformat_setup(void);
+void midiparse_setup(void);
+void minimum_setup(void);
+void mousefilter_setup(void);
+void MouseState_setup(void);
+void next_setup(void);
+void offer_setup(void);
+void onebang_setup(void);
+void past_setup(void);
+void Peak_setup(void);
+void poltocar_setup(void);
+void prepend_setup(void);
+void prob_setup(void);
+void pv_setup(void);
+void seq_setup(void);
+void sinh_setup(void);
+void speedlim_setup(void);
+void spell_setup(void);
+void split_setup(void);
+void spray_setup(void);
+void sprintf_setup(void);
+void substitute_setup(void);
+void sustain_setup(void);
+void switch_setup(void);
+void tanh_setup(void);
+void testmess_setup(void);
+void thresh_setup(void);
+void TogEdge_setup(void);
+void tosymbol_setup(void);
+void Trough_setup(void);
+void universal_setup(void);
+void urn_setup(void);
+void Uzi_setup(void);
+void xbendin2_setup(void);
+void xbendin_setup(void);
+void xbendout2_setup(void);
+void xbendout_setup(void);
+void xnotein_setup(void);
+void xnoteout_setup(void);
+void zl_setup(void);
+
+void allhammers_setup(void)
+{
+ accum_setup();
+ acos_setup();
+ active_setup();
+ anal_setup();
+ Append_setup();
+ asin_setup();
+ bangbang_setup();
+ bondo_setup();
+ Borax_setup();
+ Bucket_setup();
+ buddy_setup();
+ capture_setup();
+ cartopol_setup();
+ Clip_setup();
+ coll_setup();
+ comment_setup();
+ cosh_setup();
+ counter_setup();
+ cycle_setup();
+ decide_setup();
+ Decode_setup();
+ drunk_setup();
+ flush_setup();
+ forward_setup();
+ fromsymbol_setup();
+ funbuff_setup();
+ funnel_setup();
+ gate_setup();
+ grab_setup();
+ Histo_setup();
+ iter_setup();
+ match_setup();
+ maximum_setup();
+ mean_setup();
+ midiflush_setup();
+ midiformat_setup();
+ midiparse_setup();
+ minimum_setup();
+ mousefilter_setup();
+ MouseState_setup();
+ next_setup();
+ offer_setup();
+ onebang_setup();
+ past_setup();
+ Peak_setup();
+ poltocar_setup();
+ prepend_setup();
+ prob_setup();
+ pv_setup();
+ seq_setup();
+ sinh_setup();
+ speedlim_setup();
+ spell_setup();
+ split_setup();
+ spray_setup();
+ sprintf_setup();
+ substitute_setup();
+ sustain_setup();
+ switch_setup();
+ tanh_setup();
+ testmess_setup();
+ thresh_setup();
+ TogEdge_setup();
+ tosymbol_setup();
+ Trough_setup();
+ universal_setup();
+ urn_setup();
+ Uzi_setup();
+ xbendin2_setup();
+ xbendin_setup();
+ xbendout2_setup();
+ xbendout_setup();
+ xnotein_setup();
+ xnoteout_setup();
+ zl_setup();
+}
diff --git a/cyclone/hammer/anal.c b/cyclone/hammer/anal.c
new file mode 100644
index 0000000..477eb20
--- /dev/null
+++ b/cyclone/hammer/anal.c
@@ -0,0 +1,108 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define ANAL_DEFSIZE 128
+#define ANAL_MAXSIZE 1024
+
+typedef struct _anal
+{
+ t_object x_ob;
+ int x_value; /* negative, if initialized or reset */
+ int x_size;
+ int x_bytesize;
+ int *x_table;
+ /* CHECKED: the 'weight' count is a signed short (2 bytes),
+ wrapping into negative domain without any warning.
+ LATER consider complaining at == SHRT_MAX. */
+} t_anal;
+
+static t_class *anal_class;
+
+static void anal_reset(t_anal *x)
+{
+ x->x_value = -1;
+}
+
+static void anal_clear(t_anal *x)
+{
+ memset(x->x_table, 0, x->x_bytesize);
+}
+
+static void anal_float(t_anal *x, t_float f)
+{
+ int value;
+ if (loud_checkint((t_pd *)x, f, &value, &s_float)) /* CHECKED */
+ {
+ /* CHECKED: any input negative or >= size is ignored with an error
+ -- there is no output, and a previous state is kept. */
+ if (value >= 0 && value < x->x_size)
+ {
+ if (x->x_value >= 0)
+ {
+ t_atom at[3];
+ int ndx = x->x_value * x->x_size + value;
+ x->x_table[ndx]++;
+ SETFLOAT(at, x->x_value);
+ SETFLOAT(&at[1], value);
+ SETFLOAT(&at[2], x->x_table[ndx]);
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, 3, at);
+ }
+ x->x_value = value;
+ }
+ else loud_error((t_pd *)x, "%d outside of table bounds", value);
+ }
+}
+
+static void anal_free(t_anal *x)
+{
+ if (x->x_table)
+ freebytes(x->x_table, x->x_bytesize);
+}
+
+static void *anal_new(t_floatarg f)
+{
+ t_anal *x;
+ int size = (int)f;
+ int bytesize;
+ int *table;
+ if (size < 1)
+ /* CHECKED: 1 is allowed (such an object rejects any nonzero input) */
+ size = ANAL_DEFSIZE;
+ else if (size > ANAL_MAXSIZE)
+ {
+ /* CHECKED: */
+ loud_warning(&anal_class, "size too large, using %d", ANAL_MAXSIZE);
+ size = ANAL_MAXSIZE; /* LATER switch into a 'sparse' mode */
+ }
+ /* CHECKED: actually the bytesize is size * size * sizeof(short),
+ and it shows up in */
+ bytesize = size * size * sizeof(*table);
+ if (!(table = (int *)getbytes(bytesize)))
+ return (0);
+ x = (t_anal *)pd_new(anal_class);
+ x->x_size = size;
+ x->x_bytesize = bytesize;
+ x->x_table = table;
+ outlet_new((t_object *)x, &s_list);
+ anal_reset(x);
+ anal_clear(x);
+ return (x);
+}
+
+void anal_setup(void)
+{
+ anal_class = class_new(gensym("anal"),
+ (t_newmethod)anal_new,
+ (t_method)anal_free,
+ sizeof(t_anal), 0, A_DEFFLOAT, 0);
+ class_addfloat(anal_class, anal_float);
+ class_addmethod(anal_class, (t_method)anal_reset,
+ gensym("reset"), 0);
+ class_addmethod(anal_class, (t_method)anal_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/asin.c b/cyclone/hammer/asin.c
new file mode 100644
index 0000000..0aa8db7
--- /dev/null
+++ b/cyclone/hammer/asin.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-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"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define asinf asin
+#endif
+
+typedef struct _asin
+{
+ t_object x_ob;
+ float x_value;
+} t_asin;
+
+static t_class *asin_class;
+
+static void asin_bang(t_asin *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void asin_float(t_asin *x, t_float f)
+{
+ if (f < -1.0) f = -1.0; else if (f > 1.0) f = 1.0; /* CHECKME */
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = asinf(f));
+}
+
+static void *asin_new(t_floatarg f)
+{
+ t_asin *x = (t_asin *)pd_new(asin_class);
+ if (f < -1.0) f = -1.0; else if (f > 1.0) f = 1.0; /* CHECKME */
+ x->x_value = asinf(f);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void asin_setup(void)
+{
+ asin_class = class_new(gensym("asin"),
+ (t_newmethod)asin_new, 0,
+ sizeof(t_asin), 0, A_DEFFLOAT, 0);
+ class_addbang(asin_class, asin_bang);
+ class_addfloat(asin_class, asin_float);
+}
diff --git a/cyclone/hammer/bangbang.c b/cyclone/hammer/bangbang.c
new file mode 100644
index 0000000..bebd26e
--- /dev/null
+++ b/cyclone/hammer/bangbang.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2002-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 a modified version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define BANGBANG_MINOUTS 1
+#define BANGBANG_MAXOUTS 40 /* CHECKED (just clipped without warning) */
+#define BANGBANG_DEFOUTS 2
+
+typedef struct _bangbang
+{
+ t_object x_ob;
+ int x_nouts;
+ t_outlet **x_outs;
+ t_outlet *x_outbuf[BANGBANG_DEFOUTS];
+} t_bangbang;
+
+static t_class *bangbang_class;
+
+static void bangbang_bang(t_bangbang *x)
+{
+ int i = x->x_nouts;
+ while (i--) outlet_bang(x->x_outs[i]);
+}
+
+static void bangbang_anything(t_bangbang *x, t_symbol *s, int ac, t_atom *av)
+{
+ bangbang_bang(x);
+}
+
+static void bangbang_free(t_bangbang *x)
+{
+ if (x->x_outs != x->x_outbuf)
+ freebytes(x->x_outs, x->x_nouts * sizeof(*x->x_outs));
+}
+
+static void *bangbang_new(t_floatarg val)
+{
+ t_bangbang *x;
+ int i, nouts = (int)val;
+ t_outlet **outs;
+ if (nouts < BANGBANG_MINOUTS)
+ nouts = BANGBANG_DEFOUTS;
+ if (nouts > BANGBANG_MAXOUTS)
+ loud_incompatible_max(bangbang_class, BANGBANG_MAXOUTS, "outlets");
+ if (nouts > BANGBANG_DEFOUTS)
+ {
+ if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
+ return (0);
+ }
+ else outs = 0;
+ x = (t_bangbang *)pd_new(bangbang_class);
+ x->x_nouts = nouts;
+ x->x_outs = (outs ? outs : x->x_outbuf);
+ for (i = 0; i < nouts; i++)
+ x->x_outs[i] = outlet_new((t_object *)x, &s_bang);
+ return (x);
+}
+
+void bangbang_setup(void)
+{
+ bangbang_class = class_new(gensym("bangbang"),
+ (t_newmethod)bangbang_new,
+ (t_method)bangbang_free,
+ sizeof(t_bangbang), 0, A_DEFFLOAT, 0);
+ class_addbang(bangbang_class, bangbang_bang);
+ class_addanything(bangbang_class, bangbang_anything);
+}
diff --git a/cyclone/hammer/bondo.c b/cyclone/hammer/bondo.c
new file mode 100644
index 0000000..2fcdce3
--- /dev/null
+++ b/cyclone/hammer/bondo.c
@@ -0,0 +1,394 @@
+/* Copyright (c) 2002-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 revisit buffer handling (maxsize, reentrancy) */
+/* LATER rethink handling of symbols */
+
+/* CHECKED: if 'n' argument is given, then store whole messages, instead of
+ distributing atoms across successive slots. This is a new, buddy-like
+ behaviour. */
+/* CHECKED: without 'n' argument, 'symbol test' is parsed as two symbol atoms,
+ but 'float 1' (or 'list 1') as a single float. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define BONDO_MINSLOTS 2
+#define BONDO_INISIZE 4 /* LATER rethink (useful only in multiatom mode) */
+
+typedef struct _bondo
+{
+ t_object x_ob;
+ t_float x_delay;
+ int x_multiatom;
+ int x_nslots;
+ int x_nproxies; /* as requested (and allocated) */
+ t_pd **x_proxies;
+ t_outlet **x_outs;
+ t_clock *x_clock;
+} t_bondo;
+
+typedef struct _bondo_proxy
+{
+ t_object p_ob;
+ t_bondo *p_master;
+ int p_id;
+ t_symbol *p_selector;
+ t_float p_float;
+ t_symbol *p_symbol;
+ t_gpointer *p_pointer;
+ int p_size; /* as allocated */
+ int p_natoms; /* as used */
+ t_atom *p_message;
+ t_atom p_messini[BONDO_INISIZE];
+} t_bondo_proxy;
+
+static t_class *bondo_class;
+static t_class *bondo_proxy_class;
+
+static void bondo_doit(t_bondo *x)
+{
+ t_bondo_proxy **p = (t_bondo_proxy **)x->x_proxies;
+ int i = x->x_nslots;
+ p = (t_bondo_proxy **)x->x_proxies;
+ i = x->x_nslots;
+ while (i--)
+ {
+ t_symbol *s = p[i]->p_selector;
+ /* LATER consider complaining about extra arguments (CHECKED) */
+ if (s == &s_bang)
+ outlet_bang(x->x_outs[i]);
+ else if (s == &s_float)
+ outlet_float(x->x_outs[i], p[i]->p_float);
+ else if (s == &s_symbol && p[i]->p_symbol)
+ {
+ /* LATER rethink */
+ if (x->x_multiatom)
+ outlet_symbol(x->x_outs[i], p[i]->p_symbol);
+ else
+ outlet_anything(x->x_outs[i], p[i]->p_symbol, 0, 0);
+ }
+ else if (s == &s_pointer)
+ {
+ /* LATER */
+ }
+ else if (s == &s_list)
+ outlet_list(x->x_outs[i], s, p[i]->p_natoms, p[i]->p_message);
+ else if (s) /* CHECKED: a slot may be inactive (in multiatom mode) */
+ outlet_anything(x->x_outs[i], s, p[i]->p_natoms, p[i]->p_message);
+ }
+}
+
+static void bondo_arm(t_bondo *x)
+{
+ if (x->x_delay <= 0) bondo_doit(x);
+ else clock_delay(x->x_clock, x->x_delay);
+}
+
+static void bondo_proxy_bang(t_bondo_proxy *x)
+{
+ bondo_arm(x->p_master); /* CHECKED: bang in any inlet works in this way */
+}
+
+static void bondo_proxy_dofloat(t_bondo_proxy *x, t_float f, int doit)
+{
+ x->p_selector = &s_float;
+ x->p_float = f;
+ x->p_natoms = 0; /* defensive */
+ if (doit) bondo_arm(x->p_master);
+}
+
+static void bondo_proxy_float(t_bondo_proxy *x, t_float f)
+{
+ bondo_proxy_dofloat(x, f, 1);
+}
+
+static void bondo_proxy_dosymbol(t_bondo_proxy *x, t_symbol *s, int doit)
+{
+ x->p_selector = &s_symbol;
+ x->p_symbol = s;
+ x->p_natoms = 0; /* defensive */
+ if (doit) bondo_arm(x->p_master);
+}
+
+static void bondo_proxy_symbol(t_bondo_proxy *x, t_symbol *s)
+{
+ bondo_proxy_dosymbol(x, s, 1);
+}
+
+static void bondo_proxy_dopointer(t_bondo_proxy *x, t_gpointer *gp, int doit)
+{
+ x->p_selector = &s_pointer;
+ x->p_pointer = gp;
+ x->p_natoms = 0; /* defensive */
+ if (doit) bondo_arm(x->p_master);
+}
+
+static void bondo_proxy_pointer(t_bondo_proxy *x, t_gpointer *gp)
+{
+ bondo_proxy_dopointer(x, gp, 1);
+}
+
+/* CHECKED: the slots fire in right-to-left order,
+ but they trigger only once (refman error) */
+static void bondo_distribute(t_bondo *x, int startid,
+ t_symbol *s, int ac, t_atom *av, int doit)
+{
+ t_atom *ap = av;
+ t_bondo_proxy **pp;
+ int id = startid + ac;
+ if (s) id++;
+ if (id > x->x_nslots)
+ id = x->x_nslots;
+ ap += id - startid;
+ pp = (t_bondo_proxy **)(x->x_proxies + id);
+ if (s) ap--;
+ while (ap-- > av)
+ {
+ pp--;
+ if (ap->a_type == A_FLOAT)
+ bondo_proxy_dofloat(*pp, ap->a_w.w_float, 0);
+ else if (ap->a_type == A_SYMBOL)
+ bondo_proxy_dosymbol(*pp, ap->a_w.w_symbol, 0);
+ else if (ap->a_type == A_POINTER)
+ bondo_proxy_dopointer(*pp, ap->a_w.w_gpointer, 0);
+ }
+ if (s)
+ bondo_proxy_dosymbol((t_bondo_proxy *)x->x_proxies[startid], s, 0);
+ if (doit) bondo_arm(x);
+}
+
+static void bondo_proxy_domultiatom(t_bondo_proxy *x,
+ int ac, t_atom *av, int doit)
+{
+ if (ac > x->p_size)
+ {
+ /* LATER consider using BONDO_MAXSIZE (and warning if exceeded) */
+ x->p_message = grow_nodata(&ac, &x->p_size, x->p_message,
+ BONDO_INISIZE, x->p_messini,
+ sizeof(*x->p_message));
+ }
+ x->p_natoms = ac;
+ memcpy(x->p_message, av, ac * sizeof(*x->p_message));
+ if (doit) bondo_arm(x->p_master);
+}
+
+static void bondo_proxy_dolist(t_bondo_proxy *x, int ac, t_atom *av, int doit)
+{
+ if (x->p_master->x_multiatom)
+ {
+ x->p_selector = &s_list;
+ bondo_proxy_domultiatom(x, ac, av, doit);
+ }
+ else bondo_distribute(x->p_master, x->p_id, 0, ac, av, doit);
+}
+
+static void bondo_proxy_list(t_bondo_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ bondo_proxy_dolist(x, ac, av, 1);
+}
+
+static void bondo_proxy_doanything(t_bondo_proxy *x,
+ t_symbol *s, int ac, t_atom *av, int doit)
+{
+ if (x->p_master->x_multiatom)
+ {
+ /* LATER rethink and CHECKME */
+ if (s == &s_symbol)
+ {
+ if (ac && av->a_type == A_SYMBOL)
+ bondo_proxy_dosymbol(x, av->a_w.w_symbol, doit);
+ else
+ bondo_proxy_dosymbol(x, &s_symbol, doit);
+ }
+ else
+ {
+ x->p_selector = s;
+ bondo_proxy_domultiatom(x, ac, av, doit);
+ }
+ }
+ else bondo_distribute(x->p_master, x->p_id, s, ac, av, doit);
+}
+
+static void bondo_proxy_anything(t_bondo_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ bondo_proxy_doanything(x, s, ac, av, 1);
+}
+
+static void bondo_proxy_set(t_bondo_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ bondo_proxy_dolist(x, ac, av, 0);
+ else
+ bondo_proxy_dofloat(x, av->a_w.w_float, 0);
+ }
+ else if (av->a_type == A_SYMBOL)
+ /* CHECKED: no tests for 'set float ...' and 'set list...' --
+ the parsing is made in an output routine */
+ bondo_proxy_doanything(x, av->a_w.w_symbol, ac-1, av+1, 0);
+ else if (av->a_type == A_POINTER)
+ bondo_proxy_dopointer(x, av->a_w.w_gpointer, 0);
+ }
+ /* CHECKED: 'set' without arguments makes a slot inactive,
+ if multiatom, but is ignored, if !multiatom */
+ else if (x->p_master->x_multiatom) x->p_selector = 0;
+}
+
+static void bondo_bang(t_bondo *x)
+{
+ bondo_proxy_bang((t_bondo_proxy *)x->x_proxies[0]);
+}
+
+static void bondo_float(t_bondo *x, t_float f)
+{
+ bondo_proxy_dofloat((t_bondo_proxy *)x->x_proxies[0], f, 1);
+}
+
+static void bondo_symbol(t_bondo *x, t_symbol *s)
+{
+ bondo_proxy_dosymbol((t_bondo_proxy *)x->x_proxies[0], s, 1);
+}
+
+static void bondo_pointer(t_bondo *x, t_gpointer *gp)
+{
+ bondo_proxy_dopointer((t_bondo_proxy *)x->x_proxies[0], gp, 1);
+}
+
+static void bondo_list(t_bondo *x, t_symbol *s, int ac, t_atom *av)
+{
+ bondo_proxy_dolist((t_bondo_proxy *)x->x_proxies[0], ac, av, 1);
+}
+
+static void bondo_anything(t_bondo *x, t_symbol *s, int ac, t_atom *av)
+{
+ bondo_proxy_doanything((t_bondo_proxy *)x->x_proxies[0], s, ac, av, 1);
+}
+
+static void bondo_set(t_bondo *x, t_symbol *s, int ac, t_atom *av)
+{
+ bondo_proxy_set((t_bondo_proxy *)x->x_proxies[0], s, ac, av);
+}
+
+static void bondo_free(t_bondo *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+ if (x->x_proxies)
+ {
+ int i = x->x_nslots;
+ while (i--)
+ {
+ t_bondo_proxy *y = (t_bondo_proxy *)x->x_proxies[i];
+ if (y->p_message != y->p_messini)
+ freebytes(y->p_message, y->p_size * sizeof(*y->p_message));
+ pd_free((t_pd *)y);
+ }
+ freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies));
+ }
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_nslots * sizeof(*x->x_outs));
+}
+
+static void *bondo_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_bondo *x;
+ int i, nslots, nproxies = BONDO_MINSLOTS;
+ int multiatom = 0;
+ t_float delay = 0;
+ t_pd **proxies;
+ t_outlet **outs;
+ i = 0;
+ while (ac--)
+ {
+ /* CHECKED: no warnings */
+ if (av->a_type == A_FLOAT)
+ {
+ if (i == 0)
+ nproxies = (int)av->a_w.w_float;
+ else if (i == 1)
+ delay = av->a_w.w_float;
+ i++;
+ }
+ else if (av->a_type == A_SYMBOL)
+ {
+ if (av->a_w.w_symbol == gensym("n")) multiatom = 1;
+ /* CHECKED: 'n' has to be the last argument given;
+ the arguments after any symbol are silently ignored --
+ LATER decide if we should comply and break here */
+ }
+ av++;
+ }
+ if (nproxies < BONDO_MINSLOTS)
+ nproxies = BONDO_MINSLOTS;
+ if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies))))
+ return (0);
+ for (nslots = 0; nslots < nproxies; nslots++)
+ if (!(proxies[nslots] = pd_new(bondo_proxy_class))) break;
+ if (nslots < BONDO_MINSLOTS
+ || !(outs = (t_outlet **)getbytes(nslots * sizeof(*outs))))
+ {
+ i = nslots;
+ while (i--) pd_free(proxies[i]);
+ freebytes(proxies, nproxies * sizeof(*proxies));
+ return (0);
+ }
+ x = (t_bondo *)pd_new(bondo_class);
+ x->x_delay = delay;
+ x->x_multiatom = multiatom;
+ x->x_nslots = nslots;
+ x->x_nproxies = nproxies;
+ x->x_proxies = proxies;
+ x->x_outs = outs;
+ for (i = 0; i < nslots; i++)
+ {
+ t_bondo_proxy *y = (t_bondo_proxy *)proxies[i];
+ y->p_master = x;
+ y->p_id = i;
+ y->p_selector = &s_float; /* CHECKED: it is so in multiatom mode too */
+ y->p_float = 0;
+ y->p_symbol = 0;
+ y->p_pointer = 0;
+ y->p_size = BONDO_INISIZE;
+ y->p_natoms = 0;
+ y->p_message = y->p_messini;
+ if (i) inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ x->x_outs[i] = outlet_new((t_object *)x, &s_anything);
+ }
+ x->x_clock = clock_new(x, (t_method)bondo_doit);
+ return (x);
+}
+
+void bondo_setup(void)
+{
+ bondo_class = class_new(gensym("bondo"),
+ (t_newmethod)bondo_new,
+ (t_method)bondo_free,
+ sizeof(t_bondo), 0, A_GIMME, 0);
+ class_addbang(bondo_class, bondo_bang);
+ class_addfloat(bondo_class, bondo_float);
+ class_addsymbol(bondo_class, bondo_symbol);
+ class_addpointer(bondo_class, bondo_pointer);
+ class_addlist(bondo_class, bondo_list);
+ class_addanything(bondo_class, bondo_anything);
+ class_addmethod(bondo_class, (t_method)bondo_set,
+ gensym("set"), A_GIMME, 0);
+ bondo_proxy_class = class_new(gensym("_bondo_proxy"), 0, 0,
+ sizeof(t_bondo_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(bondo_proxy_class, bondo_proxy_bang);
+ class_addfloat(bondo_proxy_class, bondo_proxy_float);
+ class_addsymbol(bondo_proxy_class, bondo_proxy_symbol);
+ class_addpointer(bondo_proxy_class, bondo_proxy_pointer);
+ class_addlist(bondo_proxy_class, bondo_proxy_list);
+ class_addanything(bondo_proxy_class, bondo_proxy_anything);
+ class_addmethod(bondo_proxy_class, (t_method)bondo_proxy_set,
+ gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/buddy.c b/cyclone/hammer/buddy.c
new file mode 100644
index 0000000..f272739
--- /dev/null
+++ b/cyclone/hammer/buddy.c
@@ -0,0 +1,253 @@
+/* Copyright (c) 2002-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 compare with buddy.c from max sdk */
+/* LATER revisit buffer handling (maxsize, reentrancy) */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define BUDDY_MINSLOTS 2
+#define BUDDY_INISIZE 4 /* LATER rethink */
+
+typedef struct _buddy
+{
+ t_object x_ob;
+ int x_nslots;
+ int x_nproxies; /* as requested (and allocated) */
+ t_pd **x_proxies;
+ t_outlet **x_outs;
+} t_buddy;
+
+typedef struct _buddy_proxy
+{
+ t_object p_ob;
+ t_buddy *p_master;
+ t_symbol *p_selector;
+ t_float p_float;
+ t_symbol *p_symbol;
+ t_gpointer *p_pointer;
+ int p_size; /* as allocated */
+ int p_natoms; /* as used */
+ t_atom *p_message;
+ t_atom p_messini[BUDDY_INISIZE];
+} t_buddy_proxy;
+
+static t_class *buddy_class;
+static t_class *buddy_proxy_class;
+
+static void buddy_clear(t_buddy *x)
+{
+ t_buddy_proxy **p = (t_buddy_proxy **)x->x_proxies;
+ int i = x->x_nslots;
+ while (i--)
+ {
+ (*p)->p_selector = 0;
+ (*p++)->p_natoms = 0; /* defensive */
+ }
+}
+
+static void buddy_check(t_buddy *x)
+{
+ t_buddy_proxy **p = (t_buddy_proxy **)x->x_proxies;
+ int i = x->x_nslots;
+ while (i--)
+ if (!(*p++)->p_selector)
+ return;
+ p = (t_buddy_proxy **)x->x_proxies;
+ i = x->x_nslots;
+ while (i--)
+ {
+ t_symbol *s = p[i]->p_selector;
+ if (s == &s_bang)
+ outlet_bang(x->x_outs[i]);
+ else if (s == &s_float)
+ outlet_float(x->x_outs[i], p[i]->p_float);
+ else if (s == &s_symbol && p[i]->p_symbol)
+ outlet_symbol(x->x_outs[i], p[i]->p_symbol);
+ else if (s == &s_pointer)
+ {
+ /* LATER */
+ }
+ else if (s == &s_list)
+ outlet_list(x->x_outs[i], s, p[i]->p_natoms, p[i]->p_message);
+ else if (s)
+ outlet_anything(x->x_outs[i], s, p[i]->p_natoms, p[i]->p_message);
+ }
+ buddy_clear(x);
+}
+
+static void buddy_proxy_bang(t_buddy_proxy *x)
+{
+ x->p_selector = &s_bang;
+ x->p_natoms = 0; /* defensive */
+ buddy_check(x->p_master);
+}
+
+static void buddy_proxy_float(t_buddy_proxy *x, t_float f)
+{
+ x->p_selector = &s_float;
+ x->p_float = f;
+ x->p_natoms = 0; /* defensive */
+ buddy_check(x->p_master);
+}
+
+static void buddy_proxy_symbol(t_buddy_proxy *x, t_symbol *s)
+{
+ x->p_selector = &s_symbol;
+ x->p_symbol = s;
+ x->p_natoms = 0; /* defensive */
+ buddy_check(x->p_master);
+}
+
+static void buddy_proxy_pointer(t_buddy_proxy *x, t_gpointer *gp)
+{
+ x->p_selector = &s_pointer;
+ x->p_pointer = gp;
+ x->p_natoms = 0; /* defensive */
+ buddy_check(x->p_master);
+}
+
+static void buddy_proxy_domessage(t_buddy_proxy *x, int ac, t_atom *av)
+{
+ if (ac > x->p_size)
+ {
+ /* LATER consider using BUDDY_MAXSIZE (and warning if exceeded) */
+ x->p_message = grow_nodata(&ac, &x->p_size, x->p_message,
+ BUDDY_INISIZE, x->p_messini,
+ sizeof(*x->p_message));
+ }
+ x->p_natoms = ac;
+ memcpy(x->p_message, av, ac * sizeof(*x->p_message));
+ buddy_check(x->p_master);
+}
+
+static void buddy_proxy_list(t_buddy_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ x->p_selector = &s_list; /* LATER rethink */
+ buddy_proxy_domessage(x, ac, av);
+}
+
+static void buddy_proxy_anything(t_buddy_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ x->p_selector = s; /* LATER rethink */
+ buddy_proxy_domessage(x, ac, av);
+}
+
+static void buddy_bang(t_buddy *x)
+{
+ buddy_proxy_bang((t_buddy_proxy *)x->x_proxies[0]);
+}
+
+static void buddy_float(t_buddy *x, t_float f)
+{
+ buddy_proxy_float((t_buddy_proxy *)x->x_proxies[0], f);
+}
+
+static void buddy_symbol(t_buddy *x, t_symbol *s)
+{
+ buddy_proxy_symbol((t_buddy_proxy *)x->x_proxies[0], s);
+}
+
+static void buddy_pointer(t_buddy *x, t_gpointer *gp)
+{
+ buddy_proxy_pointer((t_buddy_proxy *)x->x_proxies[0], gp);
+}
+
+static void buddy_list(t_buddy *x, t_symbol *s, int ac, t_atom *av)
+{
+ buddy_proxy_list((t_buddy_proxy *)x->x_proxies[0], s, ac, av);
+}
+
+static void buddy_anything(t_buddy *x, t_symbol *s, int ac, t_atom *av)
+{
+ buddy_proxy_anything((t_buddy_proxy *)x->x_proxies[0], s, ac, av);
+}
+
+static void buddy_free(t_buddy *x)
+{
+ if (x->x_proxies)
+ {
+ int i = x->x_nslots;
+ while (i--)
+ {
+ t_buddy_proxy *y = (t_buddy_proxy *)x->x_proxies[i];
+ if (y->p_message != y->p_messini)
+ freebytes(y->p_message, y->p_size * sizeof(*y->p_message));
+ pd_free((t_pd *)y);
+ }
+ freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies));
+ }
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_nslots * sizeof(*x->x_outs));
+}
+
+static void *buddy_new(t_floatarg f)
+{
+ t_buddy *x;
+ int i, nslots, nproxies = (int)f;
+ t_pd **proxies;
+ t_outlet **outs;
+ if (nproxies < BUDDY_MINSLOTS)
+ nproxies = BUDDY_MINSLOTS;
+ if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies))))
+ return (0);
+ for (nslots = 0; nslots < nproxies; nslots++)
+ if (!(proxies[nslots] = pd_new(buddy_proxy_class))) break;
+ if (nslots < BUDDY_MINSLOTS
+ || !(outs = (t_outlet **)getbytes(nslots * sizeof(*outs))))
+ {
+ int i = nslots;
+ while (i--) pd_free(proxies[i]);
+ freebytes(proxies, nproxies * sizeof(*proxies));
+ return (0);
+ }
+ x = (t_buddy *)pd_new(buddy_class);
+ x->x_nslots = nslots;
+ x->x_nproxies = nproxies;
+ x->x_proxies = proxies;
+ x->x_outs = outs;
+ for (i = 0; i < nslots; i++)
+ {
+ t_buddy_proxy *y = (t_buddy_proxy *)proxies[i];
+ y->p_master = x;
+ y->p_selector = 0;
+ y->p_float = 0;
+ y->p_symbol = 0;
+ y->p_pointer = 0;
+ y->p_size = BUDDY_INISIZE;
+ y->p_natoms = 0;
+ y->p_message = y->p_messini;
+ if (i) inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ x->x_outs[i] = outlet_new((t_object *)x, &s_anything);
+ }
+ return (x);
+}
+
+void buddy_setup(void)
+{
+ buddy_class = class_new(gensym("buddy"),
+ (t_newmethod)buddy_new,
+ (t_method)buddy_free,
+ sizeof(t_buddy), 0, A_DEFFLOAT, 0);
+ class_addbang(buddy_class, buddy_bang);
+ class_addfloat(buddy_class, buddy_float);
+ class_addsymbol(buddy_class, buddy_symbol);
+ class_addpointer(buddy_class, buddy_pointer);
+ class_addlist(buddy_class, buddy_list);
+ class_addanything(buddy_class, buddy_anything);
+ class_addmethod(buddy_class, (t_method)buddy_clear, gensym("clear"), 0);
+ buddy_proxy_class = class_new(gensym("_buddy_proxy"), 0, 0,
+ sizeof(t_buddy_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(buddy_proxy_class, buddy_proxy_bang);
+ class_addfloat(buddy_proxy_class, buddy_proxy_float);
+ class_addsymbol(buddy_proxy_class, buddy_proxy_symbol);
+ class_addpointer(buddy_proxy_class, buddy_proxy_pointer);
+ class_addlist(buddy_proxy_class, buddy_proxy_list);
+ class_addanything(buddy_proxy_class, buddy_proxy_anything);
+}
diff --git a/cyclone/hammer/capture.c b/cyclone/hammer/capture.c
new file mode 100644
index 0000000..b36c421
--- /dev/null
+++ b/cyclone/hammer/capture.c
@@ -0,0 +1,291 @@
+/* Copyright (c) 2002-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 <stdio.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "hammer/file.h"
+
+#define CAPTURE_DEFSIZE 512
+
+typedef struct _capture
+{
+ t_object x_ob;
+ t_canvas *x_canvas;
+ char x_intmode; /* if nonzero ('x' or 'm') floats are ignored */
+ float *x_buffer;
+ int x_bufsize;
+ int x_count;
+ int x_head;
+ t_hammerfile *x_filehandle;
+} t_capture;
+
+static t_class *capture_class;
+
+static void capture_float(t_capture *x, t_float f)
+{
+ if (x->x_intmode && f != (int)f) /* CHECKME float */
+ return;
+ x->x_buffer[x->x_head++] = f;
+ if (x->x_head >= x->x_bufsize)
+ x->x_head = 0;
+ if (x->x_count < x->x_bufsize)
+ x->x_count++;
+}
+
+static void capture_list(t_capture *x, t_symbol *s, int ac, t_atom *av)
+{
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT) /* CHECKME */
+ capture_float(x, av->a_w.w_float);
+ av++;
+ }
+}
+
+static void capture_clear(t_capture *x)
+{
+ x->x_count = 0;
+ x->x_head = 0;
+}
+
+static void capture_count(t_capture *x)
+{
+ post("capture: %d items received", /* CHECKED */
+ x->x_count); /* CHECKED incompatible (4.07 seems buggy here) */
+}
+
+static void capture_dump(t_capture *x)
+{
+ int count = x->x_count;
+ if (count < x->x_bufsize)
+ {
+ float *bp = x->x_buffer;
+ while (count--)
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ }
+ else
+ {
+ float *bp = x->x_buffer + x->x_head;
+ count = x->x_bufsize - x->x_head;
+ while (count--)
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ bp = x->x_buffer;
+ count = x->x_head;
+ while (count--)
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ }
+}
+
+static int capture_formatint(int i, char *buf, int col,
+ int maxcol, char *fmt)
+{
+ char *bp = buf;
+ int cnt = 0;
+ if (col > 0)
+ *bp++ = ' ', cnt++;
+ cnt += sprintf(bp, fmt, i);
+ if (col + cnt > maxcol)
+ buf[0] = '\n', col = cnt;
+ else
+ col += cnt;
+ return (col);
+}
+
+static int capture_formatfloat(float f, char *buf, int col,
+ int maxcol, char *fmt)
+{
+ char *bp = buf;
+ int cnt = 0;
+ if (col > 0)
+ *bp++ = ' ', cnt++;
+ cnt += sprintf(bp, fmt, f);
+ if (col + cnt > maxcol)
+ buf[0] = '\n', col = cnt;
+ else
+ col += cnt;
+ return (col);
+}
+
+static int capture_formatnumber(t_capture *x, float f, char *buf,
+ int col, int maxcol)
+{
+ char intmode = x->x_intmode;
+ if (intmode == 'm')
+ intmode = (f < 128 && f > -128 ? 'd' : 'x'); /* CHECKME */
+ if (intmode == 'x')
+ col = capture_formatint((int)f, buf, col, maxcol, "%x");
+ else if (intmode)
+ col = capture_formatint((int)f, buf, col, maxcol, "%d");
+ else
+ col = capture_formatfloat(f, buf, col, maxcol, "%g");
+ return (col);
+}
+
+static int capture_writefloat(t_capture *x, float f, char *buf, int col,
+ FILE *fp)
+{
+ /* CHECKED no linebreaks (FIXME) */
+ col = capture_formatnumber(x, f, buf, col, 80);
+ return (fputs(buf, fp) < 0 ? -1 : col);
+}
+
+static void capture_dowrite(t_capture *x, t_symbol *fn)
+{
+ FILE *fp = 0;
+ int count = x->x_count;
+ char buf[MAXPDSTRING];
+ canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
+ if (fp = fopen(buf, "w")) /* LATER ask if overwriting, CHECKED */
+ {
+ int col = 0;
+ if (count < x->x_bufsize)
+ {
+ float *bp = x->x_buffer;
+ while (count--)
+ if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0)
+ goto fail;
+ }
+ else
+ {
+ float *bp = x->x_buffer + x->x_head;
+ count = x->x_bufsize - x->x_head;
+ while (count--)
+ if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0)
+ goto fail;
+ bp = x->x_buffer;
+ count = x->x_head;
+ while (count--)
+ if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0)
+ goto fail;
+ }
+ if (col) fputc('\n', fp);
+ fclose(fp);
+ return;
+ }
+fail:
+ if (fp) fclose(fp);
+ loud_syserror((t_pd *)x, 0);
+}
+
+static void capture_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ capture_dowrite((t_capture *)z, fn);
+}
+
+static void capture_write(t_capture *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ capture_dowrite(x, s);
+ else
+ hammerpanel_save(x->x_filehandle, 0, 0);
+}
+
+static int capture_appendfloat(t_capture *x, float f, char *buf, int col)
+{
+ /* CHECKED 80 columns */
+ col = capture_formatnumber(x, f, buf, col, 80);
+ hammereditor_append(x->x_filehandle, buf);
+ return (col);
+}
+
+static void capture_open(t_capture *x)
+{
+ int count = x->x_count;
+ char buf[MAXPDSTRING];
+ hammereditor_open(x->x_filehandle, "t_capture"); /* CHECKED */
+ if (count < x->x_bufsize)
+ {
+ float *bp = x->x_buffer;
+ int col = 0;
+ while (count--)
+ col = capture_appendfloat(x, *bp++, buf, col);
+ }
+ else
+ {
+ float *bp = x->x_buffer + x->x_head;
+ int col = 0;
+ count = x->x_bufsize - x->x_head;
+ while (count--)
+ col = capture_appendfloat(x, *bp++, buf, col);
+ bp = x->x_buffer;
+ count = x->x_head;
+ while (count--)
+ col = capture_appendfloat(x, *bp++, buf, col);
+ }
+}
+
+/* CHECKED without asking and storing the changes */
+static void capture_wclose(t_capture *x)
+{
+ hammereditor_close(x->x_filehandle, 0);
+}
+
+static void capture_click(t_capture *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ capture_open(x);
+}
+
+static void capture_free(t_capture *x)
+{
+ hammerfile_free(x->x_filehandle);
+ if (x->x_buffer)
+ freebytes(x->x_buffer, x->x_bufsize * sizeof(*x->x_buffer));
+}
+
+static void *capture_new(t_symbol *s, t_floatarg f)
+{
+ t_capture *x = 0;
+ float *buffer;
+ int bufsize = (int)f; /* CHECKME */
+ if (bufsize <= 0) /* CHECKME */
+ bufsize = CAPTURE_DEFSIZE;
+ if (buffer = getbytes(bufsize * sizeof(*buffer)))
+ {
+ x = (t_capture *)pd_new(capture_class);
+ x->x_canvas = canvas_getcurrent();
+ if (s && s != &s_)
+ {
+ if (s == gensym("x"))
+ x->x_intmode = 'x';
+ else if (s == gensym("m"))
+ x->x_intmode = 'm';
+ else
+ x->x_intmode = 'd'; /* ignore floats */
+ }
+ x->x_buffer = buffer;
+ x->x_bufsize = bufsize;
+ outlet_new((t_object *)x, &s_float);
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0, 0, capture_writehook, 0);
+ capture_clear(x);
+ }
+ return (x);
+}
+
+void capture_setup(void)
+{
+ capture_class = class_new(gensym("capture"),
+ (t_newmethod)capture_new,
+ (t_method)capture_free,
+ sizeof(t_capture), 0, A_DEFFLOAT, A_DEFSYM, 0);
+ class_addfloat(capture_class, capture_float);
+ class_addlist(capture_class, capture_list);
+ class_addmethod(capture_class, (t_method)capture_clear,
+ gensym("clear"), 0);
+ class_addmethod(capture_class, (t_method)capture_count,
+ gensym("count"), 0);
+ class_addmethod(capture_class, (t_method)capture_dump,
+ gensym("dump"), 0);
+ class_addmethod(capture_class, (t_method)capture_write,
+ gensym("write"), A_DEFSYM, 0);
+ class_addmethod(capture_class, (t_method)capture_open,
+ gensym("open"), 0);
+ class_addmethod(capture_class, (t_method)capture_wclose,
+ gensym("wclose"), 0);
+ class_addmethod(capture_class, (t_method)capture_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ hammerfile_setup(capture_class, 0);
+}
diff --git a/cyclone/hammer/cartopol.c b/cyclone/hammer/cartopol.c
new file mode 100644
index 0000000..4200686
--- /dev/null
+++ b/cyclone/hammer/cartopol.c
@@ -0,0 +1,44 @@
+/* Copyright (c) 2002-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"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define atan2f atan2
+#define hypotf hypot
+#endif
+
+typedef struct _cartopol
+{
+ t_object x_ob;
+ t_float x_imag;
+ t_outlet *x_out2;
+} t_cartopol;
+
+static t_class *cartopol_class;
+
+static void cartopol_float(t_cartopol *x, t_float f)
+{
+ outlet_float(x->x_out2, atan2f(x->x_imag, f));
+ outlet_float(((t_object *)x)->ob_outlet, hypotf(f, x->x_imag));
+}
+
+static void *cartopol_new(void)
+{
+ t_cartopol *x = (t_cartopol *)pd_new(cartopol_class);
+ floatinlet_new((t_object *)x, &x->x_imag);
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void cartopol_setup(void)
+{
+ cartopol_class = class_new(gensym("cartopol"),
+ (t_newmethod)cartopol_new, 0,
+ sizeof(t_cartopol), 0, 0);
+ class_addfloat(cartopol_class, cartopol_float);
+}
diff --git a/cyclone/hammer/coll.c b/cyclone/hammer/coll.c
new file mode 100644
index 0000000..c4a3388
--- /dev/null
+++ b/cyclone/hammer/coll.c
@@ -0,0 +1,1597 @@
+/* Copyright (c) 2002-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 <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "hammer/file.h"
+
+/* FIXME sort crashes after (corrupt?) transfers from the editor */
+/* LATER make sure that ``reentrancy protection hack'' is really working... */
+/* CHECKME default fname for 'write' -- c_filename, x_name, nothing? */
+
+#define COLL_DEBUG
+
+typedef struct _collelem
+{
+ int e_hasnumkey;
+ int e_numkey;
+ t_symbol *e_symkey;
+ struct _collelem *e_prev;
+ struct _collelem *e_next;
+ int e_size;
+ t_atom *e_data;
+} t_collelem;
+
+typedef struct _collcommon
+{
+ t_pd c_pd;
+ struct _coll *c_refs; /* used in read-banging and dirty flag handling */
+ int c_embedflag; /* common field (CHECKED in 'TEXT') */
+ int c_loading;
+ int c_relinked;
+ int c_selfmodified;
+ int c_entered; /* a counter, LATER rethink */
+ t_symbol *c_filename;
+ t_canvas *c_lastcanvas;
+ t_hammerfile *c_filehandle;
+ t_collelem *c_first;
+ t_collelem *c_last;
+ t_collelem *c_ahead;
+ t_collelem *c_back;
+} t_collcommon;
+
+typedef struct _coll
+{
+ t_object x_ob;
+ t_canvas *x_canvas;
+ t_symbol *x_name;
+ t_collcommon *x_common;
+ t_hammerfile *x_filehandle;
+ t_outlet *x_keyout;
+ t_outlet *x_filebangout;
+ t_outlet *x_dumpbangout;
+ struct _coll *x_next;
+} t_coll;
+
+static t_class *coll_class;
+static t_class *collcommon_class;
+
+static t_collelem *collelem_new(int ac, t_atom *av, int *np, t_symbol *s)
+{
+ t_collelem *ep = (t_collelem *)getbytes(sizeof(*ep));
+ if (ep->e_hasnumkey = (np != 0))
+ ep->e_numkey = *np;
+ ep->e_symkey = s;
+ ep->e_prev = ep->e_next = 0;
+ if (ep->e_size = ac)
+ {
+ t_atom *ap = getbytes(ac * sizeof(*ap));
+ ep->e_data = ap;
+ if (av) while (ac--)
+ *ap++ = *av++;
+ else while (ac--)
+ {
+ SETFLOAT(ap, 0);
+ ap++;
+ }
+ }
+ else ep->e_data = 0;
+ return (ep);
+}
+
+static void collelem_free(t_collelem *ep)
+{
+ if (ep->e_data)
+ freebytes(ep->e_data, ep->e_size * sizeof(*ep->e_data));
+ freebytes(ep, sizeof(*ep));
+}
+
+/* CHECKME again... apparently c74 is not able to fix this for good */
+/* result: 1 for ep1 < ep2, otherwise 0 (symbols are less then floats) */
+static int collelem_less(t_collelem *ep1, t_collelem *ep2, int ndx)
+{
+ if (ndx < 0)
+ {
+ if (ep1->e_symkey)
+ return (ep2->e_symkey ?
+ strcmp(ep1->e_symkey->s_name,
+ ep2->e_symkey->s_name) < 0
+ : 1); /* CHECKED incompatible with 4.07, but consistent */
+ else if (ep2->e_symkey)
+ return (0); /* CHECKED incompatible with 4.07, but consistent */
+ else
+ return (ep1->e_numkey < ep2->e_numkey); /* CHECKED in 4.07 */
+ }
+ else
+ {
+ t_atom *ap1 = (ndx < ep1->e_size ?
+ ep1->e_data + ndx : ep1->e_data + ep1->e_size - 1);
+ t_atom *ap2 = (ndx < ep2->e_size ?
+ ep2->e_data + ndx : ep2->e_data + ep2->e_size - 1);
+ if (ap1->a_type == A_FLOAT)
+ {
+ if (ap2->a_type == A_FLOAT)
+ return (ap1->a_w.w_float < ap2->a_w.w_float);
+ else if (ap2->a_type == A_SYMBOL)
+ return (0);
+ else
+ return (1);
+ }
+ else if (ap1->a_type == A_SYMBOL)
+ {
+ if (ap2->a_type == A_FLOAT)
+ return (1);
+ else if (ap2->a_type == A_SYMBOL)
+ return (strcmp(ap1->a_w.w_symbol->s_name,
+ ap2->a_w.w_symbol->s_name) < 0);
+ else
+ return (1);
+ }
+ else
+ return (0);
+ }
+}
+
+static void collelem_post(t_collelem *ep)
+{
+ if (ep->e_hasnumkey && ep->e_symkey)
+ startpost("%d %s:", ep->e_numkey, ep->e_symkey->s_name);
+ else if (ep->e_hasnumkey)
+ startpost("%d:", ep->e_numkey);
+ else if (ep->e_symkey)
+ startpost("%s:", ep->e_symkey->s_name);
+ else bug("collcommon_post");
+ postatom(ep->e_size, ep->e_data);
+ endpost();
+}
+
+static void collcommon_post(t_collcommon *cc)
+{
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next) collelem_post(ep);
+}
+
+static t_collelem *collcommon_numkey(t_collcommon *cc, int numkey)
+{
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ if (ep->e_hasnumkey && ep->e_numkey == numkey)
+ return (ep);
+ return (0);
+}
+
+static t_collelem *collcommon_symkey(t_collcommon *cc, t_symbol *symkey)
+{
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ if (ep->e_symkey == symkey)
+ return (ep);
+ return (0);
+}
+
+static void collcommon_takeout(t_collcommon *cc, t_collelem *ep)
+{
+ if (ep->e_prev)
+ ep->e_prev->e_next = ep->e_next;
+ else
+ cc->c_first = ep->e_next;
+ if (ep->e_next)
+ ep->e_next->e_prev = ep->e_prev;
+ else
+ cc->c_last = ep->e_prev;
+ if (cc->c_ahead == ep)
+ cc->c_ahead = ep->e_next;
+ if (cc->c_back == ep)
+ cc->c_back = ep->e_prev;
+}
+
+static void collcommon_modified(t_collcommon *cc, int relinked)
+{
+ if (cc->c_loading)
+ return;
+ if (relinked)
+ {
+ cc->c_relinked = 1;
+ }
+ if (cc->c_embedflag)
+ {
+ t_coll *x;
+ for (x = cc->c_refs; x; x = x->x_next)
+ if (x->x_canvas && glist_isvisible(x->x_canvas))
+ canvas_dirty(x->x_canvas, 1);
+ }
+}
+
+/* atomic collcommon modifiers: clearall, remove, replace,
+ putbefore, putafter, swaplinks, swapkeys, changesymkey, renumber, sort */
+
+static void collcommon_clearall(t_collcommon *cc)
+{
+ if (cc->c_first)
+ {
+ t_collelem *ep1 = cc->c_first, *ep2;
+ do
+ {
+ ep2 = ep1->e_next;
+ collelem_free(ep1);
+ }
+ while (ep1 = ep2);
+ cc->c_first = cc->c_last = 0;
+ cc->c_ahead = cc->c_back = 0;
+ collcommon_modified(cc, 1);
+ }
+}
+
+static void collcommon_remove(t_collcommon *cc, t_collelem *ep)
+{
+ collcommon_takeout(cc, ep);
+ collelem_free(ep);
+ collcommon_modified(cc, 1);
+}
+
+static void collcommon_replace(t_collcommon *cc, t_collelem *ep,
+ int ac, t_atom *av, int *np, t_symbol *s)
+{
+ if (ep->e_hasnumkey = (np != 0))
+ ep->e_numkey = *np;
+ ep->e_symkey = s;
+ if (ac)
+ {
+ int i = ac;
+ t_atom *ap;
+ if (ep->e_data)
+ {
+ if (ep->e_size != ac)
+ ap = resizebytes(ep->e_data,
+ ep->e_size * sizeof(*ap), ac * sizeof(*ap));
+ else ap = ep->e_data;
+ }
+ else
+ ap = getbytes(ac * sizeof(*ap));
+ ep->e_data = ap;
+ if (av) while (i --)
+ *ap++ = *av++;
+ else while (i --)
+ {
+ SETFLOAT(ap, 0);
+ ap++;
+ }
+ }
+ else
+ {
+ if (ep->e_data)
+ freebytes(ep->e_data, ep->e_size * sizeof(*ep->e_data));
+ ep->e_data = 0;
+ }
+ ep->e_size = ac;
+ collcommon_modified(cc, 0);
+}
+
+static void collcommon_putbefore(t_collcommon *cc,
+ t_collelem *ep, t_collelem *next)
+{
+ if (next)
+ {
+ ep->e_next = next;
+ if (ep->e_prev = next->e_prev)
+ ep->e_prev->e_next = ep;
+ else
+ cc->c_first = ep;
+ next->e_prev = ep;
+ }
+ else if (cc->c_first || cc->c_last)
+ bug("collcommon_putbefore");
+ else
+ cc->c_first = cc->c_last = ep;
+ collcommon_modified(cc, 1);
+}
+
+static void collcommon_putafter(t_collcommon *cc,
+ t_collelem *ep, t_collelem *prev)
+{
+ if (prev)
+ {
+ ep->e_prev = prev;
+ if (ep->e_next = prev->e_next)
+ ep->e_next->e_prev = ep;
+ else
+ cc->c_last = ep;
+ prev->e_next = ep;
+ }
+ else if (cc->c_first || cc->c_last)
+ bug("collcommon_putafter");
+ else
+ cc->c_first = cc->c_last = ep;
+ collcommon_modified(cc, 1);
+}
+
+/* LATER consider making it faster, if there is a real need.
+ Now called only in the sort routine, once per sort. */
+static void collcommon_swaplinks(t_collcommon *cc,
+ t_collelem *ep1, t_collelem *ep2)
+{
+ if (ep1 != ep2)
+ {
+ t_collelem *prev1 = ep1->e_prev, *prev2 = ep2->e_prev;
+ if (prev1 == ep2)
+ {
+ collcommon_takeout(cc, ep2);
+ collcommon_putafter(cc, ep2, ep1);
+ }
+ else if (prev2 == ep1)
+ {
+ collcommon_takeout(cc, ep1);
+ collcommon_putafter(cc, ep1, ep2);
+ }
+ else if (prev1)
+ {
+ if (prev2)
+ {
+ collcommon_takeout(cc, ep1);
+ collcommon_takeout(cc, ep2);
+ collcommon_putafter(cc, ep1, prev2);
+ collcommon_putafter(cc, ep2, prev1);
+ }
+ else
+ {
+ t_collelem *next2 = ep2->e_next;
+ collcommon_takeout(cc, ep1);
+ collcommon_takeout(cc, ep2);
+ collcommon_putbefore(cc, ep1, next2);
+ collcommon_putafter(cc, ep2, prev1);
+ }
+ }
+ else if (prev2)
+ {
+ t_collelem *next1 = ep1->e_next;
+ collcommon_takeout(cc, ep1);
+ collcommon_takeout(cc, ep2);
+ collcommon_putafter(cc, ep1, prev2);
+ collcommon_putbefore(cc, ep2, next1);
+ }
+ else bug("collcommon_swaplinks");
+ }
+}
+
+static void collcommon_swapkeys(t_collcommon *cc,
+ t_collelem *ep1, t_collelem *ep2)
+{
+ int hasnumkey = ep2->e_hasnumkey, numkey = ep2->e_numkey;
+ t_symbol *symkey = ep2->e_symkey;
+ ep2->e_hasnumkey = ep1->e_hasnumkey;
+ ep2->e_numkey = ep1->e_numkey;
+ ep2->e_symkey = ep1->e_symkey;
+ ep1->e_hasnumkey = hasnumkey;
+ ep1->e_numkey = numkey;
+ ep1->e_symkey = symkey;
+ collcommon_modified(cc, 0);
+}
+
+static void collcommon_changesymkey(t_collcommon *cc,
+ t_collelem *ep, t_symbol *s)
+{
+ ep->e_symkey = s;
+ collcommon_modified(cc, 0);
+}
+
+static void collcommon_renumber(t_collcommon *cc, int startkey)
+{
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ if (ep->e_hasnumkey)
+ ep->e_numkey = startkey++;
+ collcommon_modified(cc, 0);
+}
+
+/* LATER choose a better algo, after coll's storage structures stabilize.
+ Note, that even the simple insertion sort below (n-square) might prove
+ better for dlls, than theoretically efficient algo (nlogn) which requires
+ random access emulation. Avoiding recursion is not a bad idea, too. */
+static void collcommon_sort(t_collcommon *cc, int asc, int ndx)
+{
+ t_collelem *min = cc->c_first;
+ t_collelem *ep;
+ if (min && (ep = min->e_next))
+ {
+ cc->c_loading = 1;
+ /* search for a sentinel element */
+ do
+ if (collelem_less(ep, min, ndx) == asc) min = ep;
+ while (ep = ep->e_next);
+ /* prepend it */
+ collcommon_swaplinks(cc, cc->c_first, min);
+ /* sort */
+ ep = min->e_next->e_next;
+ while (ep)
+ {
+ t_collelem *next = ep->e_next;
+ for (min = ep->e_prev;
+ collelem_less(ep, min, ndx) == asc;
+ min = min->e_prev);
+ if (ep != min->e_next)
+ {
+ collcommon_takeout(cc, ep);
+ collcommon_putafter(cc, ep, min);
+ }
+ ep = next;
+ }
+ cc->c_loading = 0;
+ collcommon_modified(cc, 1);
+ }
+}
+
+static void collcommon_adddata(t_collcommon *cc, t_collelem *ep,
+ int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_atom *ap;
+ int newsize = ep->e_size + ac;
+ if (ep->e_data)
+ ap = resizebytes(ep->e_data,
+ ep->e_size * sizeof(*ap), newsize * sizeof(*ap));
+ else
+ {
+ ep->e_size = 0; /* redundant, hopefully */
+ ap = getbytes(newsize * sizeof(*ap));
+ }
+ ep->e_data = ap;
+ ap += ep->e_size;
+ if (av) while (ac--)
+ *ap++ = *av++;
+ else while (ac--)
+ {
+ SETFLOAT(ap, 0);
+ ap++;
+ }
+ ep->e_size = newsize;
+ collcommon_modified(cc, 0);
+ }
+}
+
+static t_collelem *collcommon_tonumkey(t_collcommon *cc, int numkey,
+ int ac, t_atom *av, int replace)
+{
+ t_collelem *old = collcommon_numkey(cc, numkey), *new;
+ if (old && replace)
+ collcommon_replace(cc, new = old, ac, av, &numkey, 0);
+ else
+ {
+ new = collelem_new(ac, av, &numkey, 0);
+ if (old)
+ {
+ collcommon_putbefore(cc, new, old);
+ do
+ if (old->e_hasnumkey) old->e_numkey++; /* LATER rethink */
+ while (old = old->e_next);
+ }
+ else
+ {
+ int closestkey = 0; /* LATER rethink */
+ t_collelem *closest = 0, *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ {
+ if (ep->e_hasnumkey)
+ {
+ if (numkey >= closestkey && numkey <= ep->e_numkey)
+ {
+ collcommon_putbefore(cc, new, ep);
+ break;
+ }
+ closestkey = ep->e_numkey;
+ }
+ closest = ep;
+ }
+ if (!ep)
+ {
+ if (numkey <= closestkey)
+ collcommon_putbefore(cc, new, closest);
+ else
+ collcommon_putafter(cc, new, closest);
+ }
+ }
+ }
+ return (new);
+}
+
+static t_collelem *collcommon_tosymkey(t_collcommon *cc, t_symbol *symkey,
+ int ac, t_atom *av, int replace)
+{
+ t_collelem *old = collcommon_symkey(cc, symkey), *new;
+ if (old && replace)
+ collcommon_replace(cc, new = old, ac, av, 0, symkey);
+ else
+ collcommon_putafter(cc, new = collelem_new(ac, av, 0, symkey),
+ cc->c_last);
+ return (new);
+}
+
+static int collcommon_fromlist(t_collcommon *cc, int ac, t_atom *av)
+{
+ int hasnumkey = 0, numkey;
+ t_symbol *symkey = 0;
+ int size = 0;
+ t_atom *data = 0;
+ int nlines = 0;
+ cc->c_loading = 1;
+ collcommon_clearall(cc);
+ while (ac--)
+ {
+ if (data)
+ {
+ if (av->a_type == A_SEMI)
+ {
+ t_collelem *ep = collelem_new(size, data,
+ hasnumkey ? &numkey : 0, symkey);
+ collcommon_putafter(cc, ep, cc->c_last);
+ hasnumkey = 0;
+ symkey = 0;
+ data = 0;
+ nlines++;
+ }
+ if (av->a_type == A_COMMA)
+ {
+ /* CHECKED rejecting a comma */
+ collcommon_clearall(cc); /* LATER rethink */
+ cc->c_loading = 0;
+ return (-nlines);
+ }
+ else size++;
+ }
+ else if (av->a_type == A_COMMA)
+ {
+ size = 0;
+ data = av + 1;
+ }
+ else if (av->a_type == A_SYMBOL)
+ symkey = av->a_w.w_symbol;
+ else if (av->a_type == A_FLOAT &&
+ loud_checkint(0, av->a_w.w_float, &numkey, 0))
+ hasnumkey = 1;
+ else
+ {
+ loud_error(0, "coll: bad atom");
+ collcommon_clearall(cc); /* LATER rethink */
+ cc->c_loading = 0;
+ return (-nlines);
+ }
+ av++;
+ }
+ if (data)
+ {
+ loud_error(0, "coll: incomplete");
+ collcommon_clearall(cc); /* LATER rethink */
+ cc->c_loading = 0;
+ return (-nlines);
+ }
+ cc->c_loading = 0;
+ return (nlines);
+}
+
+static int collcommon_frombinbuf(t_collcommon *cc, t_binbuf *bb)
+{
+ return (collcommon_fromlist(cc, binbuf_getnatom(bb), binbuf_getvec(bb)));
+}
+
+static void collcommon_doread(t_collcommon *cc, t_symbol *fn, t_canvas *cv)
+{
+ t_binbuf *bb;
+ int ac;
+ t_atom *av;
+ char buf[MAXPDSTRING];
+ if (!fn && !(fn = cc->c_filename)) /* !fn: 'readagain' */
+ return;
+ if (cv || (cv = cc->c_lastcanvas)) /* !cv: 'read' w/o arg, 'readagain' */
+ canvas_makefilename(cv, fn->s_name, buf, MAXPDSTRING);
+ else
+ {
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ buf[MAXPDSTRING-1] = 0;
+ }
+ if (!cc->c_refs)
+ {
+ /* loading during object creation --
+ avoid binbuf_read()'s complaints, LATER rethink */
+ FILE *fp;
+ char fname[MAXPDSTRING];
+ sys_bashfilename(buf, fname);
+ if (!(fp = fopen(fname, "r")))
+ {
+ loud_warning(&coll_class, "no coll file '%s'", fname);
+ return;
+ }
+ fclose(fp);
+ }
+ bb = binbuf_new();
+ if (binbuf_read(bb, buf, "", 0))
+ loud_error(0, "coll: error reading text file '%s'", fn->s_name);
+ else
+ {
+ int nlines = collcommon_frombinbuf(cc, bb);
+ if (nlines > 0)
+ {
+ t_coll *x;
+ /* LATER consider making this more robust */
+ for (x = cc->c_refs; x; x = x->x_next)
+ outlet_bang(x->x_filebangout);
+ cc->c_lastcanvas = cv;
+ cc->c_filename = fn;
+ post("coll: finished reading %d lines from text file '%s'",
+ nlines, fn->s_name);
+ }
+ else if (nlines < 0)
+ loud_error(0, "coll: error in line %d of text file '%s'",
+ 1 - nlines, fn->s_name);
+ else
+ loud_error(0, "coll: error reading text file '%s'", fn->s_name);
+ if (cc->c_refs)
+ collcommon_modified(cc, 1);
+ }
+ binbuf_free(bb);
+}
+
+static void collcommon_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ collcommon_doread((t_collcommon *)z, fn, 0);
+}
+
+static void collcommon_tobinbuf(t_collcommon *cc, t_binbuf *bb)
+{
+ t_collelem *ep;
+ t_atom at[3];
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ {
+ t_atom *ap = at;
+ int cnt = 1;
+ if (ep->e_hasnumkey)
+ {
+ SETFLOAT(ap, ep->e_numkey);
+ ap++; cnt++;
+ }
+ if (ep->e_symkey)
+ {
+ SETSYMBOL(ap, ep->e_symkey);
+ ap++; cnt++;
+ }
+ SETCOMMA(ap);
+ binbuf_add(bb, cnt, at);
+ binbuf_add(bb, ep->e_size, ep->e_data);
+ binbuf_addsemi(bb);
+ }
+}
+
+static void collcommon_dowrite(t_collcommon *cc, t_symbol *fn, t_canvas *cv)
+{
+ t_binbuf *bb;
+ int ac;
+ t_atom *av;
+ char buf[MAXPDSTRING];
+ if (!fn && !(fn = cc->c_filename)) /* !fn: 'writeagain' */
+ return;
+ if (cv || (cv = cc->c_lastcanvas)) /* !cv: 'write' w/o arg, 'writeagain' */
+ canvas_makefilename(cv, fn->s_name, buf, MAXPDSTRING);
+ else
+ {
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ buf[MAXPDSTRING-1] = 0;
+ }
+ bb = binbuf_new();
+ collcommon_tobinbuf(cc, bb);
+ if (binbuf_write(bb, buf, "", 0))
+ loud_error(0, "coll: error writing text file '%s'", fn->s_name);
+ else
+ {
+ cc->c_lastcanvas = cv;
+ cc->c_filename = fn;
+ }
+ binbuf_free(bb);
+}
+
+static void collcommon_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ collcommon_dowrite((t_collcommon *)z, fn, 0);
+}
+
+static void coll_embedhook(t_pd *z, t_binbuf *bb, t_symbol *bindsym)
+{
+ t_coll *x = (t_coll *)z;
+ t_collcommon *cc = x->x_common;
+ if (cc->c_embedflag)
+ {
+ t_collelem *ep;
+ t_atom at[6];
+ binbuf_addv(bb, "ssii;", bindsym, gensym("flags"), 1, 0);
+ SETSYMBOL(at, bindsym);
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ {
+ t_atom *ap = at + 1;
+ int cnt;
+ if (ep->e_hasnumkey && ep->e_symkey)
+ {
+ SETSYMBOL(ap, gensym("nstore"));
+ ap++;
+ SETSYMBOL(ap, ep->e_symkey);
+ ap++;
+ SETFLOAT(ap, ep->e_numkey);
+ cnt = 4;
+ }
+ else if (ep->e_symkey)
+ {
+ SETSYMBOL(ap, gensym("store"));
+ ap++;
+ SETSYMBOL(ap, ep->e_symkey);
+ cnt = 3;
+ }
+ else
+ {
+ SETFLOAT(ap, ep->e_numkey);
+ cnt = 2;
+ }
+ binbuf_add(bb, cnt, at);
+ binbuf_add(bb, ep->e_size, ep->e_data);
+ binbuf_addsemi(bb);
+ }
+ }
+}
+
+static void collcommon_editorhook(t_pd *z, t_symbol *s, int ac, t_atom *av)
+{
+ int nlines = collcommon_fromlist((t_collcommon *)z, ac, av);
+ if (nlines < 0)
+ loud_error(0, "coll: editing error in line %d", 1 - nlines);
+}
+
+static t_collcommon *coll_checkcommon(t_coll *x)
+{
+ if (x->x_name &&
+ x->x_common != (t_collcommon *)pd_findbyclass(x->x_name,
+ collcommon_class))
+ {
+ bug("coll_checkcommon");
+ return (0);
+ }
+ return (x->x_common);
+}
+
+static void coll_unbind(t_coll *x)
+{
+ /* LATER consider calling coll_checkcommon(x) */
+ t_collcommon *cc = x->x_common;
+ t_coll *prev, *next;
+ if ((prev = cc->c_refs) == x)
+ {
+ if (!(cc->c_refs = x->x_next))
+ {
+ hammerfile_free(cc->c_filehandle);
+ cc->c_loading = 1; /* disable dirty-flag handling, LATER rethink */
+ collcommon_clearall(cc);
+ if (x->x_name) pd_unbind(&cc->c_pd, x->x_name);
+ pd_free(&cc->c_pd);
+ }
+ }
+ else if (prev)
+ {
+ while (next = prev->x_next)
+ {
+ if (next == x)
+ {
+ prev->x_next = next->x_next;
+ break;
+ }
+ prev = next;
+ }
+ }
+ x->x_common = 0;
+ x->x_name = 0;
+ x->x_next = 0;
+}
+
+static void coll_bind(t_coll *x, t_symbol *name)
+{
+ t_collcommon *cc = 0;
+ if (name == &s_)
+ name = 0;
+ else if (name)
+ cc = (t_collcommon *)pd_findbyclass(name, collcommon_class);
+ if (!cc)
+ {
+ cc = (t_collcommon *)pd_new(collcommon_class);
+ cc->c_refs = 0;
+ cc->c_embedflag = 0;
+ cc->c_loading = 0;
+ if (name)
+ {
+ pd_bind(&cc->c_pd, name);
+ /* LATER rethink canvas unpredictability */
+ collcommon_doread(cc, name, x->x_canvas);
+ }
+ else
+ {
+ cc->c_filename = 0;
+ cc->c_lastcanvas = 0;
+ }
+ cc->c_filehandle = hammerfile_new((t_pd *)cc, 0, collcommon_readhook,
+ collcommon_writehook,
+ collcommon_editorhook);
+ }
+ x->x_common = cc;
+ x->x_name = name;
+ x->x_next = cc->c_refs;
+ cc->c_refs = x;
+}
+
+static int coll_rebind(t_coll *x, t_symbol *name)
+{
+ t_collcommon *cc;
+ if (name && name != &s_ &&
+ (cc = (t_collcommon *)pd_findbyclass(name, collcommon_class)))
+ {
+ coll_unbind(x);
+ x->x_common = cc;
+ x->x_name = name;
+ x->x_next = cc->c_refs;
+ cc->c_refs = x;
+ return (1);
+ }
+ else return (0);
+}
+
+static void coll_dooutput(t_coll *x, int ac, t_atom *av)
+{
+ if (ac > 1)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else if (av->a_type == A_SYMBOL)
+ outlet_anything(((t_object *)x)->ob_outlet,
+ av->a_w.w_symbol, ac-1, av+1);
+ }
+ else if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ outlet_symbol(((t_object *)x)->ob_outlet, av->a_w.w_symbol);
+ }
+}
+
+static void coll_keyoutput(t_coll *x, t_collelem *ep)
+{
+ t_collcommon *cc = x->x_common;
+ if (!cc->c_entered++) cc->c_selfmodified = 0;
+ cc->c_relinked = 0;
+ if (ep->e_hasnumkey)
+ outlet_float(x->x_keyout, ep->e_numkey);
+ else if (ep->e_symkey)
+ outlet_symbol(x->x_keyout, ep->e_symkey);
+ else
+ outlet_float(x->x_keyout, 0);
+ if (cc->c_relinked) cc->c_selfmodified = 1;
+ cc->c_entered--;
+}
+
+static t_collelem *coll_findkey(t_coll *x, t_atom *key, t_symbol *mess)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep = 0;
+ if (key->a_type == A_FLOAT)
+ {
+ int numkey;
+ if (loud_checkint((t_pd *)x, key->a_w.w_float, &numkey, mess))
+ ep = collcommon_numkey(cc, numkey);
+ else
+ mess = 0;
+ }
+ else if (key->a_type == A_SYMBOL)
+ ep = collcommon_symkey(cc, key->a_w.w_symbol);
+ else if (mess)
+ {
+ loud_messarg((t_pd *)x, mess);
+ mess = 0;
+ }
+ if (!ep && mess)
+ loud_error((t_pd *)x, "no such key");
+ return (ep);
+}
+
+static t_collelem *coll_tokey(t_coll *x, t_atom *key, int ac, t_atom *av,
+ int replace, t_symbol *mess)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep = 0;
+ if (key->a_type == A_FLOAT)
+ {
+ int numkey;
+ if (loud_checkint((t_pd *)x, key->a_w.w_float, &numkey, mess))
+ ep = collcommon_tonumkey(cc, numkey, ac, av, replace);
+ }
+ else if (key->a_type == A_SYMBOL)
+ ep = collcommon_tosymkey(cc, key->a_w.w_symbol, ac, av, replace);
+ else if (mess)
+ loud_messarg((t_pd *)x, mess);
+ return (ep);
+}
+
+static t_collelem *coll_firsttyped(t_coll *x, int ndx, t_atomtype type)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ if (ep->e_size > ndx && ep->e_data[ndx].a_type == type)
+ return (ep);
+ return (0);
+}
+
+/* the methods */
+
+static void coll_float(t_coll *x, t_float f)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ int numkey;
+ if (loud_checkint((t_pd *)x, f, &numkey, &s_float) &&
+ (ep = collcommon_numkey(cc, numkey)))
+ {
+ coll_keyoutput(x, ep);
+ if (!cc->c_selfmodified || (ep = collcommon_numkey(cc, numkey)))
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ }
+}
+
+static void coll_symbol(t_coll *x, t_symbol *s)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ if (ep = collcommon_symkey(cc, s))
+ {
+ coll_keyoutput(x, ep);
+ if (!cc->c_selfmodified || (ep = collcommon_symkey(cc, s)))
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ }
+}
+
+static void coll_list(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av->a_type == A_FLOAT)
+ coll_tokey(x, av, ac-1, av+1, 1, &s_list);
+ else
+ loud_messarg((t_pd *)x, &s_list);
+}
+
+static void coll_anything(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ coll_symbol(x, s);
+}
+
+static void coll_store(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2)
+ coll_tokey(x, av, ac-1, av+1, 1, s);
+ else
+ loud_messarg((t_pd *)x, s);
+}
+
+static void coll_nstore(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 3)
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ int numkey;
+ if (av->a_type == A_FLOAT && av[1].a_type == A_SYMBOL)
+ {
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
+ {
+ if (ep = collcommon_symkey(cc, av[1].a_w.w_symbol))
+ collcommon_remove(cc, ep);
+ ep = collcommon_tonumkey(cc, numkey, ac-2, av+2, 1);
+ ep->e_symkey = av[1].a_w.w_symbol;
+ }
+ }
+ else if (av->a_type == A_SYMBOL && av[1].a_type == A_FLOAT)
+ {
+ if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &numkey, s))
+ {
+ if (ep = collcommon_numkey(cc, numkey))
+ collcommon_remove(cc, ep);
+ ep = collcommon_tosymkey(cc, av->a_w.w_symbol, ac-2, av+2, 1);
+ ep->e_hasnumkey = 1;
+ ep->e_numkey = numkey;
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_insert(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av->a_type == A_FLOAT)
+ coll_tokey(x, av, ac-1, av+1, 0, s);
+ else
+ loud_messarg((t_pd *)x, s);
+}
+
+static void coll_remove(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_collelem *ep;
+ if (ep = coll_findkey(x, av, s))
+ collcommon_remove(x->x_common, ep);
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_delete(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_collelem *ep;
+ if (ep = coll_findkey(x, av, s))
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ int numkey = ep->e_numkey;
+ t_collelem *next;
+ for (next = ep->e_next; next; next = next->e_next)
+ if (next->e_hasnumkey && next->e_numkey > numkey)
+ next->e_numkey--;
+ }
+ collcommon_remove(x->x_common, ep);
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_assoc(t_coll *x, t_symbol *s, t_floatarg f)
+{
+ int numkey;
+ if (loud_checkint((t_pd *)x, f, &numkey, gensym("assoc")))
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep1, *ep2;
+ if ((ep1 = collcommon_numkey(cc, numkey)) &&
+ ep1->e_symkey != s) /* LATER rethink */
+ {
+ if (ep2 = collcommon_symkey(cc, s))
+ collcommon_remove(cc, ep2);
+ collcommon_changesymkey(cc, ep1, s);
+ }
+ }
+}
+
+static void coll_deassoc(t_coll *x, t_symbol *s, t_floatarg f)
+{
+ int numkey;
+ if (loud_checkint((t_pd *)x, f, &numkey, gensym("deassoc")))
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ if (ep = collcommon_numkey(cc, numkey))
+ collcommon_changesymkey(cc, ep, 0);
+ }
+}
+
+static void coll_subsym(t_coll *x, t_symbol *s1, t_symbol *s2)
+{
+ t_collelem *ep;
+ if (s1 != s2 && (ep = collcommon_symkey(x->x_common, s2)))
+ collcommon_changesymkey(x->x_common, ep, s1);
+}
+
+static void coll_renumber(t_coll *x, t_floatarg f)
+{
+ int startkey;
+ if (loud_checkint((t_pd *)x, f, &startkey, gensym("renumber")))
+ collcommon_renumber(x->x_common, startkey);
+}
+
+static void coll_merge(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2)
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ if (av->a_type == A_FLOAT)
+ {
+ int numkey;
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
+ {
+ if (ep = collcommon_numkey(cc, numkey))
+ collcommon_adddata(cc, ep, ac-1, av+1);
+ else /* LATER consider defining collcommon_toclosest() */
+ collcommon_tonumkey(cc, numkey, ac-1, av+1, 1);
+ }
+ }
+ else if (av->a_type == A_SYMBOL)
+ {
+ if (ep = collcommon_symkey(cc, av->a_w.w_symbol))
+ collcommon_adddata(cc, ep, ac-1, av+1);
+ else
+ {
+ ep = collelem_new(ac-1, av+1, 0, av->a_w.w_symbol);
+ collcommon_putafter(cc, ep, cc->c_last);
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_sub(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_collelem *ep;
+ if (ep = coll_findkey(x, av, s))
+ {
+ t_collcommon *cc = x->x_common;
+ t_atom *key = av++;
+ ac--;
+ while (ac >= 2)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ int ndx;
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &ndx, 0)
+ && ndx >= 1 && ndx <= ep->e_size)
+ ep->e_data[ndx-1] = av[1];
+ }
+ ac -= 2;
+ av += 2;
+ }
+ if (s == gensym("sub"))
+ {
+ coll_keyoutput(x, ep);
+ if (!cc->c_selfmodified || (ep = coll_findkey(x, key, 0)))
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ }
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_sort(t_coll *x, t_floatarg f1, t_floatarg f2)
+{
+ int dir, ndx;
+ if (loud_checkint((t_pd *)x, f1, &dir, gensym("sort")) &&
+ loud_checkint((t_pd *)x, f2, &ndx, gensym("sort")))
+ collcommon_sort(x->x_common, (dir < 0 ? 1 : 0),
+ (ndx < 0 ? -1 : (ndx ? ndx - 1 : 0)));
+}
+
+static void coll_clear(t_coll *x)
+{
+ collcommon_clearall(x->x_common);
+}
+
+/* According to the refman, the data should be swapped, rather than the keys
+ -- easy here, but apparently c74 people have chosen to avoid some effort
+ needed in case of their implementation... */
+static void coll_swap(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac == 2)
+ {
+ t_collelem *ep1, *ep2;
+ if ((ep1 = coll_findkey(x, av, s)) &&
+ (ep2 = coll_findkey(x, av + 1, s)))
+ collcommon_swapkeys(x->x_common, ep1, ep2);
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_next(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ if (!cc->c_ahead && !(cc->c_ahead = cc->c_first))
+ return;
+ coll_keyoutput(x, cc->c_ahead);
+ if (cc->c_selfmodified && !cc->c_ahead)
+ return;
+ coll_dooutput(x, cc->c_ahead->e_size, cc->c_ahead->e_data);
+ /* LATER think why c74 updates the heads prior to sendout
+ (it seems so clumsy...) */
+ if (!cc->c_ahead && !(cc->c_ahead = cc->c_first))
+ {
+ cc->c_back = 0;
+ return;
+ }
+ if (cc->c_ahead->e_next)
+ {
+ cc->c_ahead = cc->c_ahead->e_next;
+ if (!(cc->c_back = cc->c_ahead->e_prev)) /* LATER rethink */
+ cc->c_back = cc->c_last;
+ }
+ else
+ {
+ /* CHECKED wraping */
+ cc->c_back = cc->c_ahead;
+ cc->c_ahead = 0;
+ }
+}
+
+static void coll_prev(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ if (!cc->c_back && !(cc->c_back = cc->c_last))
+ return;
+ coll_keyoutput(x, cc->c_back);
+ if (cc->c_selfmodified && !cc->c_back)
+ return;
+ coll_dooutput(x, cc->c_back->e_size, cc->c_back->e_data);
+ /* LATER think why c74 updates the heads prior to sendout
+ (it seems so clumsy...) */
+ if (!cc->c_back && !(cc->c_back = cc->c_last))
+ {
+ cc->c_ahead = 0;
+ return;
+ }
+ if (cc->c_back->e_prev)
+ {
+ cc->c_back = cc->c_back->e_prev;
+ if (!(cc->c_ahead = cc->c_back->e_next)) /* LATER rethink */
+ cc->c_ahead = cc->c_first;
+ }
+ else
+ {
+ /* CHECKED wraping */
+ cc->c_ahead = cc->c_back;
+ cc->c_back = 0;
+ }
+}
+
+static void coll_end(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ cc->c_back = cc->c_ahead = cc->c_last;
+}
+
+static void coll_goto(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_collelem *ep = coll_findkey(x, av, s);
+ if (ep)
+ x->x_common->c_back = x->x_common->c_ahead = ep;
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_nth(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av[1].a_type == A_FLOAT)
+ {
+ int ndx;
+ t_collelem *ep;
+ if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &ndx, s) &&
+ (ep = coll_findkey(x, av, s)) &&
+ ep->e_size >= ndx)
+ {
+ t_atom *ap = ep->e_data + --ndx;
+ if (ap->a_type == A_FLOAT)
+ outlet_float(((t_object *)x)->ob_outlet, ap->a_w.w_float);
+ else if (ap->a_type == A_SYMBOL)
+ outlet_symbol(((t_object *)x)->ob_outlet, ap->a_w.w_symbol);
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_length(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep = cc->c_first;
+ int result = 0;
+ while (ep) result++, ep = ep->e_next;
+ outlet_float(((t_object *)x)->ob_outlet, result);
+}
+
+static void coll_min(t_coll *x, t_floatarg f)
+{
+ int ndx;
+ if (loud_checkint((t_pd *)x, f, &ndx, gensym("min")))
+ {
+ t_collelem *found;
+ if (ndx <= 0)
+ ndx = 0; /* LATER consider complaining, CHECKME */
+ else ndx--;
+ if (found = coll_firsttyped(x, ndx, A_FLOAT))
+ {
+ t_float result = found->e_data[ndx].a_w.w_float;
+ t_collelem *ep;
+ for (ep = found->e_next; ep; ep = ep->e_next)
+ {
+ if (ep->e_size > ndx &&
+ ep->e_data[ndx].a_type == A_FLOAT &&
+ ep->e_data[ndx].a_w.w_float < result)
+ {
+ found = ep;
+ result = ep->e_data[ndx].a_w.w_float;
+ }
+ }
+ coll_keyoutput(x, found);
+ outlet_float(((t_object *)x)->ob_outlet, result);
+ }
+ }
+}
+
+static void coll_max(t_coll *x, t_floatarg f)
+{
+ int ndx;
+ if (loud_checkint((t_pd *)x, f, &ndx, gensym("max")))
+ {
+ t_collelem *found;
+ if (ndx <= 0)
+ ndx = 0; /* LATER consider complaining, CHECKME */
+ else ndx--;
+ if (found = coll_firsttyped(x, ndx, A_FLOAT))
+ {
+ t_float result = found->e_data[ndx].a_w.w_float;
+ t_collelem *ep;
+ for (ep = found->e_next; ep; ep = ep->e_next)
+ {
+ if (ep->e_size > ndx &&
+ ep->e_data[ndx].a_type == A_FLOAT &&
+ ep->e_data[ndx].a_w.w_float > result)
+ {
+ found = ep;
+ result = ep->e_data[ndx].a_w.w_float;
+ }
+ }
+ coll_keyoutput(x, found);
+ outlet_float(((t_object *)x)->ob_outlet, result);
+ }
+ }
+}
+
+static void coll_refer(t_coll *x, t_symbol *s)
+{
+ if (!coll_rebind(x, s))
+ {
+ /* LATER consider complaining */
+ }
+}
+
+static void coll_flags(t_coll *x, t_float f1, t_float f2)
+{
+ int i1;
+ if (loud_checkint((t_pd *)x, f1, &i1, gensym("flags")))
+ {
+ t_collcommon *cc = x->x_common;
+ cc->c_embedflag = (i1 != 0);
+ }
+}
+
+static void coll_read(t_coll *x, t_symbol *s)
+{
+ t_collcommon *cc = x->x_common;
+ if (s && s != &s_)
+ collcommon_doread(cc, s, x->x_canvas);
+ else
+ hammerpanel_open(cc->c_filehandle);
+}
+
+static void coll_write(t_coll *x, t_symbol *s)
+{
+ t_collcommon *cc = x->x_common;
+ if (s && s != &s_)
+ collcommon_dowrite(cc, s, x->x_canvas);
+ else
+ hammerpanel_save(cc->c_filehandle, 0, 0); /* CHECKME default name */
+}
+
+static void coll_readagain(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ if (cc->c_filename)
+ collcommon_doread(cc, 0, 0);
+ else
+ hammerpanel_open(cc->c_filehandle);
+}
+
+static void coll_writeagain(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ if (cc->c_filename)
+ collcommon_dowrite(cc, 0, 0);
+ else
+ hammerpanel_save(cc->c_filehandle, 0, 0); /* CHECKME default name */
+}
+
+static void coll_filetype(t_coll *x, t_symbol *s)
+{
+ /* dummy */
+}
+
+static void coll_dump(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ {
+ coll_keyoutput(x, ep);
+ if (cc->c_selfmodified)
+ break;
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ }
+ outlet_bang(x->x_dumpbangout);
+}
+
+static void coll_open(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ t_binbuf *bb = binbuf_new();
+ int i, natoms, newline;
+ t_atom *ap;
+ char buf[MAXPDSTRING];
+ /* LATER prepend "coll: " */
+ hammereditor_open(cc->c_filehandle,
+ x->x_name ? x->x_name->s_name : "Untitled");
+ collcommon_tobinbuf(cc, bb);
+ natoms = binbuf_getnatom(bb);
+ ap = binbuf_getvec(bb);
+ newline = 1;
+ while (natoms--)
+ {
+ char *ptr = buf;
+ if (ap->a_type != A_SEMI && ap->a_type != A_COMMA && !newline)
+ *ptr++ = ' ';
+ atom_string(ap, ptr, MAXPDSTRING);
+ if (ap->a_type == A_SEMI)
+ {
+ strcat(buf, "\n");
+ newline = 1;
+ }
+ else newline = 0;
+ hammereditor_append(cc->c_filehandle, buf);
+ ap++;
+ }
+ binbuf_free(bb);
+}
+
+/* asking and storing the changes -- CHECKME close window, and 'wclose' */
+static void coll_wclose(t_coll *x)
+{
+ hammereditor_close(x->x_common->c_filehandle, 1);
+}
+
+static void coll_click(t_coll *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ coll_open(x);
+}
+
+#ifdef COLL_DEBUG
+static void coll_debug(t_coll *x, t_floatarg f)
+{
+ t_collcommon *cc = coll_checkcommon(x);
+ if (cc)
+ {
+ t_coll *x1 = cc->c_refs;
+ t_collelem *ep, *last;
+ int i = 0;
+ while (x1) i++, x1 = x1->x_next;
+ post("refcount %d", i);
+ for (ep = cc->c_first, last = 0; ep; ep = ep->e_next) last = ep;
+ if (last != cc->c_last) bug("coll_debug: last element");
+ collcommon_post(cc);
+ }
+}
+#endif
+
+static void coll_free(t_coll *x)
+{
+ hammerfile_free(x->x_filehandle);
+ coll_unbind(x);
+}
+
+static void *coll_new(t_symbol *s)
+{
+ t_coll *x = (t_coll *)pd_new(coll_class);
+ x->x_canvas = canvas_getcurrent();
+ outlet_new((t_object *)x, &s_);
+ x->x_keyout = outlet_new((t_object *)x, &s_);
+ x->x_filebangout = outlet_new((t_object *)x, &s_bang);
+ x->x_dumpbangout = outlet_new((t_object *)x, &s_bang);
+ x->x_filehandle = hammerfile_new((t_pd *)x, coll_embedhook, 0, 0, 0);
+ coll_bind(x, s);
+ return (x);
+}
+
+void coll_setup(void)
+{
+ coll_class = class_new(gensym("coll"),
+ (t_newmethod)coll_new,
+ (t_method)coll_free,
+ sizeof(t_coll), 0, A_DEFSYM, 0);
+ class_addbang(coll_class, coll_next);
+ class_addfloat(coll_class, coll_float);
+ class_addsymbol(coll_class, coll_symbol);
+ class_addlist(coll_class, coll_list);
+ class_addanything(coll_class, coll_anything);
+ class_addmethod(coll_class, (t_method)coll_store,
+ gensym("store"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_nstore,
+ gensym("nstore"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_insert,
+ gensym("insert"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_remove,
+ gensym("remove"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_delete,
+ gensym("delete"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_assoc,
+ gensym("assoc"), A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_deassoc,
+ gensym("deassoc"), A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_subsym,
+ gensym("subsym"), A_SYMBOL, A_SYMBOL, 0);
+ class_addmethod(coll_class, (t_method)coll_renumber,
+ gensym("renumber"), A_DEFFLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_merge,
+ gensym("merge"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_sub,
+ gensym("sub"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_sub,
+ gensym("nsub"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_clear,
+ gensym("clear"), 0);
+ class_addmethod(coll_class, (t_method)coll_sort,
+ gensym("sort"), A_FLOAT, A_DEFFLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_swap,
+ gensym("swap"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_next,
+ gensym("next"), 0);
+ class_addmethod(coll_class, (t_method)coll_prev,
+ gensym("prev"), 0);
+ class_addmethod(coll_class, (t_method)coll_end,
+ gensym("end"), 0);
+ class_addmethod(coll_class, (t_method)coll_goto,
+ gensym("goto"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_nth,
+ gensym("nth"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_length,
+ gensym("length"), 0);
+ class_addmethod(coll_class, (t_method)coll_min,
+ gensym("min"), A_DEFFLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_max,
+ gensym("max"), A_DEFFLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_refer,
+ gensym("refer"), A_SYMBOL, 0);
+ class_addmethod(coll_class, (t_method)coll_flags,
+ gensym("flags"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_read,
+ gensym("read"), A_DEFSYM, 0);
+ class_addmethod(coll_class, (t_method)coll_write,
+ gensym("write"), A_DEFSYM, 0);
+ class_addmethod(coll_class, (t_method)coll_readagain,
+ gensym("readagain"), 0);
+ class_addmethod(coll_class, (t_method)coll_writeagain,
+ gensym("writeagain"), 0);
+ class_addmethod(coll_class, (t_method)coll_filetype,
+ gensym("filetype"), A_SYMBOL, 0);
+ class_addmethod(coll_class, (t_method)coll_dump,
+ gensym("dump"), 0);
+ class_addmethod(coll_class, (t_method)coll_open,
+ gensym("open"), 0);
+ class_addmethod(coll_class, (t_method)coll_wclose,
+ gensym("wclose"), 0);
+ class_addmethod(coll_class, (t_method)coll_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+#ifdef COLL_DEBUG
+ class_addmethod(coll_class, (t_method)coll_debug,
+ gensym("debug"), A_DEFFLOAT, 0);
+#endif
+ hammerfile_setup(coll_class, 1);
+ collcommon_class = class_new(gensym("coll"), 0, 0,
+ sizeof(t_collcommon), CLASS_PD, 0);
+ /* this call is a nop (collcommon does not embed, and the hammerfile
+ class itself has been already set up above), but it is better to
+ have it around, just in case... */
+ hammerfile_setup(collcommon_class, 0);
+}
diff --git a/cyclone/hammer/comment.c b/cyclone/hammer/comment.c
new file mode 100644
index 0000000..e5cd5ab
--- /dev/null
+++ b/cyclone/hammer/comment.c
@@ -0,0 +1,835 @@
+/* Copyright (c) 2002-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. */
+
+/* FIXME creation lag (X-specific) */
+/* LATER think about pushing text to the text editor (ctrl-t)
+ -- not easy, because we are not 'textedfor' */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+
+/* our proxy of the text_class (not in the API), LATER do not cheat */
+static t_class *makeshift_class;
+
+//#define COMMENT_DEBUG
+
+#define COMMENT_LMARGIN 1
+#define COMMENT_RMARGIN 1
+#define COMMENT_TMARGIN 2
+#define COMMENT_BMARGIN 2
+#define COMMENT_MINWIDTH 8
+#define COMMENT_HANDLEWIDTH 8
+#define COMMENT_OUTBUFSIZE 1000
+
+typedef struct _comment
+{
+ t_object x_ob;
+ t_glist *x_glist;
+ t_canvas *x_canvas; /* also an 'isvised' flag */
+ t_symbol *x_bindsym;
+ char x_tag[32];
+ char x_texttag[32];
+ char x_outlinetag[32];
+ t_clock *x_transclock;
+ t_binbuf *x_binbuf;
+ char *x_textbuf;
+ int x_textbufsize;
+ int x_pixwidth;
+ int x_bbset;
+ int x_bbpending;
+ int x_x1;
+ int x_y1;
+ int x_x2;
+ int x_y2;
+ int x_newx2;
+ int x_dragon;
+ int x_fontsize; /* requested size */
+ t_symbol *x_fontfamily; /* requested family */
+ int x_fontprops; /* LATER pack weight and slant */
+ t_symbol *x_encoding; /* requested encoding */
+ unsigned char x_red;
+ unsigned char x_green;
+ unsigned char x_blue;
+ char x_color[8];
+ int x_selstart;
+ int x_selend;
+ int x_active;
+ int x_ready;
+} t_comment;
+
+static t_class *comment_class;
+static t_class *commentsink_class;
+
+static t_pd *commentsink = 0;
+
+static void comment_draw(t_comment *x)
+{
+ char buf[COMMENT_OUTBUFSIZE], *outbuf, *outp;
+ int cvid = (int)x->x_canvas;
+ int reqsize = x->x_textbufsize + 350; /* FIXME estimation */
+ if (reqsize > COMMENT_OUTBUFSIZE)
+ {
+#ifdef COMMENT_DEBUG
+ post("allocating %d outbuf bytes", reqsize);
+#endif
+ if (!(outbuf = getbytes(reqsize)))
+ return;
+ }
+ else outbuf = buf;
+ outp = outbuf;
+ if (x->x_encoding)
+ sprintf(outp, "set tt [comment_entext %s {%.*s}]\n",
+ x->x_encoding->s_name, x->x_textbufsize, x->x_textbuf);
+ else
+ sprintf(outp, "set tt {%.*s}\n", x->x_textbufsize, x->x_textbuf);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c create text %f %f -text $tt \
+ -tags {%s %s} -font {%s %d} -fill %s", cvid,
+ (float)(text_xpix((t_text *)x, x->x_glist) + COMMENT_LMARGIN),
+ (float)(text_ypix((t_text *)x, x->x_glist) + COMMENT_TMARGIN),
+ x->x_texttag, x->x_tag, x->x_fontfamily->s_name, x->x_fontsize,
+ (glist_isselected(x->x_glist, &x->x_glist->gl_gobj) ?
+ "blue" : x->x_color));
+ outp += strlen(outp);
+ if (x->x_pixwidth)
+ sprintf(outp, " -width %d -anchor nw\n", x->x_pixwidth);
+ else
+ strcpy(outp, " -anchor nw\n");
+ outp += strlen(outp);
+ sprintf(outp, "comment_bbox %s .x%x.c %s\n",
+ x->x_bindsym->s_name, cvid, x->x_texttag);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c bind %s <Button> {comment_click %s %%W %%x %%y %s}\n",
+ cvid, x->x_texttag, x->x_bindsym->s_name, x->x_texttag);
+ x->x_bbpending = 1;
+ sys_gui(outbuf);
+ if (outbuf != buf) freebytes(outbuf, reqsize);
+}
+
+static void comment_update(t_comment *x)
+{
+ char buf[COMMENT_OUTBUFSIZE], *outbuf, *outp;
+ int cvid = (int)x->x_canvas;
+ int reqsize = x->x_textbufsize + 250; /* FIXME estimation */
+ if (reqsize > COMMENT_OUTBUFSIZE)
+ {
+#ifdef COMMENT_DEBUG
+ post("allocating %d outbuf bytes", reqsize);
+#endif
+ if (!(outbuf = getbytes(reqsize)))
+ return;
+ }
+ else outbuf = buf;
+ outp = outbuf;
+ if (x->x_encoding)
+ sprintf(outp, "set tt [comment_entext %s {%.*s}]\n",
+ x->x_encoding->s_name, x->x_textbufsize, x->x_textbuf);
+ else
+ sprintf(outp, "set tt {%.*s}\n", x->x_textbufsize, x->x_textbuf);
+ outp += strlen(outp);
+ if (x->x_pixwidth)
+ sprintf(outp, ".x%x.c itemconfig %s -text $tt -width %d\n",
+ cvid, x->x_texttag, x->x_pixwidth);
+ else
+ sprintf(outp, ".x%x.c itemconfig %s -text $tt\n", cvid, x->x_texttag);
+ outp += strlen(outp);
+ if (x->x_active)
+ {
+ if (x->x_selend > x->x_selstart)
+ {
+ sprintf(outp, ".x%x.c select from %s %d\n",
+ cvid, x->x_texttag, x->x_selstart);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c select to %s %d\n",
+ cvid, x->x_texttag, x->x_selend);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c focus {}\n", cvid);
+ }
+ else
+ {
+ sprintf(outp, ".x%x.c select clear\n", cvid);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c icursor %s %d\n",
+ cvid, x->x_texttag, x->x_selstart);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c focus %s\n", cvid, x->x_texttag);
+ }
+ outp += strlen(outp);
+ }
+ sprintf(outp, "comment_bbox %s .x%x.c %s\n",
+ x->x_bindsym->s_name, cvid, x->x_texttag);
+ x->x_bbpending = 1;
+ sys_gui(outbuf);
+ if (outbuf != buf) freebytes(outbuf, reqsize);
+}
+
+static void comment_validate(t_comment *x, t_glist *glist)
+{
+ if (!x->x_ready)
+ {
+ t_text *t = (t_text *)x;
+ binbuf_free(t->te_binbuf);
+ t->te_binbuf = x->x_binbuf;
+ if (x->x_textbuf) freebytes(x->x_textbuf, x->x_textbufsize);
+ binbuf_gettext(x->x_binbuf, &x->x_textbuf, &x->x_textbufsize);
+ x->x_ready = 1;
+#ifdef COMMENT_DEBUG
+ post("validation done");
+#endif
+ }
+ if (glist)
+ {
+ if (glist != x->x_glist)
+ {
+ bug("comment_getcanvas");
+ x->x_glist = glist;
+ }
+ x->x_canvas = glist_getcanvas(glist);
+ }
+}
+
+static void comment_grabbedkey(void *z, t_floatarg f)
+{
+ /* LATER think about replacing #key binding/comment_float() with grabbing */
+}
+
+static void comment_dograb(t_comment *x)
+{
+ /* LATER investigate the grabbing feature.
+ Here we use it just to prevent backspace from erasing entire text.
+ This has to be done also when we are already active, because
+ after being clicked at we have lost our previous grab. */
+ glist_grab(x->x_glist, (t_gobj *)x, 0, comment_grabbedkey, 0, 0);
+}
+
+static void comment__bboxhook(t_comment *x, t_symbol *bindsym,
+ t_floatarg x1, t_floatarg y1,
+ t_floatarg x2, t_floatarg y2)
+{
+#ifdef COMMENT_DEBUG
+ post("bbox %g %g %g %g", x1, y1, x2, y2);
+#endif
+ x->x_x1 = x1;
+ x->x_y1 = y1;
+ x->x_x2 = x2;
+ x->x_y2 = y2;
+ x->x_bbset = 1;
+ x->x_bbpending = 0;
+}
+
+static void comment__clickhook(t_comment *x, t_symbol *s, int ac, t_atom *av)
+{
+ int xx, yy, ndx;
+ if (ac == 8 && av->a_type == A_SYMBOL
+ && av[1].a_type == A_FLOAT && av[2].a_type == A_FLOAT
+ && av[3].a_type == A_FLOAT
+ && av[4].a_type == A_FLOAT && av[5].a_type == A_FLOAT
+ && av[6].a_type == A_FLOAT && av[7].a_type == A_FLOAT)
+ {
+ xx = (int)av[1].a_w.w_float;
+ yy = (int)av[2].a_w.w_float;
+ ndx = (int)av[3].a_w.w_float;
+ comment__bboxhook(x, av->a_w.w_symbol,
+ av[4].a_w.w_float, av[5].a_w.w_float,
+ av[6].a_w.w_float, av[7].a_w.w_float);
+ }
+ else
+ {
+ bug("comment__clickhook");
+ return;
+ }
+ if (x->x_glist->gl_edit)
+ {
+ if (x->x_active)
+ {
+ if (ndx >= 0 && ndx < x->x_textbufsize)
+ {
+ /* set selection, LATER shift-click and drag */
+ x->x_selstart = x->x_selend = ndx;
+ comment_dograb(x);
+ comment_update(x);
+ }
+ }
+ else if (xx > x->x_x2 - COMMENT_HANDLEWIDTH)
+ {
+ /* start resizing */
+ char buf[COMMENT_OUTBUFSIZE], *outp = buf;
+ int cvid = (int)x->x_canvas;
+ sprintf(outp, ".x%x.c bind %s <ButtonRelease> \
+ {pd [concat %s _release %s \\;]}\n", cvid, x->x_texttag,
+ x->x_bindsym->s_name, x->x_bindsym->s_name);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c bind %s <Motion> \
+ {pd [concat %s _motion %s %%x %%y \\;]}\n", cvid, x->x_texttag,
+ x->x_bindsym->s_name, x->x_bindsym->s_name);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c create rectangle %d %d %d %d -outline blue \
+ -tags {%s %s}\n",
+ cvid, x->x_x1, x->x_y1, x->x_x2, x->x_y2,
+ x->x_outlinetag, x->x_tag);
+ sys_gui(buf);
+ x->x_newx2 = x->x_x2;
+ x->x_dragon = 1;
+ }
+ }
+}
+
+static void comment__releasehook(t_comment *x, t_symbol *bindsym)
+{
+ int cvid = (int)x->x_canvas;
+ sys_vgui(".x%x.c bind %s <ButtonRelease> {}\n", cvid, x->x_texttag);
+ sys_vgui(".x%x.c bind %s <Motion> {}\n", cvid, x->x_texttag);
+ sys_vgui(".x%x.c delete %s\n", cvid, x->x_outlinetag);
+ x->x_dragon = 0;
+ if (x->x_newx2 != x->x_x2)
+ {
+ x->x_pixwidth = x->x_newx2 - x->x_x1;
+ x->x_x2 = x->x_newx2;
+ comment_update(x);
+ }
+}
+
+static void comment__motionhook(t_comment *x, t_symbol *bindsym,
+ t_floatarg xx, t_floatarg yy)
+{
+ int cvid = (int)x->x_canvas;
+ if (xx > x->x_x1 + COMMENT_MINWIDTH)
+ sys_vgui(".x%x.c coords %s %d %d %d %d\n",
+ cvid, x->x_outlinetag,
+ x->x_x1, x->x_y1, x->x_newx2 = xx, x->x_y2);
+}
+
+static void commentsink__bboxhook(t_pd *x, t_symbol *bindsym,
+ t_floatarg x1, t_floatarg y1,
+ t_floatarg x2, t_floatarg y2)
+{
+ if (bindsym->s_thing == x) /* is the comment gone? */
+ {
+ pd_unbind(x, bindsym); /* if so, no need for this binding anymore */
+#ifdef COMMENT_DEBUG
+ post("sink: %s unbound", bindsym->s_name);
+#endif
+ }
+}
+
+static void commentsink_anything(t_pd *x, t_symbol *s, int ac, t_atom *av)
+{
+ /* nop */
+}
+
+static void comment_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_comment *x = (t_comment *)z;
+ if (!glist->gl_havewindow)
+ {
+ /* LATER revisit gop behaviour. Currently text_shouldvis() returns
+ true if we are on parent. Here we return a null rectangle,
+ so that any true ui object is accessible, even if it happens
+ to be covered by a comment. */
+ *xp1 = *yp1 = *xp2 = *yp2 = 0;
+ return;
+ }
+ if (x->x_bbset)
+ {
+ /* LATER think about margins */
+ *xp1 = x->x_x1;
+ *yp1 = x->x_y1;
+ *xp2 = x->x_x2;
+ *yp2 = x->x_y2;
+ }
+ else
+ {
+ int width, height;
+ float x1, y1, x2, y2;
+ comment_validate(x, glist);
+ if ((width = x->x_pixwidth) < 1)
+ /* FIXME estimation */
+ width = x->x_fontsize * x->x_textbufsize;
+ width += COMMENT_LMARGIN + COMMENT_RMARGIN;
+ /* FIXME estimation */
+ height = x->x_fontsize + COMMENT_TMARGIN + COMMENT_BMARGIN;
+ x1 = text_xpix((t_text *)x, glist);
+ y1 = text_ypix((t_text *)x, glist) + 1; /* LATER revisit */
+ x2 = x1 + width;
+ y2 = y1 + height - 2; /* LATER revisit */
+#ifdef COMMENT_DEBUG
+ post("estimated rectangle: %g %g %g %g", x1, y1, x2, y2);
+#endif
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+ }
+}
+
+static void comment_displace(t_gobj *z, t_glist *glist, int dx, int dy)
+{
+ t_comment *x = (t_comment *)z;
+ if (!x->x_active && !x->x_dragon) /* LATER rethink */
+ {
+ t_text *t = (t_text *)z;
+ comment_validate(x, glist);
+ t->te_xpix += dx;
+ t->te_ypix += dy;
+ if (x->x_bbset)
+ {
+ x->x_x1 += dx;
+ x->x_y1 += dy;
+ x->x_x2 += dx;
+ x->x_y2 += dy;
+ }
+ if (glist_isvisible(glist))
+ sys_vgui(".x%x.c move %s %d %d\n", x->x_canvas, x->x_tag, dx, dy);
+ }
+}
+
+static void comment_activate(t_gobj *z, t_glist *glist, int state)
+{
+ t_comment *x = (t_comment *)z;
+ comment_validate(x, glist);
+ if (state)
+ {
+ comment_dograb(x);
+ if (x->x_active)
+ return;
+ sys_vgui(".x%x.c focus %s\n", x->x_canvas, x->x_texttag);
+ x->x_selstart = 0;
+ x->x_selend = x->x_textbufsize;
+ x->x_active = 1;
+ pd_bind((t_pd *)x, gensym("#key"));
+ pd_bind((t_pd *)x, gensym("#keyname"));
+ }
+ else
+ {
+ if (!x->x_active)
+ return;
+ pd_unbind((t_pd *)x, gensym("#key"));
+ pd_unbind((t_pd *)x, gensym("#keyname"));
+ sys_vgui("selection clear .x%x.c\n", x->x_canvas);
+ sys_vgui(".x%x.c focus {}\n", x->x_canvas);
+ x->x_active = 0;
+ }
+ comment_update(x);
+}
+
+static void comment_select(t_gobj *z, t_glist *glist, int state)
+{
+ t_comment *x = (t_comment *)z;
+ comment_validate(x, glist);
+ if (!state && x->x_active) comment_activate(z, glist, 0);
+ sys_vgui(".x%x.c itemconfigure %s -fill %s\n", x->x_canvas,
+ x->x_texttag, (state ? "blue" : x->x_color));
+ /* A regular rtext should now set 'canvas_editing' variable to its canvas,
+ but we do not do that, because we get the keys through a global binding
+ to "#key" (and because 'canvas_editing' is not exported). */
+}
+
+static void comment_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_comment *x = (t_comment *)z;
+ t_text *t = (t_text *)z;
+ comment_validate(x, glist);
+ if (vis)
+ {
+ /* We do not need no rtext -- we are never 'textedfor' (thus
+ avoiding rtext calls). Creating an rtext has no other purpose
+ than complying to a Pd's assumption about every visible object
+ having an rtext (thus preventing canvas_doclick() from sending
+ garbage warnings). LATER revisit. */
+#ifndef PD_MINOR_VERSION
+ rtext_new(glist, t, glist->gl_editor->e_rtext, 0);
+#endif
+ if (glist->gl_havewindow)
+ comment_draw(x);
+ }
+ else
+ {
+#ifndef PD_MINOR_VERSION
+ t_rtext *rt = glist_findrtext(glist, t);
+ if (rt) rtext_free(rt);
+#endif
+ /* FIXME should we test for having a window? */
+#ifdef COMMENT_DEBUG
+ post("deleting...");
+#endif
+ sys_vgui(".x%x.c delete %s\n", x->x_canvas, x->x_tag);
+ }
+}
+
+static void comment_save(t_gobj *z, t_binbuf *b)
+{
+ t_comment *x = (t_comment *)z;
+ t_text *t = (t_text *)x;
+ comment_validate(x, 0);
+ binbuf_addv(b, "ssiisiissiiii", gensym("#X"), gensym("obj"),
+ (int)t->te_xpix, (int)t->te_ypix,
+ gensym("comment"),
+ x->x_pixwidth, x->x_fontsize, x->x_fontfamily,
+ (x->x_encoding ? x->x_encoding : gensym("?")),
+ x->x_fontprops,
+ (int)x->x_red, (int)x->x_green, (int)x->x_blue);
+ binbuf_addbinbuf(b, t->te_binbuf);
+ binbuf_addv(b, ";");
+}
+
+static t_widgetbehavior comment_widgetbehavior =
+{
+ comment_getrect,
+ comment_displace,
+ comment_select,
+ comment_activate,
+ 0,
+ comment_vis,
+ 0,
+ comment_save,
+ 0,
+};
+
+/* this fires if a transform request was sent to a symbol we are bound to */
+static void comment_transtick(t_comment *x)
+{
+ glist_delete(x->x_glist, (t_gobj *)x);
+}
+
+/* what follows is basically the original code of rtext_key() */
+
+static void comment_float(t_comment *x, t_float f)
+{
+ if (x->x_active)
+ {
+ int keynum = (int)f;
+ if (keynum)
+ {
+ int i, newsize, ndel;
+ char *s1, *s2;
+ int n = keynum;
+ if (n == '\r') n = '\n';
+ if (n == '\b')
+ {
+ if ((!x->x_selstart) && (x->x_selend == x->x_textbufsize))
+ {
+ /* LATER delete the box... this causes reentrancy
+ problems now. */
+ /* glist_delete(x->x_glist, &x->x_text->te_g); */
+ return;
+ }
+ else if (x->x_selstart && (x->x_selstart == x->x_selend))
+ x->x_selstart--;
+ }
+ ndel = x->x_selend - x->x_selstart;
+ for (i = x->x_selend; i < x->x_textbufsize; i++)
+ x->x_textbuf[i- ndel] = x->x_textbuf[i];
+ newsize = x->x_textbufsize - ndel;
+ x->x_textbuf = resizebytes(x->x_textbuf, x->x_textbufsize, newsize);
+ x->x_textbufsize = newsize;
+
+ if (n == '\n' || !iscntrl(n))
+ {
+#ifdef COMMENT_DEBUG
+ post("%d accepted", n);
+#endif
+ newsize = x->x_textbufsize+1;
+ x->x_textbuf = resizebytes(x->x_textbuf,
+ x->x_textbufsize, newsize);
+ for (i = x->x_textbufsize; i > x->x_selstart; i--)
+ x->x_textbuf[i] = x->x_textbuf[i-1];
+ x->x_textbuf[x->x_selstart] = n;
+ x->x_textbufsize = newsize;
+ x->x_selstart = x->x_selstart + 1;
+ }
+#ifdef COMMENT_DEBUG
+ else post("%d rejected", n);
+#endif
+ x->x_selend = x->x_selstart;
+ x->x_glist->gl_editor->e_textdirty = 1;
+ binbuf_text(x->x_binbuf, x->x_textbuf, x->x_textbufsize);
+ comment_update(x);
+ }
+ }
+ else bug("comment_float");
+}
+
+static void comment_list(t_comment *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!x->x_active)
+ bug("comment_list");
+ else if (ac > 1 && av->a_type == A_FLOAT && (int)av->a_w.w_float
+ && av[1].a_type == A_SYMBOL)
+ {
+ t_symbol *keysym = av[1].a_w.w_symbol;
+ if (!strcmp(keysym->s_name, "Right"))
+ {
+ if (x->x_selend == x->x_selstart &&
+ x->x_selstart < x->x_textbufsize)
+ x->x_selend = x->x_selstart = x->x_selstart + 1;
+ else
+ x->x_selstart = x->x_selend;
+ }
+ else if (!strcmp(keysym->s_name, "Left"))
+ {
+ if (x->x_selend == x->x_selstart && x->x_selstart > 0)
+ x->x_selend = x->x_selstart = x->x_selstart - 1;
+ else
+ x->x_selend = x->x_selstart;
+ }
+ /* this should be improved... life's too short */
+ else if (!strcmp(keysym->s_name, "Up"))
+ {
+ if (x->x_selstart)
+ x->x_selstart--;
+ while (x->x_selstart > 0 && x->x_textbuf[x->x_selstart] != '\n')
+ x->x_selstart--;
+ x->x_selend = x->x_selstart;
+ }
+ else if (!strcmp(keysym->s_name, "Down"))
+ {
+ while (x->x_selend < x->x_textbufsize &&
+ x->x_textbuf[x->x_selend] != '\n')
+ x->x_selend++;
+ if (x->x_selend < x->x_textbufsize)
+ x->x_selend++;
+ x->x_selstart = x->x_selend;
+ }
+ else if (!strcmp(keysym->s_name, "F4"))
+ {
+ t_text *newt, *oldt = (t_text *)x;
+ t_binbuf *bb = binbuf_new();
+ int ac = binbuf_getnatom(x->x_binbuf);
+ binbuf_addv(bb, "siissiiii", gensym("comment"), x->x_pixwidth,
+ x->x_fontsize, x->x_fontfamily,
+ (x->x_encoding ? x->x_encoding : gensym("?")),
+ x->x_fontprops,
+ (int)x->x_red, (int)x->x_green, (int)x->x_blue);
+ binbuf_add(bb, ac, binbuf_getvec(x->x_binbuf));
+ canvas_setcurrent(x->x_glist);
+ newt = (t_text *)pd_new(makeshift_class);
+ newt->te_width = 0;
+ newt->te_type = T_OBJECT;
+ newt->te_binbuf = bb;
+ newt->te_xpix = oldt->te_xpix;
+ newt->te_ypix = oldt->te_ypix;
+ glist_add(x->x_glist, &newt->te_g);
+ glist_noselect(x->x_glist);
+ glist_select(x->x_glist, &newt->te_g);
+ gobj_activate(&newt->te_g, x->x_glist, 1);
+ x->x_glist->gl_editor->e_textdirty = 1; /* force evaluation */
+ canvas_unsetcurrent(x->x_glist);
+ canvas_dirty(x->x_glist, 1);
+ clock_delay(x->x_transclock, 0); /* LATER rethink */
+ return;
+ }
+ else if (!strcmp(keysym->s_name, "F5"))
+ {
+ t_text *t = (t_text *)x;
+ t_binbuf *bb = binbuf_new();
+ int ac = binbuf_getnatom(x->x_binbuf);
+ binbuf_addv(bb, "ii", (int)t->te_xpix + 5, (int)t->te_ypix + 5);
+ binbuf_add(bb, ac, binbuf_getvec(x->x_binbuf));
+ canvas_setcurrent(x->x_glist);
+ typedmess((t_pd *)x->x_glist, gensym("text"),
+ ac + 2, binbuf_getvec(bb));
+ canvas_unsetcurrent(x->x_glist);
+ canvas_dirty(x->x_glist, 1);
+ binbuf_free(bb);
+ return;
+ }
+ else return;
+ comment_update(x);
+ }
+}
+
+static void comment_free(t_comment *x)
+{
+ if (x->x_active)
+ {
+ bug("comment_free");
+ pd_unbind((t_pd *)x, gensym("#key"));
+ pd_unbind((t_pd *)x, gensym("#keyname"));
+ }
+ if (x->x_transclock) clock_free(x->x_transclock);
+ if (x->x_bindsym)
+ {
+ pd_unbind((t_pd *)x, x->x_bindsym);
+ if (!x->x_bbpending)
+ pd_unbind(commentsink, x->x_bindsym);
+ }
+ if (x->x_binbuf && !x->x_ready) binbuf_free(x->x_binbuf);
+ if (x->x_textbuf) freebytes(x->x_textbuf, x->x_textbufsize);
+}
+
+/* the arguments in the full form of a creation message are:
+
+ width fontsize fontfamily encoding fontprops red green blue text...
+
+ For comments typed into an object box, the text part begins with
+ the first atom satisfying one of the following conditions (skipped
+ arguments get default values):
+
+ . having a different type than the corresponding argument of the
+ full form
+
+ . being preceded with a dot atom ('.') put in place of a symbol
+ argument (fontfamily or encoding)
+
+ . being the 10th atom in a box
+
+ The question mark atom ('?') may be used to supply a default fontfamily
+ or an empty encoding value.
+*/
+
+static void *comment_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_comment *x = (t_comment *)pd_new(comment_class);
+ t_text *t = (t_text *)x;
+ t_atom at;
+ char buf[32];
+ t->te_type = T_TEXT;
+ x->x_glist = canvas_getcurrent();
+ x->x_canvas = 0;
+ sprintf(x->x_tag, "all%x", (int)x);
+ sprintf(x->x_texttag, "t%x", (int)x);
+ sprintf(x->x_outlinetag, "h%x", (int)x);
+ x->x_pixwidth = 0;
+ x->x_fontsize = 0;
+ x->x_fontfamily = 0;
+ x->x_encoding = 0;
+ x->x_fontprops = 0;
+ x->x_red = 0;
+ x->x_green = 0;
+ x->x_blue = 0;
+
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_pixwidth = (int)av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_fontsize = (int)av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ if (av->a_w.w_symbol == gensym("."))
+ {
+ ac--; av++;
+ goto textpart;
+ }
+ else if (av->a_w.w_symbol != gensym("?"))
+ x->x_fontfamily = av->a_w.w_symbol;
+ ac--; av++;
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ if (av->a_w.w_symbol == gensym("."))
+ {
+ ac--; av++;
+ goto textpart;
+ }
+ else if (av->a_w.w_symbol != gensym("?"))
+ x->x_encoding = av->a_w.w_symbol;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_fontprops = (int)av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_red = (unsigned char)av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_green = (unsigned char)av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_blue = (unsigned char)av->a_w.w_float;
+ ac--; av++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+textpart:
+ if (x->x_fontsize < 1)
+ x->x_fontsize = glist_getfont(x->x_glist);
+ if (!x->x_fontfamily)
+ x->x_fontfamily = gensym("helvetica");
+ sprintf(x->x_color, "#%2.2x%2.2x%2.2x", x->x_red, x->x_green, x->x_blue);
+
+ x->x_binbuf = binbuf_new();
+ if (ac) binbuf_restore(x->x_binbuf, ac, av);
+ else
+ {
+ SETSYMBOL(&at, gensym("comment"));
+ binbuf_restore(x->x_binbuf, 1, &at);
+ }
+ x->x_textbuf = 0;
+ x->x_textbufsize = 0;
+ x->x_transclock = clock_new(x, (t_method)comment_transtick);
+ x->x_bbset = 0;
+ x->x_bbpending = 0;
+ sprintf(buf, "miXed%x", (int)x);
+ x->x_bindsym = gensym(buf);
+ pd_bind((t_pd *)x, x->x_bindsym);
+ if (!commentsink)
+ commentsink = pd_new(commentsink_class);
+ pd_bind(commentsink, x->x_bindsym);
+ x->x_ready = 0;
+ x->x_dragon = 0;
+ return (x);
+}
+
+void comment_setup(void)
+{
+ comment_class = class_new(gensym("comment"),
+ (t_newmethod)comment_new,
+ (t_method)comment_free,
+ sizeof(t_comment),
+ CLASS_NOINLET | CLASS_PATCHABLE,
+ A_GIMME, 0);
+ class_addfloat(comment_class, comment_float);
+ class_addlist(comment_class, comment_list);
+ class_addmethod(comment_class, (t_method)comment__bboxhook,
+ gensym("_bbox"),
+ A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(comment_class, (t_method)comment__clickhook,
+ gensym("_click"), A_GIMME, 0);
+ class_addmethod(comment_class, (t_method)comment__releasehook,
+ gensym("_release"), A_SYMBOL, 0);
+ class_addmethod(comment_class, (t_method)comment__motionhook,
+ gensym("_motion"), A_SYMBOL, A_FLOAT, A_FLOAT, 0);
+ class_setwidget(comment_class, &comment_widgetbehavior);
+
+ makeshift_class = class_new(gensym("text"), 0, 0,
+ sizeof(t_text),
+ CLASS_NOINLET | CLASS_PATCHABLE, 0);
+
+ commentsink_class = class_new(gensym("_commentsink"), 0, 0,
+ sizeof(t_pd), CLASS_PD, 0);
+ class_addanything(commentsink_class, commentsink_anything);
+ class_addmethod(commentsink_class, (t_method)commentsink__bboxhook,
+ gensym("_bbox"),
+ A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+
+ sys_gui("proc comment_bbox {target cvname tag} {\n\
+ pd $target _bbox $target [$cvname bbox $tag]\\;}\n");
+
+ /* LATER think about window vs canvas coords */
+ sys_gui("proc comment_click {target cvname x y tag} {\n\
+ pd $target _click $target [$cvname canvasx $x] [$cvname canvasy $y]\
+ [$cvname index $tag @$x,$y] [$cvname bbox $tag]\\;}\n");
+
+ sys_gui("proc comment_entext {enc tt} {\n\
+ set rr [catch {encoding convertfrom $enc $tt} tt1]\n\
+ if {$rr == 0} {concat $tt1} else {\n\
+ puts stderr [concat tcl/tk error: $tt1]\n\
+ concat $tt}}\n");
+}
diff --git a/cyclone/hammer/cosh.c b/cyclone/hammer/cosh.c
new file mode 100644
index 0000000..77d1567
--- /dev/null
+++ b/cyclone/hammer/cosh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-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"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define coshf cosh
+#endif
+
+typedef struct _cosh
+{
+ t_object x_ob;
+ float x_value;
+} t_cosh;
+
+static t_class *cosh_class;
+
+static void cosh_bang(t_cosh *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void cosh_float(t_cosh *x, t_float f)
+{
+ /* CHECKME large values */
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = coshf(f));
+}
+
+static void *cosh_new(t_floatarg f)
+{
+ t_cosh *x = (t_cosh *)pd_new(cosh_class);
+ /* CHECKME large values */
+ x->x_value = coshf(f);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void cosh_setup(void)
+{
+ cosh_class = class_new(gensym("cosh"),
+ (t_newmethod)cosh_new, 0,
+ sizeof(t_cosh), 0, A_DEFFLOAT, 0);
+ class_addbang(cosh_class, cosh_bang);
+ class_addfloat(cosh_class, cosh_float);
+}
diff --git a/cyclone/hammer/counter.c b/cyclone/hammer/counter.c
new file mode 100644
index 0000000..3117e6c
--- /dev/null
+++ b/cyclone/hammer/counter.c
@@ -0,0 +1,399 @@
+/* Copyright (c) 2002-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 an entirely rewritten version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+/* Beware -- the max reference manual page for the counter object
+ reflects mostly opcode max features. Apparently counter works
+ differently in cycling max (e.g. inlets 3 and 4). But I am sick
+ of checking -- I will not bother, until there is some feedback. */
+
+#include "m_pd.h"
+
+#define COUNTER_UP 0
+#define COUNTER_DOWN 1
+#define COUNTER_UPDOWN 2
+#define COUNTER_DEFMAX 0x7fffffff /* CHECKED (man says otherwise) */
+
+typedef struct _counter
+{
+ t_object x_ob;
+ int x_count;
+ int x_maxcount;
+ int x_dir;
+ int x_inc;
+ int x_min;
+ int x_max;
+ int x_carrybang;
+ int x_minhitflag;
+ int x_maxhitflag;
+ t_pd *x_proxies[4];
+ t_outlet *x_out2;
+ t_outlet *x_out3;
+ t_outlet *x_out4;
+} t_counter;
+
+typedef struct _counter_proxy
+{
+ t_object p_ob;
+ t_counter *p_master;
+ void (*p_bangmethod)(t_counter *x);
+ void (*p_floatmethod)(t_counter *x, t_float f);
+} t_counter_proxy;
+
+static t_class *counter_class;
+static t_class *counter_proxy_class;
+
+static void counter_up(t_counter *x)
+{
+ x->x_dir = COUNTER_UP;
+ x->x_inc = 1;
+}
+
+static void counter_down(t_counter *x)
+{
+ /* CHECKED: no explicit minimum needed */
+ x->x_dir = COUNTER_DOWN;
+ x->x_inc = -1;
+}
+
+static void counter_updown(t_counter *x)
+{
+ /* CHECKED: neither explicit maximum, nor minimum needed */
+ x->x_dir = COUNTER_UPDOWN;
+ /* CHECKED: x->x_inc unchanged (continuation) */
+}
+
+static void counter_dir(t_counter *x, t_floatarg f)
+{
+ switch ((int)f)
+ {
+ case COUNTER_UP:
+ counter_up(x);
+ break;
+ case COUNTER_DOWN:
+ counter_down(x);
+ break;
+ case COUNTER_UPDOWN:
+ counter_updown(x);
+ break;
+ default:
+ counter_up(x); /* CHECKED: invalid == default */
+ /* CHECKED: no warning */
+ }
+}
+
+static void counter_dobang(t_counter *x, int notjam)
+{
+ int offmin = 0, offmax = 0, onmin = 0, onmax = 0;
+ /* CHECKED: carry-off is not sent if min >= max */
+ /* LATER rethink (this is a hack) */
+ if (x->x_min < x->x_max)
+ offmin = x->x_minhitflag, offmax = x->x_maxhitflag;
+ x->x_minhitflag = x->x_maxhitflag = 0;
+
+ if (x->x_count < x->x_min)
+ {
+ if (x->x_inc == 1)
+ {
+ /* min has changed, which should imply x->x_count == x->x_min */
+ bug("counter_dobang (count < min)");
+ }
+ else if (x->x_dir == COUNTER_UPDOWN)
+ {
+ x->x_inc = 1;
+ if ((x->x_count = x->x_min + 1) > x->x_max) x->x_count = x->x_min;
+ }
+ else if ((x->x_count = x->x_max) < x->x_min) x->x_count = x->x_min;
+ }
+ else if (x->x_count > x->x_max)
+ {
+ if (x->x_inc == -1)
+ {
+ /* CHECKED: ignored */
+ }
+ else if (x->x_dir == COUNTER_UPDOWN)
+ {
+ x->x_inc = -1;
+ if ((x->x_count = x->x_max - 1) < x->x_min) x->x_count = x->x_min;
+ }
+ else x->x_count = x->x_min;
+ }
+
+ if (x->x_count == x->x_min && x->x_inc == -1)
+ {
+ /* CHECKED: 'jam' inhibits middle outlets (unless carry-off)
+ carry-on is never sent if max < min, but sent if max == min */
+ if (notjam
+ && x->x_min <= x->x_max) /* LATER rethink (this is a hack) */
+ onmin = 1;
+ }
+ else if (x->x_count == x->x_max && x->x_inc == 1)
+ {
+ /* CHECKED: this counter is never reset (and goes up to INT_MAX)
+ -- neither after dir change, nor after max change */
+ x->x_maxcount++; /* CHECKED: 'jam' does the increment */
+ outlet_float(x->x_out4, x->x_maxcount);
+ /* CHECKED: 'jam' inhibits middle outlets (unless carry-off)
+ carry-on is never sent if max < min, but sent if max == min */
+ if (notjam
+ && x->x_min <= x->x_max) /* LATER rethink (this is a hack) */
+ onmax = 1;
+ }
+
+ /* CHECKED: outlets deliver in right-to-left order */
+ if (onmax)
+ {
+ if (x->x_carrybang) outlet_bang(x->x_out3);
+ else
+ {
+ outlet_float(x->x_out3, 1);
+ x->x_maxhitflag = 1;
+ }
+ }
+ else if (offmax) outlet_float(x->x_out3, 0);
+ else if (onmin)
+ {
+ if (x->x_carrybang) outlet_bang(x->x_out2);
+ else
+ {
+ outlet_float(x->x_out2, 1);
+ x->x_minhitflag = 1;
+ }
+ }
+ else if (offmin) outlet_float(x->x_out2, 0);
+
+ outlet_float(((t_object *)x)->ob_outlet, x->x_count);
+}
+
+static void counter_bang(t_counter *x)
+{
+ x->x_count += x->x_inc;
+ counter_dobang(x, 1);
+}
+
+static void counter_float(t_counter *x, t_float dummy)
+{
+ counter_bang(x);
+}
+
+/* CHECKED: out-of-range values are ignored */
+/* CHECKED: 'down, set 3, up, bang' gives 5 */
+static void counter_set(t_counter *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i >= x->x_min && i <= x->x_max)
+ x->x_count = i - x->x_inc;
+}
+
+/* CHECKED: out-of-range values are ignored */
+static void counter_jam(t_counter *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i >= x->x_min && i <= x->x_max)
+ {
+ x->x_count = i;
+ counter_dobang(x, 0);
+ }
+}
+
+/* CHECKED: sends max carry on/off in any mode */
+static void counter_inc(t_counter *x)
+{
+ int tempdir = x->x_dir;
+ int tempinc = x->x_inc;
+ counter_up(x);
+ counter_bang(x);
+ x->x_dir = tempdir;
+ x->x_inc = tempinc;
+}
+
+/* CHECKED: sends min carry on/off in any mode */
+static void counter_dec(t_counter *x)
+{
+ int tempdir = x->x_dir;
+ int tempinc = x->x_inc;
+ counter_down(x);
+ counter_bang(x);
+ x->x_dir = tempdir;
+ x->x_inc = tempinc;
+}
+
+/* CHECKED: min can be set over max */
+static void counter_min(t_counter *x, t_floatarg f)
+{
+ /* CHECKED: min change always sets count to min and bangs */
+ /* do not use counter_jam() here -- avoid range checking */
+ x->x_count = x->x_min = (int)f;
+ counter_dobang(x, 0);
+}
+
+/* CHECKED: max can be set below min */
+static void counter_max(t_counter *x, t_floatarg f)
+{
+ x->x_max = (int)f;
+}
+
+static void counter_carrybang(t_counter *x)
+{
+ x->x_carrybang = 1;
+}
+
+static void counter_carryint(t_counter *x)
+{
+ x->x_carrybang = 0;
+}
+
+/* CHECKED: up/down switch */
+static void counter_bang1(t_counter *x)
+{
+ if (x->x_dir == COUNTER_UP)
+ counter_down(x);
+ else if (x->x_dir == COUNTER_DOWN)
+ counter_up(x);
+ else
+ x->x_inc = -x->x_inc; /* CHECKED */
+}
+
+/* CHECKED */
+static void counter_bang2(t_counter *x)
+{
+ counter_set(x, x->x_min);
+}
+
+/* CHECKED: out-of-range values are accepted (LATER rethink) */
+/* CHECKED: no resetting of min, nor of max (contrary to the man) */
+/* CHECKED: 'down, float2 3, up, bang' gives 3 (LATER rethink) */
+static void counter_float2(t_counter *x, t_floatarg f)
+{
+ counter_set(x, f); /* FIXME */
+}
+
+/* CHECKED */
+static void counter_bang3(t_counter *x)
+{
+ counter_jam(x, x->x_min);
+}
+
+/* CHECKED: out-of-range values are accepted (LATER rethink) */
+/* CHECKED: no resetting of min, nor of max (contrary to the man) */
+static void counter_float3(t_counter *x, t_floatarg f)
+{
+ counter_jam(x, f); /* FIXME */
+}
+
+/* CHECKED */
+static void counter_bang4(t_counter *x)
+{
+ counter_set(x, x->x_max);
+}
+
+static void counter_proxy_bang(t_counter_proxy *x)
+{
+ x->p_bangmethod(x->p_master);
+}
+
+static void counter_proxy_float(t_counter_proxy *x, t_float f)
+{
+ x->p_floatmethod(x->p_master, f);
+}
+
+static void counter_free(t_counter *x)
+{
+ int i;
+ for (i = 0; i < 4; i++)
+ if (x->x_proxies[i]) pd_free(x->x_proxies[i]);
+}
+
+static void *counter_new(t_floatarg f1, t_floatarg f2, t_floatarg f3)
+{
+ t_counter *x = (t_counter *)pd_new(counter_class);
+ t_counter_proxy **pp = (t_counter_proxy **)x->x_proxies;
+ int i1 = (int)f1;
+ int i2 = (int)f2;
+ int i3 = (int)f3;
+ int i;
+ static int warned = 0;
+ if (!warned)
+ {
+ post("warning: counter is not fully compatible, \
+please report differences");
+ warned = 1;
+ }
+ x->x_dir = COUNTER_UP;
+ x->x_inc = 1; /* previous value required by counter_dir() */
+ x->x_min = 0;
+ x->x_max = COUNTER_DEFMAX;
+ if (i3) x->x_dir = i1, x->x_min = i2, x->x_max = i3;
+ else if (i2) x->x_min = i1, x->x_max = i2;
+ else if (i1) x->x_max = i1;
+ x->x_carrybang = 0; /* CHECKED */
+ x->x_minhitflag = x->x_maxhitflag = 0;
+ x->x_maxcount = 0;
+ counter_dir(x, x->x_dir);
+ /* CHECKED: [counter 1 <min> <max>] starts from <max> */
+ x->x_count = (x->x_dir == COUNTER_DOWN ? x->x_max : x->x_min);
+ for (i = 0; i < 4; i++)
+ {
+ x->x_proxies[i] = pd_new(counter_proxy_class);
+ ((t_counter_proxy *)x->x_proxies[i])->p_master = x;
+ inlet_new((t_object *)x, x->x_proxies[i], 0, 0);
+ }
+ (*pp)->p_bangmethod = counter_bang1;
+ (*pp++)->p_floatmethod = counter_dir; /* CHECKED: same as dir */
+ (*pp)->p_bangmethod = counter_bang2;
+ (*pp++)->p_floatmethod = counter_float2;
+ (*pp)->p_bangmethod = counter_bang3;
+ (*pp++)->p_floatmethod = counter_float3;
+ (*pp)->p_bangmethod = counter_bang4;
+ (*pp++)->p_floatmethod = counter_max; /* CHECKED: same as max */
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_anything); /* float/bang */
+ x->x_out3 = outlet_new((t_object *)x, &s_anything); /* float/bang */
+ x->x_out4 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void counter_setup(void)
+{
+ counter_class = class_new(gensym("counter"),
+ (t_newmethod)counter_new,
+ (t_method)counter_free,
+ sizeof(t_counter), 0,
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(counter_class, counter_bang);
+ class_addfloat(counter_class, counter_float);
+ class_addmethod(counter_class, (t_method)counter_bang,
+ gensym("next"), 0);
+ class_addmethod(counter_class, (t_method)counter_set,
+ gensym("set"), A_FLOAT, 0);
+ class_addmethod(counter_class, (t_method)counter_set,
+ gensym("goto"), A_FLOAT, 0);
+ class_addmethod(counter_class, (t_method)counter_jam,
+ gensym("jam"), A_FLOAT, 0);
+ class_addmethod(counter_class, (t_method)counter_up,
+ gensym("up"), 0);
+ class_addmethod(counter_class, (t_method)counter_down,
+ gensym("down"), 0);
+ class_addmethod(counter_class, (t_method)counter_updown,
+ gensym("updown"), 0);
+ class_addmethod(counter_class, (t_method)counter_inc,
+ gensym("inc"), 0);
+ class_addmethod(counter_class, (t_method)counter_dec,
+ gensym("dec"), 0);
+ class_addmethod(counter_class, (t_method)counter_min,
+ gensym("min"), A_FLOAT, 0);
+ class_addmethod(counter_class, (t_method)counter_max,
+ gensym("max"), A_FLOAT, 0);
+ class_addmethod(counter_class, (t_method)counter_carrybang,
+ gensym("carrybang"), 0);
+ class_addmethod(counter_class, (t_method)counter_carryint,
+ gensym("carryint"), 0);
+ counter_proxy_class = class_new(gensym("_counter_proxy"), 0, 0,
+ sizeof(t_counter_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(counter_proxy_class, counter_proxy_bang);
+ class_addfloat(counter_proxy_class, counter_proxy_float);
+}
diff --git a/cyclone/hammer/cycle.c b/cyclone/hammer/cycle.c
new file mode 100644
index 0000000..faffc01
--- /dev/null
+++ b/cyclone/hammer/cycle.c
@@ -0,0 +1,153 @@
+/* Copyright (c) 2002-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 a modified version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+//#define CYCLE_USEEVENTNO
+
+#define CYCLE_MINOUTS 1
+#define CYCLE_MAXOUTS 100 /* CHECKED */
+#define CYCLE_DEFOUTS 1
+
+typedef struct _cycle
+{
+ t_object x_ob;
+ int x_eventmode;
+#ifdef CYCLE_USEEVENTNO
+ int x_lastevent;
+#else
+ double x_lastevent;
+#endif
+ int x_index;
+ int x_nouts;
+ t_outlet **x_outs;
+} t_cycle;
+
+static t_class *cycle_class;
+
+static int cycle_isnextevent(t_cycle *x)
+{
+#ifdef CYCLE_USEEVENTNO
+ int nextevent = sys_geteventno();
+#else
+ double nextevent = clock_getlogicaltime();
+#endif
+ if (x->x_lastevent == nextevent)
+ return (0);
+ else
+ {
+ x->x_lastevent = nextevent;
+ return (1);
+ }
+}
+
+static void cycle_bang(t_cycle *x)
+{
+ /* CHECKED: bangs ignored (but message 'bang' is an error -- why?) */
+}
+
+static void cycle_float(t_cycle *x, t_float f)
+{
+ if ((x->x_eventmode && cycle_isnextevent(x)) || x->x_index >= x->x_nouts)
+ x->x_index = 0;
+ outlet_float(x->x_outs[x->x_index++], f);
+}
+
+static void cycle_symbol(t_cycle *x, t_symbol *s)
+{
+ if ((x->x_eventmode && cycle_isnextevent(x)) || x->x_index >= x->x_nouts)
+ x->x_index = 0;
+ outlet_symbol(x->x_outs[x->x_index++], s);
+}
+
+/* LATER gpointer */
+
+static void cycle_list(t_cycle *x, t_symbol *s, int ac, t_atom *av)
+{
+ if ((x->x_eventmode && cycle_isnextevent(x)) || x->x_index >= x->x_nouts)
+ x->x_index = 0;
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_float(x->x_outs[x->x_index], av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ outlet_symbol(x->x_outs[x->x_index], av->a_w.w_symbol);
+ av++;
+ if (++(x->x_index) >= x->x_nouts) x->x_index = 0;
+ }
+}
+
+static void cycle_anything(t_cycle *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (s && s != &s_) cycle_symbol(x, s); /* CHECKED */
+ cycle_list(x, 0, ac, av);
+}
+
+static void cycle_set(t_cycle *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i >= 0 && i < x->x_nouts) x->x_index = i;
+}
+
+static void cycle_thresh(t_cycle *x, t_floatarg f)
+{
+ if (x->x_eventmode = (f != 0))
+#ifdef CYCLE_USEEVENTNO
+ x->x_lastevent = sys_geteventno();
+#else
+ x->x_lastevent = clock_getlogicaltime();
+#endif
+}
+
+static void cycle_free(t_cycle *x)
+{
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_nouts * sizeof(*x->x_outs));
+}
+
+static void *cycle_new(t_floatarg f1, t_floatarg f2)
+{
+ t_cycle *x;
+ int i, nouts = (int)f1;
+ t_outlet **outs;
+ if (nouts < CYCLE_MINOUTS)
+ nouts = CYCLE_DEFOUTS;
+ if (nouts > CYCLE_MAXOUTS)
+ {
+ loud_incompatible_max(cycle_class, CYCLE_MAXOUTS, "outlets");
+ /* CHECKED: max clips with an error:
+ ``perhaps you were trying to make an oscillator?'' */
+ }
+ if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
+ return (0);
+ x = (t_cycle *)pd_new(cycle_class);
+ x->x_nouts = nouts;
+ x->x_outs = outs;
+ x->x_index = 0;
+ for (i = 0; i < nouts; i++)
+ x->x_outs[i] = outlet_new((t_object *)x, &s_anything);
+ cycle_thresh(x, f2);
+ return (x);
+}
+
+void cycle_setup(void)
+{
+ cycle_class = class_new(gensym("cycle"),
+ (t_newmethod)cycle_new,
+ (t_method)cycle_free,
+ sizeof(t_cycle), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(cycle_class, cycle_bang);
+ class_addfloat(cycle_class, cycle_float);
+ class_addsymbol(cycle_class, cycle_symbol);
+ class_addlist(cycle_class, cycle_list);
+ class_addanything(cycle_class, cycle_anything);
+ class_addmethod(cycle_class, (t_method)cycle_set,
+ gensym("set"), A_FLOAT, 0); /* CHECKED: arg required */
+ class_addmethod(cycle_class, (t_method)cycle_thresh,
+ gensym("thresh"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/decide.c b/cyclone/hammer/decide.c
new file mode 100644
index 0000000..a612fbf
--- /dev/null
+++ b/cyclone/hammer/decide.c
@@ -0,0 +1,75 @@
+/* Copyright (c) 2002-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 "common/loud.h"
+
+typedef struct _decide
+{
+ t_object x_ob;
+ unsigned int x_seed;
+} t_decide;
+
+static t_class *decide_class;
+
+/* the random bit algo is taken from NR (method II in 7.4) -- CHECKED */
+#define RBIT1 1
+#define RBIT2 2
+#define RBIT5 16
+#define RBIT18 131072
+#define RBIT_MASK (RBIT1 + RBIT2 + RBIT5)
+
+static void decide_bang(t_decide *x)
+{
+ if (x->x_seed & RBIT18)
+ {
+ x->x_seed = ((x->x_seed ^ RBIT_MASK) << 1) | RBIT1;
+ outlet_float(((t_object *)x)->ob_outlet, 1);
+ }
+ else
+ {
+ x->x_seed <<= 1;
+ outlet_float(((t_object *)x)->ob_outlet, 0);
+ }
+}
+
+static void decide_float(t_decide *x, t_float f)
+{
+ /* CHECKED: float loudly rejected, int (any value) same as bang */
+ int i;
+ if (loud_checkint((t_pd *)x, f, &i, &s_float))
+ decide_bang(x);
+}
+
+static void decide_ft1(t_decide *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED */
+ if (i) /* CHECKED: negative numbers are accepted */
+ x->x_seed = i;
+ else
+ x->x_seed = 123456789; /* FIXME */
+}
+
+static void *decide_new(t_floatarg f)
+{
+ t_decide *x = (t_decide *)pd_new(decide_class);
+ x->x_seed = 123456789; /* FIXME */
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void decide_setup(void)
+{
+ decide_class = class_new(gensym("decide"),
+ (t_newmethod)decide_new, 0,
+ sizeof(t_decide), 0,
+ A_DEFFLOAT, 0);
+ class_addbang(decide_class, decide_bang);
+ class_addfloat(decide_class, decide_float);
+ class_addmethod(decide_class, (t_method)decide_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ /* CHECKED list is auto-unfolded */
+ /* CHECKED doesn't understand "seed" */
+}
diff --git a/cyclone/hammer/drunk.c b/cyclone/hammer/drunk.c
new file mode 100644
index 0000000..e08800d
--- /dev/null
+++ b/cyclone/hammer/drunk.c
@@ -0,0 +1,140 @@
+/* Copyright (c) 2002-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 first version of this code was written by Nicola Bernardini.
+ It was entirely reimplemented in the hope of adapting it to the
+ cyclone's guidelines. */
+
+#include "m_pd.h"
+#include "common/rand.h"
+
+#define DRUNK_DEFMAXVALUE 128
+#define DRUNK_DEFMAXSTEP 2
+
+typedef struct _drunk
+{
+ t_object x_ob;
+ int x_value;
+ int x_maxvalue;
+ int x_maxstep;
+ int x_minstep;
+ unsigned int x_seed;
+ unsigned int x_bitseed;
+} t_drunk;
+
+static t_class *drunk_class;
+
+static void drunk_set(t_drunk *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED float silently truncated */
+ if (i > x->x_maxvalue)
+ x->x_value = x->x_maxvalue; /* CHECKED */
+ else if (i < 0)
+ x->x_value = 0; /* CHECKED */
+ else x->x_value = i;
+}
+
+/* CHECKED: this is a superposition of two rngs -- the random bit generator,
+ and the random integer generator, which is the same (CHECKED) as the one
+ used in the 'random' class (quite lame: period 35730773, nonuniform for
+ large ranges, so I would rather not RE it...) */
+#define RBIT1 1
+#define RBIT2 2
+#define RBIT5 16
+#define RBIT18 131072
+#define RBIT_MASK (RBIT1 + RBIT2 + RBIT5)
+
+static void drunk_bang(t_drunk *x)
+{
+ int rnd = rand_int(&x->x_seed, x->x_maxstep) + x->x_minstep;
+ int val;
+ if (x->x_bitseed & RBIT18)
+ {
+ x->x_bitseed = ((x->x_bitseed ^ RBIT_MASK) << 1) | RBIT1;
+ if ((val = x->x_value + rnd) > x->x_maxvalue)
+ val = x->x_value - rnd; /* CHECKED */
+ if (val < 0)
+ val = 0; /* CHECKED (needed for maxstep > maxvalue) */
+ }
+ else
+ {
+ x->x_bitseed <<= 1;
+ if ((val = x->x_value - rnd) < 0)
+ val = x->x_value + rnd; /* CHECKED */
+ if (val > x->x_maxvalue)
+ val = x->x_maxvalue; /* CHECKED (needed for maxstep > maxvalue) */
+ }
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = val);
+}
+
+static void drunk_float(t_drunk *x, t_float f)
+{
+ drunk_set(x, f);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void drunk_ft1(t_drunk *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED float silently truncated */
+ x->x_maxvalue = (i < 0 ? 1 : i); /* CHECKED zero allowed */
+ /* CHECKED maxstep not updated */
+}
+
+static void drunk_ft2(t_drunk *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED float silently truncated */
+ if (i < 0)
+ {
+ x->x_minstep = 1;
+ i = -i;
+ }
+ else x->x_minstep = 0;
+ /* CHECKED maxstep not clipped to the maxvalue */
+ x->x_maxstep = (x->x_minstep ? i - 1 : i); /* CHECKED zero allowed */
+}
+
+/* apparently, bitseed cannot be controlled, but LATER recheck */
+static void drunk_seed(t_drunk *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED */
+ if (i < 0)
+ i = 1; /* CHECKED */
+ rand_seed(&x->x_seed, (unsigned int)i);
+}
+
+static void *drunk_new(t_floatarg f1, t_floatarg f2)
+{
+ t_drunk *x = (t_drunk *)pd_new(drunk_class);
+ x->x_maxvalue = ((int)f1 > 0 ? (int)f1 : 128); /* CHECKED */
+ x->x_maxstep = 2;
+ x->x_minstep = 0;
+ if ((int)f2) /* CHECKED */
+ drunk_ft2(x, f2);
+ x->x_value = x->x_maxvalue / 2; /* CHECKED */
+ rand_seed(&x->x_seed, 0); /* CHECKED third arg silently ignored */
+ x->x_bitseed = 123456789; /* FIXME */
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2"));
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void drunk_setup(void)
+{
+ drunk_class = class_new(gensym("drunk"),
+ (t_newmethod)drunk_new, 0,
+ sizeof(t_drunk), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(drunk_class, drunk_bang);
+ class_addfloat(drunk_class, drunk_float);
+ class_addmethod(drunk_class, (t_method)drunk_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(drunk_class, (t_method)drunk_ft2,
+ gensym("ft2"), A_FLOAT, 0);
+ /* CHECKED list is auto-unfolded */
+ class_addmethod(drunk_class, (t_method)drunk_seed,
+ gensym("seed"), A_FLOAT, 0); /* CHECKED arg obligatory */
+ class_addmethod(drunk_class, (t_method)drunk_set,
+ gensym("set"), A_FLOAT, 0); /* CHECKED arg obligatory */
+}
diff --git a/cyclone/hammer/flush.c b/cyclone/hammer/flush.c
new file mode 100644
index 0000000..751fc24
--- /dev/null
+++ b/cyclone/hammer/flush.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+
+#define FLUSH_NPITCHES 128
+
+typedef struct _flush
+{
+ t_object x_ob;
+ t_float x_velocity;
+ unsigned char x_pitches[FLUSH_NPITCHES]; /* CHECKED */
+ t_outlet *x_voutlet;
+} t_flush;
+
+static t_class *flush_class;
+
+static void flush_float(t_flush *x, t_float f)
+{
+ int pitch = (int)f;
+ if (pitch >= 0 && pitch < FLUSH_NPITCHES)
+ {
+ outlet_float(x->x_voutlet, x->x_velocity);
+ outlet_float(((t_object *)x)->ob_outlet, pitch);
+ if (x->x_velocity != 0)
+ {
+ x->x_pitches[pitch]++; /* CHECKED (lame) */
+ }
+ else if (x->x_pitches[pitch])
+ {
+ x->x_pitches[pitch]--; /* CHECKED (lame) */
+ }
+ }
+}
+
+static void flush_bang(t_flush *x)
+{
+ int i;
+ unsigned char *pp;
+ for (i = 0, pp = x->x_pitches; i < FLUSH_NPITCHES; i++, pp++)
+ {
+ while (*pp)
+ {
+ outlet_float(x->x_voutlet, 0);
+ outlet_float(((t_object *)x)->ob_outlet, i);
+ (*pp)--;
+ }
+ }
+}
+
+static void flush_clear(t_flush *x)
+{
+ memset(x->x_pitches, 0, sizeof(x->x_pitches));
+}
+
+static void *flush_new(void)
+{
+ t_flush *x = (t_flush *)pd_new(flush_class);
+ x->x_velocity = 0;
+ flush_clear(x);
+ floatinlet_new((t_object *)x, &x->x_velocity);
+ outlet_new((t_object *)x, &s_float);
+ x->x_voutlet = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void flush_setup(void)
+{
+ flush_class = class_new(gensym("flush"),
+ (t_newmethod)flush_new,
+ 0, /* CHECKED: no flushout */
+ sizeof(t_flush), 0, 0);
+ class_addfloat(flush_class, flush_float);
+ class_addbang(flush_class, flush_bang);
+ class_addmethod(flush_class, (t_method)flush_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/forward.c b/cyclone/hammer/forward.c
new file mode 100644
index 0000000..995e765
--- /dev/null
+++ b/cyclone/hammer/forward.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 1997-2002 Miller Puckette, 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"
+
+typedef struct _forward
+{
+ t_object x_ob;
+ t_symbol *x_sym;
+} t_forward;
+
+static t_class *forward_class;
+
+static void forward_bang(t_forward *x)
+{
+ if (x->x_sym->s_thing) pd_bang(x->x_sym->s_thing);
+}
+
+static void forward_float(t_forward *x, t_float f)
+{
+ if (x->x_sym->s_thing) pd_float(x->x_sym->s_thing, f);
+}
+
+static void forward_symbol(t_forward *x, t_symbol *s)
+{
+ if (x->x_sym->s_thing) pd_symbol(x->x_sym->s_thing, s);
+}
+
+static void forward_pointer(t_forward *x, t_gpointer *gp)
+{
+ if (x->x_sym->s_thing) pd_pointer(x->x_sym->s_thing, gp);
+}
+
+static void forward_list(t_forward *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_sym->s_thing) pd_list(x->x_sym->s_thing, s, ac, av);
+}
+
+static void forward_anything(t_forward *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_sym->s_thing) typedmess(x->x_sym->s_thing, s, ac, av);
+}
+
+static void forward_send(t_forward *x, t_symbol *s)
+{
+ /* CHECKED: 'send' without arguments erases destination */
+ if (s) x->x_sym = s;
+}
+
+static void *forward_new(t_symbol *s)
+{
+ t_forward *x = (t_forward *)pd_new(forward_class);
+ x->x_sym = s;
+ return (x);
+}
+
+void forward_setup(void)
+{
+ forward_class = class_new(gensym("forward"),
+ (t_newmethod)forward_new, 0,
+ sizeof(t_forward), 0, A_DEFSYM, 0);
+ class_addbang(forward_class, forward_bang);
+ class_addfloat(forward_class, forward_float);
+ class_addsymbol(forward_class, forward_symbol);
+ class_addpointer(forward_class, forward_pointer);
+ class_addlist(forward_class, forward_list);
+ class_addanything(forward_class, forward_anything);
+ class_addmethod(forward_class, (t_method)forward_send,
+ gensym("send"), A_DEFSYM, 0);
+}
diff --git a/cyclone/hammer/fromsymbol.c b/cyclone/hammer/fromsymbol.c
new file mode 100644
index 0000000..3d508e9
--- /dev/null
+++ b/cyclone/hammer/fromsymbol.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+
+typedef struct _fromsymbol
+{
+ t_object x_ob;
+} t_fromsymbol;
+
+static t_class *fromsymbol_class;
+
+static void fromsymbol_bang(t_fromsymbol *x)
+{
+ outlet_bang(((t_object *)x)->ob_outlet); /* CHECKED */
+}
+
+static void fromsymbol_float(t_fromsymbol *x, t_float f)
+{
+ /* CHECKED: fromsymbol: doesn't understand "int", "float" */
+}
+
+static void fromsymbol_symbol(t_fromsymbol *x, t_symbol *s)
+{
+ static char zero = 0;
+ char *sname = &zero;
+ if (s)
+ {
+ sname = s->s_name;
+ while (*sname == ' ' || *sname == '\t'
+ || *sname == '\n' || *sname == '\r') sname++;
+ }
+ if (*sname)
+ {
+ t_binbuf *bb = binbuf_new();
+ int ac;
+ t_atom *av;
+ binbuf_text(bb, sname, strlen(sname));
+ ac = binbuf_getnatom(bb);
+ av = binbuf_getvec(bb);
+ if (ac)
+ {
+ if (av->a_type == A_SYMBOL)
+ outlet_anything(((t_object *)x)->ob_outlet,
+ av->a_w.w_symbol, ac - 1, av + 1);
+ else if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ }
+ }
+ binbuf_free(bb);
+ }
+}
+
+static void fromsymbol_list(t_fromsymbol *x, t_symbol *s, int ac, t_atom *av)
+{
+ /* CHECKED: fromsymbol: doesn't understand "int", "float",
+ 'list <symbol>' ignored without complaining. */
+}
+
+static void fromsymbol_anything(t_fromsymbol *x, t_symbol *s, int ac, t_atom *av)
+{
+ fromsymbol_symbol(x, s); /* CHECKED */
+}
+
+static void *fromsymbol_new(void)
+{
+ t_fromsymbol *x = (t_fromsymbol *)pd_new(fromsymbol_class);
+ outlet_new((t_object *)x, &s_anything);
+ return (x);
+}
+
+void fromsymbol_setup(void)
+{
+ fromsymbol_class = class_new(gensym("fromsymbol"),
+ (t_newmethod)fromsymbol_new, 0,
+ sizeof(t_fromsymbol), 0, 0);
+ class_addbang(fromsymbol_class, fromsymbol_bang);
+ class_addfloat(fromsymbol_class, fromsymbol_float);
+ class_addsymbol(fromsymbol_class, fromsymbol_symbol);
+ class_addlist(fromsymbol_class, fromsymbol_list);
+ class_addanything(fromsymbol_class, fromsymbol_anything);
+}
diff --git a/cyclone/hammer/funbuff.c b/cyclone/hammer/funbuff.c
new file mode 100644
index 0000000..8d9d698
--- /dev/null
+++ b/cyclone/hammer/funbuff.c
@@ -0,0 +1,521 @@
+/* Copyright (c) 2002-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 "unstable/fragile.h"
+#include "common/loud.h"
+#include "common/vefl.h"
+#include "hammer/tree.h"
+#include "hammer/file.h"
+
+typedef struct _funbuff
+{
+ t_object x_ob;
+ t_canvas *x_canvas;
+ t_symbol *x_defname;
+ t_float x_value;
+ int x_valueset;
+ /* CHECKED filling with a large set, then sending 'goto', 'read', 'next'...
+ outputs the previous, replaced contents (same with deletion)
+ -- apparently a node pointer is stored, corrupt in these cases */
+ t_hammernode *x_pointer;
+ int x_pointerset; /* set-with-goto flag */
+ int x_lastdelta;
+ int x_embedflag;
+ t_hammerfile *x_filehandle;
+ t_hammertree x_tree;
+ t_outlet *x_deltaout;
+ t_outlet *x_bangout;
+} t_funbuff;
+
+static t_class *funbuff_class;
+
+static void funbuff_dooutput(t_funbuff *x, float value, float delta)
+{
+ /* CHECKED lastdelta sent for 'next', 'float', 'min', 'max',
+ 'interp', 'find' */
+ outlet_float(x->x_deltaout, delta);
+ outlet_float(((t_object *)x)->ob_outlet, value);
+}
+
+static void funbuff_bang(t_funbuff *x)
+{
+ t_hammernode *np;
+ int count = 0;
+ int xmin = 0, xmax = 0;
+ t_float ymin = 0, ymax = 0;
+ if (np = x->x_tree.t_first)
+ {
+ /* LATER consider using extra fields, updated on the fly */
+ count = 1;
+ xmin = np->n_index;
+ xmax = x->x_tree.t_last->n_index;
+ ymin = ymax = np->n_value;
+ while (np = np->n_next)
+ {
+ if (np->n_value < ymin) ymin = np->n_value;
+ else if (np->n_value > ymax) ymax = np->n_value;
+ count++;
+ }
+ }
+ /* format CHECKED */
+ post("funbuff info: %d elements long", count); /* CHECKED 0 and 1 */
+ if (count)
+ {
+ post(" -> minX= %d maxX= %d", xmin, xmax);
+ post(" -> minY= %g maxY= %g", ymin, ymax);
+ post(" -> domain= %d range= %g", xmax - xmin, ymax - ymin);
+ }
+}
+
+static void funbuff_float(t_funbuff *x, t_float f)
+{
+ int ndx = (int)f; /* CHECKED float is silently truncated */
+ t_hammernode *np;
+ if (x->x_valueset)
+ {
+ if (np = hammertree_insert(&x->x_tree, ndx))
+ np->n_value = x->x_value;
+ x->x_valueset = 0;
+ }
+ else if (np = hammertree_closest(&x->x_tree, ndx, 0))
+ funbuff_dooutput(x, np->n_value, x->x_lastdelta);
+ /* CHECKED pointer is updated --
+ 'next' outputs np also in a !valueset case (it is sent twice) */
+ x->x_pointer = np;
+ x->x_pointerset = 0;
+}
+
+static void funbuff_ft1(t_funbuff *x, t_floatarg f)
+{
+ /* this is incompatible -- CHECKED float is silently truncated */
+ x->x_value = f;
+ x->x_valueset = 1;
+}
+
+static void funbuff_clear(t_funbuff *x)
+{
+ hammertree_clear(&x->x_tree, 0);
+ /* CHECKED valueset is not cleared */
+ x->x_pointer = 0;
+}
+
+/* LATER dirty flag handling */
+static void funbuff_embed(t_funbuff *x, t_floatarg f)
+{
+ x->x_embedflag = (f != 0);
+}
+
+static void funbuff_goto(t_funbuff *x, t_floatarg f)
+{
+ /* CHECKED truncation */
+ x->x_pointer = hammertree_closest(&x->x_tree, (int)f, 1);
+ x->x_pointerset = 1; /* CHECKED delta output by 'next' will be zero */
+}
+
+/* LATER consider using an extra field, updated on the fly */
+static void funbuff_min(t_funbuff *x)
+{
+ t_hammernode *np;
+ if (np = x->x_tree.t_first) /* CHECKED nop if empty */
+ {
+ t_float result = np->n_value;
+ while (np = np->n_next)
+ if (np->n_value < result) result = np->n_value;
+ funbuff_dooutput(x, result, x->x_lastdelta);
+ /* CHECKED pointer not updated */
+ }
+}
+
+/* LATER consider using an extra field, updated on the fly */
+static void funbuff_max(t_funbuff *x)
+{
+ t_hammernode *np;
+ if (np = x->x_tree.t_first) /* CHECKED nop if empty */
+ {
+ t_float result = np->n_value;
+ while (np = np->n_next)
+ if (np->n_value > result) result = np->n_value;
+ funbuff_dooutput(x, result, x->x_lastdelta);
+ /* CHECKED pointer not updated */
+ }
+}
+
+static void funbuff_next(t_funbuff *x)
+{
+ t_hammernode *np;
+ if (!x->x_tree.t_root)
+ return;
+ if (!(np = x->x_pointer))
+ {
+ outlet_bang(x->x_bangout);
+ /* CHECKED banging until reset */
+ return;
+ }
+ if (x->x_pointerset)
+ x->x_lastdelta = 0;
+ else if (np->n_prev)
+ x->x_lastdelta = np->n_index - np->n_prev->n_index;
+ else
+ x->x_lastdelta = 0; /* CHECKED corrupt delta sent here... */
+ funbuff_dooutput(x, np->n_value, x->x_lastdelta);
+ x->x_pointer = np->n_next;
+ x->x_pointerset = 0;
+}
+
+static void funbuff_set(t_funbuff *x, t_symbol *s, int ac, t_atom *av)
+{
+ /* CHECKED symbols somehow bashed to zeros,
+ decreasing x coords corrupt the funbuff -- not emulated here... */
+ int i = ac;
+ t_atom *ap = av;
+ while (i--) if (ap++->a_type != A_FLOAT)
+ {
+ loud_error((t_pd *)x, "bad input (not a number) -- no data to set");
+ return;
+ }
+ if (!ac || (ac % 2))
+ {
+ /* CHECKED odd/null ac loudly rejected, current contents preserved */
+ loud_error((t_pd *)x, "bad input (%s) -- no data to set",
+ (ac ? "odd arg count" : "no input"));
+ return;
+ }
+ funbuff_clear(x); /* CHECKED the contents is replaced */
+ while (ac--)
+ {
+ t_hammernode *np;
+ if (np = hammertree_insert(&x->x_tree, (int)av++->a_w.w_float))
+ np->n_value = av++->a_w.w_float;
+ else return;
+ ac--;
+ }
+}
+
+static void funbuff_doread(t_funbuff *x, t_symbol *fn)
+{
+ t_binbuf *bb = binbuf_new();
+ int ac;
+ t_atom *av;
+ char buf[MAXPDSTRING];
+ canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
+ binbuf_read(bb, buf, "", 0);
+ if ((ac = binbuf_getnatom(bb)) &&
+ (av = binbuf_getvec(bb)) &&
+ av->a_type == A_SYMBOL &&
+ av->a_w.w_symbol == gensym("funbuff"))
+ {
+ post("funbuff_read: %s read successful", fn->s_name); /* CHECKED */
+ funbuff_set(x, 0, ac-1, av+1);
+ }
+ else /* CHECKED no complaints... */
+ loud_error((t_pd *)x, "invalid file %s", fn->s_name);
+ binbuf_free(bb);
+}
+
+static void funbuff_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ funbuff_doread((t_funbuff *)z, fn);
+}
+
+static void funbuff_dowrite(t_funbuff *x, t_symbol *fn)
+{
+ t_binbuf *bb = binbuf_new();
+ char buf[MAXPDSTRING];
+ t_hammernode *np;
+ binbuf_addv(bb, "s", gensym("funbuff"));
+ for (np = x->x_tree.t_first; np; np = np->n_next)
+ binbuf_addv(bb, "if", np->n_index, np->n_value);
+ canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
+ binbuf_write(bb, buf, "", 0);
+ binbuf_free(bb);
+}
+
+static void funbuff_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ funbuff_dowrite((t_funbuff *)z, fn);
+}
+
+static void funbuff_embedhook(t_pd *z, t_binbuf *bb, t_symbol *bindsym)
+{
+ t_funbuff *x = (t_funbuff *)z;
+ if (x->x_embedflag)
+ {
+ t_hammernode *np;
+ binbuf_addv(bb, "ssi;", bindsym, gensym("embed"), 1);
+ if (np = x->x_tree.t_first)
+ {
+ binbuf_addv(bb, "ss", bindsym, gensym("set"));
+ for (; np; np = np->n_next)
+ binbuf_addv(bb, "if", np->n_index, np->n_value);
+ binbuf_addsemi(bb);
+ }
+ }
+}
+
+/* CHECKED symbol arg ok */
+static void funbuff_read(t_funbuff *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ funbuff_doread(x, s);
+ else
+ hammerpanel_open(x->x_filehandle);
+}
+
+/* CHECKED symbol arg not allowed --
+ a bug? but CHECKME other classes (cf seq's filetype dilemma) */
+static void funbuff_write(t_funbuff *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ funbuff_dowrite(x, s);
+ else /* CHECKME default name */
+ hammerpanel_save(x->x_filehandle,
+ canvas_getdir(x->x_canvas), x->x_defname);
+}
+
+static void funbuff_delete(t_funbuff *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_FLOAT &&
+ (ac == 1 || (ac == 2 && av[1].a_type == A_FLOAT)))
+ {
+ /* CHECKED float is silently truncated */
+ int ndx = (int)av->a_w.w_float;
+ t_hammernode *np;
+ if ((np = hammertree_search(&x->x_tree, ndx)) &&
+ (ac == 1 || np->n_value == av[1].a_w.w_float))
+ {
+ if (np == x->x_pointer)
+ x->x_pointer = 0; /* CHECKED corrupt pointer left here... */
+ hammertree_delete(&x->x_tree, np);
+ }
+ /* CHECKED mismatch silently ignored */
+ }
+ else loud_messarg((t_pd *)x, s); /* CHECKED */
+}
+
+static void funbuff_find(t_funbuff *x, t_floatarg f)
+{
+ t_hammernode *np;
+ if (np = x->x_tree.t_first)
+ {
+ do
+ {
+ /* CHECKED lastdelta preserved */
+ if (np->n_value == f)
+ funbuff_dooutput(x, np->n_index, x->x_lastdelta);
+ }
+ while (np = np->n_next);
+ /* CHECKED no bangout, no complaint if nothing found */
+ }
+ else loud_error((t_pd *)x, "nothing to find"); /* CHECKED */
+}
+
+static void funbuff_dump(t_funbuff *x)
+{
+ t_hammernode *np;
+ if (np = x->x_tree.t_first)
+ {
+ do
+ {
+ x->x_lastdelta = np->n_value; /* CHECKED */
+ /* float value preserved (this is incompatible) */
+ funbuff_dooutput(x, np->n_index, np->n_value);
+ }
+ while (np = np->n_next);
+ /* CHECKED no bangout */
+ }
+ else loud_error((t_pd *)x, "nothing to dump"); /* CHECKED */
+}
+
+/* CHECKME if pointer is updated */
+static void funbuff_dointerp(t_funbuff *x, t_floatarg f, int vsz, t_float *vec)
+{
+ t_hammernode *np1;
+ int trunc = (int)f;
+ if (trunc > f) trunc--; /* CHECKME negative floats */
+ if (np1 = hammertree_closest(&x->x_tree, trunc, 0))
+ {
+ float value = np1->n_value;
+ t_hammernode *np2 = np1->n_next;
+ if (np2)
+ {
+ float delta = (float)(np2->n_index - np1->n_index);
+ /* this is incompatible -- CHECKED float argument is silently
+ truncated (which does not make much sense here), CHECKME again */
+ float frac = f - np1->n_index;
+ if (frac < 0 || frac >= delta)
+ {
+ bug("funbuff_dointerp");
+ return;
+ }
+ frac /= delta;
+ if (vec)
+ {
+ /* CHECKME */
+ float vpos = (vsz - 1) * frac;
+ int vndx = (int)vpos;
+ float vfrac = vpos - vndx;
+ if (vndx < 0 || vndx >= vsz - 1)
+ {
+ bug("funbuff_dointerp redundant test...");
+ return;
+ }
+ vec += vndx;
+ frac = *vec + (vec[1] - *vec) * vfrac;
+ }
+ value += (np2->n_value - np1->n_value) * frac;
+ }
+ funbuff_dooutput(x, value, x->x_lastdelta); /* CHECKME !np2 */
+ }
+ else if (np1 = hammertree_closest(&x->x_tree, trunc, 1))
+ funbuff_dooutput(x, np1->n_value, x->x_lastdelta); /* CHECKME */
+}
+
+static void funbuff_interp(t_funbuff *x, t_floatarg f)
+{
+ funbuff_dointerp(x, f, 0, 0);
+}
+
+static void funbuff_interptab(t_funbuff *x, t_symbol *s, t_floatarg f)
+{
+ int vsz;
+ t_float *vec;
+ if (vec = vefl_get(s, &vsz, 0, (t_pd *)x))
+ {
+ if (vsz > 2)
+ funbuff_dointerp(x, f, vsz, vec);
+ else
+ funbuff_dointerp(x, f, 0, 0);
+ }
+}
+
+static void funbuff_reduce(t_funbuff *x, t_floatarg f)
+{
+ loud_notimplemented((t_pd *)x, "reduce");
+}
+
+static void funbuff_select(t_funbuff *x, t_floatarg f1, t_floatarg f2)
+{
+ loud_notimplemented((t_pd *)x, "select");
+}
+
+/* CHECKED (sub)buffer's copy is stored, as expected --
+ 'delete' does not modify the clipboard */
+/* CHECKED cut entire contents if no selection */
+static void funbuff_cut(t_funbuff *x)
+{
+ loud_notimplemented((t_pd *)x, "cut");
+}
+
+/* CHECKED copy entire contents if no selection */
+static void funbuff_copy(t_funbuff *x)
+{
+ loud_notimplemented((t_pd *)x, "copy");
+}
+
+static void funbuff_paste(t_funbuff *x)
+{
+ loud_notimplemented((t_pd *)x, "paste");
+}
+
+static void funbuff_undo(t_funbuff *x)
+{
+ /* CHECKED apparently not working in 4.07 */
+ loud_notimplemented((t_pd *)x, "undo");
+}
+
+#ifdef HAMMERTREE_DEBUG
+static void funbuff_debug(t_funbuff *x, t_floatarg f)
+{
+ hammertree_debug(&x->x_tree, (int)f);
+}
+#endif
+
+static void funbuff_free(t_funbuff *x)
+{
+ hammerfile_free(x->x_filehandle);
+ hammertree_clear(&x->x_tree, 0);
+}
+
+static void *funbuff_new(t_symbol *s)
+{
+ t_funbuff *x = (t_funbuff *)pd_new(funbuff_class);
+ x->x_canvas = canvas_getcurrent();
+ x->x_valueset = 0;
+ x->x_pointer = 0;
+ x->x_pointerset = 0;
+ x->x_lastdelta = 0;
+ x->x_embedflag = 0;
+ hammertree_init(&x->x_tree, 0);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_deltaout = outlet_new((t_object *)x, &s_float);
+ x->x_bangout = outlet_new((t_object *)x, &s_bang);
+ if (s && s != &s_)
+ {
+ x->x_defname = s; /* CHECKME if 'read' changes this */
+ funbuff_doread(x, s);
+ }
+ else x->x_defname = &s_;
+ x->x_filehandle = hammerfile_new((t_pd *)x, funbuff_embedhook,
+ funbuff_readhook, funbuff_writehook, 0);
+ return (x);
+}
+
+void funbuff_setup(void)
+{
+ funbuff_class = class_new(gensym("funbuff"),
+ (t_newmethod)funbuff_new,
+ (t_method)funbuff_free,
+ sizeof(t_funbuff), 0, A_DEFSYM, 0);
+ class_addbang(funbuff_class, funbuff_bang);
+ class_addfloat(funbuff_class, funbuff_float);
+ class_addmethod(funbuff_class, (t_method)funbuff_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_clear,
+ gensym("clear"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_goto,
+ gensym("goto"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_min,
+ gensym("min"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_max,
+ gensym("max"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_next,
+ gensym("next"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_embed,
+ gensym("embed"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_read,
+ gensym("read"), A_DEFSYM, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_write,
+ gensym("write"), A_DEFSYM, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_set,
+ gensym("set"), A_GIMME, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_delete,
+ gensym("delete"), A_GIMME, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_find,
+ gensym("find"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_dump,
+ gensym("dump"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_interp,
+ gensym("interp"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_interptab,
+ gensym("interptab"), A_FLOAT, A_SYMBOL, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_reduce,
+ gensym("reduce"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_select,
+ gensym("select"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_cut,
+ gensym("cut"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_copy,
+ gensym("copy"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_paste,
+ gensym("paste"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_undo,
+ gensym("undo"), 0);
+#ifdef HAMMERTREE_DEBUG
+ class_addmethod(funbuff_class, (t_method)funbuff_debug,
+ gensym("debug"), A_DEFFLOAT, 0);
+#endif
+ hammerfile_setup(funbuff_class, 1);
+}
diff --git a/cyclone/hammer/funnel.c b/cyclone/hammer/funnel.c
new file mode 100644
index 0000000..d289d8d
--- /dev/null
+++ b/cyclone/hammer/funnel.c
@@ -0,0 +1,179 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define FUNNEL_MINSLOTS 2
+#define FUNNEL_INISIZE 32 /* LATER rethink */
+#define FUNNEL_MAXSIZE 256
+
+typedef struct _funnel
+{
+ t_object x_ob;
+ int x_nslots;
+ int x_nproxies; /* as requested (and allocated) */
+ t_pd **x_proxies;
+} t_funnel;
+
+typedef struct _funnel_proxy
+{
+ t_object p_ob;
+ t_outlet *p_out; /* master outlet (the same value for each slot) */
+ int p_id; /* adjusted according to an offset argument */
+ t_float p_value;
+ int p_size; /* as allocated */
+ t_atom *p_message;
+ t_atom p_messini[FUNNEL_INISIZE];
+ int p_entered;
+} t_funnel_proxy;
+
+static t_class *funnel_class;
+static t_class *funnel_proxy_class;
+
+static void funnel_proxy_bang(t_funnel_proxy *x)
+{
+ t_atom at[2];
+ SETFLOAT(&at[0], x->p_id);
+ SETFLOAT(&at[1], x->p_value);
+ outlet_list(x->p_out, &s_list, 2, at);
+}
+
+static void funnel_proxy_float(t_funnel_proxy *x, t_float f)
+{
+ x->p_value = f;
+ funnel_proxy_bang(x);
+}
+
+static void funnel_proxy_list(t_funnel_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ int reentered = x->p_entered;
+ int prealloc = !reentered;
+ int ntotal = ac + 1;
+ x->p_entered = 1;
+ if (prealloc && ntotal > x->p_size)
+ {
+ if (ntotal > FUNNEL_MAXSIZE)
+ prealloc = 0;
+ else
+ {
+ x->p_message = grow_nodata(&ntotal, &x->p_size, x->p_message,
+ FUNNEL_INISIZE, x->p_messini,
+ sizeof(*x->p_message));
+ ac = ntotal - 1;
+ }
+ }
+ /* LATER consider a compatibility warning if av->a_type != A_FLOAT */
+ x->p_value = ((ac && av->a_type == A_FLOAT) ? av->a_w.w_float : 0);
+ if (prealloc)
+ {
+ SETFLOAT(x->p_message, x->p_id);
+ if (ac)
+ memcpy(x->p_message + 1, av, ac * sizeof(*x->p_message));
+ outlet_list(x->p_out, &s_list, ntotal, x->p_message);
+ }
+ else
+ {
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ t_atom *buf = getbytes(ntotal * sizeof(*buf));
+ if (buf)
+ {
+ SETFLOAT(buf, x->p_id);
+ if (ac)
+ memcpy(buf + 1, av, ac * sizeof(*buf));
+ outlet_list(x->p_out, &s_list, ntotal, buf);
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+ }
+ if (!reentered) x->p_entered = 0;
+}
+
+static void funnel_bang(t_funnel *x)
+{
+ funnel_proxy_bang((t_funnel_proxy *)x->x_proxies[0]);
+}
+
+static void funnel_float(t_funnel *x, t_float f)
+{
+ funnel_proxy_float((t_funnel_proxy *)x->x_proxies[0], f);
+}
+
+static void funnel_list(t_funnel *x, t_symbol *s, int ac, t_atom *av)
+{
+ funnel_proxy_list((t_funnel_proxy *)x->x_proxies[0], s, ac, av);
+}
+
+static void funnel_free(t_funnel *x)
+{
+ if (x->x_proxies)
+ {
+ int i = x->x_nslots;
+ while (i--)
+ {
+ t_funnel_proxy *y = (t_funnel_proxy *)x->x_proxies[i];
+ if (y->p_message != y->p_messini)
+ freebytes(y->p_message, y->p_size * sizeof(*y->p_message));
+ pd_free((t_pd *)y);
+ }
+ freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies));
+ }
+}
+
+static void *funnel_new(t_floatarg f1, t_floatarg f2)
+{
+ t_funnel *x;
+ int i, nslots, nproxies = (int)f1;
+ int offset = (int)f2;
+ t_outlet *out;
+ t_pd **proxies;
+ if (nproxies < 1) /* CHECKED: one-slot funnel may be created */
+ nproxies = FUNNEL_MINSLOTS;
+ if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies))))
+ return (0);
+ for (nslots = 0; nslots < nproxies; nslots++)
+ if (!(proxies[nslots] = pd_new(funnel_proxy_class))) break;
+ if (!nslots)
+ {
+ freebytes(proxies, nproxies * sizeof(*proxies));
+ return (0);
+ }
+ x = (t_funnel *)pd_new(funnel_class);
+ x->x_nslots = nslots;
+ x->x_nproxies = nproxies;
+ x->x_proxies = proxies;
+ out = outlet_new((t_object *)x, &s_list);
+ for (i = 0; i < nslots; i++)
+ {
+ t_funnel_proxy *y = (t_funnel_proxy *)proxies[i];
+ y->p_out = out;
+ y->p_id = offset++;
+ y->p_value = 0;
+ y->p_size = FUNNEL_INISIZE;
+ y->p_message = y->p_messini;
+ y->p_entered = 0;
+ if (i) inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ }
+ return (x);
+}
+
+void funnel_setup(void)
+{
+ funnel_class = class_new(gensym("funnel"),
+ (t_newmethod)funnel_new,
+ (t_method)funnel_free,
+ sizeof(t_funnel), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(funnel_class, funnel_bang);
+ class_addfloat(funnel_class, funnel_float);
+ class_addlist(funnel_class, funnel_list);
+ /* CHECKED: funnel doesn't understand symbol, anything */
+ funnel_proxy_class = class_new(gensym("_funnel_proxy"), 0, 0,
+ sizeof(t_funnel_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(funnel_proxy_class, funnel_proxy_bang);
+ class_addfloat(funnel_proxy_class, funnel_proxy_float);
+ class_addlist(funnel_proxy_class, funnel_proxy_list);
+ /* CHECKED: funnel doesn't understand symbol, anything */
+}
diff --git a/cyclone/hammer/gate.c b/cyclone/hammer/gate.c
new file mode 100644
index 0000000..2dbae57
--- /dev/null
+++ b/cyclone/hammer/gate.c
@@ -0,0 +1,147 @@
+/* Copyright (c) 2002-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 "common/loud.h"
+
+#define GATE_MINOUTS 1
+#define GATE_MAXOUTS 100
+#define GATE_DEFOUTS 1
+
+typedef struct _gate
+{
+ t_object x_ob;
+ int x_open;
+ t_pd *x_proxy;
+ int x_nouts; /* requested + 1 (as allocated) */
+ t_outlet **x_outs;
+} t_gate;
+
+typedef struct _gate_proxy
+{
+ t_object p_ob;
+ t_gate *p_master;
+} t_gate_proxy;
+
+static t_class *gate_class;
+static t_class *gate_proxy_class;
+
+static void gate_proxy_bang(t_gate_proxy *x)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_bang(master->x_outs[master->x_open]);
+}
+
+static void gate_proxy_float(t_gate_proxy *x, t_float f)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_float(master->x_outs[master->x_open], f);
+}
+
+static void gate_proxy_symbol(t_gate_proxy *x, t_symbol *s)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_symbol(master->x_outs[master->x_open], s);
+}
+
+static void gate_proxy_pointer(t_gate_proxy *x, t_gpointer *gp)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_pointer(master->x_outs[master->x_open], gp);
+}
+
+static void gate_proxy_list(t_gate_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_list(master->x_outs[master->x_open], s, ac, av);
+}
+
+static void gate_proxy_anything(t_gate_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_anything(master->x_outs[master->x_open], s, ac, av);
+}
+
+static void gate_float(t_gate *x, t_float f)
+{
+ int i = (int)f;
+ if (i < 0) i = 1;
+ if (i >= x->x_nouts) i = x->x_nouts - 1;
+ x->x_open = i;
+}
+
+static void gate_bang(t_gate *x)
+{
+ outlet_float(x->x_outs[1], x->x_open);
+}
+
+static void gate_free(t_gate *x)
+{
+ if (x->x_proxy) pd_free(x->x_proxy);
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_nouts * sizeof(*x->x_outs));
+}
+
+static void *gate_new(t_floatarg f1, t_floatarg f2)
+{
+ t_gate *x;
+ int i, nouts = (int)f1;
+ t_outlet **outs;
+ t_pd *proxy;
+ if (nouts < GATE_MINOUTS)
+ nouts = GATE_DEFOUTS;
+ if (nouts > GATE_MAXOUTS)
+ loud_incompatible_max(gate_class, GATE_MAXOUTS, "outlets");
+ nouts++; /* for convenience (the cost is one pointer) */
+ if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
+ return (0);
+ if (!(proxy = pd_new(gate_proxy_class)))
+ {
+ freebytes(outs, nouts * sizeof(*outs));
+ return (0);
+ }
+ x = (t_gate *)pd_new(gate_class);
+ x->x_nouts = nouts;
+ x->x_outs = outs;
+ x->x_proxy = proxy;
+ ((t_gate_proxy *)proxy)->p_master = x;
+ /* from max sdk manual: ``The dst parameter can be changed (or set to 0)
+ dynamically with the inlet_to function... The gate object uses this
+ technique to assign its inlet to one of several outlets, or no outlet
+ at all.'' We have to use a proxy, because Pd's outlet is not a t_pd
+ (besides, Pd does not handle inlets with null destination). */
+ inlet_new((t_object *)x, proxy, 0, 0);
+ for (i = 1; i < nouts; i++)
+ x->x_outs[i] = outlet_new((t_object *)x, &s_anything);
+ gate_float(x, (f2 > 0 ? f2 : 0)); /* CHECKED */
+ return (x);
+}
+
+void gate_setup(void)
+{
+ gate_class = class_new(gensym("gate"),
+ (t_newmethod)gate_new,
+ (t_method)gate_free,
+ sizeof(t_gate), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(gate_class, gate_float);
+ class_addbang(gate_class, gate_bang);
+ gate_proxy_class = class_new(gensym("_gate_proxy"), 0, 0,
+ sizeof(t_gate_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addfloat(gate_proxy_class, gate_proxy_float);
+ class_addbang(gate_proxy_class, gate_proxy_bang);
+ class_addsymbol(gate_proxy_class, gate_proxy_symbol);
+ class_addpointer(gate_proxy_class, gate_proxy_pointer);
+ class_addlist(gate_proxy_class, gate_proxy_list);
+ class_addanything(gate_proxy_class, gate_proxy_anything);
+}
diff --git a/cyclone/hammer/grab.c b/cyclone/hammer/grab.c
new file mode 100644
index 0000000..a54a3eb
--- /dev/null
+++ b/cyclone/hammer/grab.c
@@ -0,0 +1,279 @@
+/* Copyright (c) 2002-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 "unstable/pd_imp.h"
+#include "unstable/fragile.h"
+#include "common/loud.h"
+
+/* LATER handle canvas grabbing (bypass) */
+/* LATER check self-grabbing */
+/* LATER fragilize */
+
+/* It would be nice to have write access to o_connections field... */
+
+struct _outlet
+{
+ t_object *o_owner;
+ struct _outlet *o_next;
+ t_outconnect *o_connections;
+ t_symbol *o_sym;
+};
+
+/* ...and to have bindlist traversal routines in Pd API. */
+
+static t_class *bindlist_class = 0;
+
+typedef struct _bindelem
+{
+ t_pd *e_who;
+ struct _bindelem *e_next;
+} t_bindelem;
+
+typedef struct _bindlist
+{
+ t_pd b_pd;
+ t_bindelem *b_list;
+} t_bindlist;
+
+typedef struct _grab
+{
+ t_object x_ob;
+ t_symbol *x_target;
+ int x_noutlets; /* not counting right one */
+ t_outconnect **x_grabcons; /* grabbed connections */
+ t_outlet *x_rightout; /* right outlet */
+ /* traversal helpers: */
+ t_object *x_grabbed; /* currently grabbed object */
+ t_outconnect *x_tograbbed; /* a connection to grabbed object */
+ int x_ngrabout; /* number of grabbed object's outlets */
+ t_bindelem *x_bindelem;
+} t_grab;
+
+static t_class *grab_class;
+
+static void grab_start(t_grab *x)
+{
+ x->x_tograbbed = 0;
+ x->x_bindelem = 0;
+ if (x->x_target)
+ {
+ t_pd *proxy = x->x_target->s_thing;
+ t_object *ob;
+ if (proxy && bindlist_class)
+ {
+ if (*proxy == bindlist_class)
+ {
+ x->x_bindelem = ((t_bindlist *)proxy)->b_list;
+ while (x->x_bindelem)
+ {
+ if (ob = pd_checkobject(x->x_bindelem->e_who))
+ {
+ x->x_tograbbed =
+ fragile_outlet_connections(ob->ob_outlet);
+ return;
+ }
+ x->x_bindelem = x->x_bindelem->e_next;
+ }
+ }
+ else if (ob = pd_checkobject(proxy))
+ x->x_tograbbed = fragile_outlet_connections(ob->ob_outlet);
+ }
+ }
+ else x->x_tograbbed = fragile_outlet_connections(x->x_rightout);
+}
+
+static t_pd *grab_next(t_grab *x)
+{
+nextremote:
+ if (x->x_tograbbed)
+ {
+ t_inlet *ip;
+ int inno;
+ x->x_tograbbed = obj_nexttraverseoutlet(x->x_tograbbed,
+ &x->x_grabbed, &ip, &inno);
+ if (x->x_grabbed)
+ {
+ if (inno)
+ {
+ if (x->x_target)
+ loud_error((t_pd *)x,
+ "right outlet must feed leftmost inlet");
+ else
+ loud_error((t_pd *)x,
+ "remote proxy must feed leftmost inlet");
+ }
+ else
+ {
+ t_outlet *op;
+ t_outlet *goutp;
+ int goutno = x->x_noutlets;
+ x->x_ngrabout = obj_noutlets(x->x_grabbed);
+ if (goutno > x->x_ngrabout) goutno = x->x_ngrabout;
+ while (goutno--)
+ {
+ x->x_grabcons[goutno] =
+ obj_starttraverseoutlet(x->x_grabbed, &goutp, goutno);
+ goutp->o_connections =
+ obj_starttraverseoutlet((t_object *)x, &op, goutno);
+ }
+ return ((t_pd *)x->x_grabbed);
+ }
+ }
+ }
+ if (x->x_bindelem) while (x->x_bindelem = x->x_bindelem->e_next)
+ {
+ t_object *ob;
+ if (ob = pd_checkobject(x->x_bindelem->e_who))
+ {
+ x->x_tograbbed = fragile_outlet_connections(ob->ob_outlet);
+ goto nextremote;
+ }
+ }
+ return (0);
+}
+
+static void grab_restore(t_grab *x)
+{
+ t_outlet *goutp;
+ int goutno = x->x_noutlets;
+ if (goutno > x->x_ngrabout) goutno = x->x_ngrabout;
+ while (goutno--)
+ {
+ obj_starttraverseoutlet(x->x_grabbed, &goutp, goutno);
+ goutp->o_connections = x->x_grabcons[goutno];
+ }
+}
+
+static void grab_bang(t_grab *x)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ pd_bang(grabbed);
+ grab_restore(x);
+ }
+}
+
+static void grab_float(t_grab *x, t_float f)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ pd_float(grabbed, f);
+ grab_restore(x);
+ }
+}
+
+static void grab_symbol(t_grab *x, t_symbol *s)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ pd_symbol(grabbed, s);
+ grab_restore(x);
+ }
+}
+
+static void grab_pointer(t_grab *x, t_gpointer *gp)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ pd_pointer(grabbed, gp);
+ grab_restore(x);
+ }
+}
+
+static void grab_list(t_grab *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ pd_list(grabbed, s, ac, av);
+ grab_restore(x);
+ }
+}
+
+static void grab_anything(t_grab *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ typedmess(grabbed, s, ac, av);
+ grab_restore(x);
+ }
+}
+
+static void grab_set(t_grab *x, t_symbol *s)
+{
+ if (x->x_target && s && s != &s_) x->x_target = s;
+}
+
+/* LATER use A_GIMME */
+static void *grab_new(t_symbol *s, t_floatarg f)
+{
+ t_grab *x;
+ t_outconnect **grabcons;
+ int i, noutlets = (int)f;
+ if (noutlets < 1) noutlets = 1;
+ if (!(grabcons = getbytes(noutlets * sizeof(*grabcons))))
+ return (0);
+ x = (t_grab *)pd_new(grab_class);
+ x->x_noutlets = noutlets;
+ x->x_grabcons = grabcons;
+ while (noutlets--) outlet_new((t_object *)x, &s_anything);
+ if (s && s != &s_)
+ {
+ x->x_target = s;
+ x->x_rightout = 0;
+ }
+ else
+ {
+ x->x_target = 0;
+ x->x_rightout = outlet_new((t_object *)x, &s_anything);
+ }
+ return (x);
+}
+
+static void grab_free(t_grab *x)
+{
+ if (x->x_grabcons)
+ freebytes(x->x_grabcons, x->x_noutlets * sizeof(*x->x_grabcons));
+}
+
+void grab_setup(void)
+{
+ t_symbol *s = gensym("grab");
+ grab_class = class_new(s, (t_newmethod)grab_new,
+ (t_method)grab_free,
+ sizeof(t_grab), 0,
+ A_DEFFLOAT, A_DEFSYMBOL, 0);
+ class_addfloat(grab_class, grab_float);
+ class_addbang(grab_class, grab_bang);
+ class_addsymbol(grab_class, grab_symbol);
+ class_addpointer(grab_class, grab_pointer);
+ class_addlist(grab_class, grab_list);
+ class_addanything(grab_class, grab_anything);
+ class_addmethod(grab_class, (t_method)grab_set,
+ gensym("set"), A_SYMBOL, 0);
+ if (!bindlist_class)
+ {
+ t_class *c = grab_class;
+ pd_bind(&grab_class, s);
+ pd_bind(&c, s);
+ if (!s->s_thing
+ || !(bindlist_class = *s->s_thing)
+ || bindlist_class->c_name != gensym("bindlist"))
+ error("grab: failure to initialize remote grabbing feature");
+ pd_unbind(&c, s);
+ pd_unbind(&grab_class, s);
+ }
+}
diff --git a/cyclone/hammer/hammer.c b/cyclone/hammer/hammer.c
new file mode 100644
index 0000000..a4d7efe
--- /dev/null
+++ b/cyclone/hammer/hammer.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2002-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 <stdio.h>
+#include "m_pd.h"
+#include "unstable/fragile.h"
+#include "common/loud.h"
+#include "common/port.h"
+#include "hammer/file.h"
+#include "../build_counter"
+void allhammers_setup(void);
+
+typedef struct _hammer
+{
+ t_object x_ob;
+ t_symbol *x_dir;
+ t_hammerfile *x_filehandle;
+} t_hammer;
+
+static t_class *hammer_class;
+static int hammer_firstndx;
+static int hammer_lastndx;
+
+static void hammer_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ import_max(fn->s_name, "");
+}
+
+static void hammer_import(t_hammer *x, t_symbol *fn, t_symbol *dir)
+{
+ if (fn && fn != &s_)
+ {
+ if (!dir || dir == &s_) dir = x->x_dir;
+ import_max(fn->s_name, (dir && dir != &s_) ? dir->s_name : "");
+ }
+ else
+ hammerpanel_open(x->x_filehandle);
+}
+
+static void hammer_click(t_hammer *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ hammer_import(x, 0, 0);
+}
+
+static void hammer_bang(t_hammer *x)
+{
+ fragile_class_printnames("hammer classes are: ",
+ hammer_firstndx, hammer_lastndx);
+}
+
+static void hammer_free(t_hammer *x)
+{
+ hammerfile_free(x->x_filehandle);
+}
+
+static void *hammer_new(t_symbol *s)
+{
+ t_hammer *x = (t_hammer *)pd_new(hammer_class);
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0, hammer_readhook, 0, 0);
+ x->x_dir = (s && s != &s_ ? s : canvas_getdir(x->x_filehandle->f_canvas));
+ return (x);
+}
+
+void hammer_setup(void)
+{
+ if (canvas_getcurrent())
+ {
+ /* Loading the library by object creation is banned, because of a danger
+ of having some of the classes already loaded. LATER rethink. */
+ loud_error(0, "apparently an attempt to create a 'hammer' object");
+ loud_errand(0, "without having hammer library preloaded");
+ return;
+ }
+ if (!zgetfn(&pd_objectmaker, gensym("cyclone")))
+ post("this is hammer %s, %s %s build",
+ CYCLONE_VERSION, loud_ordinal(CYCLONE_BUILD), CYCLONE_RELEASE);
+ hammer_class = class_new(gensym("hammer"),
+ (t_newmethod)hammer_new,
+ (t_method)hammer_free,
+ sizeof(t_hammer), 0, A_DEFSYM, 0);
+ class_addbang(hammer_class, hammer_bang);
+ class_addmethod(hammer_class, (t_method)hammer_import,
+ gensym("import"), A_DEFSYM, A_DEFSYM, 0);
+ class_addmethod(hammer_class, (t_method)hammer_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ hammerfile_setup(hammer_class, 0);
+ hammer_firstndx = fragile_class_count();
+ allhammers_setup();
+ hammer_lastndx = fragile_class_count() - 1;
+}
diff --git a/cyclone/hammer/iter.c b/cyclone/hammer/iter.c
new file mode 100644
index 0000000..0aa5ef8
--- /dev/null
+++ b/cyclone/hammer/iter.c
@@ -0,0 +1,112 @@
+/* Copyright (c) 2002-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 a modified version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+/* LATER compare with iter.c from max sdk */
+/* LATER clean up buffer handling */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define ITER_INISIZE 8 /* LATER rethink */
+
+typedef struct _iter
+{
+ t_object x_ob;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ t_symbol *x_selector;
+ t_atom *x_message;
+ t_atom x_messini[ITER_INISIZE];
+} t_iter;
+
+static t_class *iter_class;
+
+/* CHECKED: both floats and symbols */
+static void iter_dobang(t_iter *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (s && s != &s_)
+ outlet_symbol(((t_object *)x)->ob_outlet, s);
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ outlet_symbol(((t_object *)x)->ob_outlet, av->a_w.w_symbol);
+ av++;
+ }
+}
+
+static void iter_bang(t_iter *x)
+{
+ iter_dobang(x, x->x_selector, x->x_natoms, x->x_message);
+}
+
+static void iter_float(t_iter *x, t_float f)
+{
+ outlet_float(((t_object *)x)->ob_outlet, f);
+ x->x_selector = 0;
+ x->x_natoms = 1;
+ SETFLOAT(x->x_message, f);
+}
+
+/* CHECKME */
+static void iter_symbol(t_iter *x, t_symbol *s)
+{
+ outlet_symbol(((t_object *)x)->ob_outlet, s);
+ x->x_selector = 0;
+ x->x_natoms = 1;
+ SETSYMBOL(x->x_message, s);
+}
+
+/* LATER gpointer */
+
+static void iter_anything(t_iter *x, t_symbol *s, int ac, t_atom *av)
+{
+ iter_dobang(x, s, ac, av);
+ x->x_selector = s;
+ if (ac > x->x_size)
+ x->x_message = grow_nodata(&ac, &x->x_size, x->x_message,
+ ITER_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ x->x_natoms = ac;
+ memcpy(x->x_message, av, ac * sizeof(*x->x_message));
+}
+
+static void iter_list(t_iter *x, t_symbol *s, int ac, t_atom *av)
+{
+ iter_anything(x, 0, ac, av);
+}
+
+static void iter_free(t_iter *x)
+{
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_natoms * sizeof(*x->x_message));
+}
+
+static void *iter_new(void)
+{
+ t_iter *x = (t_iter *)pd_new(iter_class);
+ x->x_size = ITER_INISIZE;
+ x->x_natoms = 0;
+ x->x_message = x->x_messini;
+ outlet_new((t_object *)x, &s_anything);
+ return (x);
+}
+
+void iter_setup(void)
+{
+ iter_class = class_new(gensym("iter"),
+ (t_newmethod)iter_new,
+ (t_method)iter_free,
+ sizeof(t_iter), 0, 0);
+ class_addbang(iter_class, iter_bang);
+ class_addfloat(iter_class, iter_float);
+ class_addsymbol(iter_class, iter_symbol);
+ class_addlist(iter_class, iter_list);
+ class_addanything(iter_class, iter_anything);
+}
diff --git a/cyclone/hammer/match.c b/cyclone/hammer/match.c
new file mode 100644
index 0000000..d5b03c7
--- /dev/null
+++ b/cyclone/hammer/match.c
@@ -0,0 +1,216 @@
+/* Copyright (c) 2002-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 compare with match.c from max sdk */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define MATCH_INISIZE 8 /* LATER rethink */
+
+typedef struct _match
+{
+ t_object x_ob;
+ int x_size; /* as allocated */
+ int x_patlen; /* as used */
+ t_atom *x_pattern;
+ t_atom x_patini[MATCH_INISIZE];
+ int x_quelen;
+ t_atom *x_queue;
+ t_atom x_queini[MATCH_INISIZE];
+ t_atom *x_queend;
+ t_atom *x_queptr; /* writing head, post-incremented (oldest-pointing) */
+} t_match;
+
+static t_class *match_class;
+
+static void match_clear(t_match *x)
+{
+ x->x_quelen = 0;
+ x->x_queptr = x->x_queue;
+}
+
+/* x->x_patlen > 0 is assumed */
+/* LATER use a lock to disable reentrant calls. I do not see any
+ purpose of reentering match, but lets CHECKME first... */
+static void match_checkin(t_match *x)
+{
+ int i, patlen = x->x_patlen;
+ t_atom *queptr, *pp, *qp;
+ if (x->x_queptr >= x->x_queend)
+ x->x_queptr = x->x_queue;
+ else x->x_queptr++;
+ if (x->x_quelen < patlen && ++(x->x_quelen) < patlen)
+ return;
+
+ qp = queptr = x->x_queptr;
+ for (i = 0, pp = x->x_pattern; i < patlen; i++, pp++)
+ {
+ if (pp->a_type == A_FLOAT)
+ {
+ if (qp->a_type != A_FLOAT || qp->a_w.w_float != pp->a_w.w_float)
+ break;
+ }
+ else if (pp->a_type == A_SYMBOL)
+ {
+ if (qp->a_type != A_SYMBOL || qp->a_w.w_symbol != pp->a_w.w_symbol)
+ break;
+ }
+ else if (pp->a_type == A_NULL)
+ {
+ if (qp->a_type == A_FLOAT || qp->a_type == A_SYMBOL)
+ {
+ /* instantiating a pattern */
+ *pp = *qp;
+ qp->a_type = A_NULL;
+ }
+ else break; /* LATER rethink */
+ }
+ else break; /* LATER rethink */
+ if (qp >= x->x_queend)
+ qp = x->x_queue;
+ else qp++;
+ }
+ if (i == patlen)
+ {
+ pp = x->x_pattern;
+ if (pp->a_type == A_FLOAT)
+ {
+ if (patlen == 1)
+ outlet_float(((t_object *)x)->ob_outlet, pp->a_w.w_float);
+ else
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, patlen, pp);
+ }
+ else /* assuming A_SYMBOL (see above) */
+ {
+ if (pp->a_w.w_symbol == &s_symbol /* bypassing typedmess() */
+ && patlen == 2 && pp[1].a_type == A_SYMBOL)
+ outlet_symbol(((t_object *)x)->ob_outlet, pp[1].a_w.w_symbol);
+ else
+ outlet_anything(((t_object *)x)->ob_outlet, pp->a_w.w_symbol,
+ patlen - 1, pp + 1);
+ }
+ /* CHECKED: no implicit clear (resolving overlapping patterns) */
+ }
+ /* restoring a pattern */
+ for (i = 0, pp = x->x_pattern; i < patlen; i++, pp++)
+ {
+ if (queptr->a_type == A_NULL)
+ {
+ queptr->a_type = pp->a_type;
+ pp->a_type = A_NULL;
+ }
+ if (queptr >= x->x_queend)
+ queptr = x->x_queue;
+ else queptr++;
+ }
+}
+
+static void match_float(t_match *x, t_float f)
+{
+ if (x->x_patlen)
+ {
+ SETFLOAT(x->x_queptr, f);
+ match_checkin(x);
+ }
+}
+
+static void match_symbol(t_match *x, t_symbol *s)
+{
+ if (s && s != &s_ && x->x_patlen)
+ {
+ SETSYMBOL(x->x_queptr, s);
+ match_checkin(x);
+ }
+}
+
+/* LATER gpointer */
+
+static void match_list(t_match *x, t_symbol *s, int ac, t_atom *av)
+{
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT) match_float(x, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL) match_symbol(x, av->a_w.w_symbol);
+ av++;
+ }
+}
+
+static void match_anything(t_match *x, t_symbol *s, int ac, t_atom *av)
+{
+ match_symbol(x, s);
+ match_list(x, 0, ac, av);
+}
+
+static void match_set(t_match *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac) /* CHECKED */
+ {
+ t_atom *pp;
+ t_symbol *ps_nn;
+ int newlen = ac * 2;
+ if (newlen > x->x_size)
+ {
+ x->x_pattern = grow_nodata(&newlen, &x->x_size, x->x_pattern,
+ MATCH_INISIZE * 2, x->x_patini,
+ sizeof(*x->x_pattern));
+ if (newlen == MATCH_INISIZE * 2)
+ {
+ x->x_queue = x->x_queini;
+ ac = MATCH_INISIZE;
+ }
+ else x->x_queue = x->x_pattern + x->x_size / 2;
+ }
+ x->x_patlen = ac;
+ x->x_queend = x->x_queue + ac - 1;
+ match_clear(x); /* CHECKED */
+ memcpy(x->x_pattern, av, ac * sizeof(*x->x_pattern));
+ pp = x->x_pattern;
+ ps_nn = gensym("nn");
+ while (ac--)
+ {
+ if (pp->a_type == A_SYMBOL && pp->a_w.w_symbol == ps_nn)
+ pp->a_type = A_NULL;
+ pp++;
+ }
+ }
+}
+
+static void match_free(t_match *x)
+{
+ if (x->x_pattern != x->x_patini)
+ freebytes(x->x_pattern, 2 * x->x_size * sizeof(*x->x_pattern));
+}
+
+static void *match_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_match *x = (t_match *)pd_new(match_class);
+ x->x_size = MATCH_INISIZE * 2;
+ x->x_patlen = 0;
+ x->x_pattern = x->x_patini;
+ x->x_queue = x->x_queini;
+ /* x->x_queend is not used unless x->x_patlen > 0,
+ LATER consider chosing a more defensive way... */
+ outlet_new((t_object *)x, &s_anything);
+ match_clear(x);
+ match_set(x, 0, ac, av);
+ return (x);
+}
+
+void match_setup(void)
+{
+ match_class = class_new(gensym("match"),
+ (t_newmethod)match_new,
+ (t_method)match_free,
+ sizeof(t_match), 0, A_GIMME, 0);
+ class_addfloat(match_class, match_float);
+ class_addsymbol(match_class, match_symbol);
+ class_addlist(match_class, match_list);
+ class_addanything(match_class, match_anything);
+ class_addmethod(match_class, (t_method)match_set,
+ gensym("set"), A_GIMME, 0);
+ class_addmethod(match_class, (t_method)match_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/maximum.c b/cyclone/hammer/maximum.c
new file mode 100644
index 0000000..038d8f1
--- /dev/null
+++ b/cyclone/hammer/maximum.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2002-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 "common/loud.h"
+
+typedef struct _maximum
+{
+ t_object x_ob;
+ t_float x_last;
+ t_float x_test;
+} t_maximum;
+
+static t_class *maximum_class;
+
+static void maximum_bang(t_maximum *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_last);
+}
+
+static void maximum_float(t_maximum *x, t_float f)
+{
+ outlet_float(((t_object *)x)->ob_outlet,
+ x->x_last = (f > x->x_test ? f : x->x_test));
+}
+
+static void maximum_list(t_maximum *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac > 256) loud_incompatible_max(*(t_pd *)x, 256, "items");
+ while (ac && av->a_type != A_FLOAT) ac--, av++; /* CHECKME (a warning?) */
+ if (ac)
+ {
+ t_float fpick = av->a_w.w_float;
+ ac--; av++;
+ while (ac && av->a_type != A_FLOAT) ac--, av++; /* CHECKME */
+ if (ac)
+ {
+ t_float fnext, f = av->a_w.w_float;
+ if (f > fpick)
+ {
+ fnext = fpick;
+ fpick = f;
+ }
+ else fnext = f;
+ ac--; av++;
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ f = av->a_w.w_float;
+ if (f > fpick)
+ {
+ fnext = fpick;
+ fpick = f;
+ }
+ else if (f > fnext) fnext = f;
+ }
+ /* CHECKME else */
+ av++;
+ }
+ x->x_test = fnext;
+ outlet_float(((t_object *)x)->ob_outlet, x->x_last = fpick);
+ }
+ else maximum_float(x, fpick); /* CHECKME */
+ }
+ /* CHECKME else */
+}
+
+static void *maximum_new(t_floatarg f)
+{
+ t_maximum *x = (t_maximum *)pd_new(maximum_class);
+ x->x_last = 0; /* CHECKME */
+ x->x_test = f;
+ floatinlet_new((t_object *)x, &x->x_test);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void maximum_setup(void)
+{
+ maximum_class = class_new(gensym("maximum"),
+ (t_newmethod)maximum_new, 0,
+ sizeof(t_maximum), 0, A_DEFFLOAT, 0);
+ class_addbang(maximum_class, maximum_bang);
+ class_addfloat(maximum_class, maximum_float);
+ class_addlist(maximum_class, maximum_list);
+}
diff --git a/cyclone/hammer/mean.c b/cyclone/hammer/mean.c
new file mode 100644
index 0000000..13d69ff
--- /dev/null
+++ b/cyclone/hammer/mean.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2002-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"
+
+typedef struct _mean
+{
+ t_object x_ob;
+ double x_accum;
+ unsigned x_count;
+ t_float x_mean;
+ t_outlet *x_countout;
+} t_mean;
+
+static t_class *mean_class;
+
+static void mean_clear(t_mean *x)
+{
+ x->x_accum = 0;
+ x->x_count = 0;
+ x->x_mean = 0;
+}
+
+static void mean_bang(t_mean *x)
+{
+ /* CHECKED: count is always sent (first) */
+ outlet_float(x->x_countout, x->x_count);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_mean);
+}
+
+static void mean_float(t_mean *x, t_float f)
+{
+ x->x_accum += f;
+ if (++x->x_count)
+ x->x_mean = (t_float)(x->x_accum / (double)x->x_count);
+ else mean_clear(x);
+ mean_bang(x);
+}
+
+static void mean_list(t_mean *x, t_symbol *s, int ac, t_atom *av)
+{
+ mean_clear(x);
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ x->x_accum += av->a_w.w_float;
+ x->x_count++;
+ }
+ av++;
+ }
+ if (x->x_count)
+ x->x_mean = (t_float)(x->x_accum / (double)x->x_count);
+ else mean_clear(x);
+ mean_bang(x);
+ /* CHECKED: no clear after list -- subsequent floats are added */
+}
+
+static void *mean_new(void)
+{
+ t_mean *x = (t_mean *)pd_new(mean_class);
+ mean_clear(x);
+ outlet_new((t_object *)x, &s_float);
+ x->x_countout = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void mean_setup(void)
+{
+ mean_class = class_new(gensym("mean"),
+ (t_newmethod)mean_new, 0,
+ sizeof(t_mean), 0, 0);
+ class_addbang(mean_class, mean_bang);
+ class_addfloat(mean_class, mean_float);
+ class_addlist(mean_class, mean_list);
+ class_addmethod(mean_class, (t_method)mean_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/midiflush.c b/cyclone/hammer/midiflush.c
new file mode 100644
index 0000000..592d9e0
--- /dev/null
+++ b/cyclone/hammer/midiflush.c
@@ -0,0 +1,102 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+
+#define MIDIFLUSH_NCHANNELS 16
+#define MIDIFLUSH_NPITCHES 128
+#define MIDIFLUSH_VOIDPITCH 0xFF
+
+typedef struct _midiflush
+{
+ t_object x_ob;
+ unsigned char x_status;
+ unsigned char x_channel;
+ unsigned char x_pitch;
+ unsigned char x_notes[MIDIFLUSH_NCHANNELS][MIDIFLUSH_NPITCHES];
+} t_midiflush;
+
+static t_class *midiflush_class;
+
+static void midiflush_float(t_midiflush *x, t_float f)
+{
+ int ival = (int)f;
+ if (ival >= 0 && ival < 256)
+ {
+ unsigned char bval = ival;
+ outlet_float(((t_object *)x)->ob_outlet, bval);
+ if (bval & 0x80)
+ {
+ x->x_status = bval & 0xF0;
+ if (x->x_status == 0x80 || x->x_status == 0x90)
+ x->x_channel = bval & 0x0F;
+ else
+ x->x_status = 0;
+ }
+ else if (x->x_status)
+ {
+ if (x->x_pitch == MIDIFLUSH_VOIDPITCH)
+ {
+ x->x_pitch = bval;
+ return;
+ }
+ else if (x->x_status == 0x90 && bval)
+ {
+ x->x_notes[x->x_channel][x->x_pitch]++;
+ }
+ else
+ {
+ x->x_notes[x->x_channel][x->x_pitch]--;
+ }
+ }
+ }
+ x->x_pitch = MIDIFLUSH_VOIDPITCH;
+}
+
+static void midiflush_bang(t_midiflush *x)
+{
+ int chn, pch;
+ for (chn = 0; chn < MIDIFLUSH_NCHANNELS; chn++)
+ {
+ for (pch = 0; pch < MIDIFLUSH_NPITCHES; pch++)
+ {
+ int status = 0x090 | chn;
+ while (x->x_notes[chn][pch])
+ {
+ outlet_float(((t_object *)x)->ob_outlet, status);
+ outlet_float(((t_object *)x)->ob_outlet, pch);
+ outlet_float(((t_object *)x)->ob_outlet, 0);
+ x->x_notes[chn][pch]--;
+ }
+ }
+ }
+}
+
+static void midiflush_clear(t_midiflush *x)
+{
+ memset(x->x_notes, 0, sizeof(x->x_notes));
+}
+
+static void *midiflush_new(void)
+{
+ t_midiflush *x = (t_midiflush *)pd_new(midiflush_class);
+ x->x_status = 0; /* `not a note' */
+ x->x_pitch = MIDIFLUSH_VOIDPITCH;
+ midiflush_clear(x);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void midiflush_setup(void)
+{
+ midiflush_class = class_new(gensym("midiflush"),
+ (t_newmethod)midiflush_new,
+ 0, /* CHECKED: no flushout */
+ sizeof(t_midiflush), 0, 0);
+ class_addfloat(midiflush_class, midiflush_float);
+ class_addbang(midiflush_class, midiflush_bang);
+ class_addmethod(midiflush_class, (t_method)midiflush_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/midiformat.c b/cyclone/hammer/midiformat.c
new file mode 100644
index 0000000..fa0612b
--- /dev/null
+++ b/cyclone/hammer/midiformat.c
@@ -0,0 +1,112 @@
+/* Copyright (c) 2002-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"
+
+typedef struct _midiformat
+{
+ t_object x_ob;
+ t_float x_channel;
+} t_midiformat;
+
+static t_class *midiformat_class;
+
+static int midiformat_channel(t_midiformat *x)
+{
+ int ch = (int)x->x_channel;
+ return (ch > 0 ? (ch - 1) & 0x0F : 0);
+}
+
+static void midiformat_note(t_midiformat *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av[0].a_type == A_FLOAT && av[1].a_type == A_FLOAT)
+ {
+ int pitch = (int)av[0].a_w.w_float; /* CHECKED: anything goes */
+ int velocity = (int)av[1].a_w.w_float;
+ outlet_float(((t_object *)x)->ob_outlet, 0x90 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, pitch);
+ outlet_float(((t_object *)x)->ob_outlet, velocity);
+ }
+}
+
+static void midiformat_polytouch(t_midiformat *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av[0].a_type == A_FLOAT && av[1].a_type == A_FLOAT)
+ {
+ int touch = (int)av[0].a_w.w_float;
+ int key = (int)av[1].a_w.w_float;
+ outlet_float(((t_object *)x)->ob_outlet, 0xA0 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, key);
+ outlet_float(((t_object *)x)->ob_outlet, touch);
+ }
+}
+
+static void midiformat_controller(t_midiformat *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av[0].a_type == A_FLOAT && av[1].a_type == A_FLOAT)
+ {
+ int val = (int)av[0].a_w.w_float;
+ int ctl = (int)av[1].a_w.w_float;
+ outlet_float(((t_object *)x)->ob_outlet, 0xB0 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, ctl);
+ outlet_float(((t_object *)x)->ob_outlet, val);
+ }
+}
+
+static void midiformat_program(t_midiformat *x, t_floatarg f)
+{
+ int pgm = (int)f;
+ outlet_float(((t_object *)x)->ob_outlet, 0xC0 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, pgm);
+}
+
+static void midiformat_touch(t_midiformat *x, t_floatarg f)
+{
+ int touch = (int)f;
+ outlet_float(((t_object *)x)->ob_outlet, 0xD0 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, touch);
+}
+
+static void midiformat_bend(t_midiformat *x, t_floatarg f)
+{
+ int val = (int)f;
+ outlet_float(((t_object *)x)->ob_outlet, 0xE0 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, 0);
+ outlet_float(((t_object *)x)->ob_outlet, val);
+}
+
+static void *midiformat_new(t_floatarg f)
+{
+ t_midiformat *x = (t_midiformat *)pd_new(midiformat_class);
+ x->x_channel = f;
+ inlet_new((t_object *)x, (t_pd *)x, &s_list, gensym("lst1"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_list, gensym("lst2"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft3"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft4"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft5"));
+ floatinlet_new((t_object *)x, &x->x_channel);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void midiformat_setup(void)
+{
+ midiformat_class = class_new(gensym("midiformat"),
+ (t_newmethod)midiformat_new, 0,
+ sizeof(t_midiformat), 0,
+ A_DEFFLOAT, 0);
+ class_addlist(midiformat_class, midiformat_note);
+ class_addmethod(midiformat_class, (t_method)midiformat_polytouch,
+ gensym("lst1"), A_GIMME, 0);
+ class_addmethod(midiformat_class, (t_method)midiformat_controller,
+ gensym("lst2"), A_GIMME, 0);
+ class_addmethod(midiformat_class, (t_method)midiformat_program,
+ gensym("ft3"), A_FLOAT, 0);
+ class_addmethod(midiformat_class, (t_method)midiformat_touch,
+ gensym("ft4"), A_FLOAT, 0);
+ class_addmethod(midiformat_class, (t_method)midiformat_bend,
+ gensym("ft5"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/midiparse.c b/cyclone/hammer/midiparse.c
new file mode 100644
index 0000000..9a79a39
--- /dev/null
+++ b/cyclone/hammer/midiparse.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2002-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"
+
+typedef struct _midiparse
+{
+ t_object x_ob;
+ unsigned char x_ready;
+ unsigned char x_status;
+ unsigned char x_channel;
+ unsigned char x_data1;
+ t_outlet *x_polyout;
+ t_outlet *x_ctlout;
+ t_outlet *x_pgmout;
+ t_outlet *x_touchout;
+ t_outlet *x_bendout;
+ t_outlet *x_chanout;
+} t_midiparse;
+
+static t_class *midiparse_class;
+
+static void midiparse_clear(t_midiparse *x)
+{
+ x->x_status = 0;
+ x->x_ready = 0;
+}
+
+static void midiparse_float(t_midiparse *x, t_float f)
+{
+ int ival = (int)f; /* CHECKED */
+ if (ival < 0)
+ {
+ /* CHECKME */
+ return;
+ }
+ if (ival < 256) /* CHECKED clear if input over 255 */
+ {
+ unsigned char bval = ival;
+ if (bval & 0x80)
+ {
+ unsigned char status = bval & 0xF0;
+ if (status == 0xF0)
+ {
+ /* CHECKED no such test in max -- this is incompatible,
+ but real-time messages are out-of-band, and they
+ should be ignored here. LATER rethink the 0xFE case. */
+ if (bval < 0xF8)
+ midiparse_clear(x);
+ }
+ else
+ {
+ x->x_status = status;
+ x->x_channel = bval & 0x0F;
+ x->x_ready = (status == 0xC0 || status == 0xD0);
+ }
+ }
+ else if (x->x_ready)
+ {
+ t_atom at[2];
+ x->x_ready = 0;
+ outlet_float(x->x_chanout, x->x_channel + 1);
+ switch (x->x_status)
+ {
+ case 0x80:
+ SETFLOAT(&at[0], x->x_data1);
+ SETFLOAT(&at[1], 0);
+ outlet_list(((t_object *)x)->ob_outlet, 0, 2, at);
+ break;
+ case 0x90:
+ SETFLOAT(&at[0], x->x_data1);
+ SETFLOAT(&at[1], bval);
+ outlet_list(((t_object *)x)->ob_outlet, 0, 2, at);
+ break;
+ case 0xA0:
+ SETFLOAT(&at[0], bval);
+ SETFLOAT(&at[1], x->x_data1);
+ outlet_list(x->x_polyout, 0, 2, at);
+ break;
+ case 0xB0:
+ SETFLOAT(&at[0], bval);
+ SETFLOAT(&at[1], x->x_data1);
+ outlet_list(x->x_ctlout, 0, 2, at);
+ break;
+ case 0xC0:
+ outlet_float(x->x_pgmout, bval);
+ x->x_ready = 1;
+ break;
+ case 0xD0:
+ outlet_float(x->x_touchout, bval);
+ x->x_ready = 1;
+ break;
+ case 0xE0:
+ /* CHECKED: ignores data1 */
+ outlet_float(x->x_bendout, bval);
+ break;
+ default:;
+ }
+ }
+ else if (x->x_status)
+ {
+ x->x_data1 = bval; /* CHECKED key #0 accepted */
+ x->x_ready = 1;
+ }
+ }
+ else midiparse_clear(x);
+}
+
+static void *midiparse_new(void)
+{
+ t_midiparse *x = (t_midiparse *)pd_new(midiparse_class);
+ outlet_new((t_object *)x, &s_list);
+ x->x_polyout = outlet_new((t_object *)x, &s_list);
+ x->x_ctlout = outlet_new((t_object *)x, &s_list);
+ x->x_pgmout = outlet_new((t_object *)x, &s_float);
+ x->x_touchout = outlet_new((t_object *)x, &s_float);
+ x->x_bendout = outlet_new((t_object *)x, &s_float);
+ x->x_chanout = outlet_new((t_object *)x, &s_float);
+ midiparse_clear(x);
+ return (x);
+}
+
+void midiparse_setup(void)
+{
+ midiparse_class = class_new(gensym("midiparse"),
+ (t_newmethod)midiparse_new, 0,
+ sizeof(t_midiparse), 0, 0);
+ class_addbang(midiparse_class, midiparse_clear);
+ class_addfloat(midiparse_class, midiparse_float);
+ /* CHECKED autocasting lists to floats */
+}
diff --git a/cyclone/hammer/minimum.c b/cyclone/hammer/minimum.c
new file mode 100644
index 0000000..466b6f8
--- /dev/null
+++ b/cyclone/hammer/minimum.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2002-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 "common/loud.h"
+
+typedef struct _minimum
+{
+ t_object x_ob;
+ t_float x_last;
+ t_float x_test;
+} t_minimum;
+
+static t_class *minimum_class;
+
+static void minimum_bang(t_minimum *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_last);
+}
+
+static void minimum_float(t_minimum *x, t_float f)
+{
+ outlet_float(((t_object *)x)->ob_outlet,
+ x->x_last = (f < x->x_test ? f : x->x_test));
+}
+
+static void minimum_list(t_minimum *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac > 256) loud_incompatible_max(*(t_pd *)x, 256, "items");
+ while (ac && av->a_type != A_FLOAT) ac--, av++; /* CHECKME (a warning?) */
+ if (ac)
+ {
+ t_float fpick = av->a_w.w_float;
+ ac--; av++;
+ while (ac && av->a_type != A_FLOAT) ac--, av++; /* CHECKME */
+ if (ac)
+ {
+ t_float fnext, f = av->a_w.w_float;
+ if (f < fpick)
+ {
+ fnext = fpick;
+ fpick = f;
+ }
+ else fnext = f;
+ ac--; av++;
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ f = av->a_w.w_float;
+ if (f < fpick)
+ {
+ fnext = fpick;
+ fpick = f;
+ }
+ else if (f < fnext) fnext = f;
+ }
+ /* CHECKME else */
+ av++;
+ }
+ x->x_test = fnext;
+ outlet_float(((t_object *)x)->ob_outlet, x->x_last = fpick);
+ }
+ else minimum_float(x, fpick); /* CHECKME */
+ }
+ /* CHECKME else */
+}
+
+static void *minimum_new(t_floatarg f)
+{
+ t_minimum *x = (t_minimum *)pd_new(minimum_class);
+ x->x_last = 0; /* CHECKME */
+ x->x_test = f;
+ floatinlet_new((t_object *)x, &x->x_test);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void minimum_setup(void)
+{
+ minimum_class = class_new(gensym("minimum"),
+ (t_newmethod)minimum_new, 0,
+ sizeof(t_minimum), 0, A_DEFFLOAT, 0);
+ class_addbang(minimum_class, minimum_bang);
+ class_addfloat(minimum_class, minimum_float);
+ class_addlist(minimum_class, minimum_list);
+}
diff --git a/cyclone/hammer/mousefilter.c b/cyclone/hammer/mousefilter.c
new file mode 100644
index 0000000..e2e3cc5
--- /dev/null
+++ b/cyclone/hammer/mousefilter.c
@@ -0,0 +1,70 @@
+/* Copyright (c) 2002-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 "hammer/gui.h"
+
+typedef struct _mousefilter
+{
+ t_object x_ob;
+ int x_isup;
+ int x_ispending;
+ t_float x_value;
+} t_mousefilter;
+
+static t_class *mousefilter_class;
+
+static void mousefilter_float(t_mousefilter *x, t_float f)
+{
+ if (x->x_isup)
+ outlet_float(((t_object *)x)->ob_outlet, f);
+ else
+ {
+ x->x_ispending = 1;
+ x->x_value = f;
+ }
+}
+
+static void mousefilter_anything(t_mousefilter *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ /* dummy method, filtering out those messages from gui,
+ which are not handled explicitly */
+}
+
+static void mousefilter_doup(t_mousefilter *x, t_floatarg f)
+{
+ if ((x->x_isup = (int)f) && x->x_ispending)
+ {
+ x->x_ispending = 0;
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+ }
+}
+
+static void mousefilter_free(t_mousefilter *x)
+{
+ hammergui_unbindmouse((t_pd *)x);
+}
+
+static void *mousefilter_new(void)
+{
+ t_mousefilter *x = (t_mousefilter *)pd_new(mousefilter_class);
+ x->x_isup = 0; /* LATER rethink */
+ x->x_ispending = 0;
+ outlet_new((t_object *)x, &s_float);
+ hammergui_bindmouse((t_pd *)x);
+ return (x);
+}
+
+void mousefilter_setup(void)
+{
+ mousefilter_class = class_new(gensym("mousefilter"),
+ (t_newmethod)mousefilter_new,
+ (t_method)mousefilter_free,
+ sizeof(t_mousefilter), 0, 0);
+ class_addfloat(mousefilter_class, mousefilter_float);
+ class_addanything(mousefilter_class, mousefilter_anything);
+ class_addmethod(mousefilter_class, (t_method)mousefilter_doup,
+ gensym("_up"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/next.c b/cyclone/hammer/next.c
new file mode 100644
index 0000000..3fe7d6e
--- /dev/null
+++ b/cyclone/hammer/next.c
@@ -0,0 +1,58 @@
+/* Copyright (c) 2002-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"
+
+//#define NEXT_USEEVENTNO
+
+typedef struct _next
+{
+ t_object x_ob;
+#ifdef NEXT_USEEVENTNO
+ int x_lastevent;
+#else
+ double x_lastevent;
+#endif
+ t_outlet *x_out2;
+} t_next;
+
+static t_class *next_class;
+
+/* CHECKME first call, CHECKME if the outlets are not swapped */
+static void next_anything(t_next *x, t_symbol *s, int ac, t_atom *av)
+{
+#ifdef NEXT_USEEVENTNO
+ int nextevent = sys_geteventno();
+#else
+ double nextevent = clock_getlogicaltime();
+#endif
+ if (x->x_lastevent == nextevent)
+ outlet_bang(x->x_out2);
+ else
+ {
+ x->x_lastevent = nextevent;
+ outlet_bang(((t_object *)x)->ob_outlet);
+ }
+}
+
+static void *next_new(void)
+{
+ t_next *x = (t_next *)pd_new(next_class);
+ outlet_new((t_object *)x, &s_bang);
+ x->x_out2 = outlet_new((t_object *)x, &s_bang);
+#ifdef NEXT_USEEVENTNO
+ x->x_lastevent = sys_geteventno();
+#else
+ x->x_lastevent = clock_getlogicaltime();
+#endif
+ return (x);
+}
+
+void next_setup(void)
+{
+ next_class = class_new(gensym("next"),
+ (t_newmethod)next_new, 0,
+ sizeof(t_next), 0, 0);
+ class_addanything(next_class, next_anything);
+}
diff --git a/cyclone/hammer/offer.c b/cyclone/hammer/offer.c
new file mode 100644
index 0000000..3823c85
--- /dev/null
+++ b/cyclone/hammer/offer.c
@@ -0,0 +1,94 @@
+/* Copyright (c) 2002-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 "common/loud.h"
+#include "hammer/tree.h"
+
+/* As a class `derived' from the common hammertree code (also in funbuff),
+ offer uses the auxiliary list, generally not needed here.
+ As a side-effect, it gets a bonus of a small speedup of deletion,
+ and a penalty of a small slowdown of insertion. */
+
+typedef struct _offer
+{
+ t_object x_ob;
+ t_float x_value;
+ int x_valueset;
+ t_hammertree x_tree;
+} t_offer;
+
+static t_class *offer_class;
+
+static void offer_float(t_offer *x, t_float f)
+{
+ int ndx;
+ if (loud_checkint((t_pd *)x, f, &ndx, &s_float)) /* CHECKED */
+ {
+ t_hammernode *np;
+ if (x->x_valueset)
+ {
+ if (np = hammertree_insert(&x->x_tree, ndx))
+ np->n_value = x->x_value;
+ x->x_valueset = 0;
+ }
+ else if (np = hammertree_search(&x->x_tree, ndx))
+ {
+ outlet_float(((t_object *)x)->ob_outlet, np->n_value);
+ hammertree_delete(&x->x_tree, np);
+ }
+ }
+}
+
+static void offer_ft1(t_offer *x, t_floatarg f)
+{
+ /* this is incompatible -- CHECKED float is silently truncated */
+ x->x_value = f;
+ x->x_valueset = 1;
+}
+
+static void offer_clear(t_offer *x)
+{
+ hammertree_clear(&x->x_tree, 0);
+ /* CHECKED valueset is not cleared */
+}
+
+#ifdef HAMMERTREE_DEBUG
+static void offer_debug(t_offer *x, t_floatarg f)
+{
+ hammertree_debug(&x->x_tree, (int)f);
+}
+#endif
+
+static void offer_free(t_offer *x)
+{
+ hammertree_clear(&x->x_tree, 0);
+}
+
+static void *offer_new(void)
+{
+ t_offer *x = (t_offer *)pd_new(offer_class);
+ x->x_valueset = 0;
+ hammertree_init(&x->x_tree, 0);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void offer_setup(void)
+{
+ offer_class = class_new(gensym("offer"),
+ (t_newmethod)offer_new,
+ (t_method)offer_free,
+ sizeof(t_offer), 0, 0);
+ class_addfloat(offer_class, offer_float);
+ class_addmethod(offer_class, (t_method)offer_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(offer_class, (t_method)offer_clear,
+ gensym("clear"), 0);
+#ifdef HAMMERTREE_DEBUG
+ class_addmethod(offer_class, (t_method)offer_debug,
+ gensym("debug"), A_DEFFLOAT, 0);
+#endif
+}
diff --git a/cyclone/hammer/onebang.c b/cyclone/hammer/onebang.c
new file mode 100644
index 0000000..a4132dc
--- /dev/null
+++ b/cyclone/hammer/onebang.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2002-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"
+
+typedef struct _onebang
+{
+ t_object x_ob;
+ int x_isopen;
+} t_onebang;
+
+static t_class *onebang_class;
+
+static void onebang_bang(t_onebang *x)
+{
+ if (x->x_isopen)
+ {
+ outlet_bang(((t_object *)x)->ob_outlet);
+ x->x_isopen = 0;
+ }
+}
+
+static void onebang_bang1(t_onebang *x)
+{
+ x->x_isopen = 1;
+}
+
+static void *onebang_new(t_floatarg f)
+{
+ t_onebang *x = (t_onebang *)pd_new(onebang_class);
+ x->x_isopen = ((int)f != 0); /* CHECKED */
+ inlet_new((t_object *)x, (t_pd *)x, &s_bang, gensym("bang1"));
+ outlet_new((t_object *)x, &s_bang);
+ return (x);
+}
+
+void onebang_setup(void)
+{
+ onebang_class = class_new(gensym("onebang"),
+ (t_newmethod)onebang_new, 0,
+ sizeof(t_onebang), 0, A_DEFFLOAT, 0);
+ class_addbang(onebang_class, onebang_bang);
+ class_addmethod(onebang_class, (t_method)onebang_bang1,
+ gensym("bang1"), 0);
+}
diff --git a/cyclone/hammer/past.c b/cyclone/hammer/past.c
new file mode 100644
index 0000000..eb29c8e
--- /dev/null
+++ b/cyclone/hammer/past.c
@@ -0,0 +1,154 @@
+/* Copyright (c) 2002-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. */
+
+/* CHECKED:
+ bang for a float at > (refman error: >=)
+ bang for a list if all >= (refman page says the same)
+ bang for a list if any is >, even if the rest (but not previous) is <
+ well...
+*/
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/grow.h"
+
+#define PAST_MAXSIZE 8 /* CHECKED */
+
+typedef struct past
+{
+ t_object x_ob;
+ int x_low;
+ int x_size; /* as allocated */
+ int x_nthresh; /* as used */
+ t_atom *x_thresh;
+ t_atom x_thrini[PAST_MAXSIZE];
+} t_past;
+
+static t_class *past_class;
+
+static int past_compare(t_past *x, t_float f, t_atom *ap)
+{
+ if (ap->a_type == A_FLOAT)
+ {
+ if (f > ap->a_w.w_float)
+ return (1);
+ else if (f == ap->a_w.w_float)
+ return (0);
+ else
+ return (-1);
+ }
+ else /* CHECKED */
+ {
+ if (f > 0.)
+ return (1);
+ else if (f == 0.)
+ return (0);
+ else
+ return (-1);
+ }
+}
+
+static void past_float(t_past *x, t_float f)
+{
+ if (x->x_nthresh == 1)
+ {
+ if (past_compare(x, f, x->x_thresh) > 0) /* CHECKED: equal is low */
+ {
+ if (x->x_low)
+ {
+ x->x_low = 0;
+ outlet_bang(((t_object *)x)->ob_outlet);
+ }
+ }
+ else x->x_low = 1;
+ }
+ else if (past_compare(x, f, x->x_thresh) < 0) x->x_low = 1;
+}
+
+/* CHECKME: x_low handling */
+static void past_list(t_past *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && ac <= x->x_nthresh)
+ {
+ int result;
+ t_atom *vp = x->x_thresh;
+ if (av->a_type == A_FLOAT
+ && (result = past_compare(x, av->a_w.w_float, vp)) >= 0)
+ {
+ if (!result)
+ {
+ for (ac--, av++, vp++; ac; ac--, av++, vp++)
+ {
+ if (av->a_type != A_FLOAT
+ || (result =
+ past_compare(x, av->a_w.w_float, vp++)) < 0)
+ {
+ x->x_low = 1;
+ return;
+ }
+ if (result) break;
+ }
+ }
+ if (x->x_low)
+ {
+ x->x_low = 0;
+ outlet_bang(((t_object *)x)->ob_outlet);
+ }
+ }
+ else x->x_low = 1;
+ }
+}
+
+static void past_clear(t_past *x)
+{
+ x->x_low = 1;
+}
+
+static void past_set(t_past *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_atom *vp = x->x_thresh;
+ if (ac > x->x_size)
+ {
+ loud_incompatible_max(past_class, PAST_MAXSIZE, "guard points");
+ x->x_thresh = grow_nodata(&ac, &x->x_size, x->x_thresh,
+ PAST_MAXSIZE, x->x_thrini,
+ sizeof(*x->x_thresh));
+ }
+ x->x_nthresh = ac;
+ while (ac--) *vp++ = *av++;
+ /* CHECKED: x_low is not set here */
+ }
+}
+
+static void past_free(t_past *x)
+{
+ if (x->x_thresh != x->x_thrini)
+ freebytes(x->x_thresh, x->x_size * sizeof(*x->x_thresh));
+}
+
+static void *past_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_past *x = (t_past *)pd_new(past_class);
+ x->x_low = 1;
+ x->x_nthresh = 0;
+ x->x_size = PAST_MAXSIZE;
+ x->x_thresh = x->x_thrini;
+ outlet_new((t_object *)x, &s_bang);
+ past_set(x, 0, ac, av);
+ return (x);
+}
+
+void past_setup(void)
+{
+ past_class = class_new(gensym("past"),
+ (t_newmethod)past_new,
+ (t_method)past_free,
+ sizeof(t_past), 0, A_GIMME, 0);
+ class_addfloat(past_class, past_float);
+ class_addlist(past_class, past_list);
+ class_addmethod(past_class, (t_method)past_clear, gensym("clear"), 0);
+ class_addmethod(past_class, (t_method)past_set, gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/pd-lib-notes.txt b/cyclone/hammer/pd-lib-notes.txt
new file mode 100644
index 0000000..8b45005
--- /dev/null
+++ b/cyclone/hammer/pd-lib-notes.txt
@@ -0,0 +1,61 @@
+modifications to Joseph A. Sarlo's code (formerly part of `pd-lib')
+-------------------------------------------------------------------
+
+LATER: more testing, max-checking, resolving reentrancy, gc, etc.
+
+accum: only cosmetics
+
+bangbang:
+- if argument > 2 the array is dynamically allocated
+- if argument > 40 (max in max), a warning is printed
+- accepts any message
+
+Bucket:
+- arrays are dynamically allocated, no upper limit (max has no limit too)
+- outlets output in right-to-left order
+- added: 'set' method, 'l2r' and 'r2l' aliases
+
+buddy: coded from scratch
+- using array of proxy objects (accepting any message)
+- no upper limit for number of slots
+
+capture: coded from scratch
+- text editor, savepanel
+- any size
+- circular buffering
+
+counter (rewritten entirely):
+- using proxies to handle bangs and floats in other inlets than first
+- new `engine', counter_dobang(), coded from scratch
+- various adjustments of things that turned out to work differently in max,
+ too many to list here (and probably more are required -- please let me know!)
+
+cycle:
+- the array of outlets is dynamically allocated
+- fixing cycle_list()'s bugs
+- accepting (and sending) both floats and symbols, accepting anything
+- 'thresh' and 'set' methods
+- event-sensitive mode emulation (a temporary hack)
+
+Decode (rewritten entirely):
+- if argument > 8 the array is dynamically allocated (with a warning)
+- all outlets deliver after any action
+- outlets output in right-to-left order
+- while in all-off mode, input is stored, not ignored
+- out-of-range input is clipped, not ignored
+
+Histo (rewritten entirely):
+- creation argument added (size)
+- the array is dynamically allocated, no upper limit (max has no limit too)
+- check if input is in range, to prevent crashes :)
+- 'bang' method
+
+iter:
+- different method of memory allocation
+- dripping both floats and symbols (max4 feature)
+- 'anything' method
+
+match: coded from scratch
+- matching stream of both floats and symbols (max4 feature)
+- scanning all kinds of messages, not only separate floats
+- recognizing overlapping patterns
diff --git a/cyclone/hammer/poltocar.c b/cyclone/hammer/poltocar.c
new file mode 100644
index 0000000..486eead
--- /dev/null
+++ b/cyclone/hammer/poltocar.c
@@ -0,0 +1,44 @@
+/* Copyright (c) 2002-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"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define sinf sin
+#define cosf cos
+#endif
+
+typedef struct _poltocar
+{
+ t_object x_ob;
+ t_float x_phase;
+ t_outlet *x_out2;
+} t_poltocar;
+
+static t_class *poltocar_class;
+
+static void poltocar_float(t_poltocar *x, t_float f)
+{
+ outlet_float(x->x_out2, f * sinf(x->x_phase));
+ outlet_float(((t_object *)x)->ob_outlet, f * cosf(x->x_phase));
+}
+
+static void *poltocar_new(void)
+{
+ t_poltocar *x = (t_poltocar *)pd_new(poltocar_class);
+ floatinlet_new((t_object *)x, &x->x_phase);
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void poltocar_setup(void)
+{
+ poltocar_class = class_new(gensym("poltocar"),
+ (t_newmethod)poltocar_new, 0,
+ sizeof(t_poltocar), 0, 0);
+ class_addfloat(poltocar_class, poltocar_float);
+}
diff --git a/cyclone/hammer/prepend.c b/cyclone/hammer/prepend.c
new file mode 100644
index 0000000..567bb73
--- /dev/null
+++ b/cyclone/hammer/prepend.c
@@ -0,0 +1,258 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/grow.h"
+
+#define PREPEND_INISIZE 32 /* LATER rethink */
+#define PREPEND_MAXSIZE 256
+
+typedef struct _prepend
+{
+ t_object x_ob;
+ t_symbol *x_selector;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ t_atom *x_message;
+ t_atom x_messini[PREPEND_INISIZE];
+ int x_entered;
+ int x_auxsize;
+ t_atom *x_auxbuf;
+} t_prepend;
+
+static t_class *prepend_class;
+
+/* Usually a preallocation method is used, except in special cases of:
+ 1) reentrant output request, or 2) an output request which would cause
+ resizing to more than MAXSIZE (no such limit for a 'set' message).
+ In both special cases, a temporary output buffer is allocated.
+ A separately preallocated output buffer is not used, thus avoiding
+ memcpying of the stored message (a small performance gain when the
+ preallocation method is chosen). Instead, self-invoked 'set'
+ messages are postponed, using an auxiliary buffer.
+*/
+
+static void prepend_dooutput(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (s == &s_float)
+ {
+ if (ac > 1)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ }
+ else if (s == &s_list)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else if (s)
+ /* CHECKED: 'bang' is prepended -- we cannot do so...
+ ('symbol' cannot be compatible too) */
+ {
+ outlet_anything(((t_object *)x)->ob_outlet, s, ac, av);
+ }
+}
+
+static void prepend_anything(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ int ntotal = x->x_natoms + ac;
+ t_atom *buf;
+ x->x_entered = 1;
+ if (s == &s_) s = 0;
+ if (s)
+ ntotal++;
+ if (prealloc && ntotal > x->x_size)
+ {
+ if (ntotal > PREPEND_MAXSIZE)
+ prealloc = 0;
+ else
+ {
+ int nrequested = ntotal;
+ x->x_message = grow_withdata(&nrequested, &x->x_natoms,
+ &x->x_size, x->x_message,
+ PREPEND_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ prealloc = (nrequested == ntotal);
+ }
+ }
+ if (prealloc)
+ {
+ buf = x->x_message + x->x_natoms;
+ if (s)
+ {
+ SETSYMBOL(buf, s);
+ buf++;
+ }
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ prepend_dooutput(x, x->x_selector, ntotal, x->x_message);
+ }
+ else
+ {
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ if (buf = getbytes(ntotal * sizeof(*buf)))
+ {
+ t_atom *bp = buf + x->x_natoms;
+ if (x->x_natoms)
+ memcpy(buf, x->x_message, x->x_natoms * sizeof(*buf));
+ if (s)
+ {
+ SETSYMBOL(bp, s);
+ bp++;
+ }
+ if (ac)
+ memcpy(bp, av, ac * sizeof(*bp));
+ prepend_dooutput(x, x->x_selector, ntotal, buf);
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+ }
+ if (!reentered)
+ {
+ x->x_entered = 0;
+ if (x->x_auxbuf)
+ {
+ if (x->x_auxsize <= x->x_size)
+ {
+ x->x_natoms = x->x_auxsize / 2;
+ memcpy(x->x_message, x->x_auxbuf,
+ x->x_natoms * sizeof(*x->x_message));
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ }
+ else
+ {
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+ x->x_size = x->x_auxsize;
+ x->x_message = x->x_auxbuf;
+ x->x_natoms = x->x_auxsize / 2;
+ }
+ x->x_auxbuf = 0;
+ }
+ }
+}
+
+static void prepend_bang(t_prepend *x)
+{
+ t_atom at;
+ SETSYMBOL(&at, &s_bang); /* CHECKED */
+ prepend_anything(x, 0, 1, &at);
+}
+
+static void prepend_float(t_prepend *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ prepend_anything(x, 0, 1, &at);
+}
+
+static void prepend_symbol(t_prepend *x, t_symbol *s)
+{
+ t_atom at;
+ SETSYMBOL(&at, s);
+ prepend_anything(x, 0, 1, &at);
+}
+
+/* LATER gpointer */
+
+static void prepend_list(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ prepend_anything(x, 0, ac, av);
+}
+
+static void prepend_set(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ int newsize;
+ if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1) x->x_selector = &s_list;
+ else x->x_selector = &s_float;
+ }
+ else if (av->a_type == A_SYMBOL)
+ {
+ x->x_selector = av->a_w.w_symbol;
+ ac--;
+ av++;
+ }
+ else
+ return; /* LATER rethink */
+ newsize = ac * 2;
+ if (x->x_entered)
+ {
+ if (x->x_auxbuf)
+ {
+ loud_warning((t_pd *)x, "'set' message overridden");
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ x->x_auxsize = 0;
+ }
+ if (x->x_auxbuf = getbytes(newsize * sizeof(*x->x_auxbuf)))
+ {
+ memcpy(x->x_auxbuf, av, ac * sizeof(*x->x_auxbuf));
+ x->x_auxsize = newsize;
+ }
+ }
+ else
+ {
+ t_atom *ap;
+ if (newsize > x->x_size)
+ {
+ int sz = newsize;
+ x->x_message = grow_nodata(&sz, &x->x_size, x->x_message,
+ PREPEND_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ if (sz != newsize)
+ ac = sz / 2; /* LATER rethink */
+ }
+ x->x_natoms = ac;
+ ap = x->x_message;
+ while (ac--) *ap++ = *av++;
+ }
+ }
+}
+
+static void prepend_free(t_prepend *x)
+{
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+}
+
+static void *prepend_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_prepend *x = (t_prepend *)pd_new(prepend_class);
+ x->x_selector = 0;
+ x->x_size = PREPEND_INISIZE;
+ x->x_natoms = 0;
+ x->x_message = x->x_messini;
+ x->x_auxbuf = 0;
+ x->x_entered = 0;
+ if (!ac)
+ {
+ loud_incompatible(prepend_class,
+ "creating an object without an argument");
+ /* CHECKED: this is not compatible -- in max an object without an outlet
+ is created, and there is no warning if loading from a file. */
+ }
+ outlet_new((t_object *)x, &s_anything);
+ prepend_set(x, 0, ac, av);
+ return (x);
+}
+
+void prepend_setup(void)
+{
+ prepend_class = class_new(gensym("prepend"),
+ (t_newmethod)prepend_new,
+ (t_method)prepend_free,
+ sizeof(t_prepend), 0,
+ A_GIMME, 0);
+ class_addbang(prepend_class, prepend_bang);
+ class_addfloat(prepend_class, prepend_float);
+ class_addsymbol(prepend_class, prepend_symbol);
+ class_addlist(prepend_class, prepend_list);
+ class_addanything(prepend_class, prepend_anything);
+ class_addmethod(prepend_class, (t_method)prepend_set,
+ gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/prob.c b/cyclone/hammer/prob.c
new file mode 100644
index 0000000..5227870
--- /dev/null
+++ b/cyclone/hammer/prob.c
@@ -0,0 +1,312 @@
+/* Copyright (c) 2002-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 <stdio.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/rand.h"
+#include "hammer/file.h"
+
+/* CHECKED: no preallocation. Apparently, it looks like if the new
+ state-entries were added to the list's head, and the new transition-entries
+ were added to the sublist's head. No sorting of any kind. */
+
+#define PROB_DEBUG 0
+
+typedef struct _probtrans
+{
+ int tr_value; /* state (if a header trans), or suffix value (otherwise) */
+ int tr_count; /* (a total in case of a header trans) */
+ struct _probtrans *tr_suffix; /* header trans of a suffix state */
+ struct _probtrans *tr_nexttrans; /* next trans of this state */
+ struct _probtrans *tr_nextstate; /* header trans of a next state */
+} t_probtrans;
+
+typedef struct _prob
+{
+ t_object x_ob;
+ t_probtrans *x_translist;
+ t_probtrans *x_state;
+ t_probtrans *x_default;
+ int x_embedmode;
+ int x_silent;
+ unsigned int x_seed;
+ t_outlet *x_bangout;
+ t_hammerfile *x_filehandle;
+} t_prob;
+
+static t_class *prob_class;
+
+static t_probtrans *prob_findstate(t_prob *x, int value, int complain)
+{
+ t_probtrans *state;
+ for (state = x->x_translist; state; state = state->tr_nextstate)
+ if (state->tr_value == value)
+ break;
+ if (!state && complain && !x->x_silent)
+ loud_error((t_pd *)x, "no state %d", value); /* CHECKED */
+ return (state);
+}
+
+static void prob_reset(t_prob *x, t_floatarg f)
+{
+ int value = (int)f; /* CHECKED: float converted to int */
+ t_probtrans *state = prob_findstate(x, value, 1);
+ if (state) /* CHECKED */
+ {
+ x->x_default = state;
+ /* CHECKED (sort of): */
+ if (!x->x_state->tr_nexttrans)
+ x->x_state = state;
+ }
+}
+
+/*
+CHECKED: embedmode off:
+#N prob;
+#P newobj ... prob;
+
+CHECKED: embedmode on, after clear:
+#N prob;
+#T embed 1;
+#P newobj ... prob;
+
+CHECKED: embedmode on, filled:
+#N prob;
+#T <preffix> <suffix> <count>
+...
+#T embed 1;
+#T reset <default>; (if set)
+#P newobj ... prob;
+*/
+static void prob_embed(t_prob *x, t_floatarg f)
+{
+ x->x_embedmode = ((int)f != 0);
+ if (x->x_embedmode)
+ loud_incompatible(prob_class, "embedding not supported (yet)...");
+}
+
+static void prob_clear(t_prob *x)
+{
+ t_probtrans *state, *nextstate;
+ for (state = x->x_translist; state; state = nextstate)
+ {
+ t_probtrans *trans, *nexttrans;
+ for (trans = state->tr_nexttrans; trans; trans = nexttrans)
+ {
+ nexttrans = trans->tr_nexttrans;
+ freebytes(trans, sizeof(*trans));
+ }
+ nextstate = state->tr_nextstate;
+ freebytes(state, sizeof(*state));
+ }
+ x->x_translist = 0;
+ x->x_state = 0;
+ x->x_default = 0; /* CHECKED: default number is not kept */
+ /* CHECKED embedmode is kept */
+}
+
+/* CHECKED */
+static void prob_dump(t_prob *x)
+{
+ t_probtrans *state;
+ post("transition probabilities:");
+ for (state = x->x_translist; state; state = state->tr_nextstate)
+ {
+ t_probtrans *trans;
+ for (trans = state->tr_nexttrans; trans; trans = trans->tr_nexttrans)
+ post(" from %3d to %3d: %d",
+ state->tr_value, trans->tr_value, trans->tr_count);
+ /* CHECKED: dead-ends are reported */
+ post("total weights for state %d: %d",
+ state->tr_value, state->tr_count);
+ }
+}
+
+static void prob_bang(t_prob *x)
+{
+ if (x->x_state) /* CHECKED: no output after clear */
+ {
+ int rnd = rand_int(&x->x_seed, x->x_state->tr_count);
+ t_probtrans *trans = x->x_state->tr_nexttrans;
+ if (trans)
+ {
+ for (trans = x->x_state->tr_nexttrans; trans;
+ trans = trans->tr_nexttrans)
+ if ((rnd -= trans->tr_count) < 0)
+ break;
+ if (trans)
+ {
+ t_probtrans *nextstate = trans->tr_suffix;
+ if (nextstate)
+ {
+ outlet_float(((t_object *)x)->ob_outlet,
+ nextstate->tr_value);
+ x->x_state = nextstate;
+ }
+ else bug("prob_bang: void suffix");
+ }
+ else bug("prob_bang: search overflow");
+ }
+ else
+ {
+ outlet_bang(x->x_bangout);
+ if (x->x_default) /* CHECKED: stays at dead-end if no default */
+ x->x_state = x->x_default;
+ }
+ }
+}
+
+static void prob_float(t_prob *x, t_float f)
+{
+ int value;
+ if (loud_checkint((t_pd *)x, f, &value, &s_float)) /* CHECKED */
+ {
+ t_probtrans *state = prob_findstate(x, value, 1);
+ if (state) /* CHECKED */
+ x->x_state = state;
+ }
+}
+
+static void prob_list(t_prob *x, t_symbol *s, int ac, t_atom *av)
+{
+ int prefval, suffval, count;
+ if (ac == 3 && av->a_type == A_FLOAT
+ && av[1].a_type == A_FLOAT && av[2].a_type == A_FLOAT
+ && (prefval = (int)av->a_w.w_float) == av->a_w.w_float
+ && (suffval = (int)av[1].a_w.w_float) == av[1].a_w.w_float
+ && (count = (int)av[2].a_w.w_float) == av[2].a_w.w_float)
+ {
+ t_probtrans *prefix = prob_findstate(x, prefval, 0);
+ t_probtrans *suffix = prob_findstate(x, suffval, 0);
+ t_probtrans *trans;
+ if (prefix && suffix)
+ {
+ for (trans = prefix->tr_nexttrans; trans;
+ trans = trans->tr_nexttrans)
+ if (trans->tr_suffix == suffix)
+ break;
+ if (trans)
+ {
+ /* the transition already exists... */
+ prefix->tr_count += (count - trans->tr_count);
+ trans->tr_count = count;
+ return;
+ }
+ }
+ if (!prefix)
+ {
+ if (!(prefix = getbytes(sizeof(*prefix))))
+ return;
+ prefix->tr_value = prefval;
+ prefix->tr_count = 0;
+ prefix->tr_suffix = 0;
+ prefix->tr_nexttrans = 0;
+ prefix->tr_nextstate = x->x_translist;
+ x->x_translist = prefix;
+ if (suffval == prefval)
+ suffix = prefix;
+ }
+ if (!suffix)
+ {
+ if (!(suffix = getbytes(sizeof(*suffix))))
+ return;
+ suffix->tr_value = suffval;
+ suffix->tr_count = 0;
+ suffix->tr_suffix = 0;
+ suffix->tr_nexttrans = 0;
+ suffix->tr_nextstate = x->x_translist;
+ x->x_translist = suffix;
+ }
+ if (trans = getbytes(sizeof(*trans)))
+ {
+ trans->tr_value = suffval;
+ trans->tr_count = count;
+ trans->tr_suffix = suffix;
+ trans->tr_nexttrans = prefix->tr_nexttrans;
+ trans->tr_nextstate = prefix->tr_nextstate;
+ prefix->tr_count += count;
+ prefix->tr_nexttrans = trans;
+ }
+ if (!x->x_state) /* CHECKED */
+ x->x_state = prefix; /* CHECKED */
+ }
+ else loud_error((t_pd *)x, "bad list message format"); /* CHECKED */
+}
+
+static void prob_silent(t_prob *x)
+{
+ if (!x->x_silent)
+ {
+ loud_incompatible(prob_class, "no 'silent' message in max");
+ x->x_silent = 1;
+ }
+}
+
+static void prob_click(t_prob *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ t_probtrans *state;
+ char buf[64];
+ hammereditor_open(x->x_filehandle, "prob");
+ for (state = x->x_translist; state; state = state->tr_nextstate)
+ {
+ t_probtrans *trans;
+ for (trans = state->tr_nexttrans; trans; trans = trans->tr_nexttrans)
+ {
+ sprintf(buf, "%d %d %d\n",
+ state->tr_value, trans->tr_value, trans->tr_count);
+ hammereditor_append(x->x_filehandle, buf);
+ }
+ }
+}
+
+static void prob_free(t_prob *x)
+{
+ prob_clear(x);
+ hammerfile_free(x->x_filehandle);
+}
+
+static void *prob_new(void)
+{
+ t_prob *x = (t_prob *)pd_new(prob_class);
+ x->x_translist = 0;
+ x->x_state = 0;
+ x->x_default = 0;
+ x->x_embedmode = 0; /* CHECKED */
+ x->x_silent = 0;
+ rand_seed(&x->x_seed, 0);
+ outlet_new((t_object *)x, &s_float);
+ x->x_bangout = outlet_new((t_object *)x, &s_bang);
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0, 0, 0, 0);
+ return (x);
+}
+
+void prob_setup(void)
+{
+ prob_class = class_new(gensym("prob"),
+ (t_newmethod)prob_new,
+ (t_method)prob_free,
+ sizeof(t_prob), 0, 0);
+ class_addbang(prob_class, prob_bang);
+ class_addfloat(prob_class, prob_float);
+ class_addlist(prob_class, prob_list);
+ class_addmethod(prob_class, (t_method)prob_embed,
+ gensym("embed"), A_FLOAT, 0);
+ class_addmethod(prob_class, (t_method)prob_reset,
+ gensym("reset"), A_FLOAT, 0);
+ class_addmethod(prob_class, (t_method)prob_clear,
+ gensym("clear"), 0);
+ class_addmethod(prob_class, (t_method)prob_dump,
+ gensym("dump"), 0);
+ /* CHECKED: doesn't understand "seed" */
+
+ /* below are the incompatible extensions... */
+ class_addmethod(prob_class, (t_method)prob_silent,
+ gensym("silent"), 0);
+ class_addmethod(prob_class, (t_method)prob_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ hammerfile_setup(prob_class, 0); /* LATER embedding (, 1) */
+}
diff --git a/cyclone/hammer/pv.c b/cyclone/hammer/pv.c
new file mode 100644
index 0000000..235da2c
--- /dev/null
+++ b/cyclone/hammer/pv.c
@@ -0,0 +1,457 @@
+/* Copyright (c) 2002-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. */
+
+/* CHECKED (it cannot be emulated): creating [s/r <pv-symbol>] prints
+ "error:send/receive:<pv-symbol>:already exists"
+*/
+
+#include <string.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "common/grow.h"
+
+#define PV_INISIZE 32 /* LATER rethink */
+#define PV_MAXSIZE 256
+
+typedef struct _pvfamily
+{
+ t_symbol *f_selector;
+ t_float f_float;
+ t_symbol *f_symbol;
+ t_gpointer *f_pointer;
+ int f_size; /* as allocated */
+ int f_natoms; /* as used */
+ t_atom *f_message;
+ t_atom f_messini[PV_INISIZE];
+ t_glist *f_glist; /* root glist of a family */
+ t_symbol *f_name;
+ struct _pvfamily *f_next;
+} t_pvfamily;
+
+typedef struct _pvlist
+{
+ t_pd l_pd;
+ int l_refcount;
+ t_symbol *l_name;
+ t_pvfamily *l_pvlist;
+} t_pvlist;
+
+typedef struct _pv
+{
+ t_object x_ob;
+ t_glist *x_glist;
+ t_symbol *x_name;
+ t_pvfamily *x_family;
+} t_pv;
+
+static t_class *pv_class;
+static t_class *pvlist_class;
+
+static void pvlist_decrement(t_pvlist *pl)
+{
+ if (!--pl->l_refcount)
+ {
+ pd_unbind(&pl->l_pd, pl->l_name);
+ pd_free(&pl->l_pd);
+ }
+}
+
+static t_pvlist *pv_getlist(t_symbol *s, int create)
+{
+ t_pvlist *pl = (t_pvlist *)pd_findbyclass(s, pvlist_class);
+ if (pl)
+ {
+ if (create) pl->l_refcount++;
+ }
+ else
+ {
+ if (create)
+ {
+ pl = (t_pvlist *)pd_new(pvlist_class);
+ pl->l_refcount = 1;
+ pl->l_name = s;
+ pl->l_pvlist = 0;
+ pd_bind(&pl->l_pd, s);
+ }
+ else bug("pv_getlist");
+ }
+ return (pl);
+}
+
+static t_pvfamily *pv_newfamily(t_pvlist *pvlist)
+{
+ t_pvfamily *pf = (t_pvfamily *)getbytes(sizeof(*pf));
+ pf->f_name = pvlist->l_name;
+ pf->f_next = pvlist->l_pvlist;
+ pvlist->l_pvlist = pf;
+ pf->f_selector = 0;
+ pf->f_float = 0;
+ pf->f_symbol = 0;
+ pf->f_pointer = 0;
+ pf->f_size = PV_INISIZE;
+ pf->f_natoms = 0;
+ pf->f_message = pf->f_messini;
+ return (pf);
+}
+
+static void pvfamily_free(t_pvfamily *pf)
+{
+ if (pf->f_message != pf->f_messini)
+ freebytes(pf->f_message, pf->f_size * sizeof(*pf->f_message));
+ freebytes(pf, sizeof(*pf));
+}
+
+static void pv_update(t_glist *glist, t_pvfamily *pf)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ pv_update((t_glist *)g, pf);
+ else if (pd_class(&g->g_pd) == pv_class
+ && ((t_pv *)g)->x_name == pf->f_name)
+ ((t_pv *)g)->x_family = pf;
+}
+
+static t_pvfamily *pvfamily_reusable;
+
+static void pv_breakup(t_pvlist *pvlist, t_glist *glist)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ {
+ if (pd_class(&g->g_pd) == pv_class
+ && ((t_pv *)g)->x_name == pvlist->l_name)
+ {
+ t_pvfamily *pf;
+ if (!(pf = pvfamily_reusable))
+ pf = pv_newfamily(pvlist);
+ else pvfamily_reusable = 0;
+ pf->f_glist = glist;
+ pv_update(glist, pf);
+ /* LATER keep current value */
+ return;
+ }
+ }
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ pv_breakup(pvlist, (t_glist *)g);
+}
+
+/* join all families of a 'pvlist' rooted in any subglist of a 'glist' */
+static t_pvfamily *pv_joinup(t_pvlist *pvlist, t_glist *glist)
+{
+ t_pvfamily *result = 0;
+ t_pvfamily *pf, *pfprev, *pfnext;
+ for (pfprev = 0, pf = pvlist->l_pvlist; pf; pfprev = pf, pf = pfnext)
+ {
+ t_glist *gl;
+ pfnext = pf->f_next;
+ for (gl = pf->f_glist; gl; gl = gl->gl_owner)
+ {
+ if (gl == glist)
+ {
+ if (result)
+ {
+ pvfamily_free(pf);
+ if (pfprev)
+ pfprev->f_next = pfnext;
+ else
+ pvlist->l_pvlist = pfnext;
+ pf = pfprev;
+ }
+ else result = pf;
+ break;
+ }
+ }
+ }
+ return (result);
+}
+
+/* Called normally with either 'create' or 'destroy' set to 1,
+ but it might be called with both set to 0 for testing. */
+static t_pvfamily *pv_getfamily(t_glist *glist, t_symbol *s,
+ int create, int destroy)
+{
+ t_pvlist *pl = pv_getlist(s, create);
+ if (pl)
+ {
+ if (destroy)
+ {
+ t_pvfamily *pf, *mypf;
+ t_glist *gl;
+ for (mypf = pl->l_pvlist; mypf; mypf = mypf->f_next)
+ if (mypf->f_glist == glist)
+ break;
+ /* mypf is not null iff we are invoked via a [pv] in root */
+ /* now check if there is a family rooted in a super-branch */
+ for (gl = glist->gl_owner; gl; gl = gl->gl_owner)
+ {
+ for (pf = pl->l_pvlist; pf; pf = pf->f_next)
+ {
+ if (pf->f_glist == gl)
+ {
+ if (mypf)
+ bug("pv_getfamily 1: %s in %s",
+ mypf->f_name->s_name,
+ mypf->f_glist->gl_name->s_name);
+ else
+ return (0);
+ }
+ }
+ }
+ if (mypf)
+ {
+ pvfamily_reusable = mypf;
+ pv_breakup(pl, glist);
+ if (pvfamily_reusable == mypf)
+ {
+ pvfamily_reusable = 0;
+ if (pl->l_pvlist == mypf)
+ pl->l_pvlist = mypf->f_next;
+ else
+ {
+ for (pf = pl->l_pvlist; pf; pf = pf->f_next)
+ {
+ if (pf->f_next == mypf)
+ {
+ pf->f_next = mypf->f_next;
+ break;
+ }
+ }
+ if (!pf) bug("pv_getfamily 2");
+ }
+ pvfamily_free(mypf);
+ }
+ }
+ else bug("pv_getfamily 3");
+ pvlist_decrement(pl);
+ }
+ else
+ {
+ t_pvfamily *pf;
+ t_glist *gl;
+ for (gl = glist; gl; gl = gl->gl_owner)
+ for (pf = pl->l_pvlist; pf; pf = pf->f_next)
+ if (pf->f_glist == gl)
+ return (pf);
+ if (create)
+ {
+ if (!(pf = pv_joinup(pl, glist)))
+ pf = pv_newfamily(pl);
+ pf->f_glist = glist;
+ pv_update(glist, pf);
+ return (pf);
+ }
+ else bug("pv_getfamily 4");
+ }
+ }
+ else bug("pv_getfamily 5");
+ return (0);
+}
+
+static t_pvfamily *pv_checkfamily(t_pv *x)
+{
+ if (!x->x_family)
+ {
+ bug("pv_checkfamily");
+ x->x_family = pv_getfamily(x->x_glist, x->x_name, 0, 0);
+ }
+ return (x->x_family);
+}
+
+static void pv_bang(t_pv *x)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ t_symbol *s = pf->f_selector;
+ if (s == &s_bang)
+ outlet_bang(((t_object *)x)->ob_outlet);
+ else if (s == &s_float)
+ outlet_float(((t_object *)x)->ob_outlet, pf->f_float);
+ else if (s == &s_symbol && pf->f_symbol)
+ outlet_symbol(((t_object *)x)->ob_outlet, pf->f_symbol);
+ else if (s == &s_pointer)
+ {
+ /* LATER */
+ }
+ else if (s == &s_list)
+ outlet_list(((t_object *)x)->ob_outlet,
+ s, pf->f_natoms, pf->f_message);
+ else if (s)
+ outlet_anything(((t_object *)x)->ob_outlet,
+ s, pf->f_natoms, pf->f_message);
+ }
+}
+
+static void pv_float(t_pv *x, t_float f)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ pf->f_selector = &s_float;
+ pf->f_float = f;
+ pf->f_natoms = 0; /* defensive */
+ }
+}
+
+static void pv_symbol(t_pv *x, t_symbol *s)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ pf->f_selector = &s_symbol;
+ pf->f_symbol = s;
+ pf->f_natoms = 0; /* defensive */
+ }
+}
+
+static void pv_pointer(t_pv *x, t_gpointer *gp)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ pf->f_selector = &s_pointer;
+ pf->f_pointer = gp;
+ pf->f_natoms = 0; /* defensive */
+ }
+}
+
+static void pvfamily_domessage(t_pvfamily *pf, int ac, t_atom *av)
+{
+ if (ac > pf->f_size)
+ {
+ /* LATER consider using PV_MAXSIZE (and warning if exceeded) */
+ pf->f_message = grow_nodata(&ac, &pf->f_size, pf->f_message,
+ PV_INISIZE, pf->f_messini,
+ sizeof(*pf->f_message));
+ }
+ pf->f_natoms = ac;
+ memcpy(pf->f_message, av, ac * sizeof(*pf->f_message));
+}
+
+static void pv_list(t_pv *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ pf->f_selector = &s_list; /* LATER rethink */
+ pvfamily_domessage(pf, ac, av);
+ }
+}
+
+static void pv_anything(t_pv *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ pf->f_selector = s; /* LATER rethink */
+ pvfamily_domessage(pf, ac, av);
+ }
+}
+
+static void pv_objstatus(t_pv *x, t_glist *glist)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ {
+ if (g == (t_gobj *)x)
+ post("%x (this object) owning patcher [%s]",
+ (int)g, glist->gl_name->s_name);
+ else if (pd_class(&g->g_pd) == pv_class
+ && ((t_pv *)g)->x_name == x->x_name)
+ post("%x owning patcher [%s]", (int)g, glist->gl_name->s_name);
+ }
+}
+
+static void pv_status(t_pv *x)
+{
+ t_pvlist *pl = pv_getlist(x->x_name, 0);
+ post("pv status: Tied to %s", x->x_name->s_name);
+ if (pl)
+ {
+ t_pvfamily *pf;
+ int fcount;
+ for (pf = pl->l_pvlist, fcount = 1; pf; pf = pf->f_next, fcount++)
+ {
+ t_glist *glist = pf->f_glist;
+ t_gobj *g;
+ post("Family %d:", fcount);
+ pv_objstatus(x, glist);
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ pv_objstatus(x, (t_glist *)g);
+ }
+ }
+}
+
+static void pv_free(t_pv *x)
+{
+ pv_getfamily(x->x_glist, x->x_name, 0, 1);
+}
+
+static void *pv_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_pv *x = 0;
+ if (ac && av->a_type == A_SYMBOL)
+ s = av->a_w.w_symbol;
+ else s = 0;
+ if (s && s != &s_)
+ {
+ t_glist *gl = canvas_getcurrent();
+ t_pvfamily *pf = pv_getfamily(gl, s, 1, 0);
+ x = (t_pv *)pd_new(pv_class);
+ x->x_glist = gl;
+ x->x_name = s;
+ x->x_family = pf;
+ outlet_new((t_object *)x, &s_float);
+ if (--ac)
+ {
+ av++;
+ if (av->a_type == A_SYMBOL)
+ {
+ if (av->a_w.w_symbol == &s_symbol)
+ {
+ if (ac > 1 && av[1].a_type == A_SYMBOL)
+ pv_symbol(x, av[1].a_w.w_symbol);
+ }
+ /* LATER rethink 'pv <name> bang' (now it is accepted) */
+ else pv_anything(x, av->a_w.w_symbol, ac - 1, av + 1);
+ }
+ else if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ pv_list(x, &s_list, ac, av);
+ else pv_float(x, av->a_w.w_float);
+ }
+ }
+
+ }
+ else
+ /* CHECKED: "error: missing or bad arguments",
+ a box is created without inlets and outlets */
+ loud_classarg(pv_class);
+ return (x);
+}
+
+void pv_setup(void)
+{
+ pv_class = class_new(gensym("pv"),
+ (t_newmethod)pv_new,
+ (t_method)pv_free,
+ sizeof(t_pv), 0, A_GIMME, 0);
+ class_addbang(pv_class, pv_bang);
+ class_addfloat(pv_class, pv_float);
+ class_addsymbol(pv_class, pv_symbol);
+ class_addpointer(pv_class, pv_pointer);
+ class_addlist(pv_class, pv_list);
+ class_addanything(pv_class, pv_anything);
+ class_addmethod(pv_class, (t_method)pv_status,
+ gensym("status"), 0);
+ /* CHECKED: sending bang (or int, list, status, etc.) with '; <pv-symbol>'
+ "error::doesn't understand bang" (class name is an empty string) */
+ pvlist_class = class_new(&s_, 0, 0,
+ sizeof(t_pvlist), CLASS_PD, 0);
+}
diff --git a/cyclone/hammer/seq.c b/cyclone/hammer/seq.c
new file mode 100644
index 0000000..503b205
--- /dev/null
+++ b/cyclone/hammer/seq.c
@@ -0,0 +1,825 @@
+/* Copyright (c) 2002-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. */
+
+/* CHECKED no sharing of data among seq objects having the same creation arg */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "common/loud.h"
+#include "common/grow.h"
+#include "common/sq.h"
+#include "common/bifi.h"
+#include "common/mifi.h"
+#include "hammer/file.h"
+
+#define SEQ_DEBUG
+
+#define SEQ_INISIZE 256 /* LATER rethink */
+#define SEQ_EOM 255 /* end of message marker, LATER rethink */
+
+typedef struct _seqevent
+{
+ int e_delta;
+ unsigned char e_bytes[4];
+} t_seqevent;
+
+typedef struct _seq
+{
+ t_object x_ob;
+ t_canvas *x_canvas;
+ t_symbol *x_defname;
+ t_hammerfile *x_filehandle;
+ int x_isplaying;
+ int x_isrecording;
+ int x_playhead;
+ float x_tempo;
+ double x_prevtime;
+ unsigned char x_status;
+ int x_evesize;
+ int x_expectedsize;
+ int x_size; /* as allocated */
+ int x_nevents; /* as used */
+ t_seqevent *x_sequence;
+ t_seqevent x_seqini[SEQ_INISIZE];
+ t_clock *x_clock;
+ t_outlet *x_bangout;
+} t_seq;
+
+static t_class *seq_class;
+
+static void seq_doclear(t_seq *x, int dofree)
+{
+ if (dofree && x->x_sequence != x->x_seqini)
+ {
+ freebytes(x->x_sequence, x->x_size * sizeof(*x->x_sequence));
+ x->x_sequence = x->x_seqini;
+ x->x_size = SEQ_INISIZE;
+ }
+ x->x_nevents = 0;
+}
+
+static void seq_complete(t_seq *x)
+{
+ if (x->x_evesize < x->x_expectedsize)
+ {
+ /* CHECKED no warning if no data after status byte requiring data */
+ if (x->x_evesize > 1)
+ post("seq: truncated midi message"); /* CHECKED */
+ /* CHECKED nothing stored */
+ }
+ else
+ {
+ t_seqevent *ep = &x->x_sequence[x->x_nevents];
+ double elapsed = clock_gettimesince(x->x_prevtime);
+ ep->e_delta = (int)elapsed;
+ x->x_prevtime = clock_getlogicaltime();
+ if (x->x_evesize < 4)
+ ep->e_bytes[x->x_evesize] = SEQ_EOM;
+ x->x_nevents++;
+ if (x->x_nevents >= x->x_size)
+ {
+ int nexisting = x->x_size;
+ /* store-ahead scheme, LATER consider using x_currevent */
+ int nrequested = x->x_nevents + 1;
+#ifdef SEQ_DEBUG
+ post("growing...");
+#endif
+ x->x_sequence =
+ grow_withdata(&nrequested, &nexisting,
+ &x->x_size, x->x_sequence,
+ SEQ_INISIZE, x->x_seqini, sizeof(*x->x_sequence));
+ if (nrequested <= x->x_nevents)
+ x->x_nevents = 0;
+ }
+ }
+ x->x_evesize = 0;
+}
+
+static void seq_checkstatus(t_seq *x, unsigned char c)
+{
+ if (x->x_status && x->x_evesize > 1) /* LATER rethink */
+ seq_complete(x);
+ if (c < 192)
+ x->x_expectedsize = 3;
+ else if (c < 224)
+ x->x_expectedsize = 2;
+ else if (c < 240)
+ x->x_expectedsize = 3;
+ else if (c < 248)
+ {
+ /* FIXME */
+ x->x_expectedsize = -1;
+ }
+ else
+ {
+ x->x_sequence[x->x_nevents].e_bytes[0] = c;
+ x->x_evesize = x->x_expectedsize = 1;
+ seq_complete(x);
+ return;
+ }
+ x->x_status = x->x_sequence[x->x_nevents].e_bytes[0] = c;
+ x->x_evesize = 1;
+}
+
+static void seq_addbyte(t_seq *x, unsigned char c, int docomplete)
+{
+ x->x_sequence[x->x_nevents].e_bytes[x->x_evesize++] = c;
+ if (x->x_evesize == x->x_expectedsize)
+ {
+ seq_complete(x);
+ if (x->x_status)
+ {
+ x->x_sequence[x->x_nevents].e_bytes[0] = x->x_status;
+ x->x_evesize = 1;
+ }
+ }
+ else if (x->x_evesize == 4)
+ {
+ if (x->x_status != 240)
+ bug("seq_addbyte");
+ /* CHECKED sysex is broken into 4-byte packets marked with
+ the actual delta time of last byte received in a packet */
+ seq_complete(x);
+ }
+ else if (docomplete) seq_complete(x);
+}
+
+static void seq_endofsysex(t_seq *x)
+{
+ seq_addbyte(x, 247, 1);
+ x->x_status = 0;
+}
+
+static void seq_stopplayback(t_seq *x)
+{
+ /* FIXME */
+ /* CHECKED "seq: incomplete sysex" at playback stop, 247 added implicitly */
+ /* CHECKME resetting controllers, etc. */
+ /* CHECKED bang not sent if playback stopped early */
+ clock_unset(x->x_clock);
+ x->x_playhead = 0;
+ x->x_isplaying = 0;
+}
+
+static void seq_stoprecording(t_seq *x)
+{
+ if (x->x_status == 240)
+ {
+ post("seq: incomplete sysex"); /* CHECKED */
+ seq_endofsysex(x); /* CHECKED 247 added implicitly */
+ }
+ else if (x->x_status)
+ seq_complete(x);
+ /* CHECKED running status used in recording, but not across recordings */
+ x->x_status = 0;
+ x->x_isrecording = 0;
+}
+
+static void seq_tick(t_seq *x)
+{
+ if (x->x_isplaying)
+ {
+ t_seqevent *ep = &x->x_sequence[x->x_playhead++];
+ unsigned char *bp = ep->e_bytes;
+nextevent:
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ if (*bp != SEQ_EOM)
+ {
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ if (*bp != SEQ_EOM)
+ {
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ if (*bp != SEQ_EOM)
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ }
+ }
+ if (!x->x_isplaying) /* reentrancy protection */
+ return;
+ if (x->x_playhead < x->x_nevents)
+ {
+ ep++;
+ if (ep->e_delta <= 0)
+ /* continue output in the same scheduler event, LATER rethink */
+ {
+ x->x_playhead++;
+ bp = ep->e_bytes;
+ goto nextevent;
+ }
+ else clock_delay(x->x_clock, ep->e_delta);
+ }
+ else
+ {
+ seq_stopplayback(x);
+ /* CHECKED bang sent immediately _after_ last byte */
+ outlet_bang(x->x_bangout); /* LATER think about reentrancy */
+ }
+ }
+}
+
+/* CHECKED running status not used in playback */
+static void seq_dostart(t_seq *x, float tempo)
+{
+ if (x->x_isplaying)
+ {
+ /* CHECKED tempo change */
+ x->x_tempo = tempo;
+ /* FIXME update the clock */
+ }
+ else
+ {
+ if (x->x_isrecording) /* CHECKED 'start' stops recording */
+ seq_stoprecording(x);
+ /* CHECKED bang not sent if a sequence is empty */
+ if (x->x_nevents)
+ {
+ x->x_tempo = tempo;
+ x->x_playhead = 0;
+ x->x_isplaying = 1;
+ /* playback data never sent within the scheduler event of
+ a start message (even for the first delta <= 0), LATER rethink */
+ clock_delay(x->x_clock, x->x_sequence->e_delta);
+ }
+ }
+}
+
+static void seq_bang(t_seq *x)
+{
+ seq_dostart(x, 1.0);
+}
+
+static void seq_float(t_seq *x, t_float f)
+{
+ if (x->x_isrecording)
+ {
+ /* CHECKED noninteger and out of range silently truncated */
+ unsigned char c = (unsigned char)f;
+ if (c < 128)
+ {
+ if (x->x_status) seq_addbyte(x, c, 0);
+ }
+ else if (c != 254) /* CHECKED active sensing ignored */
+ {
+ if (x->x_status == 240)
+ {
+ if (c == 247) seq_endofsysex(x);
+ else
+ {
+ /* CHECKED rt bytes alike */
+ post("seq: unterminated sysex"); /* CHECKED */
+ seq_endofsysex(x); /* CHECKED 247 added implicitly */
+ seq_checkstatus(x, c);
+ }
+ }
+ else if (c != 247) seq_checkstatus(x, c);
+ }
+ }
+}
+
+static void seq_symbol(t_seq *x, t_symbol *s)
+{
+ loud_nomethod((t_pd *)x, &s_symbol); /* CHECKED */
+}
+
+static void seq_list(t_seq *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_FLOAT) seq_float(x, av->a_w.w_float);
+ /* CHECKED anything else/more silently ignored */
+}
+
+static void seq_record(t_seq *x)
+{
+ /* CHECKED 'record' resets recording */
+ if (x->x_isplaying) /* CHECKED 'record' stops playback */
+ seq_stopplayback(x);
+ seq_doclear(x, 0);
+ x->x_isrecording = 1;
+ x->x_prevtime = clock_getlogicaltime();
+ x->x_status = 0;
+ x->x_evesize = 0;
+ x->x_expectedsize = -1; /* LATER rethink */
+}
+
+static void seq_append(t_seq *x)
+{
+ if (x->x_isrecording)
+ return; /* CHECKME 'append' does not reset recording */
+ if (x->x_isplaying) /* CHECKME 'append' stops playback */
+ seq_stopplayback(x);
+ x->x_isrecording = 1;
+ x->x_prevtime = clock_getlogicaltime();
+ x->x_status = 0;
+ x->x_evesize = 0;
+ x->x_expectedsize = -1; /* LATER rethink */
+}
+
+static void seq_stop(t_seq *x)
+{
+ if (x->x_isplaying)
+ seq_stopplayback(x);
+ else if (x->x_isrecording)
+ seq_stoprecording(x);
+}
+
+static int seq_dogrowing(t_seq *x, int nevents)
+{
+ if (nevents > x->x_size)
+ {
+ int nrequested = nevents;
+#ifdef SEQ_DEBUG
+ post("growing...");
+#endif
+ x->x_sequence =
+ grow_nodata(&nrequested, &x->x_size, x->x_sequence,
+ SEQ_INISIZE, x->x_seqini, sizeof(*x->x_sequence));
+ if (nrequested < nevents)
+ {
+ x->x_nevents = 0;
+ return (0);
+ }
+ }
+ x->x_nevents = nevents;
+ return (1);
+}
+
+static int seq_seekhook(t_squiter *it, int offset)
+{
+ t_seq *x = (t_seq *)it->i_owner;
+ post("seek in %d", x->x_nevents);
+ it->i_nelems = x->x_nevents;
+ it->i_sequence = x->x_sequence;
+ if (offset < 0)
+ offset += it->i_nelems;
+ if (offset >= 0 && offset < it->i_nelems)
+ {
+ it->i_element = (t_seqevent *)it->i_sequence + offset;
+ it->i_index = offset;
+ return (1);
+ }
+ else return (0);
+}
+
+static void seq_incrhook(t_squiter *it)
+{
+ ((t_seqevent *)it->i_element)++;
+ it->i_index++;
+}
+
+/* LATER put seq_mfwrite_doit() functionality here */
+static void seq_getevehook(t_squiter *it, t_mifi_event *mev, int *ret)
+{
+ *ret = 1;
+}
+
+static void seq_setevehook(t_squiter *it, t_mifi_event *mev, int *ret)
+{
+ t_seqevent *sev = it->i_element;
+ sev->e_delta = mev->e_delay;
+ sev->e_bytes[0] = mev->e_status | mev->e_channel;
+ sev->e_bytes[1] = mev->e_data[0];
+ if (MIFI_ONE_DATABYTE(mev->e_status))
+ sev->e_bytes[2] = SEQ_EOM;
+ else
+ {
+ sev->e_bytes[2] = mev->e_data[1];
+ sev->e_bytes[3] = SEQ_EOM;
+ }
+ *ret = 1;
+}
+
+static t_float seq_gettimhook(t_squiter *it, int *ret)
+{
+ t_seqevent *sev = it->i_element;
+ *ret = 1;
+ return (sev->e_delta);
+}
+
+static void seq_settimhook(t_squiter *it, t_float f, int *ret)
+{
+ t_seqevent *sev = it->i_element;
+ sev->e_delta = f;
+ *ret = 1;
+}
+
+static t_symbol *seq_gettarhook(t_squiter *it, int *ret)
+{
+ *ret = 1;
+ return (0);
+}
+
+static void seq_settarhook(t_squiter *it, t_symbol *s, int *ret)
+{
+ *ret = 1;
+}
+
+static int seq_make_iterator(t_seq *x, t_mifi_stream *stp)
+{
+ t_squiter *it = squiter_new(stp);
+ if (it)
+ {
+ it->i_owner = x;
+ it->i_nelems = x->x_nevents;
+ it->i_sequence = it->i_element = x->x_sequence;
+ it->i_index = 0;
+ it->i_hooks[SQUITER_SEEKHOOK] = (t_squiterhook)seq_seekhook;
+ it->i_hooks[SQUITER_INCRHOOK] = (t_squiterhook)seq_incrhook;
+ it->i_hooks[SQUITER_GETEVEHOOK] = (t_squiterhook)seq_getevehook;
+ it->i_hooks[SQUITER_SETEVEHOOK] = (t_squiterhook)seq_setevehook;
+ it->i_hooks[SQUITER_GETTIMHOOK] = (t_squiterhook)seq_gettimhook;
+ it->i_hooks[SQUITER_SETTIMHOOK] = (t_squiterhook)seq_settimhook;
+ it->i_hooks[SQUITER_GETTARHOOK] = (t_squiterhook)seq_gettarhook;
+ it->i_hooks[SQUITER_SETTARHOOK] = (t_squiterhook)seq_settarhook;
+ return (1);
+ }
+ else return (0);
+}
+
+static t_mifi_stream *seq_makestream(t_seq *x)
+{
+ t_mifi_stream *stp = 0;
+ if (stp = mifi_stream_new())
+ {
+ if (seq_make_iterator(x, stp))
+ return (stp);
+ else
+ mifi_stream_free(stp);
+ }
+ return (0);
+}
+
+static int seq_comparehook(const void *e1, const void *e2)
+{
+ return (((t_seqevent *)e1)->e_delta > ((t_seqevent *)e2)->e_delta ? 1 : -1);
+}
+
+/* FIXME */
+static int seq_mfread(t_seq *x, char *path)
+{
+ int result = 0;
+ t_mifi_stream *stp = 0;
+ if (!(stp = seq_makestream(x)) ||
+ !mifi_read_start(stp, path, "", 0))
+ goto readfailed;
+#ifdef SEQ_DEBUG
+ if (stp->s_nframes)
+ post("midifile (format %d): %d tracks, %d ticks (%d smpte frames)",
+ stp->s_format, stp->s_hdtracks, stp->s_nticks, stp->s_nframes);
+ else
+ post("midifile (format %d): %d tracks, %d ticks per beat",
+ stp->s_format, stp->s_hdtracks, stp->s_nticks);
+#endif
+ if (mifi_read_analyse(stp) != MIFI_READ_EOF ||
+ !seq_dogrowing(x, stp->s_nevents) ||
+ !mifi_read_restart(stp) ||
+ mifi_read_doit(stp) != MIFI_READ_EOF)
+ goto readfailed;
+ squmpi_sort(stp);
+ qsort(x->x_sequence, stp->s_nevents, sizeof(*x->x_sequence),
+ seq_comparehook);
+ sq_fold_time(stp);
+#ifdef SEQ_DEBUG
+ post("finished reading %d events from midifile", stp->s_nevents);
+#endif
+ result = 1;
+readfailed:
+ if (stp)
+ {
+ mifi_read_end(stp);
+ mifi_stream_free(stp);
+ }
+ return (result);
+}
+
+/* FIXME */
+static int seq_mfwrite_doit(t_seq *x, t_mifi_stream *stp)
+{
+ t_mifi_event *mev = stp->s_auxeve;
+ t_seqevent *sev = x->x_sequence;
+ int nevents = x->x_nevents;
+ while (nevents--)
+ {
+ unsigned char *bp = sev->e_bytes;
+ int i;
+ mev->e_delay = (uint32)(sev->e_delta * stp->s_timecoef);
+ mev->e_status = *bp & 0xf0;
+ mev->e_channel = *bp & 0x0f;
+ /* FIXME sysex continuation */
+ for (i = 0, bp++; i < 3 && *bp != SEQ_EOM; i++, bp++)
+ mev->e_data[i] = *bp;
+ if (!mifi_write_event(stp, mev))
+ return (0);
+ sev++;
+ }
+ return (1);
+}
+
+/* FIXME */
+static int seq_mfwrite(t_seq *x, char *path)
+{
+ int result = 0;
+ t_mifi_stream *stp = 0;
+ if (!(stp = seq_makestream(x)))
+ goto writefailed;
+ stp->s_ntracks = 1;
+ stp->s_hdtracks = 1;
+ stp->s_format = 0;
+ if (!mifi_write_start(stp, path, ""))
+ goto writefailed;
+ mifi_event_settext(stp->s_auxeve, MIFI_META_TRACKNAME, "seq-track");
+ if (!mifi_write_start_track(stp) ||
+ !mifi_write_event(stp, stp->s_auxeve) ||
+ !seq_mfwrite_doit(x, stp) ||
+ !mifi_write_adjust_track(stp, 0))
+ goto writefailed;
+ result = 1;
+writefailed:
+ if (stp)
+ {
+ mifi_write_end(stp);
+ mifi_stream_free(stp);
+ }
+ return (result);
+}
+
+/* FIXME */
+/* CHECKED absolute timestamps, semi-terminated, verified */
+static int seq_frombinbuf(t_seq *x, t_binbuf *bb)
+{
+ int nevents = 0;
+ int ac = binbuf_getnatom(bb);
+ t_atom *av = binbuf_getvec(bb);
+ while (ac--)
+ if (av++->a_type == A_SEMI) /* FIXME parsing */
+ nevents++;
+ if (nevents)
+ {
+ t_seqevent *ep;
+ float prevtime = 0;
+ int i = -1;
+ if (!seq_dogrowing(x, nevents))
+ return (0);
+ nevents = 0;
+ ac = binbuf_getnatom(bb);
+ av = binbuf_getvec(bb);
+ ep = x->x_sequence;
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ if (i < 0)
+ {
+ ep->e_delta = av->a_w.w_float - prevtime;
+ prevtime = av->a_w.w_float;
+ i = 0;
+ }
+ else if (i < 4)
+ ep->e_bytes[i++] = av->a_w.w_float;
+ /* CHECKME else */
+ }
+ else if (av->a_type == A_SEMI && i > 0)
+ {
+ if (i < 4)
+ ep->e_bytes[i] = SEQ_EOM;
+ nevents++;
+ ep++;
+ i = -1;
+ }
+ /* CHECKME else */
+ av++;
+ }
+ x->x_nevents = nevents;
+ }
+ return (nevents);
+}
+
+static void seq_tobinbuf(t_seq *x, t_binbuf *bb)
+{
+ int nevents = x->x_nevents;
+ t_seqevent *ep = x->x_sequence;
+ t_atom at[5];
+ float timestamp = 0;
+ while (nevents--)
+ {
+ unsigned char *bp = ep->e_bytes;
+ int i;
+ t_atom *ap = at;
+ timestamp += ep->e_delta;
+ SETFLOAT(ap, timestamp); /* CHECKED same for sysex continuation */
+ ap++;
+ SETFLOAT(ap, *bp);
+ for (i = 0, ap++, bp++; i < 3 && *bp != SEQ_EOM; i++, ap++, bp++)
+ SETFLOAT(ap, *bp);
+ binbuf_add(bb, i + 2, at);
+ binbuf_addsemi(bb);
+ ep++;
+ }
+}
+
+static void seq_textread(t_seq *x, char *path)
+{
+ t_binbuf *bb;
+ bb = binbuf_new();
+ if (binbuf_read(bb, path, "", 0))
+ {
+ /* CHECKED no complaint, open dialog presented */
+ hammerpanel_open(x->x_filehandle); /* LATER rethink */
+ }
+ else
+ {
+ int nlines = seq_frombinbuf(x, bb);
+ if (nlines < 0)
+ /* CHECKED "bad MIDI file (truncated)" alert, even if a text file */
+ loud_error((t_pd *)x, "bad text file (truncated)");
+ else if (nlines == 0)
+ {
+ /* CHECKED no complaint, sequence erased, LATER rethink */
+ }
+ }
+ binbuf_free(bb);
+}
+
+static void seq_textwrite(t_seq *x, char *path)
+{
+ t_binbuf *bb;
+ bb = binbuf_new();
+ seq_tobinbuf(x, bb);
+ /* CHECKED empty sequence stored as an empty file */
+ if (binbuf_write(bb, path, "", 0))
+ {
+ /* CHECKME complaint and FIXME */
+ loud_error((t_pd *)x, "error writing text file");
+ }
+ binbuf_free(bb);
+}
+
+static void seq_doread(t_seq *x, t_symbol *fn, int creation)
+{
+ char buf[MAXPDSTRING];
+ if (x->x_canvas)
+ canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
+ else
+ {
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ buf[MAXPDSTRING-1] = 0;
+ }
+ if (creation)
+ {
+ /* loading during object creation -- CHECKED no warning if a file
+ specified with an arg does not exist, LATER rethink */
+ FILE *fp;
+ char path[MAXPDSTRING];
+ sys_bashfilename(buf, path);
+ if (!(fp = fopen(path, "r")))
+ return;
+ fclose(fp);
+ }
+ /* CHECKED all cases: arg or not, message and creation */
+ post("seq: reading %s", fn->s_name);
+ if (!seq_mfread(x, buf))
+ seq_textread(x, buf);
+}
+
+static void seq_dowrite(t_seq *x, t_symbol *fn)
+{
+ char buf[MAXPDSTRING], *dotp;
+ if (x->x_canvas)
+ canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
+ else
+ {
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ buf[MAXPDSTRING-1] = 0;
+ }
+ post("seq: writing %s", fn->s_name); /* CHECKED arg or not */
+ /* save as text for any extension other then ".mid" */
+ if ((dotp = strrchr(fn->s_name, '.')) && strcmp(dotp + 1, "mid"))
+ seq_textwrite(x, buf);
+ else /* save as mf for ".mid" or no extension at all, LATER rethink */
+ seq_mfwrite(x, buf);
+}
+
+static void seq_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ seq_doread((t_seq *)z, fn, 0);
+}
+
+static void seq_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ seq_dowrite((t_seq *)z, fn);
+}
+
+static void seq_read(t_seq *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ seq_doread(x, s, 0);
+ else /* CHECKED no default */
+ hammerpanel_open(x->x_filehandle);
+}
+
+static void seq_write(t_seq *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ seq_dowrite(x, s);
+ else /* CHECKED creation arg is a default */
+ hammerpanel_save(x->x_filehandle,
+ canvas_getdir(x->x_canvas), x->x_defname);
+}
+
+static void seq_print(t_seq *x)
+{
+ int nevents = x->x_nevents;
+ startpost("midiseq:"); /* CHECKED */
+ if (nevents)
+ {
+ t_seqevent *ep = x->x_sequence;
+ int truncated;
+ if (nevents > 16)
+ nevents = 16, truncated = 1;
+ else
+ truncated = 0;
+ while (nevents--)
+ {
+ unsigned char *bp = ep->e_bytes;
+ int i;
+ if (*bp < 128 || *bp == 247)
+ /* CHECKED (sysex continuation) */
+ startpost("\n(%d)->", ep->e_delta);
+ else
+ startpost("\n(%d)", ep->e_delta);
+ /* CHECKED space-separated, no semi */
+ postfloat((float)*bp);
+ for (i = 0, bp++; i < 3 && *bp != SEQ_EOM; i++, bp++)
+ postfloat((float)*bp);
+ ep++;
+ }
+ endpost();
+ if (truncated) post("..."); /* CHECKED */
+ }
+ else post(" no sequence"); /* CHECKED */
+}
+
+static void seq_free(t_seq *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+ hammerfile_free(x->x_filehandle);
+ if (x->x_sequence != x->x_seqini)
+ freebytes(x->x_sequence, x->x_size * sizeof(*x->x_sequence));
+}
+
+static void *seq_new(t_symbol *s)
+{
+ t_seq *x = (t_seq *)pd_new(seq_class);
+ static int warned = 0;
+ if (!warned)
+ {
+ loud_warning((t_pd *)x, "seq is not ready yet");
+ warned = 1;
+ }
+ x->x_canvas = canvas_getcurrent();
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0,
+ seq_readhook, seq_writehook, 0);
+ x->x_prevtime = 0;
+ x->x_size = SEQ_INISIZE;
+ x->x_nevents = 0;
+ x->x_sequence = x->x_seqini;
+ outlet_new((t_object *)x, &s_anything);
+ x->x_bangout = outlet_new((t_object *)x, &s_bang);
+ if (s && s != &s_)
+ {
+ x->x_defname = s; /* CHECKME if 'read' changes this */
+ seq_doread(x, s, 1);
+ }
+ else x->x_defname = &s_;
+ x->x_clock = clock_new(x, (t_method)seq_tick);
+ return (x);
+}
+
+void seq_setup(void)
+{
+ seq_class = class_new(gensym("seq"),
+ (t_newmethod)seq_new,
+ (t_method)seq_free,
+ sizeof(t_seq), 0,
+ A_DEFSYM, 0);
+ class_addbang(seq_class, seq_bang);
+ class_addfloat(seq_class, seq_float);
+ /* CHECKED symbol rejected */
+ class_addsymbol(seq_class, seq_symbol);
+ /* CHECKED 1st atom of a list accepted if a float, ignored if a symbol */
+ class_addlist(seq_class, seq_list);
+ class_addmethod(seq_class, (t_method)seq_record,
+ gensym("record"), 0);
+ class_addmethod(seq_class, (t_method)seq_append,
+ gensym("append"), 0);
+ class_addmethod(seq_class, (t_method)seq_stop,
+ gensym("stop"), 0);
+ class_addmethod(seq_class, (t_method)seq_read,
+ gensym("read"), A_DEFSYM, 0);
+ class_addmethod(seq_class, (t_method)seq_write,
+ gensym("write"), A_DEFSYM, 0);
+ class_addmethod(seq_class, (t_method)seq_print,
+ gensym("print"), 0);
+ hammerfile_setup(seq_class, 0);
+}
diff --git a/cyclone/hammer/sinh.c b/cyclone/hammer/sinh.c
new file mode 100644
index 0000000..93fb6fa
--- /dev/null
+++ b/cyclone/hammer/sinh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-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"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define sinhf sinh
+#endif
+
+typedef struct _sinh
+{
+ t_object x_ob;
+ float x_value;
+} t_sinh;
+
+static t_class *sinh_class;
+
+static void sinh_bang(t_sinh *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void sinh_float(t_sinh *x, t_float f)
+{
+ /* CHECKME large values */
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = sinhf(f));
+}
+
+static void *sinh_new(t_floatarg f)
+{
+ t_sinh *x = (t_sinh *)pd_new(sinh_class);
+ /* CHECKME large values */
+ x->x_value = sinhf(f);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void sinh_setup(void)
+{
+ sinh_class = class_new(gensym("sinh"),
+ (t_newmethod)sinh_new, 0,
+ sizeof(t_sinh), 0, A_DEFFLOAT, 0);
+ class_addbang(sinh_class, sinh_bang);
+ class_addfloat(sinh_class, sinh_float);
+}
diff --git a/cyclone/hammer/speedlim.c b/cyclone/hammer/speedlim.c
new file mode 100644
index 0000000..3cad0f7
--- /dev/null
+++ b/cyclone/hammer/speedlim.c
@@ -0,0 +1,173 @@
+/* Copyright (c) 2002-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 'clock' method */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define SPEEDLIM_INISIZE 32 /* LATER rethink */
+#define SPEEDLIM_MAXSIZE 256 /* not used */
+
+typedef struct _speedlim
+{
+ t_object x_ob;
+ int x_open;
+ t_float x_delta;
+ t_symbol *x_selector;
+ t_float x_float;
+ t_symbol *x_symbol;
+ t_gpointer *x_pointer;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ t_atom *x_message;
+ t_atom x_messini[SPEEDLIM_INISIZE];
+ int x_entered;
+ t_clock *x_clock;
+} t_speedlim;
+
+static t_class *speedlim_class;
+
+static void speedlim_dooutput(t_speedlim *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_open = 0; /* so there will be no reentrant calls of dooutput */
+ x->x_entered = 1; /* this prevents a message from being overridden */
+ clock_unset(x->x_clock);
+ if (s == &s_bang)
+ outlet_bang(((t_object *)x)->ob_outlet);
+ else if (s == &s_float)
+ outlet_float(((t_object *)x)->ob_outlet, x->x_float);
+ else if (s == &s_symbol && x->x_symbol)
+ {
+ /* if x_symbol is null, then symbol &s_ is passed
+ by outlet_anything() -> typedmess() */
+ outlet_symbol(((t_object *)x)->ob_outlet, x->x_symbol);
+ x->x_symbol = 0;
+ }
+ else if (s == &s_pointer && x->x_pointer)
+ {
+ /* LATER */
+ x->x_pointer = 0;
+ }
+ else if (s == &s_list)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else if (s)
+ outlet_anything(((t_object *)x)->ob_outlet, s, ac, av);
+ x->x_selector = 0;
+ x->x_natoms = 0;
+ if (x->x_delta > 0)
+ clock_delay(x->x_clock, x->x_delta);
+ else
+ x->x_open = 1;
+ x->x_entered = 0;
+}
+
+static void speedlim_tick(t_speedlim *x)
+{
+ if (x->x_selector)
+ speedlim_dooutput(x, x->x_selector, x->x_natoms, x->x_message);
+ else
+ x->x_open = 1;
+}
+
+static void speedlim_anything(t_speedlim *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_open)
+ speedlim_dooutput(x, s, ac, av);
+ else if (s && s != &s_ && !x->x_entered)
+ {
+ if (ac > x->x_size)
+ /* MAXSIZE not used, not even a warning...
+ LATER consider clipping */
+ x->x_message = grow_nodata(&ac, &x->x_size, x->x_message,
+ SPEEDLIM_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ x->x_selector = s;
+ x->x_natoms = ac;
+ if (ac)
+ memcpy(x->x_message, av, ac * sizeof(*x->x_message));
+ }
+}
+
+static void speedlim_bang(t_speedlim *x)
+{
+ x->x_selector = &s_bang;
+ speedlim_anything(x, x->x_selector, 0, 0);
+}
+
+static void speedlim_float(t_speedlim *x, t_float f)
+{
+ x->x_selector = &s_float;
+ x->x_float = f;
+ speedlim_anything(x, x->x_selector, 0, 0);
+}
+
+static void speedlim_symbol(t_speedlim *x, t_symbol *s)
+{
+ x->x_selector = &s_symbol;
+ x->x_symbol = s;
+ speedlim_anything(x, x->x_selector, 0, 0);
+}
+
+/* LATER gpointer */
+
+static void speedlim_list(t_speedlim *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_selector = &s_list;
+ speedlim_anything(x, x->x_selector, ac, av);
+}
+
+static void speedlim_ft1(t_speedlim *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0; /* redundant (and CHECKED) */
+ x->x_delta = f;
+ /* CHECKED: no rearming --
+ if clock is set, then new delta value is not used until next tick */
+}
+
+static void speedlim_free(t_speedlim *x)
+{
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+ if (x->x_clock)
+ clock_free(x->x_clock);
+}
+
+static void *speedlim_new(t_floatarg f)
+{
+ t_speedlim *x = (t_speedlim *)pd_new(speedlim_class);
+ x->x_open = 1; /* CHECKED */
+ x->x_delta = 0;
+ x->x_selector = 0;
+ x->x_float = 0;
+ x->x_symbol = 0;
+ x->x_pointer = 0;
+ x->x_size = SPEEDLIM_INISIZE;
+ x->x_natoms = 0;
+ x->x_message = x->x_messini;
+ x->x_entered = 0;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_anything);
+ x->x_clock = clock_new(x, (t_method)speedlim_tick);
+ speedlim_ft1(x, f);
+ return (x);
+}
+
+void speedlim_setup(void)
+{
+ speedlim_class = class_new(gensym("speedlim"),
+ (t_newmethod)speedlim_new,
+ (t_method)speedlim_free,
+ sizeof(t_speedlim), 0,
+ A_DEFFLOAT, 0);
+ class_addbang(speedlim_class, speedlim_bang);
+ class_addfloat(speedlim_class, speedlim_float);
+ class_addsymbol(speedlim_class, speedlim_symbol);
+ class_addlist(speedlim_class, speedlim_list);
+ class_addanything(speedlim_class, speedlim_anything);
+ class_addmethod(speedlim_class, (t_method)speedlim_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/spell.c b/cyclone/hammer/spell.c
new file mode 100644
index 0000000..f9a32d6
--- /dev/null
+++ b/cyclone/hammer/spell.c
@@ -0,0 +1,149 @@
+/* Copyright (c) 2002-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 <stdio.h>
+#include "m_pd.h"
+#include "common/loud.h"
+
+typedef struct _spell
+{
+ t_object x_ob;
+ int x_minsize;
+ int x_padchar; /* actually, any nonnegative integer (CHECKED) */
+} t_spell;
+
+static t_class *spell_class;
+
+static void spell_fill(t_spell *x, int cnt)
+{
+ for (; cnt < x->x_minsize; cnt++)
+ outlet_float(((t_object *)x)->ob_outlet, x->x_padchar);
+}
+
+/* CHECKED: chars are spelled as signed */
+static int spell_out(t_spell *x, char *ptr, int flush)
+{
+ int cnt = 0;
+ while (*ptr)
+ outlet_float(((t_object *)x)->ob_outlet, *ptr++), cnt++;
+ if (flush)
+ {
+ spell_fill(x, cnt);
+ return (0);
+ }
+ return (cnt);
+}
+
+static void spell_bang(t_spell *x)
+{
+ /* need to somehow override a default bang-to-empty-list conversion... */
+ loud_nomethod((t_pd *)x, &s_bang); /* CHECKED */
+}
+
+static void spell_float(t_spell *x, t_float f)
+{
+ int i;
+ if (loud_checkint((t_pd *)x, f, &i, &s_float)) /* CHECKED */
+ {
+ char buf[16];
+ sprintf(buf, "%d", i); /* CHECKED (negative numbers) */
+ spell_out(x, buf, 1);
+ }
+}
+
+/* CHECKED: 'symbol' selector is not spelled! */
+static void spell_symbol(t_spell *x, t_symbol *s)
+{
+ spell_out(x, s->s_name, 1);
+}
+
+static void spell_list(t_spell *x, t_symbol *s, int ac, t_atom *av)
+{
+ int cnt = 0;
+ int addsep = 0;
+ while (ac--)
+ {
+ if (addsep)
+ {
+ outlet_float(((t_object *)x)->ob_outlet, x->x_padchar);
+ cnt++;
+ }
+ else addsep = 1;
+ if (av->a_type == A_FLOAT)
+ {
+ int i;
+ /* CHECKME */
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &i, &s_list))
+ {
+ char buf[16];
+ sprintf(buf, "%d", i); /* CHECKED (negative numbers) */
+ cnt += spell_out(x, buf, 0);
+ }
+ /* CHECKED: floats as empty strings (separator is added) */
+ }
+ /* CHECKED: symbols as empty strings (separator is added) */
+ av++;
+ }
+ if (cnt) /* CHECKED: empty list is silently ignored */
+ spell_fill(x, cnt);
+}
+
+static void spell_anything(t_spell *x, t_symbol *s, int ac, t_atom *av)
+{
+ int cnt = 0;
+ int addsep = 0;
+ if (s)
+ {
+ cnt += spell_out(x, s->s_name, 0);
+ addsep = 1;
+ }
+ while (ac--)
+ {
+ if (addsep)
+ {
+ outlet_float(((t_object *)x)->ob_outlet, x->x_padchar);
+ cnt++;
+ }
+ else addsep = 1;
+ if (av->a_type == A_FLOAT)
+ {
+ int i;
+ /* CHECKME */
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &i, &s_list))
+ {
+ char buf[16];
+ sprintf(buf, "%d", i); /* CHECKED (negative numbers) */
+ cnt += spell_out(x, buf, 0);
+ }
+ /* CHECKED: floats as empty strings (separator is added) */
+ }
+ else if (av->a_type == A_SYMBOL && av->a_w.w_symbol)
+ cnt += spell_out(x, av->a_w.w_symbol->s_name, 0);
+ av++;
+ }
+ if (cnt) /* CHECKED: empty list is silently ignored */
+ spell_fill(x, cnt);
+}
+
+static void *spell_new(t_floatarg f1, t_floatarg f2)
+{
+ t_spell *x = (t_spell *)pd_new(spell_class);
+ int i2 = (int)f2; /* CHECKED */
+ x->x_minsize = (f1 > 0 ? (int)f1 : 0);
+ x->x_padchar = (i2 < 0 ? 0 : (i2 > 0 ? i2 : ' ')); /* CHECKED */
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void spell_setup(void)
+{
+ spell_class = class_new(gensym("spell"),
+ (t_newmethod)spell_new, 0,
+ sizeof(t_spell), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(spell_class, spell_bang);
+ class_addfloat(spell_class, spell_float);
+ class_addsymbol(spell_class, spell_symbol);
+ class_addlist(spell_class, spell_list);
+ class_addanything(spell_class, spell_anything);
+}
diff --git a/cyclone/hammer/split.c b/cyclone/hammer/split.c
new file mode 100644
index 0000000..2865f66
--- /dev/null
+++ b/cyclone/hammer/split.c
@@ -0,0 +1,64 @@
+/* Copyright (c) 2002-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"
+
+/* CHECKED:
+ 'list <symbol>' silently ignored (LATER remove a warning)
+ '<number> <symbol>' as '<number>' (LATER remove a warning)
+ LATER more compatibility checks are needed...
+ LATER sort out float/int dilemmas
+*/
+
+typedef struct _split
+{
+ t_object x_ob;
+ int x_floatmode;
+ t_float x_min;
+ t_float x_max;
+ t_outlet *x_out2;
+} t_split;
+
+static t_class *split_class;
+
+static void split_float(t_split *x, t_float f)
+{
+ if (x->x_floatmode)
+ {
+ if (f >= x->x_min && f <= x->x_max)
+ outlet_float(((t_object *)x)->ob_outlet, f);
+ else outlet_float(x->x_out2, f);
+ }
+ else
+ {
+ /* CHECKED: no pre-truncation */
+ if (f >= x->x_min && f <= x->x_max)
+ outlet_float(((t_object *)x)->ob_outlet, (int)f);
+ else outlet_float(x->x_out2, (int)f);
+ }
+}
+
+static void *split_new(t_floatarg f1, t_floatarg f2)
+{
+ t_split *x = (t_split *)pd_new(split_class);
+ x->x_floatmode = (f1 != (int)f1);
+ /* CHECKED: defaults are [0..0] and [0..f1] (for positive f1) or [f1..0] */
+ if (f1 < f2) /* CHECKED */
+ x->x_min = f1, x->x_max = f2;
+ else
+ x->x_min = f2, x->x_max = f1;
+ floatinlet_new((t_object *)x, &x->x_min);
+ floatinlet_new((t_object *)x, &x->x_max);
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void split_setup(void)
+{
+ split_class = class_new(gensym("split"),
+ (t_newmethod)split_new, 0,
+ sizeof(t_split), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(split_class, split_float);
+}
diff --git a/cyclone/hammer/spray.c b/cyclone/hammer/spray.c
new file mode 100644
index 0000000..8aa0556
--- /dev/null
+++ b/cyclone/hammer/spray.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2002-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 "common/loud.h"
+
+#define SPRAY_MINOUTS 1
+/* CHECKED: no upper limit */
+#define SPRAY_DEFOUTS 2
+
+typedef struct _spray
+{
+ t_object x_ob;
+ int x_offset;
+ int x_nouts;
+ t_outlet **x_outs;
+} t_spray;
+
+static t_class *spray_class;
+
+static void spray_float(t_spray *x, t_float f)
+{
+ /* CHECKED: floats ignored (LATER rethink), ints loudly rejected */
+ if (f == (int)f) loud_error((t_pd *)x, "requires list");
+}
+
+/* LATER decide, whether float in first atom is to be truncated,
+ or causing a list to be ignored as in max (CHECKED) */
+static void spray_list(t_spray *x, t_symbol *s, int ac, t_atom *av)
+{
+ int ndx;
+ if (ac >= 2 && av->a_type == A_FLOAT
+ /* CHECKED: lists with negative effective ndx are ignored */
+ && (ndx = (int)av->a_w.w_float - x->x_offset) >= 0
+ && ndx < x->x_nouts)
+ {
+ /* CHECKED: ignored atoms (symbols and floats) are counted */
+ /* CHECKED: we must spray in right-to-left order */
+ t_atom *argp;
+ t_outlet **outp;
+ int last = ac - 1 + ndx; /* ndx of last outlet filled (first is 1) */
+ if (last > x->x_nouts)
+ {
+ argp = av + 1 + x->x_nouts - ndx;
+ outp = x->x_outs + x->x_nouts;
+ }
+ else
+ {
+ argp = av + ac;
+ outp = x->x_outs + last;
+ }
+ /* argp/outp now point to one after the first atom/outlet to deliver */
+ for (argp--, outp--; argp > av; argp--, outp--)
+ if (argp->a_type == A_FLOAT)
+ outlet_float(*outp, argp->a_w.w_float);
+ }
+}
+
+static void spray_free(t_spray *x)
+{
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_nouts * sizeof(*x->x_outs));
+}
+
+static void *spray_new(t_floatarg f1, t_floatarg f2)
+{
+ t_spray *x;
+ int i, nouts = (int)f1;
+ t_outlet **outs;
+ if (nouts < SPRAY_MINOUTS)
+ nouts = SPRAY_DEFOUTS;
+ if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
+ return (0);
+ x = (t_spray *)pd_new(spray_class);
+ x->x_nouts = nouts;
+ x->x_outs = outs;
+ x->x_offset = (int)f2;
+ for (i = 0; i < nouts; i++)
+ x->x_outs[i] = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void spray_setup(void)
+{
+ spray_class = class_new(gensym("spray"),
+ (t_newmethod)spray_new,
+ (t_method)spray_free,
+ sizeof(t_spray), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ /* CHECKED: bang, symbol, anything -- ``doesn't understand'' */
+ class_addfloat(spray_class, spray_float);
+ class_addlist(spray_class, spray_list);
+}
diff --git a/cyclone/hammer/sprintf.c b/cyclone/hammer/sprintf.c
new file mode 100644
index 0000000..aebfed3
--- /dev/null
+++ b/cyclone/hammer/sprintf.c
@@ -0,0 +1,634 @@
+/* Copyright (c) 2002-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. */
+
+/* FIXME empty string as a default for %s */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define SPRINTF_DEBUG 0
+
+/* Pattern types. These are the parsing routine's return values.
+ If returned value is >= SPRINTF_MINSLOTTYPE, then another slot
+ is created (i.e. an inlet, and a proxy handling it). */
+#define SPRINTF_UNSUPPORTED 0
+#define SPRINTF_LITERAL 1
+#define SPRINTF_MINSLOTTYPE 2
+#define SPRINTF_INT 2
+#define SPRINTF_FLOAT 3
+#define SPRINTF_CHAR 4
+#define SPRINTF_STRING 5
+
+/* Numbers: assuming max 62 digits preceding a decimal point in any
+ fixed-point representation of a t_float (39 in my system)
+ -- need to be sure, that using max precision would never produce
+ a representation longer than max width. If this is so, then no number
+ representation would exceed max width (presumably...).
+ Strings: for the time being, any string longer than max width would
+ be truncated (somehow compatible with Str256, but LATER warn-and-allow). */
+/* LATER rethink it all */
+#define SPRINTF_MAXPRECISION 192
+#define SPRINTF_MAXWIDTH 256
+
+typedef struct _sprintf
+{
+ t_object x_ob;
+ int x_nslots;
+ int x_nproxies; /* as requested (and allocated) */
+ t_pd **x_proxies;
+ int x_fsize; /* as allocated (i.e. including a terminating 0) */
+ char *x_fstring;
+} t_sprintf;
+
+typedef struct _sprintf_proxy
+{
+ t_object p_ob;
+ t_sprintf *p_master;
+ int p_id;
+ int p_type; /* a value #defined above */
+ char *p_pattern;
+ char *p_pattend;
+ t_atom p_atom; /* current input */
+ int p_size; /* also an input validation flag */
+} t_sprintf_proxy;
+
+static t_class *sprintf_class;
+static t_class *sprintf_proxy_class;
+
+/* CHECKED: 'symout' argument has no special meaning in max4.07,
+ LATER investigate */
+
+/* LATER use snprintf, if it is available on other systems (should be...) */
+static void sprintf_proxy_checkit(t_sprintf_proxy *x, char *buf, int checkin)
+{
+ int result = 0;
+ char *pattend = x->p_pattend;
+ if (pattend)
+ {
+ char tmp = *pattend;
+ *pattend = 0;
+ if (x->p_atom.a_type == A_FLOAT)
+ {
+ t_float f = x->p_atom.a_w.w_float;
+ if (x->p_type == SPRINTF_INT)
+ /* CHECKME large/negative values */
+ result = sprintf(buf, x->p_pattern, (int)f);
+ else if (x->p_type == SPRINTF_FLOAT)
+ result = sprintf(buf, x->p_pattern, f);
+ else if (x->p_type == SPRINTF_CHAR)
+ /* CHECKED: if 0 is input into a %c-slot, the whole output
+ string is null-terminated */
+ /* CHECKED: float into a %c-slot is truncated,
+ but CHECKME large/negative values */
+ result = sprintf(buf, x->p_pattern, (unsigned char)f);
+ else if (x->p_type == SPRINTF_STRING)
+ {
+ /* CHECKED: any number input into a %s-slot is ok */
+ char tmp[64]; /* LATER rethink */
+ sprintf(tmp, "%g", f);
+ result = sprintf(buf, x->p_pattern, tmp);
+ }
+ else /* LATER consider calling it a bug(), rather than error? */
+ loud_error((t_pd *)x->p_master,
+ "can't convert float to type of argument %d",
+ x->p_id + 1);
+ }
+ else if (x->p_atom.a_type == A_SYMBOL)
+ {
+ t_symbol *s = x->p_atom.a_w.w_symbol;
+ if (x->p_type == SPRINTF_STRING)
+ {
+ if (strlen(s->s_name) > SPRINTF_MAXWIDTH)
+ {
+ strncpy(buf, s->s_name, SPRINTF_MAXWIDTH);
+ buf[SPRINTF_MAXWIDTH] = 0;
+ result = SPRINTF_MAXWIDTH;
+ }
+ else result = sprintf(buf, x->p_pattern, s->s_name);
+ }
+ else /* CHECKED */
+ loud_error((t_pd *)x->p_master,
+ "can't convert symbol to type of argument %d",
+ x->p_id + 1);
+ }
+ *pattend = tmp;
+ }
+ else bug("sprintf_proxy_checkit");
+ if (result > 0)
+ {
+#if SPRINTF_DEBUG
+ if (checkin) post("[%d in \"%s\"]", result, buf);
+#endif
+ x->p_size = result;
+ }
+ else
+ {
+#if SPRINTF_DEBUG
+ if (checkin) post("checkit failed");
+#endif
+ x->p_size = 0;
+ }
+}
+
+static void sprintf_dooutput(t_sprintf *x)
+{
+ int i, outsize;
+ char *outstring;
+ outsize = x->x_fsize; /* this is strlen() + 1 */
+ /* LATER consider subtracting format pattern sizes */
+ for (i = 0; i < x->x_nslots; i++)
+ {
+ t_sprintf_proxy *y = (t_sprintf_proxy *)x->x_proxies[i];
+ if (y->p_size)
+ outsize += y->p_size;
+ else
+ {
+ /* slot i has received an invalid input -- CHECKME if this
+ condition blocks all subsequent output requests? */
+ return;
+ }
+ }
+ if (outsize > 0 && (outstring = getbytes(outsize)))
+ {
+ char *inp = x->x_fstring;
+ char *outp = outstring;
+ for (i = 0; i < x->x_nslots; i++)
+ {
+ t_sprintf_proxy *y = (t_sprintf_proxy *)x->x_proxies[i];
+ int len = y->p_pattern - inp;
+ if (len > 0)
+ {
+ strncpy(outp, inp, len);
+ outp += len;
+ }
+ sprintf_proxy_checkit(y, outp, 0);
+ outp += y->p_size; /* p_size is never negative */
+ inp = y->p_pattend;
+ }
+ strcpy(outp, inp);
+
+ outp = outstring;
+ while (*outp == ' ' || *outp == '\t'
+ || *outp == '\n' || *outp == '\r') outp++;
+ if (*outp)
+ {
+ t_binbuf *bb = binbuf_new();
+ int ac;
+ t_atom *av;
+ binbuf_text(bb, outp, strlen(outp));
+ ac = binbuf_getnatom(bb);
+ av = binbuf_getvec(bb);
+ if (ac)
+ {
+ if (av->a_type == A_SYMBOL)
+ outlet_anything(((t_object *)x)->ob_outlet,
+ av->a_w.w_symbol, ac - 1, av + 1);
+ else if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ outlet_list(((t_object *)x)->ob_outlet,
+ &s_list, ac, av);
+ else
+ outlet_float(((t_object *)x)->ob_outlet,
+ av->a_w.w_float);
+ }
+ }
+ binbuf_free(bb);
+ }
+ freebytes(outstring, outsize);
+ }
+}
+
+static void sprintf_proxy_bang(t_sprintf_proxy *x)
+{
+ sprintf_dooutput(x->p_master); /* CHECKED (in any inlet) */
+}
+
+static void sprintf_proxy_float(t_sprintf_proxy *x, t_float f)
+{
+ char buf[SPRINTF_MAXWIDTH + 1]; /* LATER rethink */
+ SETFLOAT(&x->p_atom, f);
+ sprintf_proxy_checkit(x, buf, 1);
+ if (x->p_id == 0 && x->p_size)
+ sprintf_dooutput(x->p_master); /* CHECKED: only first inlet */
+}
+
+static void sprintf_proxy_symbol(t_sprintf_proxy *x, t_symbol *s)
+{
+ char buf[SPRINTF_MAXWIDTH + 1]; /* LATER rethink */
+ if (s && *s->s_name)
+ SETSYMBOL(&x->p_atom, s);
+ else
+ SETFLOAT(&x->p_atom, 0);
+ sprintf_proxy_checkit(x, buf, 1);
+ if (x->p_id == 0 && x->p_size)
+ sprintf_dooutput(x->p_master); /* CHECKED: only first inlet */
+}
+
+static void sprintf_dolist(t_sprintf *x,
+ t_symbol *s, int ac, t_atom *av, int startid)
+{
+ int cnt = x->x_nslots - startid;
+ if (ac > cnt)
+ ac = cnt;
+ if (ac-- > 0)
+ {
+ int id;
+ for (id = startid + ac, av += ac; id >= startid; id--, av--)
+ {
+ if (av->a_type == A_FLOAT)
+ sprintf_proxy_float((t_sprintf_proxy *)x->x_proxies[id],
+ av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ sprintf_proxy_symbol((t_sprintf_proxy *)x->x_proxies[id],
+ av->a_w.w_symbol);
+ }
+ }
+}
+
+static void sprintf_doanything(t_sprintf *x,
+ t_symbol *s, int ac, t_atom *av, int startid)
+{
+ if (s && s != &s_)
+ {
+ sprintf_dolist(x, 0, ac, av, startid + 1);
+ sprintf_proxy_symbol((t_sprintf_proxy *)x->x_proxies[startid], s);
+ }
+ else sprintf_dolist(x, 0, ac, av, startid);
+}
+
+static void sprintf_proxy_list(t_sprintf_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ sprintf_dolist(x->p_master, s, ac, av, x->p_id);
+}
+
+static void sprintf_proxy_anything(t_sprintf_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ sprintf_doanything(x->p_master, s, ac, av, x->p_id);
+}
+
+static void sprintf_bang(t_sprintf *x)
+{
+ if (x->x_nslots)
+ sprintf_proxy_bang((t_sprintf_proxy *)x->x_proxies[0]);
+}
+
+static void sprintf_float(t_sprintf *x, t_float f)
+{
+ if (x->x_nslots)
+ sprintf_proxy_float((t_sprintf_proxy *)x->x_proxies[0], f);
+}
+
+static void sprintf_symbol(t_sprintf *x, t_symbol *s)
+{
+ if (x->x_nslots)
+ sprintf_proxy_symbol((t_sprintf_proxy *)x->x_proxies[0], s);
+}
+
+static void sprintf_list(t_sprintf *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_nslots)
+ sprintf_dolist(x, s, ac, av, 0);
+}
+
+static void sprintf_anything(t_sprintf *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_nslots)
+ sprintf_doanything(x, s, ac, av, 0);
+}
+
+/* adjusted binbuf_gettext(), LATER do it right */
+static char *hammer_gettext(int ac, t_atom *av, int *sizep)
+{
+ char *buf = getbytes(1);
+ int size = 1;
+ char atomtext[MAXPDSTRING];
+ while (ac--)
+ {
+ char *newbuf;
+ int newsize;
+ if (buf[size-1] == 0 || av->a_type == A_SEMI || av->a_type == A_COMMA)
+ size--;
+ atom_string(av, atomtext, MAXPDSTRING);
+ newsize = size + strlen(atomtext) + 1;
+ if (!(newbuf = resizebytes(buf, size, newsize)))
+ {
+ *sizep = 1;
+ return (getbytes(1));
+ }
+ buf = newbuf;
+ strcpy(buf + size, atomtext);
+ size = newsize;
+ buf[size-1] = ' ';
+ av++;
+ }
+ buf[size-1] = 0;
+ *sizep = size;
+ return (buf);
+}
+
+/* Called twice: 1st pass (with x == 0) is used for counting valid patterns;
+ 2nd pass (after object allocation) -- for initializing the proxies.
+ If there is a "%%" pattern, then the buffer is shrinked in the second pass
+ (LATER rethink). */
+static int sprintf_parsepattern(t_sprintf *x, char **patternp)
+{
+ int type = SPRINTF_UNSUPPORTED;
+ char errstring[MAXPDSTRING];
+ char *ptr;
+ char modifier = 0;
+ int width = 0;
+ int precision = 0;
+ int *numfield = &width;
+ int dotseen = 0;
+ *errstring = 0;
+ for (ptr = *patternp; *ptr; ptr++)
+ {
+ if (*ptr >= '0' && *ptr <= '9')
+ {
+ if (!numfield)
+ {
+ if (x) sprintf(errstring, "extra number field");
+ break;
+ }
+ *numfield = 10 * *numfield + *ptr - '0';
+ if (dotseen)
+ {
+ if (precision > SPRINTF_MAXPRECISION)
+ {
+ if (x) sprintf(errstring, "precision field too large");
+ break;
+ }
+ }
+ else
+ {
+ if (width > SPRINTF_MAXWIDTH)
+ {
+ if (x) sprintf(errstring, "width field too large");
+ break;
+ }
+ }
+ continue;
+ }
+ if (*numfield)
+ numfield = 0;
+
+ if (strchr("diouxX", *ptr))
+ {
+ type = SPRINTF_INT;
+ break;
+ }
+ else if (strchr("aAeEfgG", *ptr))
+ {
+ if (modifier)
+ {
+ if (x) sprintf(errstring,
+ "\'%c\' modifier not supported", modifier);
+ break;
+ }
+ type = SPRINTF_FLOAT;
+ break;
+ }
+ else if (strchr("c", *ptr))
+ {
+ if (modifier)
+ {
+ if (x) sprintf(errstring,
+ "\'%c\' modifier not supported", modifier);
+ break;
+ }
+ type = SPRINTF_CHAR;
+ break;
+ }
+ else if (strchr("s", *ptr))
+ {
+ if (modifier)
+ {
+ if (x) sprintf(errstring,
+ "\'%c\' modifier not supported", modifier);
+ break;
+ }
+ type = SPRINTF_STRING;
+ break;
+ }
+ else if (*ptr == '%')
+ {
+ type = SPRINTF_LITERAL;
+ if (x)
+ { /* buffer-shrinking hack, LATER rethink */
+ char *p1 = ptr, *p2 = ptr + 1;
+ do
+ *p1++ = *p2;
+ while (*p2++);
+ ptr--;
+ }
+ break;
+ }
+ else if (strchr("CSnm", *ptr))
+ {
+ if (x) sprintf(errstring, "\'%c\' type not supported", *ptr);
+ break;
+ }
+ else if (strchr("l", *ptr))
+ {
+ if (modifier)
+ {
+ if (x) sprintf(errstring, "only single modifier is supported");
+ break;
+ }
+ modifier = *ptr;
+ }
+ else if (strchr("hjLqtzZ", *ptr))
+ {
+ if (x) sprintf(errstring, "\'%c\' modifier not supported", *ptr);
+ break;
+ }
+ else if (*ptr == '.')
+ {
+ if (dotseen)
+ {
+ if (x) sprintf(errstring, "multiple dots");
+ break;
+ }
+ numfield = &precision;
+ dotseen = 1;
+ }
+ else if (*ptr == '$')
+ {
+ if (x) sprintf(errstring, "parameter number field not supported");
+ break;
+ }
+ else if (*ptr == '*')
+ {
+ if (x) sprintf(errstring, "%s parameter not supported",
+ (dotseen ? "precision" : "width"));
+ break;
+ }
+ else if (!strchr("-+ #\'", *ptr))
+ {
+ if (x) sprintf(errstring,
+ "\'%c\' format character not supported", *ptr);
+ break;
+ }
+ }
+ if (*ptr)
+ ptr++; /* LATER rethink */
+ else
+ if (x) sprintf(errstring, "type not specified");
+ if (x && type == SPRINTF_UNSUPPORTED)
+ {
+ if (*errstring)
+ loud_error((t_pd *)x, "slot skipped (%s %s)",
+ errstring, "in a format pattern");
+ else
+ loud_error((t_pd *)x, "slot skipped");
+ }
+ *patternp = ptr;
+ return (type);
+}
+
+static void sprintf_free(t_sprintf *x)
+{
+ if (x->x_proxies)
+ {
+ int i = x->x_nslots;
+ while (i--)
+ {
+ t_sprintf_proxy *y = (t_sprintf_proxy *)x->x_proxies[i];
+ pd_free((t_pd *)y);
+ }
+ freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies));
+ }
+ if (x->x_fstring)
+ freebytes(x->x_fstring, x->x_fsize);
+}
+
+static void *sprintf_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_sprintf *x;
+ int fsize;
+ char *fstring;
+ char *p1, *p2;
+ int i, nslots, nproxies = 0;
+ t_pd **proxies;
+ fstring = hammer_gettext(ac, av, &fsize);
+ p1 = fstring;
+ while (p2 = strchr(p1, '%'))
+ {
+ int type;
+ p1 = p2 + 1;
+ type = sprintf_parsepattern(0, &p1);
+ if (type >= SPRINTF_MINSLOTTYPE)
+ nproxies++;
+ }
+ if (!nproxies)
+ {
+ /* CHECKED: an object without arguments, if created in the editor,
+ has no inlets/outlets, but it would have one inlet (no outlets)
+ upon loading. Error message is printed in either case. */
+ x = (t_sprintf *)pd_new(sprintf_class);
+ x->x_nslots = 0;
+ x->x_nproxies = 0;
+ x->x_proxies = 0;
+ x->x_fsize = fsize;
+ x->x_fstring = fstring;
+ p1 = fstring;
+ while (p2 = strchr(p1, '%'))
+ {
+ p1 = p2 + 1;
+ sprintf_parsepattern(x, &p1);
+ }
+ loud_error((t_pd *)x,
+ "an object created without valid format patterns...");
+ return (x);
+ }
+#if SPRINTF_DEBUG
+ post("%d slots:", nproxies);
+#endif
+ /* CHECKED: max creates as many inlets, as there are %-signs, no matter
+ if they are valid, or not -- if not, it prints ``can't convert'' errors
+ for any input... */
+ if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies))))
+ {
+ freebytes(fstring, fsize);
+ return (0);
+ }
+ for (nslots = 0; nslots < nproxies; nslots++)
+ if (!(proxies[nslots] = pd_new(sprintf_proxy_class))) break;
+ if (!nslots)
+ {
+ freebytes(fstring, fsize);
+ freebytes(proxies, nproxies * sizeof(*proxies));
+ return (0);
+ }
+ x = (t_sprintf *)pd_new(sprintf_class);
+ x->x_nslots = nslots;
+ x->x_nproxies = nproxies;
+ x->x_proxies = proxies;
+ x->x_fsize = fsize;
+ x->x_fstring = fstring;
+ p1 = fstring;
+ i = 0;
+ while (p2 = strchr(p1, '%'))
+ {
+ int type;
+ p1 = p2 + 1;
+ type = sprintf_parsepattern(x, &p1);
+ if (type >= SPRINTF_MINSLOTTYPE)
+ {
+#if SPRINTF_DEBUG
+ char tmp = *++p1;
+ *p1 = 0;
+ poststring(p2);
+ endpost();
+ *p1 = tmp;
+#endif
+ if (i < nslots)
+ {
+ char buf[SPRINTF_MAXWIDTH + 1]; /* LATER rethink */
+ t_sprintf_proxy *y = (t_sprintf_proxy *)proxies[i];
+ y->p_master = x;
+ y->p_id = i;
+ y->p_type = type;
+ y->p_pattern = p2;
+ y->p_pattend = p1;
+ SETFLOAT(&y->p_atom, 0);
+ y->p_size = 0;
+ if (i) inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ sprintf_proxy_checkit(y, buf, 1);
+ i++;
+ }
+ }
+ }
+#if SPRINTF_DEBUG
+ post("printf(\"%s\", ...)", fstring);
+#endif
+ outlet_new((t_object *)x, &s_anything);
+ return (x);
+}
+
+void sprintf_setup(void)
+{
+ sprintf_class = class_new(gensym("sprintf"),
+ (t_newmethod)sprintf_new,
+ (t_method)sprintf_free,
+ sizeof(t_sprintf), 0, A_GIMME, 0);
+ class_addbang(sprintf_class, sprintf_bang);
+ class_addfloat(sprintf_class, sprintf_float);
+ class_addsymbol(sprintf_class, sprintf_symbol);
+ class_addlist(sprintf_class, sprintf_list);
+ class_addanything(sprintf_class, sprintf_anything);
+ sprintf_proxy_class = class_new(gensym("_sprintf_proxy"), 0, 0,
+ sizeof(t_sprintf_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(sprintf_proxy_class, sprintf_proxy_bang);
+ class_addfloat(sprintf_proxy_class, sprintf_proxy_float);
+ class_addsymbol(sprintf_proxy_class, sprintf_proxy_symbol);
+ class_addlist(sprintf_proxy_class, sprintf_proxy_list);
+ class_addanything(sprintf_proxy_class, sprintf_proxy_anything);
+}
diff --git a/cyclone/hammer/substitute.c b/cyclone/hammer/substitute.c
new file mode 100644
index 0000000..48a9b9d
--- /dev/null
+++ b/cyclone/hammer/substitute.c
@@ -0,0 +1,340 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define SUBSTITUTE_INISIZE 32 /* LATER rethink */
+#define SUBSTITUTE_MAXSIZE 256
+
+typedef struct _substitute
+{
+ t_object x_ob;
+ t_pd *x_proxy;
+ t_atom x_match;
+ t_atom x_repl;
+ int x_size; /* as allocated */
+ t_atom *x_message;
+ t_atom x_messini[SUBSTITUTE_INISIZE];
+ int x_entered;
+ t_atom x_auxmatch;
+ t_atom x_auxrepl;
+ t_outlet *x_passout;
+} t_substitute;
+
+typedef struct _substitute_proxy
+{
+ t_object p_ob;
+ t_atom *p_match; /* pointing to parent's (aux)match */
+ t_atom *p_repl;
+} t_substitute_proxy;
+
+static t_class *substitute_class;
+static t_class *substitute_proxy_class;
+
+/* LATER rethink */
+static void substitute_dooutput(t_substitute *x,
+ t_symbol *s, int ac, t_atom *av, int pass)
+{
+ t_outlet *out = (pass ? x->x_passout : ((t_object *)x)->ob_outlet);
+ if (s == &s_float)
+ {
+ if (ac > 1)
+ outlet_list(out, &s_list, ac, av);
+ else
+ outlet_float(out, av->a_w.w_float);
+ }
+ else if (s == &s_bang && !ac) /* CHECKED */
+ outlet_bang(out);
+ else if (s == &s_symbol && ac == 1 && av->a_type == A_SYMBOL)
+ outlet_symbol(out, av->a_w.w_symbol);
+ else if (s)
+ outlet_anything(out, s, ac, av);
+ else if (ac)
+ outlet_list(out, &s_list, ac, av);
+}
+
+static int substitute_check(t_substitute *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_repl.a_type == A_NULL)
+ return (-2);
+ /* see substitute_proxy_validate() for possible types and values */
+ if (x->x_match.a_type == A_FLOAT)
+ {
+ t_float f = x->x_match.a_w.w_float;
+ int i;
+ for (i = 0; i < ac; i++, av++)
+ if (av->a_type == A_FLOAT && av->a_w.w_float == f)
+ return (i);
+ }
+ else if (x->x_match.a_type == A_SYMBOL)
+ {
+ /* match symbol is validated -- never null */
+ t_symbol *match = x->x_match.a_w.w_symbol;
+ int i;
+ if (s == match)
+ return (-1);
+ for (i = 0; i < ac; i++, av++)
+ if (av->a_type == A_SYMBOL && av->a_w.w_symbol == match)
+ return (i);
+ }
+ return (-2);
+}
+
+static void substitute_doit(t_substitute *x,
+ t_symbol *s, int ac, t_atom *av, int startndx)
+{
+ int cnt = ac - startndx;
+ if (cnt > 0)
+ {
+ t_atom *ap = av + startndx;
+ if (x->x_match.a_type == A_FLOAT)
+ {
+ t_float f = x->x_match.a_w.w_float;
+ while (cnt--)
+ {
+ if (ap->a_type == A_FLOAT && ap->a_w.w_float == f)
+ *ap = x->x_repl;
+ ap++;
+ }
+ }
+ else if (x->x_match.a_type == A_SYMBOL)
+ {
+ t_symbol *match = x->x_match.a_w.w_symbol;
+ while (cnt--)
+ {
+ if (ap->a_type == A_SYMBOL && ap->a_w.w_symbol == match)
+ *ap = x->x_repl;
+ ap++;
+ }
+ }
+ }
+ substitute_dooutput(x, s, ac, av, 0);
+}
+
+static void substitute_anything(t_substitute *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ int matchndx = substitute_check(x, s, ac, av);
+ if (matchndx < -1)
+ substitute_dooutput(x, s, ac, av, 1);
+ else
+ {
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ int ntotal = ac;
+ t_atom *buf;
+ t_substitute_proxy *proxy = (t_substitute_proxy *)x->x_proxy;
+ x->x_entered = 1;
+ proxy->p_match = &x->x_auxmatch;
+ proxy->p_repl = &x->x_auxrepl;
+ if (s == &s_) s = 0;
+ if (matchndx == -1)
+ {
+ if (x->x_repl.a_type == A_FLOAT)
+ {
+ ntotal++;
+ if (ac) s = &s_list;
+ else s = &s_float;
+ }
+ else if (x->x_repl.a_type == A_SYMBOL)
+ {
+ s = x->x_repl.a_w.w_symbol;
+ matchndx = 0;
+ }
+ }
+ else if (matchndx == 0
+ && (!s || s == &s_list || s == &s_float)
+ && av->a_type == A_FLOAT
+ && x->x_repl.a_type == A_SYMBOL)
+ {
+ s = x->x_repl.a_w.w_symbol;
+ ac--;
+ av++;
+ ntotal = ac;
+ }
+ if (prealloc && ac > x->x_size)
+ {
+ if (ntotal > SUBSTITUTE_MAXSIZE)
+ prealloc = 0;
+ else
+ x->x_message = grow_nodata(&ntotal, &x->x_size, x->x_message,
+ SUBSTITUTE_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ }
+ if (prealloc) buf = x->x_message;
+ else
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ buf = getbytes(ntotal * sizeof(*buf));
+ if (buf)
+ {
+ int ncopy = ntotal;
+ t_atom *bp = buf;
+ if (matchndx == -1)
+ {
+ SETFLOAT(bp++, x->x_repl.a_w.w_float);
+ ncopy--;
+ }
+ if (ncopy)
+ memcpy(bp, av, ncopy * sizeof(*buf));
+ substitute_doit(x, s, ntotal, buf, matchndx);
+ if (buf != x->x_message)
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+ if (!reentered)
+ {
+ x->x_entered = 0;
+ if (x->x_auxmatch.a_type != A_NULL)
+ {
+ x->x_match = x->x_auxmatch;
+ x->x_auxmatch.a_type = A_NULL;
+ }
+ if (x->x_auxrepl.a_type != A_NULL)
+ {
+ x->x_repl = x->x_auxrepl;
+ x->x_auxrepl.a_type = A_NULL;
+ }
+ proxy->p_match = &x->x_match;
+ proxy->p_repl = &x->x_repl;
+ }
+ }
+}
+
+static void substitute_bang(t_substitute *x)
+{
+ substitute_anything(x, &s_bang, 0, 0);
+}
+
+static void substitute_float(t_substitute *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ substitute_anything(x, 0, 1, &at);
+}
+
+/* CHECKED (but LATER rethink) */
+static void substitute_symbol(t_substitute *x, t_symbol *s)
+{
+ t_atom at;
+ SETSYMBOL(&at, s);
+ substitute_anything(x, &s_symbol, 1, &at);
+}
+
+/* LATER gpointer */
+
+static void substitute_list(t_substitute *x, t_symbol *s, int ac, t_atom *av)
+{
+ substitute_anything(x, 0, ac, av);
+}
+
+static int substitute_atomvalidate(t_atom *ap)
+{
+ return (ap->a_type == A_FLOAT
+ || (ap->a_type == A_SYMBOL
+ && ap->a_w.w_symbol && ap->a_w.w_symbol != &s_));
+}
+
+/* CHECKED: 'set' is ignored, single '<atom>' does not modify a replacement */
+static void substitute_proxy_anything(t_substitute_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (s == &s_) s = 0;
+ if (s)
+ {
+ SETSYMBOL(x->p_match, s);
+ if (ac && substitute_atomvalidate(av))
+ *x->p_repl = *av;
+ }
+ else if (ac && substitute_atomvalidate(av))
+ {
+ *x->p_match = *av++;
+ if (ac > 1 && substitute_atomvalidate(av))
+ *x->p_repl = *av;
+ }
+}
+
+static void substitute_proxy_bang(t_substitute_proxy *x)
+{
+ SETSYMBOL(x->p_match, &s_bang);
+}
+
+static void substitute_proxy_float(t_substitute_proxy *x, t_float f)
+{
+ SETFLOAT(x->p_match, f);
+}
+
+/* CHECKED (but LATER rethink) */
+static void substitute_proxy_symbol(t_substitute_proxy *x, t_symbol *s)
+{
+ SETSYMBOL(x->p_match, &s_symbol);
+ SETSYMBOL(x->p_repl, s);
+}
+
+/* LATER gpointer */
+
+static void substitute_proxy_list(t_substitute_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ substitute_proxy_anything(x, 0, ac, av);
+}
+
+static void substitute_free(t_substitute *x)
+{
+ if (x->x_proxy) pd_free(x->x_proxy);
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+}
+
+static void *substitute_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_substitute *x = 0;
+ t_substitute_proxy *proxy =
+ (t_substitute_proxy *)pd_new(substitute_proxy_class);
+ if (proxy)
+ {
+ x = (t_substitute *)pd_new(substitute_class);
+ proxy->p_match = &x->x_match;
+ proxy->p_repl = &x->x_repl;
+ x->x_proxy = (t_pd *)proxy;
+ x->x_size = SUBSTITUTE_INISIZE;
+ x->x_message = x->x_messini;
+ x->x_entered = 0;
+ /* CHECKED: everything is to be passed unchanged, until both are set */
+ /* CHECKED: max crashes if a match has been set, but not a replacement,
+ and there is a match */
+ x->x_match.a_type = x->x_repl.a_type = A_NULL;
+ x->x_auxmatch.a_type = x->x_auxrepl.a_type = A_NULL;
+ inlet_new((t_object *)x, (t_pd *)proxy, 0, 0);
+ outlet_new((t_object *)x, &s_anything);
+ /* CHECKED (refman error: 'a bang is sent') */
+ x->x_passout = outlet_new((t_object *)x, &s_anything);
+ substitute_proxy_anything(proxy, 0, ac, av);
+ }
+ return (x);
+}
+
+void substitute_setup(void)
+{
+ substitute_class = class_new(gensym("substitute"),
+ (t_newmethod)substitute_new,
+ (t_method)substitute_free,
+ sizeof(t_substitute), 0,
+ A_GIMME, 0);
+ class_addbang(substitute_class, substitute_bang);
+ class_addfloat(substitute_class, substitute_float);
+ class_addsymbol(substitute_class, substitute_symbol);
+ class_addlist(substitute_class, substitute_list);
+ class_addanything(substitute_class, substitute_anything);
+ substitute_proxy_class = class_new(gensym("_substitute_proxy"), 0, 0,
+ sizeof(t_substitute_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(substitute_proxy_class, substitute_proxy_bang);
+ class_addfloat(substitute_proxy_class, substitute_proxy_float);
+ class_addsymbol(substitute_proxy_class, substitute_proxy_symbol);
+ class_addlist(substitute_proxy_class, substitute_proxy_list);
+ class_addanything(substitute_proxy_class, substitute_proxy_anything);
+ class_addmethod(substitute_proxy_class, (t_method)substitute_proxy_list,
+ gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/sustain.c b/cyclone/hammer/sustain.c
new file mode 100644
index 0000000..975e6aa
--- /dev/null
+++ b/cyclone/hammer/sustain.c
@@ -0,0 +1,85 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+
+#define SUSTAIN_NPITCHES 128
+
+typedef struct _sustain
+{
+ t_object x_ob;
+ t_float x_velocity;
+ int x_switch;
+ unsigned char x_pitches[SUSTAIN_NPITCHES];
+ t_outlet *x_voutlet;
+} t_sustain;
+
+static t_class *sustain_class;
+
+static void sustain_float(t_sustain *x, t_float f)
+{
+ int pitch = (int)f;
+ if (pitch >= 0 && pitch < SUSTAIN_NPITCHES)
+ {
+ if (x->x_velocity || !x->x_switch)
+ {
+ outlet_float(x->x_voutlet, x->x_velocity);
+ outlet_float(((t_object *)x)->ob_outlet, pitch);
+ }
+ else x->x_pitches[pitch]++;
+ }
+}
+
+static void sustain_bang(t_sustain *x)
+{
+ int i;
+ unsigned char *pp;
+ for (i = 0, pp = x->x_pitches; i < SUSTAIN_NPITCHES; i++, pp++)
+ {
+ while (*pp)
+ {
+ outlet_float(x->x_voutlet, 0);
+ outlet_float(((t_object *)x)->ob_outlet, i);
+ (*pp)--;
+ }
+ }
+}
+
+static void sustain_clear(t_sustain *x)
+{
+ memset(x->x_pitches, 0, sizeof(x->x_pitches));
+}
+
+static void sustain_ft2(t_sustain *x, t_floatarg f)
+{
+ int newstate = ((int)f != 0);
+ if (x->x_switch && !newstate) sustain_bang(x);
+ x->x_switch = newstate;
+}
+
+static void *sustain_new(void)
+{
+ t_sustain *x = (t_sustain *)pd_new(sustain_class);
+ x->x_velocity = 0;
+ x->x_switch = 0;
+ sustain_clear(x);
+ floatinlet_new((t_object *)x, &x->x_velocity);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_voutlet = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void sustain_setup(void)
+{
+ sustain_class = class_new(gensym("sustain"),
+ (t_newmethod)sustain_new,
+ 0, /* CHECKED: no flushout */
+ sizeof(t_sustain), 0, 0);
+ class_addfloat(sustain_class, sustain_float);
+ class_addbang(sustain_class, sustain_bang);
+ class_addmethod(sustain_class, (t_method)sustain_ft2,
+ gensym("ft2"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/switch.c b/cyclone/hammer/switch.c
new file mode 100644
index 0000000..69317a1
--- /dev/null
+++ b/cyclone/hammer/switch.c
@@ -0,0 +1,152 @@
+/* Copyright (c) 2002-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 "common/loud.h"
+
+#define SWITCH_MININLETS 2 /* LATER consider using 1 (with a warning) */
+#define SWITCH_MAXINLETS 100
+#define SWITCH_DEFINLETS 2
+
+typedef struct _switch
+{
+ t_object x_ob;
+ int x_open;
+ int x_ninlets; /* not counting left one */
+ int x_nproxies; /* as requested (and allocated) */
+ t_pd **x_proxies;
+} t_switch;
+
+typedef struct _switch_proxy
+{
+ t_object p_ob;
+ t_switch *p_master;
+ int p_id;
+} t_switch_proxy;
+
+static t_class *switch_class;
+static t_class *switch_proxy_class;
+
+static void switch_proxy_bang(t_switch_proxy *x)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_bang(((t_object *)master)->ob_outlet);
+}
+
+static void switch_proxy_float(t_switch_proxy *x, t_float f)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_float(((t_object *)master)->ob_outlet, f);
+}
+
+static void switch_proxy_symbol(t_switch_proxy *x, t_symbol *s)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_symbol(((t_object *)master)->ob_outlet, s);
+}
+
+static void switch_proxy_pointer(t_switch_proxy *x, t_gpointer *gp)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_pointer(((t_object *)master)->ob_outlet, gp);
+}
+
+static void switch_proxy_list(t_switch_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_list(((t_object *)master)->ob_outlet, s, ac, av);
+}
+
+static void switch_proxy_anything(t_switch_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_anything(((t_object *)master)->ob_outlet, s, ac, av);
+}
+
+static void switch_float(t_switch *x, t_float f)
+{
+ int i = (int)f;
+ if (i < 0) i = -i;
+ if (i > x->x_ninlets) i = x->x_ninlets;
+ x->x_open = i;
+}
+
+static void switch_bang(t_switch *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_open);
+}
+
+static void switch_free(t_switch *x)
+{
+ if (x->x_proxies)
+ {
+ int i = x->x_ninlets;
+ while (i--) pd_free(x->x_proxies[i]);
+ freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies));
+ }
+}
+
+static void *switch_new(t_floatarg f1, t_floatarg f2)
+{
+ t_switch *x;
+ int i, ninlets, nproxies = (int)f1;
+ t_pd **proxies;
+ if (nproxies < SWITCH_MININLETS)
+ nproxies = SWITCH_DEFINLETS;
+ if (nproxies > SWITCH_MAXINLETS)
+ loud_incompatible_max(switch_class, SWITCH_MAXINLETS, "inlets");
+ if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies))))
+ return (0);
+ for (ninlets = 0; ninlets < nproxies; ninlets++)
+ if (!(proxies[ninlets] = pd_new(switch_proxy_class))) break;
+ if (ninlets < SWITCH_MININLETS)
+ {
+ int i = ninlets;
+ while (i--) pd_free(proxies[i]);
+ freebytes(proxies, nproxies * sizeof(*proxies));
+ return (0);
+ }
+ x = (t_switch *)pd_new(switch_class);
+ x->x_ninlets = ninlets;
+ x->x_nproxies = nproxies;
+ x->x_proxies = proxies;
+ for (i = 0; i < ninlets; i++)
+ {
+ t_switch_proxy *y = (t_switch_proxy *)proxies[i];
+ y->p_master = x;
+ y->p_id = i + 1;
+ inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ }
+ outlet_new((t_object *)x, &s_anything);
+ switch_float(x, (f2 > 0 ? f2 : 0)); /* CHECKED */
+ return (x);
+}
+
+void switch_setup(void)
+{
+ switch_class = class_new(gensym("switch"),
+ (t_newmethod)switch_new,
+ (t_method)switch_free,
+ sizeof(t_switch), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(switch_class, switch_float);
+ class_addbang(switch_class, switch_bang);
+ switch_proxy_class = class_new(gensym("_switch_proxy"), 0, 0,
+ sizeof(t_switch_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addfloat(switch_proxy_class, switch_proxy_float);
+ class_addbang(switch_proxy_class, switch_proxy_bang);
+ class_addsymbol(switch_proxy_class, switch_proxy_symbol);
+ class_addpointer(switch_proxy_class, switch_proxy_pointer);
+ class_addlist(switch_proxy_class, switch_proxy_list);
+ class_addanything(switch_proxy_class, switch_proxy_anything);
+}
diff --git a/cyclone/hammer/tanh.c b/cyclone/hammer/tanh.c
new file mode 100644
index 0000000..e124d4c
--- /dev/null
+++ b/cyclone/hammer/tanh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-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"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define tanhf tanh
+#endif
+
+typedef struct _tanh
+{
+ t_object x_ob;
+ float x_value;
+} t_tanh;
+
+static t_class *tanh_class;
+
+static void tanh_bang(t_tanh *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void tanh_float(t_tanh *x, t_float f)
+{
+ /* CHECKME large values */
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = tanhf(f));
+}
+
+static void *tanh_new(t_floatarg f)
+{
+ t_tanh *x = (t_tanh *)pd_new(tanh_class);
+ /* CHECKME large values */
+ x->x_value = tanhf(f);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void tanh_setup(void)
+{
+ tanh_class = class_new(gensym("tanh"),
+ (t_newmethod)tanh_new, 0,
+ sizeof(t_tanh), 0, A_DEFFLOAT, 0);
+ class_addbang(tanh_class, tanh_bang);
+ class_addfloat(tanh_class, tanh_float);
+}
diff --git a/cyclone/hammer/testmess.c b/cyclone/hammer/testmess.c
new file mode 100644
index 0000000..a6e8fe4
--- /dev/null
+++ b/cyclone/hammer/testmess.c
@@ -0,0 +1,245 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+
+#define TESTMESS_INISIZE 4 /* LATER rethink */
+#define TESTMESS_STACKSIZE 256
+
+typedef struct _testmess
+{
+ t_object x_ob;
+ t_symbol *x_method;
+ void (*x_messfun)(struct _testmess *, t_symbol *s, int, t_atom *);
+ int x_appendmode;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ int x_tailwise; /* data is moved to the end of a buffer */
+ t_atom *x_message;
+ t_atom *x_messbuf;
+ t_atom x_messini[TESTMESS_INISIZE];
+} t_testmess;
+
+static t_class *testmess_class;
+
+static void testmess_setnatoms(t_testmess *x, int natoms)
+{
+ if (x->x_tailwise)
+ x->x_message = x->x_messbuf + x->x_size - natoms;
+ else
+ x->x_message = x->x_messbuf;
+ x->x_natoms = natoms;
+}
+
+static int testmess_makeroom(t_testmess *x, int natoms, int preserve)
+{
+ if (x->x_size < natoms)
+ {
+ int newsize = x->x_size * 2;
+ while (newsize < natoms) newsize *= 2;
+ post("makeroom %s %d %d %d", x->x_method->s_name,
+ preserve, natoms, newsize);
+ if (x->x_messbuf == x->x_messini)
+ {
+ if (!(x->x_messbuf =
+ (t_atom *)getbytes(newsize * sizeof(*x->x_messbuf))))
+ {
+ x->x_messbuf = x->x_messini;
+ testmess_setnatoms(x, preserve ? x->x_natoms : 0);
+ return (0);
+ }
+ x->x_size = newsize;
+ testmess_setnatoms(x, preserve ? x->x_natoms : 0);
+ if (x->x_natoms)
+ {
+ if (x->x_tailwise)
+ memcpy(x->x_message,
+ x->x_messini + TESTMESS_INISIZE - x->x_natoms,
+ x->x_natoms * sizeof(*x->x_message));
+ else
+ memcpy(x->x_message,
+ x->x_messini, x->x_natoms * sizeof(*x->x_message));
+ }
+ }
+ else
+ {
+ int oldsize = x->x_size;
+ if (!(x->x_messbuf =
+ (t_atom *)resizebytes(x->x_messbuf,
+ x->x_size * sizeof(*x->x_messbuf),
+ newsize * sizeof(*x->x_messbuf))))
+ {
+ x->x_messbuf = x->x_messini;
+ x->x_size = TESTMESS_INISIZE;
+ testmess_setnatoms(x, 0);
+ return (0);
+ }
+ x->x_size = newsize;
+ testmess_setnatoms(x, preserve ? x->x_natoms : 0);
+ if (x->x_natoms && x->x_tailwise)
+ memmove(x->x_message, x->x_messbuf + oldsize - x->x_natoms,
+ x->x_natoms * sizeof(*x->x_message));
+ }
+ }
+ return (1);
+}
+
+static void testmess_stackmess(t_testmess *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_atom buf[TESTMESS_STACKSIZE];
+ int natoms = x->x_natoms;
+ if (x->x_appendmode)
+ {
+ int left = TESTMESS_STACKSIZE - ac;
+ if (left < 0) ac = TESTMESS_STACKSIZE, natoms = 0;
+ else if (natoms > left) natoms = left;
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ if (natoms)
+ memcpy(buf + ac, x->x_message, natoms * sizeof(*buf));
+ }
+ else
+ {
+ int left = TESTMESS_STACKSIZE - natoms;
+ if (left < 0) natoms = TESTMESS_STACKSIZE, ac = 0;
+ else if (ac > left) ac = left;
+ if (natoms)
+ memcpy(buf, x->x_message, natoms * sizeof(*buf));
+ if (ac)
+ memcpy(buf + natoms, av, ac * sizeof(*buf));
+ }
+ outlet_anything(((t_object *)x)->ob_outlet, s, natoms + ac, buf);
+}
+
+static void testmess_heapmess(t_testmess *x, t_symbol *s, int ac, t_atom *av)
+{
+ int ntotal = x->x_natoms + ac;
+ t_atom *buf = getbytes(ntotal * sizeof(*buf));
+ if (buf)
+ {
+ if (x->x_appendmode)
+ {
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ if (x->x_natoms)
+ memcpy(buf + ac, x->x_message, x->x_natoms * sizeof(*buf));
+ }
+ else
+ {
+ if (x->x_natoms)
+ memcpy(buf, x->x_message, x->x_natoms * sizeof(*buf));
+ if (ac)
+ memcpy(buf + x->x_natoms, av, ac * sizeof(*buf));
+ }
+ outlet_anything(((t_object *)x)->ob_outlet, s, ntotal, buf);
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+}
+
+static void testmess_premess(t_testmess *x, t_symbol *s, int ac, t_atom *av)
+{
+ int ntotal = x->x_natoms + ac;
+ if (testmess_makeroom(x, ntotal, 1))
+ {
+ t_atom *buf;
+ if (x->x_appendmode)
+ {
+ buf = x->x_messbuf + x->x_size - ntotal;
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ }
+ else
+ {
+ buf = x->x_messbuf;
+ if (ac)
+ memcpy(buf + x->x_natoms, av, ac * sizeof(*buf));
+ }
+ outlet_anything(((t_object *)x)->ob_outlet, s, ntotal, buf);
+ }
+}
+
+static void testmess_bang(t_testmess *x)
+{
+ if (x->x_natoms)
+ x->x_messfun(x, &s_list, 0, 0);
+}
+
+static void testmess_float(t_testmess *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ x->x_messfun(x, (x->x_natoms ? &s_list : &s_float), 1, &at);
+}
+
+static void testmess_symbol(t_testmess *x, t_symbol *s)
+{
+ x->x_messfun(x, s, 0, 0);
+}
+
+static void testmess_anything(t_testmess *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_messfun(x, s, ac, av);
+}
+
+static void testmess_set(t_testmess *x, t_floatarg f1, t_floatarg f2)
+{
+ int natoms = (int)f1;
+ if (natoms > 0 && testmess_makeroom(x, natoms * 2, 0))
+ {
+ t_atom *ap;
+ int i = (int)f2;;
+ testmess_setnatoms(x, natoms);
+ ap = x->x_message;
+ while (natoms--)
+ {
+ SETFLOAT(ap, i);
+ i++; ap++;
+ }
+ }
+}
+
+static void testmess_free(t_testmess *x)
+{
+ if (x->x_messbuf != x->x_messini)
+ freebytes(x->x_messbuf, x->x_size * sizeof(*x->x_messbuf));
+}
+
+static void *testmess_new(t_symbol *s, t_floatarg f)
+{
+ t_testmess *x = (t_testmess *)pd_new(testmess_class);
+ x->x_appendmode = 1;
+ x->x_tailwise = 0;
+ if (s == gensym("stack"))
+ x->x_method = s, x->x_messfun = testmess_stackmess;
+ else if (s == gensym("heap"))
+ x->x_method = s, x->x_messfun = testmess_heapmess;
+ else
+ {
+ x->x_method = gensym("prealloc");
+ x->x_messfun = testmess_premess;
+ x->x_tailwise = x->x_appendmode;
+ }
+ x->x_size = TESTMESS_INISIZE;
+ x->x_messbuf = x->x_messini;
+ outlet_new((t_object *)x, &s_anything);
+ testmess_setnatoms(x, 0);
+ testmess_set(x, f, 0);
+ return (x);
+}
+
+void testmess_setup(void)
+{
+ testmess_class = class_new(gensym("testmess"),
+ (t_newmethod)testmess_new,
+ (t_method)testmess_free,
+ sizeof(t_testmess), 0,
+ A_DEFFLOAT, A_DEFSYM, 0);
+ class_addbang(testmess_class, testmess_bang);
+ class_addfloat(testmess_class, testmess_float);
+ class_addsymbol(testmess_class, testmess_symbol);
+ class_addanything(testmess_class, testmess_anything);
+ class_addmethod(testmess_class, (t_method)testmess_set,
+ gensym("set"), A_FLOAT, A_DEFFLOAT, 0);
+}
diff --git a/cyclone/hammer/thresh.c b/cyclone/hammer/thresh.c
new file mode 100644
index 0000000..6890dcc
--- /dev/null
+++ b/cyclone/hammer/thresh.c
@@ -0,0 +1,134 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define THRESH_INISIZE 32 /* LATER rethink */
+#define THRESH_MAXSIZE 256
+#define THRESH_DEFTHRESH 10
+
+typedef struct _thresh
+{
+ t_object x_ob;
+ t_float x_thresh;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ t_atom *x_message;
+ t_atom x_messini[THRESH_INISIZE];
+ t_clock *x_clock;
+} t_thresh;
+
+static t_class *thresh_class;
+
+static void thresh_tick(t_thresh *x)
+{
+ int ac = x->x_natoms;
+ if (ac)
+ {
+ t_atom *av = x->x_message;
+ if (av->a_type == A_FLOAT) /* redundant, but we might need it LATER */
+ {
+ if (ac > 1)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ }
+ x->x_natoms = 0;
+ }
+}
+
+static void thresh_anything(t_thresh *x, t_symbol *s, int ac, t_atom *av)
+{
+ int ntotal = x->x_natoms + ac;
+ t_atom *buf;
+ clock_unset(x->x_clock);
+ if (s == &s_) s = 0;
+ if (s)
+ ntotal++;
+ if (ntotal > x->x_size)
+ {
+ /* LATER if (ntotal > THRESH_MAXSIZE)... (cf prepend) */
+ int nrequested = ntotal;
+ x->x_message = grow_withdata(&nrequested, &x->x_natoms,
+ &x->x_size, x->x_message,
+ THRESH_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ if (nrequested != ntotal)
+ {
+ x->x_natoms = 0;
+ if (ac >= x->x_size)
+ ac = (s ? x->x_size - 1 : x->x_size);
+ }
+ }
+ buf = x->x_message + x->x_natoms;
+ if (s)
+ {
+ SETSYMBOL(buf, s);
+ buf++;
+ x->x_natoms++;
+ }
+ if (ac)
+ {
+ memcpy(buf, av, ac * sizeof(*buf));
+ x->x_natoms += ac;
+ }
+ clock_delay(x->x_clock, x->x_thresh);
+}
+
+static void thresh_float(t_thresh *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ thresh_anything(x, 0, 1, &at);
+}
+
+static void thresh_list(t_thresh *x, t_symbol *s, int ac, t_atom *av)
+{
+ thresh_anything(x, 0, ac, av);
+}
+
+static void thresh_ft1(t_thresh *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0; /* CHECKED */
+ x->x_thresh = f;
+ /* CHECKED: no rearming */
+}
+
+static void thresh_free(t_thresh *x)
+{
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+ if (x->x_clock)
+ clock_free(x->x_clock);
+}
+
+static void *thresh_new(t_floatarg f)
+{
+ t_thresh *x = (t_thresh *)pd_new(thresh_class);
+ x->x_thresh = (f > 0 ? f : THRESH_DEFTHRESH);
+ x->x_size = THRESH_INISIZE;
+ x->x_natoms = 0;
+ x->x_message = x->x_messini;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_list); /* LATER rethink: list or float */
+ x->x_clock = clock_new(x, (t_method)thresh_tick);
+ return (x);
+}
+
+void thresh_setup(void)
+{
+ thresh_class = class_new(gensym("thresh"),
+ (t_newmethod)thresh_new,
+ (t_method)thresh_free,
+ sizeof(t_thresh), 0,
+ A_DEFFLOAT, 0);
+ class_addfloat(thresh_class, thresh_float);
+ class_addlist(thresh_class, thresh_list);
+ class_addmethod(thresh_class, (t_method)thresh_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ /* CHECKED: thresh: doesn't understand bang, symbol, anything */
+}
diff --git a/cyclone/hammer/tosymbol.c b/cyclone/hammer/tosymbol.c
new file mode 100644
index 0000000..8b45ad0
--- /dev/null
+++ b/cyclone/hammer/tosymbol.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2002-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 <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define TOSYMBOL_INISTRING 128 /* LATER rethink */
+#define TOSYMBOL_MAXSTRING 2048 /* the refman says so, later CHECKME */
+static char tosymbol_defseparator[] = " ";
+
+typedef struct _tosymbol
+{
+ t_object x_ob;
+ t_symbol *x_separator;
+ int x_bufsize;
+ char *x_buffer;
+ char x_bufini[TOSYMBOL_INISTRING];
+ int x_entered;
+} t_tosymbol;
+
+static t_class *tosymbol_class;
+static char tosymbol_buffer[TOSYMBOL_MAXSTRING];
+static int tosymbol_bufferlocked = 0;
+/* The idea is to prevent two different tosymbol objects from using the static
+ buffer at the same time. In the current scenario this buffer is never used
+ for output, so this lock is unnecessary... but it does no harm either... */
+
+static void tosymbol_flushbuffer(t_tosymbol *x)
+{
+ if (*x->x_buffer)
+ {
+ x->x_entered = 1;
+ outlet_symbol(((t_object *)x)->ob_outlet, gensym(x->x_buffer));
+ x->x_entered = 0;
+ }
+}
+
+static void tosymbol_bang(t_tosymbol *x)
+{
+ outlet_bang(((t_object *)x)->ob_outlet); /* CHECKED */
+}
+
+static void tosymbol_float(t_tosymbol *x, t_float f)
+{
+ if (!x->x_entered)
+ {
+ sprintf(x->x_buffer, "%g", f);
+ tosymbol_flushbuffer(x);
+ }
+}
+
+static void tosymbol_symbol(t_tosymbol *x, t_symbol *s)
+{
+ outlet_symbol(((t_object *)x)->ob_outlet, s);
+}
+
+static void tosymbol_pointer(t_tosymbol *x, t_gpointer *gp)
+{
+ /* nop: otherwise gpointer would be converted to 'list <gp>' */
+}
+
+static int tosymbol_parse(t_symbol *s, int ac, t_atom *av, t_symbol *separator,
+ int bufsize, char *buffer)
+{
+ int nleft = bufsize - 1;
+ int len;
+ char *bp = buffer;
+ bp[0] = bp[nleft] = 0;
+ if (s)
+ strncpy(bp, s->s_name, nleft);
+ len = strlen(bp);
+ nleft -= len;
+ bp += len;
+ if (ac && nleft > 0)
+ {
+ char *sepstring = (separator ?
+ separator->s_name : tosymbol_defseparator);
+ while (ac--)
+ {
+ if (*sepstring && bp > buffer)
+ {
+ strncpy(bp, sepstring, nleft);
+ len = strlen(bp);
+ nleft -= len;
+ if (nleft <= 0) break;
+ bp += len;
+ }
+ /* LATER rethink: type-checking */
+ atom_string(av, bp, nleft);
+ len = strlen(bp);
+ nleft -= len;
+ bp += len;
+ if (nleft <= 0) break;
+ av++;
+ }
+ }
+ if (nleft < 0)
+ {
+ bug("tosymbol_parse");
+ return (bufsize);
+ }
+ return (bufsize - nleft);
+}
+
+static void tosymbol_anything(t_tosymbol *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!x->x_entered)
+ {
+ if (tosymbol_bufferlocked)
+ {
+ bug("tosymbol_anything");
+ tosymbol_parse(s, ac, av, x->x_separator,
+ x->x_bufsize, x->x_buffer);
+ }
+ else
+ {
+ int ntotal;
+ tosymbol_bufferlocked = 1;
+ ntotal = tosymbol_parse(s, ac, av, x->x_separator,
+ TOSYMBOL_MAXSTRING, tosymbol_buffer);
+ if (ntotal > x->x_bufsize)
+ {
+ int newtotal = ntotal;
+ x->x_buffer = grow_nodata(&newtotal, &x->x_bufsize, x->x_buffer,
+ TOSYMBOL_INISTRING, x->x_bufini,
+ sizeof(*x->x_buffer));
+ if (newtotal < ntotal)
+ {
+ ntotal = newtotal - 1;
+ x->x_buffer[ntotal] = 0;
+ }
+ }
+ memcpy(x->x_buffer, tosymbol_buffer, ntotal);
+ tosymbol_bufferlocked = 0;
+ }
+ tosymbol_flushbuffer(x);
+ }
+}
+
+static void tosymbol_list(t_tosymbol *x, t_symbol *s, int ac, t_atom *av)
+{
+ tosymbol_anything(x, 0, ac, av);
+}
+
+static void tosymbol_separator(t_tosymbol *x, t_symbol *s)
+{
+ x->x_separator = (s ? s : &s_); /* default: empty string */
+}
+
+static void tosymbol_free(t_tosymbol *x)
+{
+ if (x->x_buffer != x->x_bufini)
+ freebytes(x->x_buffer, x->x_bufsize);
+}
+
+static void *tosymbol_new(void)
+{
+ t_tosymbol *x = (t_tosymbol *)pd_new(tosymbol_class);
+ x->x_separator = 0; /* default: a space */
+ x->x_bufsize = TOSYMBOL_INISTRING;
+ x->x_buffer = x->x_bufini;
+ x->x_entered = 0;
+ outlet_new((t_object *)x, &s_symbol);
+ return (x);
+}
+
+void tosymbol_setup(void)
+{
+ tosymbol_class = class_new(gensym("tosymbol"),
+ (t_newmethod)tosymbol_new,
+ (t_method)tosymbol_free,
+ sizeof(t_tosymbol), 0, 0);
+ class_addbang(tosymbol_class, tosymbol_bang);
+ class_addfloat(tosymbol_class, tosymbol_float);
+ class_addsymbol(tosymbol_class, tosymbol_symbol);
+ class_addpointer(tosymbol_class, tosymbol_pointer);
+ class_addlist(tosymbol_class, tosymbol_list);
+ class_addanything(tosymbol_class, tosymbol_anything);
+ class_addmethod(tosymbol_class, (t_method)tosymbol_separator,
+ gensym("separator"), A_DEFSYM, 0);
+}
diff --git a/cyclone/hammer/universal.c b/cyclone/hammer/universal.c
new file mode 100644
index 0000000..b1731d8
--- /dev/null
+++ b/cyclone/hammer/universal.c
@@ -0,0 +1,167 @@
+/* Copyright (c) 2002-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 "g_canvas.h"
+#include "unstable/pd_imp.h"
+#include "common/loud.h"
+
+/* LATER fragilize */
+
+typedef struct _universal
+{
+ t_object x_ob;
+ t_glist *x_glist;
+ t_int x_descend;
+} t_universal;
+
+static t_class *universal_class;
+
+static void universal_dobang(t_glist *glist, int descend, t_symbol *cname)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ pd_bang(&g->g_pd);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_dobang((t_glist *)g, descend, cname);
+}
+
+static void universal_dofloat(t_glist *glist, int descend, t_symbol *cname,
+ t_float f)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ pd_float(&g->g_pd, f);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_dofloat((t_glist *)g, descend, cname, f);
+}
+
+static void universal_dosymbol(t_glist *glist, int descend, t_symbol *cname,
+ t_symbol *s)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ pd_symbol(&g->g_pd, s);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_dosymbol((t_glist *)g, descend, cname, s);
+}
+
+static void universal_dopointer(t_glist *glist, int descend, t_symbol *cname,
+ t_gpointer *gp)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ pd_pointer(&g->g_pd, gp);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_dopointer((t_glist *)g, descend, cname, gp);
+}
+
+static void universal_dolist(t_glist *glist, int descend, t_symbol *cname,
+ int ac, t_atom *av)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ pd_list(&g->g_pd, &s_list, ac, av);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_dolist((t_glist *)g, descend, cname, ac, av);
+}
+
+static void universal_doanything(t_glist *glist, int descend, t_symbol *cname,
+ t_symbol *s, int ac, t_atom *av)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ typedmess(&g->g_pd, s, ac, av);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_doanything((t_glist *)g, descend, cname, s, ac, av);
+}
+
+/* LATER rethink type-checking -- it is borrowed from typedmess().
+ Anyway, do it once, before traversal, bypassing the generic mechanism
+ performed for every object. */
+static void universal_anything(t_universal *x, t_symbol *s, int ac, t_atom *av)
+{
+ /* CHECKED selector without arguments ignored with no complaints */
+ if (x->x_glist && s && ac)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ universal_dolist(x->x_glist, x->x_descend, s, ac, av);
+ else
+ universal_dofloat(x->x_glist, x->x_descend, s, av->a_w.w_float);
+ }
+ else if (av->a_type == A_SYMBOL)
+ {
+ if (av->a_w.w_symbol == &s_bang)
+ universal_dobang(x->x_glist, x->x_descend, s);
+ else if (av->a_w.w_symbol == &s_float)
+ {
+ if (ac == 1)
+ universal_dofloat(x->x_glist, x->x_descend, s, 0.);
+ else if (av[1].a_type == A_FLOAT)
+ universal_dofloat(x->x_glist, x->x_descend, s,
+ av[1].a_w.w_float);
+ else
+ loud_error((t_pd *)x, "Bad argument for message 'float'");
+ }
+ else if (av->a_w.w_symbol == &s_symbol)
+ universal_dosymbol(x->x_glist, x->x_descend, s,
+ (ac > 1 && av[1].a_type == A_SYMBOL ?
+ av[1].a_w.w_symbol : &s_));
+ else if (av->a_w.w_symbol == &s_list)
+ universal_dolist(x->x_glist, x->x_descend, s, ac - 1, av + 1);
+ else
+ universal_doanything(x->x_glist, x->x_descend, s,
+ av->a_w.w_symbol, ac - 1, av + 1);
+ }
+ if (av->a_type == A_POINTER)
+ universal_dopointer(x->x_glist, x->x_descend, s,
+ av->a_w.w_gpointer);
+ }
+}
+
+static void universal_send(t_universal *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_SYMBOL)
+ universal_anything(x, av->a_w.w_symbol, ac - 1, av + 1);
+ /* CHECKED: else ignored without complaints */
+}
+
+static void *universal_new(t_floatarg f)
+{
+ t_universal *x = (t_universal *)pd_new(universal_class);
+ x->x_glist = canvas_getcurrent();
+ x->x_descend = ((int)f != 0); /* CHECKED */
+ return (x);
+}
+
+void universal_setup(void)
+{
+ universal_class = class_new(gensym("universal"),
+ (t_newmethod)universal_new, 0,
+ sizeof(t_universal), 0, A_DEFFLOAT, 0);
+ class_addanything(universal_class, universal_anything);
+ /* CHECKED: 'send', not 'sendmessage' */
+ class_addmethod(universal_class, (t_method)universal_send,
+ gensym("send"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/urn.c b/cyclone/hammer/urn.c
new file mode 100644
index 0000000..59b140e
--- /dev/null
+++ b/cyclone/hammer/urn.c
@@ -0,0 +1,148 @@
+/* Copyright (c) 2002-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 think again about avoiding memory allocation overhead in run-time.
+ One would need to use a creation argument greater than any future right
+ inlet value. But this is incompatible (max uses a `static', max-size
+ array), and should be put somewhere in the docs... */
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/rand.h"
+#include "common/grow.h"
+
+#define URN_INISIZE 128 /* LATER rethink */
+#define URN_MAXSIZE 4096 /* CHECKED */
+#define URN_MAXIMUMSIZE 65536 /* LATER use USHRT_MAX */
+
+typedef struct _urn
+{
+ t_object x_ob;
+ int x_count;
+ int x_size; /* as allocated (in bytes) */
+ int x_range; /* as used */
+ unsigned short *x_urn;
+ unsigned short x_urnini[URN_INISIZE];
+ unsigned int x_seed;
+ t_outlet *x_bangout;
+} t_urn;
+
+static t_class *urn_class;
+
+static int urn_resize(t_urn *x, t_float f, int init)
+{
+ int maxmax = URN_MAXSIZE;
+ int range = (int)f; /* CHECKED silent truncation */
+ if (init)
+ {
+ maxmax--; /* CHECKED: max 4095 here (a bug, sort of) */
+ /* CHECKED in the constructor this is silent
+ (also > maxmax clipped without complaining) */
+ if (range < 1)
+ range = 1;
+ }
+ else if (range < 1)
+ {
+ /* CHECKED (the same for > maxmax) */
+ loud_error((t_pd *)x, "illegal size %d", f);
+ return (0);
+ }
+ if (range > URN_MAXIMUMSIZE)
+ {
+ loud_warning((t_pd *)x,
+ "requested size (%d) clipped -- effective size is %d",
+ range, URN_MAXIMUMSIZE);
+ range = URN_MAXIMUMSIZE;
+ }
+ if (range > maxmax)
+ loud_incompatible_max(urn_class, maxmax, "elements");
+ x->x_range = range;
+ if (range > x->x_size)
+ x->x_urn = grow_nodata(&x->x_range, &x->x_size, x->x_urn,
+ URN_INISIZE, x->x_urnini,
+ sizeof(*x->x_urn));
+ return (1);
+}
+
+static void urn_bang(t_urn *x)
+{
+ if (x->x_count)
+ {
+ int ndx = rand_int(&x->x_seed, x->x_count);
+ unsigned short pick = x->x_urn[ndx];
+ x->x_urn[ndx] = x->x_urn[--x->x_count];
+ outlet_float(((t_object *)x)->ob_outlet, pick);
+ }
+ /* CHECKED: start banging when the first bang is input
+ into an empty urn (and not when the last value is output).
+ CHECKED: keep banging until cleared. */
+ else outlet_bang(x->x_bangout);
+}
+
+static void urn_clear(t_urn *x)
+{
+ int i;
+ x->x_count = x->x_range;
+ for (i = 0; i < x->x_count; i++) x->x_urn[i] = i;
+}
+
+static void urn_float(t_urn *x, t_float f)
+{
+ /* CHECKED: float loudly rejected, int (any value) same as bang */
+ int i;
+ if (loud_checkint((t_pd *)x, f, &i, &s_float))
+ urn_bang(x);
+}
+
+static void urn_ft1(t_urn *x, t_floatarg f)
+{
+ if (urn_resize(x, f, 0)) /* CHECKED cleared only if a legal resize */
+ urn_clear(x);
+}
+
+static void urn_seed(t_urn *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED */
+ if (i < 0)
+ i = 1; /* CHECKED */
+ rand_seed(&x->x_seed, (unsigned int)i);
+}
+
+static void urn_free(t_urn *x)
+{
+ if (x->x_urn != x->x_urnini)
+ freebytes(x->x_urn, x->x_size * sizeof(*x->x_urn));
+}
+
+static void *urn_new(t_floatarg f1, t_floatarg f2)
+{
+ t_urn *x = (t_urn *)pd_new(urn_class);
+ x->x_size = URN_INISIZE;
+ x->x_urn = x->x_urnini;
+ urn_resize(x, f1, 1);
+ urn_seed(x, f2); /* CHECKME */
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_bangout = outlet_new((t_object *)x, &s_bang);
+ urn_clear(x);
+ return (x);
+}
+
+void urn_setup(void)
+{
+ urn_class = class_new(gensym("urn"),
+ (t_newmethod)urn_new,
+ (t_method)urn_free,
+ sizeof(t_urn), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(urn_class, urn_bang);
+ class_addfloat(urn_class, urn_float);
+ class_addmethod(urn_class, (t_method)urn_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ /* CHECKED list is auto-unfolded */
+ class_addmethod(urn_class, (t_method)urn_seed,
+ gensym("seed"), A_FLOAT, 0); /* CHECKED arg obligatory */
+ class_addmethod(urn_class, (t_method)urn_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/xbendin.c b/cyclone/hammer/xbendin.c
new file mode 100644
index 0000000..54082b3
--- /dev/null
+++ b/cyclone/hammer/xbendin.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2002-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"
+
+typedef struct _xbendin
+{
+ t_object x_ob;
+ int x_omni;
+ unsigned char x_ready;
+ unsigned char x_status;
+ unsigned char x_channel;
+ unsigned char x_lsb;
+ t_outlet *x_chanout;
+} t_xbendin;
+
+static t_class *xbendin_class;
+
+static void xbendin_clear(t_xbendin *x)
+{
+ x->x_status = 0;
+ x->x_ready = 0;
+}
+
+static void xbendin_float(t_xbendin *x, t_float f)
+{
+ int ival = (int)f; /* CHECKME */
+ if (ival < 0)
+ {
+ /* CHECKME */
+ return;
+ }
+ if (ival < 256) /* CHECKME */
+ {
+ unsigned char bval = ival;
+ if (bval & 0x80)
+ {
+ unsigned char status = bval & 0xF0;
+ if (status == 0xF0)
+ {
+ /* CHECKME */
+ if (bval < 0xF8)
+ xbendin_clear(x);
+ }
+ else if (status == 0xE0)
+ {
+ unsigned char channel = bval & 0x0F;
+ if (x->x_omni)
+ x->x_channel = channel;
+ x->x_status = (x->x_channel == channel);
+ x->x_ready = 0;
+ }
+ else xbendin_clear(x);
+ }
+ else if (x->x_ready)
+ {
+ if (x->x_omni)
+ outlet_float(x->x_chanout, x->x_channel + 1);
+ outlet_float(((t_object *)x)->ob_outlet, (bval << 7) + x->x_lsb);
+ x->x_ready = 0;
+ }
+ else if (x->x_status)
+ {
+ x->x_lsb = bval;
+ x->x_ready = 1;
+ }
+ }
+ else xbendin_clear(x);
+}
+
+static void *xbendin_new(t_floatarg f)
+{
+ int channel = (int)f; /* CHECKME */
+ t_xbendin *x = (t_xbendin *)pd_new(xbendin_class);
+ outlet_new((t_object *)x, &s_float);
+ if (x->x_omni = (channel == 0)) /* CHECKME */
+ x->x_chanout = outlet_new((t_object *)x, &s_float);
+ else
+ x->x_channel = (unsigned char)--channel; /* CHECKME */
+ xbendin_clear(x);
+ return (x);
+}
+
+void xbendin_setup(void)
+{
+ xbendin_class = class_new(gensym("xbendin"),
+ (t_newmethod)xbendin_new, 0,
+ sizeof(t_xbendin), 0,
+ A_DEFFLOAT, 0);
+ class_addfloat(xbendin_class, xbendin_float);
+ /* CHECKME autocasting lists to floats */
+}
diff --git a/cyclone/hammer/xbendin2.c b/cyclone/hammer/xbendin2.c
new file mode 100644
index 0000000..1336800
--- /dev/null
+++ b/cyclone/hammer/xbendin2.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2002-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"
+
+/* LATER find a better way to synchronize with xbendin,
+ while avoiding the c74's bug... */
+
+typedef struct _xbendin2
+{
+ t_object x_ob;
+ int x_omni;
+ unsigned char x_ready;
+ unsigned char x_status;
+ unsigned char x_channel;
+ unsigned char x_lsb;
+ t_outlet *x_lsbout;
+ t_outlet *x_chanout;
+} t_xbendin2;
+
+static t_class *xbendin2_class;
+
+static void xbendin2_clear(t_xbendin2 *x)
+{
+ x->x_status = 0;
+ x->x_ready = 0;
+}
+
+static void xbendin2_float(t_xbendin2 *x, t_float f)
+{
+ int ival = (int)f; /* CHECKME */
+ if (ival < 0)
+ {
+ /* CHECKME */
+ return;
+ }
+ if (ival < 256) /* CHECKME */
+ {
+ unsigned char bval = ival;
+ if (bval & 0x80)
+ {
+ unsigned char status = bval & 0xF0;
+ if (status == 0xF0)
+ {
+ /* CHECKME */
+ if (bval < 0xF8)
+ xbendin2_clear(x);
+ }
+ else if (status == 0xE0)
+ {
+ unsigned char channel = bval & 0x0F;
+ if (x->x_omni)
+ x->x_channel = channel;
+ x->x_status = (x->x_channel == channel);
+ x->x_ready = 0;
+ }
+ else xbendin2_clear(x);
+ }
+ else if (x->x_ready)
+ {
+ if (x->x_omni)
+ outlet_float(x->x_chanout, x->x_channel + 1);
+ outlet_float(x->x_lsbout, x->x_lsb);
+ outlet_float(((t_object *)x)->ob_outlet, bval);
+ x->x_ready = 0;
+ }
+ else if (x->x_status)
+ {
+ x->x_lsb = bval;
+ x->x_ready = 1;
+ }
+ }
+ else xbendin2_clear(x);
+}
+
+static void *xbendin2_new(t_floatarg f)
+{
+ int channel = (int)f; /* CHECKME */
+ t_xbendin2 *x = (t_xbendin2 *)pd_new(xbendin2_class);
+ outlet_new((t_object *)x, &s_float);
+ x->x_lsbout = outlet_new((t_object *)x, &s_float);
+ if (x->x_omni = (channel == 0)) /* CHECKME */
+ x->x_chanout = outlet_new((t_object *)x, &s_float);
+ else
+ x->x_channel = (unsigned char)--channel; /* CHECKME */
+ xbendin2_clear(x);
+ return (x);
+}
+
+void xbendin2_setup(void)
+{
+ xbendin2_class = class_new(gensym("xbendin2"),
+ (t_newmethod)xbendin2_new, 0,
+ sizeof(t_xbendin2), 0,
+ A_DEFFLOAT, 0);
+ class_addfloat(xbendin2_class, xbendin2_float);
+ /* CHECKME autocasting lists to floats */
+}
diff --git a/cyclone/hammer/xbendout.c b/cyclone/hammer/xbendout.c
new file mode 100644
index 0000000..faa401e
--- /dev/null
+++ b/cyclone/hammer/xbendout.c
@@ -0,0 +1,54 @@
+/* Copyright (c) 2002-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"
+
+typedef struct _xbendout
+{
+ t_object x_ob;
+ t_float x_channel;
+ int x_value;
+} t_xbendout;
+
+static t_class *xbendout_class;
+
+static void xbendout_dooutput(t_xbendout *x)
+{
+ int value = x->x_value;
+ int channel = (int)x->x_channel; /* CHECKME */
+ if (value >= 0 && /* CHECKME */
+ value <= 16383 && /* CHECKME */
+ channel > 0) /* CHECKME */
+ {
+ outlet_float(((t_object *)x)->ob_outlet, 224 + ((channel-1) & 0x0F));
+ outlet_float(((t_object *)x)->ob_outlet, value & 0x7F);
+ outlet_float(((t_object *)x)->ob_outlet, value >> 7);
+ }
+}
+
+static void xbendout_float(t_xbendout *x, t_float f)
+{
+ x->x_value = (int)f; /* CHECKME */
+ xbendout_dooutput(x);
+}
+
+static void *xbendout_new(t_floatarg f)
+{
+ t_xbendout *x = (t_xbendout *)pd_new(xbendout_class);
+ floatinlet_new((t_object *)x, &x->x_channel);
+ outlet_new((t_object *)x, &s_float);
+ x->x_channel = ((int)f > 0 ? f : 1); /* CHECKME */
+ x->x_value = 8192; /* CHECKME if not -1 */
+ return (x);
+}
+
+void xbendout_setup(void)
+{
+ xbendout_class = class_new(gensym("xbendout"),
+ (t_newmethod)xbendout_new, 0,
+ sizeof(t_xbendout), 0,
+ A_DEFFLOAT, 0);
+ class_addbang(xbendout_class, xbendout_dooutput);
+ class_addfloat(xbendout_class, xbendout_float);
+}
diff --git a/cyclone/hammer/xbendout2.c b/cyclone/hammer/xbendout2.c
new file mode 100644
index 0000000..a2f8817
--- /dev/null
+++ b/cyclone/hammer/xbendout2.c
@@ -0,0 +1,60 @@
+/* Copyright (c) 2002-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"
+
+typedef struct _xbendout2
+{
+ t_object x_ob;
+ t_float x_channel;
+ t_float x_lsb;
+ int x_msb;
+} t_xbendout2;
+
+static t_class *xbendout2_class;
+
+static void xbendout2_dooutput(t_xbendout2 *x)
+{
+ int msb = x->x_msb;
+ int lsb = (int)x->x_lsb; /* CHECKME */
+ int channel = (int)x->x_channel; /* CHECKME */
+ if (msb >= 0 && /* CHECKME */
+ msb <= 127 && /* CHECKME */
+ lsb >= 0 && /* CHECKME */
+ lsb <= 127 && /* CHECKME */
+ channel > 0) /* CHECKME */
+ {
+ outlet_float(((t_object *)x)->ob_outlet, 224 + ((channel-1) & 0x0F));
+ outlet_float(((t_object *)x)->ob_outlet, lsb);
+ outlet_float(((t_object *)x)->ob_outlet, msb);
+ }
+}
+
+static void xbendout2_float(t_xbendout2 *x, t_float f)
+{
+ x->x_msb = (int)f; /* CHECKME */
+ xbendout2_dooutput(x);
+}
+
+static void *xbendout2_new(t_floatarg f)
+{
+ t_xbendout2 *x = (t_xbendout2 *)pd_new(xbendout2_class);
+ floatinlet_new((t_object *)x, &x->x_lsb);
+ floatinlet_new((t_object *)x, &x->x_channel);
+ outlet_new((t_object *)x, &s_float);
+ x->x_channel = ((int)f > 0 ? f : 1); /* CHECKME */
+ x->x_lsb = 0;
+ x->x_msb = 64; /* CHECKME if not -1 */
+ return (x);
+}
+
+void xbendout2_setup(void)
+{
+ xbendout2_class = class_new(gensym("xbendout2"),
+ (t_newmethod)xbendout2_new, 0,
+ sizeof(t_xbendout2), 0,
+ A_DEFFLOAT, 0);
+ class_addbang(xbendout2_class, xbendout2_dooutput);
+ class_addfloat(xbendout2_class, xbendout2_float);
+}
diff --git a/cyclone/hammer/xnotein.c b/cyclone/hammer/xnotein.c
new file mode 100644
index 0000000..73b271b
--- /dev/null
+++ b/cyclone/hammer/xnotein.c
@@ -0,0 +1,100 @@
+/* Copyright (c) 2002-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"
+
+typedef struct _xnotein
+{
+ t_object x_ob;
+ int x_omni;
+ unsigned char x_ready;
+ unsigned char x_status;
+ unsigned char x_channel;
+ unsigned char x_pitch;
+ t_outlet *x_velout;
+ t_outlet *x_flagout;
+ t_outlet *x_chanout;
+} t_xnotein;
+
+static t_class *xnotein_class;
+
+static void xnotein_clear(t_xnotein *x)
+{
+ x->x_status = 0;
+ x->x_ready = 0;
+}
+
+static void xnotein_float(t_xnotein *x, t_float f)
+{
+ int ival = (int)f; /* CHECKME */
+ if (ival < 0)
+ {
+ /* CHECKME */
+ return;
+ }
+ if (ival < 256) /* CHECKME */
+ {
+ unsigned char bval = ival;
+ if (bval & 0x80)
+ {
+ unsigned char status = bval & 0xF0;
+ if (status == 0xF0)
+ {
+ /* CHECKME */
+ if (bval < 0xF8)
+ xnotein_clear(x);
+ }
+ else if (status == 0x80 || status == 0x90)
+ {
+ unsigned char channel = bval & 0x0F;
+ if (x->x_omni)
+ x->x_channel = channel;
+ x->x_status = (x->x_channel == channel ? status : 0);
+ x->x_ready = 0;
+ }
+ else xnotein_clear(x);
+ }
+ else if (x->x_ready)
+ {
+ int flag = (x->x_status == 0x90 && bval);
+ if (x->x_omni)
+ outlet_float(x->x_chanout, x->x_channel + 1);
+ outlet_float(x->x_flagout, flag);
+ outlet_float(x->x_velout, bval);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_pitch);
+ x->x_ready = 0;
+ }
+ else if (x->x_status)
+ {
+ x->x_pitch = bval;
+ x->x_ready = 1;
+ }
+ }
+ else xnotein_clear(x);
+}
+
+static void *xnotein_new(t_floatarg f)
+{
+ int channel = (int)f; /* CHECKME */
+ t_xnotein *x = (t_xnotein *)pd_new(xnotein_class);
+ outlet_new((t_object *)x, &s_float);
+ x->x_velout = outlet_new((t_object *)x, &s_float);
+ x->x_flagout = outlet_new((t_object *)x, &s_float);
+ if (x->x_omni = (channel == 0)) /* CHECKME */
+ x->x_chanout = outlet_new((t_object *)x, &s_float);
+ else
+ x->x_channel = (unsigned char)--channel; /* CHECKME */
+ xnotein_clear(x);
+ return (x);
+}
+
+void xnotein_setup(void)
+{
+ xnotein_class = class_new(gensym("xnotein"),
+ (t_newmethod)xnotein_new, 0,
+ sizeof(t_xnotein), 0,
+ A_DEFFLOAT, 0);
+ class_addfloat(xnotein_class, xnotein_float);
+ /* CHECKME autocasting lists to floats */
+}
diff --git a/cyclone/hammer/xnoteout.c b/cyclone/hammer/xnoteout.c
new file mode 100644
index 0000000..058c7f9
--- /dev/null
+++ b/cyclone/hammer/xnoteout.c
@@ -0,0 +1,62 @@
+/* Copyright (c) 2002-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"
+
+typedef struct _xnoteout
+{
+ t_object x_ob;
+ t_float x_channel;
+ t_float x_flag;
+ t_float x_velocity;
+ int x_pitch;
+} t_xnoteout;
+
+static t_class *xnoteout_class;
+
+static void xnoteout_dooutput(t_xnoteout *x)
+{
+ int status = ((int)x->x_flag ? 0x90 : 0x80); /* CHECKME */
+ int channel = (int)x->x_channel; /* CHECKME */
+ int pitch = x->x_pitch;
+ int velocity = (int)x->x_velocity & 0x7F; /* CHECKME */
+ if (pitch >= 0 && /* CHECKME */
+ pitch <= 127 && /* CHECKME */
+ channel > 0) /* CHECKME */
+ {
+ outlet_float(((t_object *)x)->ob_outlet, status + ((channel-1) & 0x0F));
+ outlet_float(((t_object *)x)->ob_outlet, pitch);
+ outlet_float(((t_object *)x)->ob_outlet, velocity);
+ }
+}
+
+static void xnoteout_float(t_xnoteout *x, t_float f)
+{
+ x->x_pitch = (int)f; /* CHECKME */
+ xnoteout_dooutput(x);
+}
+
+static void *xnoteout_new(t_floatarg f)
+{
+ t_xnoteout *x = (t_xnoteout *)pd_new(xnoteout_class);
+ floatinlet_new((t_object *)x, &x->x_velocity);
+ floatinlet_new((t_object *)x, &x->x_flag);
+ floatinlet_new((t_object *)x, &x->x_channel);
+ outlet_new((t_object *)x, &s_float);
+ x->x_channel = ((int)f > 0 ? f : 1); /* CHECKME */
+ x->x_flag = 0; /* CHECKME */
+ x->x_velocity = 0; /* CHECKME */
+ x->x_pitch = -1; /* CHECKME */
+ return (x);
+}
+
+void xnoteout_setup(void)
+{
+ xnoteout_class = class_new(gensym("xnoteout"),
+ (t_newmethod)xnoteout_new, 0,
+ sizeof(t_xnoteout), 0,
+ A_DEFFLOAT, 0);
+ class_addbang(xnoteout_class, xnoteout_dooutput);
+ class_addfloat(xnoteout_class, xnoteout_float);
+}
diff --git a/cyclone/hammer/zl.c b/cyclone/hammer/zl.c
new file mode 100644
index 0000000..566c18e
--- /dev/null
+++ b/cyclone/hammer/zl.c
@@ -0,0 +1,982 @@
+/* Copyright (c) 2002-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 <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/grow.h"
+
+/* LATER test reentrancy, tune speedwise */
+
+#define ZL_DEBUG
+
+#define ZL_INISIZE 32 /* LATER rethink */
+#define ZL_MAXSIZE 256
+#define ZL_MAXMODES 16
+#define ZL_DEFMODE 0
+
+struct _zl;
+typedef int (*t_zlintargfn)(struct _zl *, int);
+typedef void (*t_zlanyargfn)(struct _zl *, t_symbol *, int, t_atom *);
+typedef int (*t_zlnatomsfn)(struct _zl *);
+typedef void (*t_zldoitfn)(struct _zl *, int, t_atom *);
+
+static int zl_nmodes = 0;
+static t_symbol *zl_modesym[ZL_MAXMODES];
+static int zl_modeflags[ZL_MAXMODES];
+static t_zlintargfn zl_intargfn[ZL_MAXMODES];
+static t_zlanyargfn zl_anyargfn[ZL_MAXMODES];
+static t_zlnatomsfn zl_natomsfn[ZL_MAXMODES];
+static t_zldoitfn zl_doitfn[ZL_MAXMODES];
+
+typedef struct _zldata
+{
+ int d_size; /* as allocated */
+ int d_natoms; /* as used */
+ t_atom *d_buf;
+ t_atom d_bufini[ZL_INISIZE];
+} t_zldata;
+
+typedef struct _zl
+{
+ t_object x_ob;
+ struct _zlproxy *x_proxy;
+ int x_entered;
+ int x_locked; /* locking inbuf1 in modes: iter, reg, slice */
+ t_zldata x_inbuf1;
+ t_zldata x_inbuf2;
+ t_zldata x_outbuf;
+ int x_mode;
+ int x_modearg;
+ t_outlet *x_out2;
+} t_zl;
+
+typedef struct _zlproxy
+{
+ t_object p_ob;
+ t_zl *p_master;
+} t_zlproxy;
+
+static t_class *zl_class;
+static t_class *zlproxy_class;
+
+static void zldata_init(t_zldata *d)
+{
+ d->d_size = ZL_INISIZE;
+ d->d_natoms = 0;
+ d->d_buf = d->d_bufini;
+}
+
+static void zldata_free(t_zldata *d)
+{
+ if (d->d_buf != d->d_bufini)
+ freebytes(d->d_buf, d->d_size * sizeof(*d->d_buf));
+}
+
+static void zldata_setfloat(t_zldata *d, t_float f)
+{
+ SETFLOAT(d->d_buf, f);
+ d->d_natoms = 1;
+}
+
+static void zldata_addfloat(t_zldata *d, t_float f)
+{
+ int natoms = d->d_natoms;
+ int nrequested = natoms + 1;
+ if (nrequested > d->d_size)
+ {
+ d->d_buf = grow_withdata(&nrequested, &natoms, &d->d_size,
+ d->d_buf, ZL_INISIZE, d->d_bufini,
+ sizeof(*d->d_buf));
+ if (natoms >= nrequested)
+ natoms = nrequested - 1;
+ }
+ SETFLOAT(d->d_buf + natoms, f);
+ d->d_natoms = natoms + 1;
+}
+
+static void zldata_setsymbol(t_zldata *d, t_symbol *s)
+{
+ SETSYMBOL(d->d_buf, s);
+ d->d_natoms = 1;
+}
+
+static void zldata_addsymbol(t_zldata *d, t_symbol *s)
+{
+ int natoms = d->d_natoms;
+ int nrequested = natoms + 1;
+ if (nrequested > d->d_size)
+ {
+ d->d_buf = grow_withdata(&nrequested, &natoms, &d->d_size,
+ d->d_buf, ZL_INISIZE, d->d_bufini,
+ sizeof(*d->d_buf));
+ if (natoms >= nrequested)
+ natoms = nrequested - 1;
+ }
+ SETSYMBOL(d->d_buf + natoms, s);
+ d->d_natoms = natoms + 1;
+}
+
+static void zldata_setlist(t_zldata *d, int ac, t_atom *av)
+{
+ int nrequested = ac;
+ if (nrequested > d->d_size)
+ d->d_buf = grow_nodata(&nrequested, &d->d_size, d->d_buf,
+ ZL_INISIZE, d->d_bufini, sizeof(*d->d_buf));
+ if (d->d_natoms = nrequested)
+ memcpy(d->d_buf, av, nrequested * sizeof(*d->d_buf));
+}
+
+static void zldata_addlist(t_zldata *d, int ac, t_atom *av)
+{
+ int natoms = d->d_natoms;
+ int nrequested = natoms + ac;
+ if (nrequested > d->d_size)
+ {
+ d->d_buf = grow_withdata(&nrequested, &natoms, &d->d_size,
+ d->d_buf, ZL_INISIZE, d->d_bufini,
+ sizeof(*d->d_buf));
+ if (natoms + ac > nrequested)
+ {
+ natoms = nrequested - ac;
+ if (natoms < 0)
+ natoms = 0, ac = nrequested;
+ }
+ }
+ if (d->d_natoms = natoms + ac)
+ memcpy(d->d_buf + natoms, av, ac * sizeof(*d->d_buf));
+}
+
+static void zldata_set(t_zldata *d, t_symbol *s, int ac, t_atom *av)
+{
+ if (s && s != &s_)
+ {
+ int nrequested = ac + 1;
+ if (nrequested > d->d_size)
+ d->d_buf = grow_nodata(&nrequested, &d->d_size, d->d_buf,
+ ZL_INISIZE, d->d_bufini, sizeof(*d->d_buf));
+ if (d->d_natoms = nrequested)
+ {
+ SETSYMBOL(d->d_buf, s);
+ if (--nrequested)
+ memcpy(d->d_buf + 1, av, nrequested * sizeof(*d->d_buf));
+ }
+ }
+ else zldata_setlist(d, ac, av);
+}
+
+static void zldata_add(t_zldata *d, t_symbol *s, int ac, t_atom *av)
+{
+ if (s && s != &s_)
+ {
+ int natoms = d->d_natoms;
+ int nrequested = natoms + 1 + ac;
+ if (nrequested > d->d_size)
+ {
+ d->d_buf = grow_withdata(&nrequested, &natoms, &d->d_size,
+ d->d_buf, ZL_INISIZE, d->d_bufini,
+ sizeof(*d->d_buf));
+ if (natoms + 1 + ac > nrequested)
+ {
+ natoms = nrequested - 1 - ac;
+ if (natoms < 0)
+ natoms = 0, ac = nrequested - 1;
+ }
+ }
+ if (d->d_natoms = natoms + 1 + ac)
+ {
+ SETSYMBOL(d->d_buf + natoms, s);
+ if (ac > 0)
+ memcpy(d->d_buf + natoms + 1, av, ac * sizeof(*d->d_buf));
+ }
+ }
+ else zldata_addlist(d, ac, av);
+}
+
+/* LATER rethink */
+static void zl_dooutput(t_outlet *o, int ac, t_atom *av)
+{
+ if (ac > 1)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_list(o, &s_list, ac, av);
+ else if (av->a_type == A_SYMBOL)
+ outlet_anything(o, av->a_w.w_symbol, ac - 1, av + 1);
+ }
+ else if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_float(o, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+#if 1
+ outlet_anything(o, av->a_w.w_symbol, 0, 0); /* CHECKED */
+#else
+ outlet_symbol(o, av->a_w.w_symbol); /* LATER rethink */
+#endif
+ }
+}
+
+static void zl_output(t_zl *x, int ac, t_atom *av)
+{
+ zl_dooutput(((t_object *)x)->ob_outlet, ac, av);
+}
+
+static void zl_output2(t_zl *x, int ac, t_atom *av)
+{
+ zl_dooutput(x->x_out2, ac, av);
+}
+
+static int zl_equal(t_atom *ap1, t_atom *ap2)
+{
+ return (ap1->a_type == ap2->a_type
+ &&
+ ((ap1->a_type == A_FLOAT
+ && ap1->a_w.w_float == ap2->a_w.w_float)
+ ||
+ (ap1->a_type == A_SYMBOL
+ && ap1->a_w.w_symbol == ap2->a_w.w_symbol)));
+}
+
+/* Mode handlers:
+ If zl_<mode>_count's return value is positve, then the main routine
+ uses an output buffer 'buf' (outbuf, or a separately allocated one).
+ If zl_<mode>_count's return value is zero, then the main routine is
+ passed a null 'buf' (see below); if it is negative, then the main
+ routine is not being called.
+ zl_<mode> (main routine) arguments: if 'buf' is null, 'natoms'
+ is always zero -- in modes other than len (no buffer used), group,
+ iter, reg, slice/ecils (inbuf1 used), there should be no output.
+ If 'buf' is not null, then 'natoms' is guaranteed to be positive.
+*/
+
+static int zl_nop_count(t_zl *x)
+{
+ return (0);
+}
+
+static void zl_nop(t_zl *x, int natoms, t_atom *buf)
+{
+ loud_warning((t_pd *)x, "unknown mode");
+}
+
+static int zl_ecils_intarg(t_zl *x, int i)
+{
+ return (i > 0 ? i : 0); /* CHECKED */
+}
+
+static int zl_ecils_count(t_zl *x)
+{
+ return (x->x_entered ? -1 : 0);
+}
+
+static void zl_ecils(t_zl *x, int natoms, t_atom *buf)
+{
+ int cnt1, cnt2 = x->x_modearg;
+ natoms = x->x_inbuf1.d_natoms;
+ buf = x->x_inbuf1.d_buf;
+ if (cnt2 > natoms)
+ cnt2 = natoms, cnt1 = 0; /* CHECKED */
+ else
+ cnt1 = natoms - cnt2;
+ x->x_locked = 1;
+ if (cnt2)
+ zl_output2(x, cnt2, buf + cnt1);
+ if (cnt1)
+ zl_output(x, cnt1, buf);
+}
+
+static int zl_group_intarg(t_zl *x, int i)
+{
+ return (i > 0 ? i : 0); /* CHECKED */
+}
+
+static int zl_group_count(t_zl *x)
+{
+ return (x->x_entered ? -1 : 0);
+}
+
+static void zl_group(t_zl *x, int natoms, t_atom *buf)
+{
+ int cnt = x->x_modearg;
+ if (cnt > 0)
+ {
+ natoms = x->x_inbuf1.d_natoms;
+ buf = x->x_inbuf1.d_buf;
+ if (natoms >= cnt)
+ {
+ t_atom *from;
+ x->x_locked = 1;
+ for (from = buf; natoms >= cnt; natoms -= cnt, from += cnt)
+ zl_output(x, cnt, from);
+ x->x_inbuf1.d_natoms = natoms;
+ while (natoms--) *buf++ = *from++;
+ }
+ }
+ else x->x_inbuf1.d_natoms = 0; /* CHECKED */
+}
+
+static int zl_iter_intarg(t_zl *x, int i)
+{
+ return (i > 0 ? i : 0); /* CHECKED */
+}
+
+static int zl_iter_count(t_zl *x)
+{
+ return (x->x_entered ?
+ (x->x_modearg < x->x_inbuf1.d_natoms ?
+ x->x_modearg : x->x_inbuf1.d_natoms)
+ : 0);
+}
+
+static void zl_iter(t_zl *x, int natoms, t_atom *buf)
+{
+ int nremaining = x->x_inbuf1.d_natoms;
+ t_atom *ptr = x->x_inbuf1.d_buf;
+ if (!buf)
+ {
+ if (natoms = (x->x_modearg < nremaining ?
+ x->x_modearg : nremaining))
+ x->x_locked = 1;
+ else
+ return;
+ }
+ while (nremaining)
+ {
+ if (natoms > nremaining)
+ natoms = nremaining;
+ if (buf)
+ {
+ memcpy(buf, ptr, natoms * sizeof(*buf));
+ zl_output(x, natoms, buf);
+ }
+ else zl_output(x, natoms, ptr);
+ nremaining -= natoms;
+ ptr += natoms;
+ }
+}
+
+static int zl_join_count(t_zl *x)
+{
+ return (x->x_inbuf1.d_natoms + x->x_inbuf2.d_natoms);
+}
+
+static void zl_join(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf)
+ {
+ int ac1 = x->x_inbuf1.d_natoms, ac2 = x->x_inbuf2.d_natoms;
+ if (ac1)
+ memcpy(buf, x->x_inbuf1.d_buf, ac1 * sizeof(*buf));
+ if (ac2)
+ memcpy(buf + ac1, x->x_inbuf2.d_buf, ac2 * sizeof(*buf));
+ zl_output(x, natoms, buf);
+ }
+}
+
+static int zl_len_count(t_zl *x)
+{
+ return (0);
+}
+
+static void zl_len(t_zl *x, int natoms, t_atom *buf)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_inbuf1.d_natoms);
+}
+
+static int zl_nth_intarg(t_zl *x, int i)
+{
+ return (i > 0 ? i : 0); /* CHECKED */
+}
+
+static void zl_nth_anyarg(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!s && ac && av->a_type == A_FLOAT)
+ zldata_setlist(&x->x_inbuf2, ac - 1, av + 1);
+}
+
+static int zl_nth_count(t_zl *x)
+{
+ int ac1 = x->x_inbuf1.d_natoms;
+ if (ac1)
+ {
+ if (x->x_modearg > 0)
+ return (ac1 - 1 + x->x_inbuf2.d_natoms);
+ else
+ return (x->x_entered ? ac1 : 0);
+ }
+ else return (-1);
+}
+
+static void zl_nth(t_zl *x, int natoms, t_atom *buf)
+{
+ int ac1 = x->x_inbuf1.d_natoms,
+ ndx = x->x_modearg - 1; /* CHECKED one-based */
+ if (ac1 && ndx < ac1) /* CHECKED */
+ {
+ t_atom *av1 = x->x_inbuf1.d_buf;
+ if (ndx < 0)
+ {
+ if (buf) memcpy(buf, av1, ac1 * sizeof(*buf));
+ else
+ {
+ buf = av1;
+ x->x_locked = 1;
+ }
+ zl_output2(x, ac1, buf);
+ }
+ else
+ {
+ t_atom at = av1[ndx];
+ if (buf)
+ {
+ int ac2 = x->x_inbuf2.d_natoms, ntail = ac1 - ndx + 1;
+ t_atom *ptr = buf;
+ if (ndx)
+ {
+ memcpy(ptr, av1, ndx * sizeof(*buf));
+ ptr += ndx;
+ }
+ if (ac2)
+ {
+ memcpy(ptr, x->x_inbuf2.d_buf, ac2 * sizeof(*buf));
+ ptr += ac2;
+ }
+ if (ntail)
+ memcpy(ptr, av1 + ndx + 1, ntail * sizeof(*buf));
+ zl_output2(x, natoms, buf);
+ }
+ zl_output(x, 1, &at);
+ }
+ }
+}
+
+static void zl_reg_anyarg(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!x->x_locked)
+ zldata_set(&x->x_inbuf1, s, ac, av);
+}
+
+static int zl_reg_count(t_zl *x)
+{
+ return (x->x_entered ? x->x_inbuf1.d_natoms : 0);
+}
+
+static void zl_reg(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf) memcpy(buf, x->x_inbuf1.d_buf, natoms * sizeof(*buf));
+ else
+ {
+ natoms = x->x_inbuf1.d_natoms;
+ buf = x->x_inbuf1.d_buf;
+ x->x_locked = 1;
+ }
+ if (natoms)
+ zl_output(x, natoms, buf);
+}
+
+static int zl_rev_count(t_zl *x)
+{
+ return (x->x_inbuf1.d_natoms);
+}
+
+static void zl_rev(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf)
+ {
+ t_atom *from = x->x_inbuf1.d_buf, *to = buf + natoms;
+ while (to-- > buf)
+ *to = *from++;
+ zl_output(x, natoms, buf);
+ }
+}
+
+static int zl_rot_intarg(t_zl *x, int i)
+{
+ return (i); /* CHECKED anything goes (modulo) */
+}
+
+static int zl_rot_count(t_zl *x)
+{
+ return (x->x_inbuf1.d_natoms);
+}
+
+static void zl_rot(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf)
+ {
+ int cnt1 = x->x_modearg, cnt2;
+ if (cnt1)
+ {
+ if (cnt1 > 0)
+ {
+ cnt1 %= natoms;
+ cnt2 = natoms - cnt1;
+ }
+ else
+ {
+ cnt2 = -cnt1 % natoms;
+ cnt1 = natoms - cnt2;
+ }
+ /* CHECKED right rotation for positive args */
+ memcpy(buf, x->x_inbuf1.d_buf + cnt2, cnt1 * sizeof(*buf));
+ memcpy(buf + cnt1, x->x_inbuf1.d_buf, cnt2 * sizeof(*buf));
+ }
+ else memcpy(buf, x->x_inbuf1.d_buf, natoms * sizeof(*buf));
+ zl_output(x, natoms, buf);
+ }
+}
+
+/* LATER rethink */
+static int zl_sect_count(t_zl *x)
+{
+ int result = 0;
+ int ac1 = x->x_inbuf1.d_natoms, ac2 = x->x_inbuf2.d_natoms, i1;
+ t_atom *av1 = x->x_inbuf1.d_buf, *av2 = x->x_inbuf2.d_buf, *ap1;
+ for (i1 = 0, ap1 = av1; i1 < ac1; i1++, ap1++)
+ {
+ int i2;
+ t_atom *testp;
+ for (i2 = 0, testp = av1; i2 < i1; i2++, testp++)
+ if (zl_equal(ap1, testp))
+ goto skip;
+ for (i2 = 0, testp = av2; i2 < ac2; i2++, testp++)
+ {
+ if (zl_equal(ap1, testp))
+ {
+ result++;
+ break;
+ }
+ }
+ skip:;
+ }
+ return (result);
+}
+
+/* CHECKED in-buffer duplicates are skipped */
+static void zl_sect(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf)
+ {
+ int ac1 = x->x_inbuf1.d_natoms, ac2 = x->x_inbuf2.d_natoms, i1;
+ t_atom *ap1 = x->x_inbuf1.d_buf, *av2 = x->x_inbuf2.d_buf, *to = buf;
+ for (i1 = 0; i1 < ac1; i1++, ap1++)
+ {
+ int i2;
+ t_atom *testp;
+ for (testp = buf; testp < to; testp++)
+ if (zl_equal(ap1, testp))
+ goto skip;
+ for (i2 = 0, testp = av2; i2 < ac2; i2++, testp++)
+ {
+ if (zl_equal(ap1, testp))
+ {
+ *to++ = *ap1;
+ break;
+ }
+ }
+ skip:;
+ }
+ zl_output(x, natoms, buf);
+ }
+}
+
+static int zl_slice_intarg(t_zl *x, int i)
+{
+ return (i > 0 ? i : 0); /* CHECKED */
+}
+
+static int zl_slice_count(t_zl *x)
+{
+ return (x->x_entered ? -1 : 0);
+}
+
+static void zl_slice(t_zl *x, int natoms, t_atom *buf)
+{
+ int cnt1 = x->x_modearg, cnt2;
+ natoms = x->x_inbuf1.d_natoms;
+ buf = x->x_inbuf1.d_buf;
+ if (cnt1 > natoms)
+ cnt1 = natoms, cnt2 = 0; /* CHECKED */
+ else
+ cnt2 = natoms - cnt1;
+ x->x_locked = 1;
+ if (cnt2)
+ zl_output2(x, cnt2, buf + cnt1);
+ if (cnt1)
+ zl_output(x, cnt1, buf);
+}
+
+static int zl_sub_count(t_zl *x)
+{
+ return (0);
+}
+
+static void zl_sub(t_zl *x, int natoms, t_atom *buf)
+{
+ int natoms2 = x->x_inbuf2.d_natoms;
+ if (natoms2)
+ {
+ int ndx1, natoms1 = x->x_inbuf1.d_natoms;
+ t_atom *av1 = x->x_inbuf1.d_buf, *av2 = x->x_inbuf2.d_buf;
+ for (ndx1 = 0; ndx1 < natoms1; ndx1++, av1++)
+ {
+ int ndx2;
+ t_atom *ap1 = av1, *ap2 = av2;
+ for (ndx2 = 0; ndx2 < natoms2; ndx2++, ap1++, ap2++)
+ if (!zl_equal(ap1, ap2))
+ break;
+ if (ndx2 == natoms2)
+ /* CHECKED output position is zero-based */
+ outlet_float(((t_object *)x)->ob_outlet, ndx1);
+ }
+ }
+}
+
+/* LATER rethink */
+static int zl_union_count(t_zl *x)
+{
+ int result, ac1 = x->x_inbuf1.d_natoms, ac2 = x->x_inbuf2.d_natoms, i2;
+ t_atom *av1 = x->x_inbuf1.d_buf, *ap2 = x->x_inbuf2.d_buf;
+ result = ac1 + ac2;
+ for (i2 = 0; i2 < ac2; i2++, ap2++)
+ {
+ int i1;
+ t_atom *ap1;
+ for (i1 = 0, ap1 = av1; i1 < ac1; i1++, ap1++)
+ {
+ if (zl_equal(ap1, ap2))
+ {
+ result--;
+ break;
+ }
+ }
+ }
+ return (result);
+}
+
+/* CHECKED in-buffer duplicates not skipped */
+static void zl_union(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf)
+ {
+ int ac1 = x->x_inbuf1.d_natoms, ac2 = x->x_inbuf2.d_natoms, i2;
+ t_atom *av1 = x->x_inbuf1.d_buf, *ap2 = x->x_inbuf2.d_buf;
+ if (ac1)
+ {
+ t_atom *to = buf + ac1;
+ memcpy(buf, av1, ac1 * sizeof(*buf));
+ for (i2 = 0; i2 < ac2; i2++, ap2++)
+ {
+ int i1;
+ t_atom *ap1;
+ for (i1 = 0, ap1 = av1; i1 < ac1; i1++, ap1++)
+ if (zl_equal(ap1, ap2))
+ break;
+ if (i1 == ac1)
+ *to++ = *ap2;
+ }
+ }
+ else memcpy(buf, ap2, ac2 * sizeof(*buf));
+ zl_output(x, natoms, buf);
+ }
+}
+
+static void zl_doit(t_zl *x)
+{
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ int natoms = (*zl_natomsfn[x->x_mode])(x);
+ if (natoms < 0)
+ return;
+ x->x_entered = 1;
+ if (natoms)
+ {
+ t_zldata *d = &x->x_outbuf;
+ t_atom *buf;
+ if (prealloc && natoms > d->d_size)
+ {
+ if (natoms > ZL_MAXSIZE)
+ prealloc = 0;
+ else
+ {
+ int nrequested = natoms;
+ d->d_buf = grow_nodata(&nrequested, &d->d_size, d->d_buf,
+ ZL_INISIZE, d->d_bufini,
+ sizeof(*d->d_buf));
+ if (nrequested != natoms)
+ prealloc = 0;
+ }
+ }
+ /* LATER consider using the stack if !prealloc && natoms <= MAXSTACK */
+ if (buf = (prealloc ? d->d_buf : getbytes(natoms * sizeof(*buf))))
+ {
+ (*zl_doitfn[x->x_mode])(x, natoms, buf);
+ if (buf != d->d_buf)
+ freebytes(buf, natoms * sizeof(*buf));
+ }
+ }
+ else (*zl_doitfn[x->x_mode])(x, 0, 0);
+ if (!reentered)
+ x->x_entered = x->x_locked = 0;
+}
+
+static void zl_bang(t_zl *x)
+{
+ /* CHECKED bang is a nop in len mode, LATER consider emulating this */
+ /* CHECKED 'mode len, bang'->[zl]->[print] crashes max 4.0.7... */
+ zl_doit(x);
+}
+
+static void zl_float(t_zl *x, t_float f)
+{
+ if (!x->x_locked)
+ {
+ if (zl_modeflags[x->x_mode])
+ zldata_addfloat(&x->x_inbuf1, f);
+ else
+ zldata_setfloat(&x->x_inbuf1, f);
+ }
+ zl_doit(x);
+}
+
+static void zl_symbol(t_zl *x, t_symbol *s)
+{
+ if (!x->x_locked)
+ {
+ if (zl_modeflags[x->x_mode])
+ zldata_addsymbol(&x->x_inbuf1, s);
+ else
+ zldata_setsymbol(&x->x_inbuf1, s);
+ }
+ zl_doit(x);
+}
+
+/* LATER gpointer */
+
+static void zl_list(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!x->x_locked)
+ {
+ if (zl_modeflags[x->x_mode])
+ zldata_addlist(&x->x_inbuf1, ac, av);
+ else
+ zldata_setlist(&x->x_inbuf1, ac, av);
+ }
+ zl_doit(x);
+}
+
+static void zl_anything(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!x->x_locked)
+ {
+ if (zl_modeflags[x->x_mode])
+ zldata_add(&x->x_inbuf1, s, ac, av);
+ else
+ zldata_set(&x->x_inbuf1, s, ac, av);
+ }
+ zl_doit(x);
+}
+
+static int zl_modeargfn(t_zl *x)
+{
+ return (zl_intargfn[x->x_mode] || zl_anyargfn[x->x_mode]);
+}
+
+static void zl_setmodearg(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (zl_intargfn[x->x_mode])
+ {
+ int i = (!s && ac && av->a_type == A_FLOAT ?
+ (int)av->a_w.w_float : /* CHECKED silent truncation */
+ 0); /* CHECKED current x->x_modearg not kept */
+ x->x_modearg = (*zl_intargfn[x->x_mode])(x, i);
+ }
+ if (zl_anyargfn[x->x_mode])
+ (*zl_anyargfn[x->x_mode])(x, s, ac, av);
+}
+
+static void zl_mode(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ t_symbol *modesym = av->a_w.w_symbol;
+ int i;
+ for (i = 0; i < zl_nmodes; i++)
+ if (modesym == zl_modesym[i])
+ break;
+ /* LATER consider making this compatible:
+ CHECKED setting unknown mode makes a zl nop */
+ if (i && i < zl_nmodes)
+ {
+ x->x_mode = i;
+ zl_setmodearg(x, 0, ac - 1, av + 1);
+ }
+ }
+}
+
+static void zlproxy_bang(t_zlproxy *d)
+{
+ /* CHECKED a nop */
+}
+
+static void zlproxy_float(t_zlproxy *p, t_float f)
+{
+ t_zl *x = p->p_master;
+ if (zl_modeargfn(x))
+ {
+ t_atom at;
+ SETFLOAT(&at, f);
+ zl_setmodearg(x, 0, 1, &at);
+ }
+ else /* CHECKED inbuf2 filled only when used */
+ zldata_setfloat(&x->x_inbuf2, f);
+}
+
+static void zlproxy_symbol(t_zlproxy *p, t_symbol *s)
+{
+ t_zl *x = p->p_master;
+ if (zl_modeargfn(x))
+ {
+ t_atom at;
+ SETSYMBOL(&at, s);
+ zl_setmodearg(x, 0, 1, &at);
+ }
+ else /* CHECKED inbuf2 filled only when used */
+ zldata_setsymbol(&x->x_inbuf2, s);
+}
+
+/* LATER gpointer */
+
+static void zlproxy_list(t_zlproxy *p, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_zl *x = p->p_master;
+ if (zl_modeargfn(x))
+ zl_setmodearg(x, 0, ac, av);
+ else /* CHECKED inbuf2 filled only when used */
+ zldata_setlist(&x->x_inbuf2, ac, av);
+ }
+}
+
+static void zlproxy_anything(t_zlproxy *p, t_symbol *s, int ac, t_atom *av)
+{
+ t_zl *x = p->p_master;
+ if (zl_modeargfn(x))
+ zl_setmodearg(x, s, ac, av);
+ else /* CHECKED inbuf2 filled only when used */
+ zldata_set(&x->x_inbuf2, s, ac, av);
+}
+
+#ifdef ZL_DEBUG
+static void zl_debug(t_zl *x, t_floatarg f)
+{
+ startpost("mode %s", zl_modesym[x->x_mode]->s_name);
+ if (zl_intargfn[x->x_mode])
+ post(" %d", x->x_modearg);
+ else
+ endpost();
+ if ((int)f)
+ {
+ startpost("first:");
+ postatom(x->x_inbuf1.d_natoms, x->x_inbuf1.d_buf);
+ endpost();
+ startpost("second:");
+ postatom(x->x_inbuf2.d_natoms, x->x_inbuf2.d_buf);
+ endpost();
+ }
+}
+#endif
+
+static void zl_free(t_zl *x)
+{
+ zldata_free(&x->x_inbuf1);
+ zldata_free(&x->x_inbuf2);
+ zldata_free(&x->x_outbuf);
+ if (x->x_proxy) pd_free((t_pd *)x->x_proxy);
+}
+
+static void *zl_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_zl *x = (t_zl *)pd_new(zl_class);
+ t_zlproxy *y = (t_zlproxy *)pd_new(zlproxy_class);
+ x->x_proxy = y;
+ y->p_master = x;
+ x->x_entered = 0;
+ x->x_locked = 0;
+ zldata_init(&x->x_inbuf1);
+ zldata_init(&x->x_inbuf2);
+ zldata_init(&x->x_outbuf);
+ x->x_mode = ZL_DEFMODE;
+ zl_mode(x, s, ac, av);
+ inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ outlet_new((t_object *)x, &s_anything);
+ x->x_out2 = outlet_new((t_object *)x, &s_anything);
+ return (x);
+}
+
+static void zl_setupmode(char *id, int flags,
+ t_zlintargfn ifn, t_zlanyargfn afn,
+ t_zlnatomsfn nfn, t_zldoitfn dfn)
+{
+ if (zl_nmodes < ZL_MAXMODES)
+ {
+ zl_modesym[zl_nmodes] = gensym(id);
+ zl_modeflags[zl_nmodes] = flags;
+ zl_intargfn[zl_nmodes] = ifn;
+ zl_anyargfn[zl_nmodes] = afn;
+ zl_natomsfn[zl_nmodes] = nfn;
+ zl_doitfn[zl_nmodes] = dfn;
+ zl_nmodes++;
+ }
+ else bug("zl_setupmode");
+}
+
+static void zl_setupallmodes(void)
+{
+ zl_setupmode("unknown", 0, 0, 0, zl_nop_count, zl_nop);
+ zl_setupmode("ecils", 0, zl_ecils_intarg, 0, zl_ecils_count, zl_ecils);
+ zl_setupmode("group", 1, zl_group_intarg, 0, zl_group_count, zl_group);
+ zl_setupmode("iter", 0, zl_iter_intarg, 0, zl_iter_count, zl_iter);
+ zl_setupmode("join", 0, 0, 0, zl_join_count, zl_join);
+ zl_setupmode("len", 0, 0, 0, zl_len_count, zl_len);
+ zl_setupmode("nth", 0, zl_nth_intarg, zl_nth_anyarg, zl_nth_count, zl_nth);
+ zl_setupmode("reg", 0, 0, zl_reg_anyarg, zl_reg_count, zl_reg);
+ zl_setupmode("rev", 0, 0, 0, zl_rev_count, zl_rev);
+ zl_setupmode("rot", /* CHECKED (refman error) */
+ 0, zl_rot_intarg, 0, zl_rot_count, zl_rot);
+ zl_setupmode("sect", 0, 0, 0, zl_sect_count, zl_sect);
+ zl_setupmode("slice", 0, zl_slice_intarg, 0, zl_slice_count, zl_slice);
+ zl_setupmode("sub", 0, 0, 0, zl_sub_count, zl_sub);
+ zl_setupmode("union", 0, 0, 0, zl_union_count, zl_union);
+}
+
+void zl_setup(void)
+{
+ zl_class = class_new(gensym("zl"),
+ (t_newmethod)zl_new,
+ (t_method)zl_free,
+ sizeof(t_zl), 0,
+ A_GIMME, 0);
+ class_addbang(zl_class, zl_bang);
+ class_addfloat(zl_class, zl_float);
+ class_addsymbol(zl_class, zl_symbol);
+ class_addlist(zl_class, zl_list);
+ class_addanything(zl_class, zl_anything);
+ class_addmethod(zl_class, (t_method)zl_mode,
+ gensym("mode"), A_GIMME, 0);
+#ifdef ZL_DEBUG
+ class_addmethod(zl_class, (t_method)zl_debug,
+ gensym("debug"), A_DEFFLOAT, 0);
+#endif
+ zlproxy_class = class_new(gensym("_zlproxy"), 0, 0,
+ sizeof(t_zlproxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(zlproxy_class, zlproxy_bang);
+ class_addfloat(zlproxy_class, zlproxy_float);
+ class_addsymbol(zlproxy_class, zlproxy_symbol);
+ class_addlist(zlproxy_class, zlproxy_list);
+ class_addanything(zlproxy_class, zlproxy_anything);
+ zl_setupallmodes();
+}