diff options
Diffstat (limited to 'cyclone/hammer')
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(); +} |