diff options
author | N.N. <krzyszcz@users.sourceforge.net> | 2003-05-23 12:29:55 +0000 |
---|---|---|
committer | N.N. <krzyszcz@users.sourceforge.net> | 2003-05-23 12:29:55 +0000 |
commit | faada59567f8cb252f4a909116595ce309ff5828 (patch) | |
tree | 5874954c6f2d5392d921208e49a45ef266beeb7f /cyclone |
This commit was generated by cvs2svn to compensate for changes in r647,svn2git-root
which included commits to RCS files with non-trunk default branches.
svn path=/trunk/externals/miXed/; revision=648
Diffstat (limited to 'cyclone')
164 files changed, 24624 insertions, 0 deletions
diff --git a/cyclone/Makefile b/cyclone/Makefile new file mode 100644 index 0000000..fc022be --- /dev/null +++ b/cyclone/Makefile @@ -0,0 +1,2 @@ +ROOT_DIR = .. +include $(ROOT_DIR)/Makefile.common diff --git a/cyclone/Makefile.dirs b/cyclone/Makefile.dirs new file mode 100644 index 0000000..0dde72f --- /dev/null +++ b/cyclone/Makefile.dirs @@ -0,0 +1,2 @@ +MIXED_DIRS = shadow hammer sickle +RELEASE_DIRS = shadow hammer sickle diff --git a/cyclone/Makefile.objects b/cyclone/Makefile.objects new file mode 100644 index 0000000..9b421fe --- /dev/null +++ b/cyclone/Makefile.objects @@ -0,0 +1,24 @@ +HLOUD_OBJECTS = common/loud.o +HFRAGILE_OBJECTS = common/loud.o unstable/fragile.o +HGROW_OBJECTS = common/grow.o common/loud.o +HFILE_OBJECTS = hammer/file.o common/loud.o +HRAND_OBJECTS = common/rand.o common/loud.o +HRANDFILE_OBJECTS = common/rand.o hammer/file.o common/loud.o +HRANDGROW_OBJECTS = common/rand.o common/grow.o common/loud.o +HTREE_OBJECTS = hammer/tree.o common/loud.o +HTREEFILEVEFL_OBJECTS = hammer/tree.o hammer/file.o \ + common/vefl.o common/loud.o unstable/fragile.o +HGUI_OBJECTS = hammer/gui.o common/loud.o +HSEQ_OBJECTS = common/sq.o common/bifi.o common/mifi.o \ + hammer/file.o common/grow.o common/loud.o +SSIC_OBJECTS = sickle/sic.o common/loud.o +SFORKY_OBJECTS = sickle/sic.o common/loud.o unstable/forky.o +SFRAGILE_OBJECTS = sickle/sic.o common/loud.o unstable/fragile.o +SGROW_OBJECTS = common/grow.o sickle/sic.o common/loud.o +SGROWFORKY_OBJECTS = common/grow.o sickle/sic.o common/loud.o unstable/forky.o +SVEFL_OBJECTS = common/vefl.o sickle/sic.o common/loud.o unstable/fragile.o +SARSIC_OBJECTS = sickle/sic.o sickle/arsic.o common/vefl.o \ + common/loud.o unstable/fragile.o +SFILE_OBJECTS = hammer/file.o sickle/sic.o common/loud.o +RELEASE_LIBS = cyclone hammer sickle +RELEASE_APPS = cyclist diff --git a/cyclone/Makefile.sources b/cyclone/Makefile.sources new file mode 100644 index 0000000..4d6cc29 --- /dev/null +++ b/cyclone/Makefile.sources @@ -0,0 +1,191 @@ +TYPES = HPLAIN HLOUD HFRAGILE HGROW HFILE HRAND HRANDFILE HRANDGROW \ + HTREE HTREEFILEVEFL HGUI HSEQ \ + SPLAINNOTILDE SPLAIN SSIC SFORKY SFRAGILE SGROW SGROWFORKY \ + SVEFL SARSIC SFILE + +HPLAIN_SOURCES = \ +hammer/testmess.c \ +hammer/accum.c \ +hammer/acos.c \ +hammer/asin.c \ +hammer/Bucket.c \ +hammer/cartopol.c \ +hammer/cosh.c \ +hammer/counter.c \ +hammer/flush.c \ +hammer/forward.c \ +hammer/fromsymbol.c \ +hammer/mean.c \ +hammer/midiflush.c \ +hammer/midiformat.c \ +hammer/midiparse.c \ +hammer/next.c \ +hammer/onebang.c \ +hammer/Peak.c \ +hammer/poltocar.c \ +hammer/sinh.c \ +hammer/split.c \ +hammer/sustain.c \ +hammer/tanh.c \ +hammer/Trough.c \ +hammer/Uzi.c \ +hammer/xbendin.c \ +hammer/xbendin2.c \ +hammer/xbendout.c \ +hammer/xbendout2.c \ +hammer/xnotein.c \ +hammer/xnoteout.c + +HLOUD_SOURCES = \ +hammer/anal.c \ +hammer/bangbang.c \ +hammer/Borax.c \ +hammer/comment.c \ +hammer/cycle.c \ +hammer/decide.c \ +hammer/Decode.c \ +hammer/gate.c \ +hammer/Histo.c \ +hammer/maximum.c \ +hammer/minimum.c \ +hammer/spell.c \ +hammer/spray.c \ +hammer/sprintf.c \ +hammer/switch.c \ +hammer/TogEdge.c + +HFRAGILE_SOURCES = \ +hammer/grab.c \ +hammer/universal.c + +HGROW_SOURCES = \ +hammer/Append.c \ +hammer/bondo.c \ +hammer/buddy.c \ +hammer/Clip.c \ +hammer/funnel.c \ +hammer/iter.c \ +hammer/match.c \ +hammer/past.c \ +hammer/prepend.c \ +hammer/pv.c \ +hammer/speedlim.c \ +hammer/substitute.c \ +hammer/thresh.c \ +hammer/tosymbol.c \ +hammer/zl.c + +HFILE_SOURCES = \ +hammer/capture.c \ +hammer/coll.c + +HRAND_SOURCES = \ +hammer/drunk.c + +HRANDFILE_SOURCES = \ +hammer/prob.c + +HRANDGROW_SOURCES = \ +hammer/urn.c + +HTREE_SOURCES = \ +hammer/offer.c + +HTREEFILEVEFL_SOURCES = \ +hammer/funbuff.c + +HGUI_SOURCES = \ +hammer/active.c \ +hammer/mousefilter.c \ +hammer/MouseState.c + +HSEQ_SOURCES = \ +hammer/seq.c + +SPLAINNOTILDE_SOURCES = \ +sickle/linedrive.c + +SSIC_TILDE = $(TILDE) +SSIC_SOURCES = \ +sickle/abs.c \ +sickle/acos.c \ +sickle/acosh.c \ +sickle/allpass.c \ +sickle/asin.c \ +sickle/asinh.c \ +sickle/atan.c \ +sickle/atan2.c \ +sickle/atanh.c \ +sickle/average.c \ +sickle/avg.c \ +sickle/bitnot.c \ +sickle/bitshift.c \ +sickle/change.c \ +sickle/Clip.c \ +sickle/comb.c \ +sickle/cosh.c \ +sickle/cosx.c \ +sickle/count.c \ +sickle/delay.c \ +sickle/delta.c \ +sickle/deltaclip.c \ +sickle/edge.c \ +sickle/kink.c \ +sickle/log.c \ +sickle/minmax.c \ +sickle/peakamp.c \ +sickle/phasewrap.c \ +sickle/pow.c \ +sickle/rampsmooth.c \ +sickle/rand.c \ +sickle/sah.c \ +sickle/sinh.c \ +sickle/sinx.c \ +sickle/slide.c \ +sickle/Snapshot.c \ +sickle/spike.c \ +sickle/tanh.c \ +sickle/tanx.c \ +sickle/train.c \ +sickle/trapezoid.c \ +sickle/triangle.c \ +sickle/vectral.c + +SFORKY_TILDE = $(TILDE) +SFORKY_SOURCES = \ +sickle/bitand.c \ +sickle/bitor.c \ +sickle/bitxor.c + +SFRAGILE_TILDE = $(TILDE) +SFRAGILE_SOURCES = \ +sickle/cartopol.c \ +sickle/poltocar.c + +SGROW_TILDE = $(TILDE) +SGROW_SOURCES = \ +sickle/click.c \ +sickle/frameaccum.c \ +sickle/framedelta.c \ +sickle/Line.c + +SGROWFORKY_TILDE = $(TILDE) +SGROWFORKY_SOURCES = \ +sickle/Scope.c + +SVEFL_TILDE = $(TILDE) +SVEFL_SOURCES = \ +sickle/cycle.c + +SARSIC_TILDE = $(TILDE) +SARSIC_SOURCES = \ +sickle/index.c \ +sickle/lookup.c \ +sickle/peek.c \ +sickle/play.c \ +sickle/record.c \ +sickle/wave.c + +SFILE_TILDE = $(TILDE) +SFILE_SOURCES = \ +sickle/capture.c diff --git a/cyclone/build_counter b/cyclone/build_counter new file mode 100644 index 0000000..1e05d4b --- /dev/null +++ b/cyclone/build_counter @@ -0,0 +1,3 @@ +#define CYCLONE_VERSION "0.1" +#define CYCLONE_RELEASE "alpha" +#define CYCLONE_BUILD 42 diff --git a/cyclone/cyclone-all.exclude b/cyclone/cyclone-all.exclude new file mode 100644 index 0000000..8b8d91f --- /dev/null +++ b/cyclone/cyclone-all.exclude @@ -0,0 +1,9 @@ +*~ +*.o +*.gz +*.html +*.out +*/*/old +*/*/old/* +*/*/ref +*/*/ref/* diff --git a/cyclone/cyclone-shared.include b/cyclone/cyclone-shared.include new file mode 100644 index 0000000..49cc815 --- /dev/null +++ b/cyclone/cyclone-shared.include @@ -0,0 +1,35 @@ +shared/shared.c +shared/shared.h +shared/unstable/forky.c +shared/unstable/forky.h +shared/unstable/fragile.c +shared/unstable/fragile.h +shared/unstable/pd_imp.h +shared/common/grow.c +shared/common/grow.h +shared/common/loud.c +shared/common/loud.h +shared/common/binport.c +shared/common/binport.h +shared/common/port.c +shared/common/port.h +shared/common/rand.c +shared/common/rand.h +shared/common/vefl.c +shared/common/vefl.h +shared/common/sq.c +shared/common/sq.h +shared/common/bifi.c +shared/common/bifi.h +shared/common/mifi.c +shared/common/mifi.h +shared/hammer/file.c +shared/hammer/file.h +shared/hammer/gui.c +shared/hammer/gui.h +shared/hammer/tree.c +shared/hammer/tree.h +shared/sickle/sic.c +shared/sickle/sic.h +shared/sickle/arsic.c +shared/sickle/arsic.h diff --git a/cyclone/cyclone-test.exclude b/cyclone/cyclone-test.exclude new file mode 100644 index 0000000..ec84f87 --- /dev/null +++ b/cyclone/cyclone-test.exclude @@ -0,0 +1,4 @@ +*~ +import-result.pd +temporary +temporary/* diff --git a/cyclone/cyclone-vicious.exclude b/cyclone/cyclone-vicious.exclude new file mode 100644 index 0000000..5e5a82e --- /dev/null +++ b/cyclone/cyclone-vicious.exclude @@ -0,0 +1,3 @@ +*~ +old +old/* 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(); +} diff --git a/cyclone/shadow/Makefile b/cyclone/shadow/Makefile new file mode 100644 index 0000000..b700e5e --- /dev/null +++ b/cyclone/shadow/Makefile @@ -0,0 +1,7 @@ +ROOT_DIR = ../.. +redefault: default $(ROOT_DIR)/bin/cyclist +include $(ROOT_DIR)/Makefile.common + +$(ROOT_DIR)/bin/cyclist: $(SHARED_DIR)/common/binport.c + $(CC) -DBINPORT_STANDALONE -o $@ $< + diff --git a/cyclone/shadow/Makefile.objects b/cyclone/shadow/Makefile.objects new file mode 100644 index 0000000..f77675c --- /dev/null +++ b/cyclone/shadow/Makefile.objects @@ -0,0 +1,9 @@ +SHARED_OBJECTS = \ +common/loud.o \ +common/grow.o \ +common/binport.o \ +common/port.o \ +hammer/file.o \ +sickle/sic.o \ +unstable/fragile.o \ +unstable/loader.o diff --git a/cyclone/shadow/Makefile.sources b/cyclone/shadow/Makefile.sources new file mode 100644 index 0000000..8ba4681 --- /dev/null +++ b/cyclone/shadow/Makefile.sources @@ -0,0 +1,6 @@ +CX_SOURCES = \ +cyclone.c + +OTHER_SOURCES = \ +nettles.c \ +dummies.c diff --git a/cyclone/shadow/cyclone.c b/cyclone/shadow/cyclone.c new file mode 100644 index 0000000..047d39d --- /dev/null +++ b/cyclone/shadow/cyclone.c @@ -0,0 +1,159 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* Never use forked calls in shadow code... */ + +#include <stdio.h> +#include "m_pd.h" +#include "common/loud.h" +#include "common/port.h" +#include "hammer/file.h" +#include "unstable/fragile.h" +#include "unstable/loader.h" +#include "shadow.h" +#include "../build_counter" + +typedef struct _cyclone +{ + t_object x_ob; + t_symbol *x_dir; + t_hammerfile *x_filehandle; +} t_cyclone; + +static t_class *cyclone_class; +static int cyclone_hammerndx; +static int cyclone_sicklendx; +static int cyclone_nettlesndx; +static int cyclone_dummiesndx; +static int cyclone_lastndx; + +static void cyclone_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av) +{ + import_max(fn->s_name, ""); +} + +static void cyclone_import(t_cyclone *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 cyclone_click(t_cyclone *x, t_floatarg xpos, t_floatarg ypos, + t_floatarg shift, t_floatarg ctrl, t_floatarg alt) +{ + cyclone_import(x, 0, 0); +} + +static void cyclone_bang(t_cyclone *x) +{ + int i; + fragile_class_printnames("hammer classes are: ", + cyclone_hammerndx, cyclone_sicklendx - 1); + fragile_class_printnames("sickle classes are: ", + cyclone_sicklendx, cyclone_nettlesndx - 1); + fragile_class_printnames("nettles are: ", + cyclone_nettlesndx, cyclone_dummiesndx - 1); + if (i = dummy_nreplacements()) + post("send 'reps' message to see the list of %d \ +replacement abstractions", i); + else + post("no replacement abstractions"); + post("send 'dummies' message to see the list of %d dummy classes", + /* cyclone_lastndx points to the "_dummy" sentinel class */ + cyclone_lastndx - cyclone_dummiesndx); +} + +static void cyclone_reps(t_cyclone *x) +{ + if (dummy_nreplacements()) + dummy_printreplacements("replacement abstractions are: "); + else + post("no replacement abstractions"); +} + +static void cyclone_dummies(t_cyclone *x) +{ + fragile_class_printnames("dummies are: ", + cyclone_dummiesndx, cyclone_lastndx); +} + +static void cyclone_free(t_cyclone *x) +{ + hammerfile_free(x->x_filehandle); +} + +static void *cyclone_new(t_symbol *s) +{ + t_cyclone *x = (t_cyclone *)pd_new(cyclone_class); + x->x_filehandle = hammerfile_new((t_pd *)x, 0, cyclone_readhook, 0, 0); + x->x_dir = (s && s != &s_ ? s : canvas_getdir(x->x_filehandle->f_canvas)); + return (x); +} + +void cyclone_setup(void) +{ + int hresult, sresult; + hresult = sresult = LOADER_OK; + 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 'cyclone' object"); + loud_errand(0, "without having cyclone library preloaded"); + return; + } + post("this is cyclone %s, %s %s build", + CYCLONE_VERSION, loud_ordinal(CYCLONE_BUILD), CYCLONE_RELEASE); + cyclone_class = class_new(gensym("cyclone"), + (t_newmethod)cyclone_new, + (t_method)cyclone_free, + sizeof(t_cyclone), 0, A_DEFSYM, 0); + class_addbang(cyclone_class, cyclone_bang); + class_addmethod(cyclone_class, (t_method)cyclone_reps, + gensym("reps"), 0); + class_addmethod(cyclone_class, (t_method)cyclone_dummies, + gensym("dummies"), 0); + class_addmethod(cyclone_class, (t_method)cyclone_import, + gensym("import"), A_DEFSYM, A_DEFSYM, 0); + class_addmethod(cyclone_class, (t_method)cyclone_click, + gensym("click"), + A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); + hammerfile_setup(cyclone_class, 0); + + cyclone_hammerndx = fragile_class_count(); + if (zgetfn(&pd_objectmaker, gensym("hammer"))) + loud_warning(0, "hammer is already loaded"); + else + hresult = unstable_load_lib("", "hammer"); + + cyclone_sicklendx = fragile_class_count(); + if (zgetfn(&pd_objectmaker, gensym("sickle"))) + loud_warning(0, "sickle is already loaded"); + else + sresult = unstable_load_lib("", "sickle"); + + cyclone_nettlesndx = fragile_class_count(); + allnettles_setup(); + + cyclone_dummiesndx = fragile_class_count(); + alldummies_setup(); + cyclone_lastndx = fragile_class_count() - 1; + + if (hresult == LOADER_NOFILE) + loud_error(0, "hammer library is missing"); + else if (sresult == LOADER_NOFILE) + loud_error(0, "sickle library is missing"); + else if (!zgetfn(&pd_objectmaker, gensym("hammer")) || + !zgetfn(&pd_objectmaker, gensym("sickle"))) + { + loud_error(0, "version mismatch"); + loud_errand(0, + "use a more recent Pd release (or recompile the cyclone)."); + } +} diff --git a/cyclone/shadow/dummies.c b/cyclone/shadow/dummies.c new file mode 100644 index 0000000..272fd45 --- /dev/null +++ b/cyclone/shadow/dummies.c @@ -0,0 +1,664 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include <string.h> +#ifdef UNIX +#include <unistd.h> +#endif +#ifdef NT +#include <io.h> +#endif +#include "m_pd.h" +#include "common/loud.h" +#include "shadow.h" + +static int dummy_nclasses = 0; +static t_class **dummy_classes; +static int dummy_nreps = 0; + +typedef struct _dummy_slot +{ + char *s_name; + int s_nins; + int s_nouts; + int s_warned; + t_newmethod s_method; /* a specialized constructor */ +} t_dummy_slot; + +static t_object *dummy_newobject(t_symbol *s, t_dummy_slot **slotp); +static void dummy_io(t_object *x, int nins, int nouts); + +static void *dummy_2dwave_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nouts = 0; + if (ac && av->a_type == A_SYMBOL) + { + if (ac > 3 && av[3].a_type == A_FLOAT) + nouts = (int)av[3].a_w.w_float; + } + else loud_classarg(*(t_pd *)x); + if (nouts < 1) + nouts = 1; + dummy_io(x, sl->s_nins, nouts); + return (x); +} + +static void *dummy_adoutput_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nouts = 0; + while (ac--) + { + if (av++->a_type == A_FLOAT) nouts++; + else + { + loud_classarg(*(t_pd *)x); + break; + } + } + if (nouts < 1) + nouts = 2; + dummy_io(x, sl->s_nins, nouts); + return (x); +} + +static void *dummy_fffb_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nouts = 0; + if (ac && av->a_type == A_FLOAT) + nouts = (int)av->a_w.w_float; + if (nouts < 1) + { + loud_classarg(*(t_pd *)x); + nouts = 1; + } + dummy_io(x, sl->s_nins, nouts); + return (x); +} + +static void *dummy_gate_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nouts = 0; + if (ac && av->a_type == A_FLOAT) + nouts = (int)av->a_w.w_float; + if (nouts < 1) + nouts = 1; + dummy_io(x, sl->s_nins, nouts); + return (x); +} + +static void *dummy_groove_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nouts = 0; + if (ac && av->a_type == A_SYMBOL) + { + if (ac > 1 && av[1].a_type == A_FLOAT) + nouts = (int)av[1].a_w.w_float; + } + else loud_classarg(*(t_pd *)x); + if (nouts < 1) + nouts = 1; + dummy_io(x, sl->s_nins, nouts + 1); + return (x); +} + +/* FIXME */ +static void *dummy_if_new(t_symbol *s, int ac, t_atom *av) +{ + t_object *x = dummy_newobject(s, 0); + int nins = 0; + int nouts = 1; + t_symbol *ps_out2 = gensym("out2"); + while (ac--) + { + if (av->a_type == A_SYMBOL) + { + if (av->a_w.w_symbol == ps_out2) + nouts = 2; + else + { + char *name = av->a_w.w_symbol->s_name; + if (strlen(name) >= 3 && *name == '$') + { + char c = name[2]; + if (c > '1' && c <= '9' && c > '0' + nins) + nins = c - '0'; + } + } + } + av++; + } + dummy_io(x, nins, nouts); + return (x); +} + +static void *dummy_matrix_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nins = 0, nouts = 0; + if (ac && av->a_type == A_FLOAT) + { + nins = (int)av->a_w.w_float; + if (ac > 1 && av[1].a_type == A_FLOAT) + nouts = (int)av[1].a_w.w_float; + } + if (nins < 1 || nouts < 1) + { + loud_classarg(*(t_pd *)x); + if (nins < 1) nins = 1; + if (nouts < 1) nouts = 1; + } + dummy_io(x, nins, nouts + 1); /* CHECKME */ + return (x); +} + +static void *dummy_mtr_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nios = 0; + if (ac && av->a_type == A_FLOAT) + nios = (int)av->a_w.w_float; + if (nios < 1) + nios = 1; + dummy_io(x, nios + 1, nios + 1); + return (x); +} + +/* CHECKME */ +static void *dummy_pong_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nins = 0; + if (ac) + { + if (av->a_type == A_FLOAT) + { + ac--; av++; + if (ac) + { + if (av->a_type == A_FLOAT) nins = 3; + } + else nins = 2; + } + } + else nins = 2; + if (nins < 1) + { + loud_classarg(*(t_pd *)x); + nins = 2; + } + dummy_io(x, nins, sl->s_nouts); + return (x); +} + +static void *dummy_rewire_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nouts = 0; + if (ac && av->a_type == A_FLOAT) + nouts = (int)av->a_w.w_float; + else if (ac > 1 && av[1].a_type == A_FLOAT) + nouts = (int)av[1].a_w.w_float; + if (nouts < 1) + nouts = 1; /* CHECKME */ + dummy_io(x, sl->s_nins, nouts + 4); + return (x); +} + +static void *dummy_selector_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nins = 0; + if (ac && av->a_type == A_FLOAT) + nins = (int)av->a_w.w_float; + if (nins < 1) + nins = 1; + dummy_io(x, nins + 1, sl->s_nouts); + return (x); +} + +static void *dummy_sfplay_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nouts = 0; + if (ac) + { + if (av->a_type == A_FLOAT) + nouts = (int)av->a_w.w_float; + else if (ac > 1 && av[1].a_type == A_FLOAT) + nouts = (int)av[1].a_w.w_float; + } + if (nouts < 1) + nouts = 1; + dummy_io(x, sl->s_nins, nouts + 1); + return (x); +} + +static void *dummy_sfrecord_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nins = 0; + if (ac && av->a_type == A_FLOAT) + nins = (int)av->a_w.w_float; + if (nins < 1) + nins = 1; + dummy_io(x, nins, sl->s_nouts); + return (x); +} + +static void *dummy_stutter_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nios = 0; + if (ac > 4 && av[4].a_type == A_FLOAT) + nios = (int)av[4].a_w.w_float; + if (nios < 1) + nios = 1; + dummy_io(x, nios + 2, nios); + return (x); +} + +static void *dummy_sxformat_new(t_symbol *s, int ac, t_atom *av) +{ + return (dummy_if_new(s, ac, av)); /* FIXME */ +} + +static void *dummy_tapout_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int warned = 0, nios = 0; + while (ac--) + if (av++->a_type == A_FLOAT) + nios++; + else if (!warned++) + loud_classarg(*(t_pd *)x); + if (nios < 1) + nios = 1; + dummy_io(x, nios, nios); + return (x); +} + +/* CHECKME */ +static void *dummy_tiCmd_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nouts = 0; + if (ac > 1) + { + ac--; av++; + while (ac--) + { + char c = 0; + if (av->a_type == A_SYMBOL) + { + c = *av->a_w.w_symbol->s_name; + if (c == 'i' || c == 'f' || c == 'l' + || c == 'b' || c == 's' || c == 'a') + nouts++; + else + c = 0; + } + if (c == 0) + { + loud_classarg(*(t_pd *)x); + break; + } + av++; + } + } + if (nouts < 1) + nouts = 0; + dummy_io(x, sl->s_nins, nouts + 2); + return (x); +} + +/* CHECKME */ +static void *dummy_timeline_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nouts = 0; + if (ac) + { + if (av->a_type == A_FLOAT) + nouts = (int)av->a_w.w_float; + else if (ac > 1 && av[1].a_type == A_FLOAT) + nouts = (int)av[1].a_w.w_float; + } + if (nouts < 1) + nouts = 0; + dummy_io(x, sl->s_nins, nouts); + return (x); +} + +static void *dummy_vexpr_new(t_symbol *s, int ac, t_atom *av) +{ + return (dummy_if_new(s, ac, av)); /* FIXME */ +} + +static void *dummy_vst_tilde_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + int nins = 0, nouts = 0; + if (ac > 1 && av[1].a_type == A_FLOAT) + { + if (av->a_type == A_FLOAT) + { + nins = (int)av->a_w.w_float; + nouts = (int)av[1].a_w.w_float; + } + } + else if (ac && av->a_type == A_FLOAT) + nouts = (int)av->a_w.w_float; + if (nins < 1) + nins = 2; /* CHECKME */ + if (nouts < 1) + nouts = 2; /* CHECKME */ + dummy_io(x, nins, nouts + 4); /* CHECKME */ + return (x); +} + +static t_dummy_slot dummy_slots[] = +{ + { "2d.wave~", 4, -1, 0, (t_newmethod)dummy_2dwave_tilde_new }, + { "absolutepath", 1, 1, 0, 0 }, + { "acosh", 1, 1, 0, 0 }, + { "adoutput~", 1, -1, 0, (t_newmethod)dummy_adoutput_tilde_new }, + { "adstatus", 2, 2, 0, 0 }, + { "asinh", 1, 1, 0, 0 }, + { "atanh", 1, 1, 0, 0 }, + { "begin~", 0, 1, 0, 0 }, + { "Biquad~", 6, 1, 0, 0 }, + /* LATER try mapping bpatcher to a gop abstraction/subpatch */ + { "buffer~", 1, 2, 0, 0 }, + { "buffir~", 3, 1, 0, 0 }, + { "cd", 1, 2, 0, 0 }, /* CHECKED (refman error?) */ + { "cd~", 1, 6, 0, 0 }, /* CHECKED (refman error?) */ + { "Change", 1, 3, 0, 0 }, + { "clocker", 2, 1, 0, 0 }, + { "closebang", 0, 1, 0, 0 }, + { "colorpicker", 1, 1, 0, 0 }, + { "curve~", 3, 2, 0, 0 }, + { "date", 1, 3, 0, 0 }, + { "defer", 1, 1, 0, 0 }, /* LATER pass anything through */ + { "degrade~", 3, 1, 0, 0 }, + { "detonate", 8, 8, 0, 0 }, + { "dial", 1, 1, 0, 0 }, + { "dialog", 2, 1, 0, 0 }, + { "downsamp~", 2, 1, 0, 0 }, + { "dropfile", 1, 2, 0, 0 }, + { "dspstate~", 1, 3, 0, 0 }, + { "dsptime~", 1, 1, 0, 0 }, + { "env", 1, 1, 0, 0 }, + { "envi", 1, 1, 0, 0 }, + { "error", 1, 1, 0, 0 }, + { "ezadc~", 1, 2, 0, 0 }, + { "ezdac~", 2, 0, 0, 0 }, + { "fffb~", 1, -1, 0, (t_newmethod)dummy_fffb_tilde_new }, + /* LATER Fft~ */ + /* LATER pfft~-specific classes: fftin~, fftinfo~, fftout~ */ + { "filedate", 1, 1, 0, 0 }, + { "filein", 3, 3, 0, 0 }, + { "filepath", 1, 1, 0, 0 }, + { "filtergraph~", 8, 6, 0, 0 }, + { "folder", 1, 1, 0, 0 }, /* CHECKME 2nd outlet */ + { "follow", 1, 2, 0, 0 }, + { "fpic", 1, 0, 0, 0 }, + { "frame", 6, 0, 0, 0 }, + { "function", 1, 4, 0, 0 }, + { "gain~", 2, 2, 0, 0 }, + { "gate~", 2, -1, 0, (t_newmethod)dummy_gate_tilde_new }, + { "gestalt", 1, 2, 0, 0 }, + { "Ggate", 2, 2, 0, 0 }, + /* LATER glove? */ + { "graphic", 1, 0, 0, 0 }, + { "groove~", 3, -1, 0, (t_newmethod)dummy_groove_tilde_new }, + { "Gswitch", 3, 1, 0, 0 }, + { "hint", 1, 1, 0, 0 }, + { "if", -1, -1, 0, (t_newmethod)dummy_if_new }, + /* LATER Ifft~ */ + { "imovie", 1, 3, 0, 0 }, + { "IncDec", 1, 1, 0, 0 }, + { "info~", 1, 8, 0, 0 }, /* CHECKME nouts */ + { "ioscbank~", 4, 1, 0, 0 }, + { "Key", 0, 3, 0, 0 }, + { "Keyup", 0, 3, 0, 0 }, + { "kslider", 2, 2, 0, 0 }, + { "lcd", 1, 4, 0, 0 }, /* CHECKME nouts */ + { "led", 1, 1, 0, 0 }, + { "Line", 3, 2, 0, 0 }, + { "lores~", 3, 1, 0, 0 }, + { "matrixctrl", 1, 1, 0, 0 }, /* CHECKME nins, nouts */ + { "matrix~", -1, -1, 0, (t_newmethod)dummy_matrix_tilde_new }, + { "maximum~", 2, 1, 0, 0 }, + { "menubar", 1, 4, 0, 0 }, /* LATER parse #Xs (additional outs) */ + { "meter~", 1, 1, 0, 0 }, /* LATER consider mapping to the vu */ + { "minimum~", 2, 1, 0, 0 }, + { "movie", 1, 3, 0, 0 }, + /* CHECKME msd */ + { "mstosamps~", 1, 2, 0, 0 }, + { "mtr", -1, -1, 0, (t_newmethod)dummy_mtr_new }, + { "multiSlider", 1, 1, 0, 0 }, + { "mute~", 1, 1, 0, 0 }, + { "normalize~", 2, 1, 0, 0 }, + { "number~", 2, 2, 0, 0 }, + { "numkey", 1, 2, 0, 0 }, + { "omscontrollers", 4, 2, 0, 0 }, /* CHECKME osx */ + { "omsinfo", 2, 1, 0, 0 }, /* LATER midiinfo? */ + { "omsnotes", 4, 2, 0, 0 }, /* CHECKME osx */ + { "omspatches", 3, 2, 0, 0 }, /* CHECKME osx */ + { "onecopy", 0, 0, 0, 0 }, /* CHECKME */ + { "onepole~", 2, 1, 0, 0 }, + { "opendialog", 1, 2, 0, 0 }, + { "oscbank~", 4, 1, 0, 0 }, + { "oval", 6, 0, 0, 0 }, + { "overdrive~", 2, 1, 0, 0 }, + { "panel", 1, 0, 0, 0 }, + { "pass~", 1, 1, 0, 0 }, + { "pcontrol", 1, 1, 0, 0 }, + /* LATER pfft~ */ + { "phaseshift~", 3, 1, 0, 0 }, + { "pics", 3, 0, 0, 0 }, /* CHECKME */ + { "pics2", 3, 0, 0, 0 }, /* CHECKME */ + { "pict", 3, 0, 0, 0 }, + { "pictctrl", 1, 1, 0, 0 }, + { "pictslider", 2, 2, 0, 0 }, /* CHECKME one-dimensional mode */ + { "pink~", 1, 1, 0, 0 }, /* CHECKME inlet */ + { "playbar", 1, 2, 0, 0 }, /* CHECKME */ + { "plugconfig", 1, 0, 0, 0 }, + { "plugin~", 2, 2, 0, 0 }, + { "plugmidiin", 0, 1, 0, 0 }, + { "plugmidiout", 1, 0, 0, 0 }, + { "plugmod", 5, 3, 0, 0 }, + { "plugmorph", 2, 3, 0, 0 }, + { "plugmultiparam", 1, 2, 0, 0 }, + { "plugout~", 2, 2, 0, 0 }, /* CHECKME nouts */ + { "plugphasor~", 0, 1, 0, 0 }, /* CHECKME nouts */ + { "plugreceive~", 1, 1, 0, 0 }, + { "plugsend~", 1, 0, 0, 0 }, + { "plugstore", 1, 1, 0, 0 }, /* CHECKME nouts */ + { "plugsync~", 0, 9, 0, 0 }, /* CHECKME nouts */ + { "poke~", 3, 0, 0, 0 }, + { "Poly", 2, 4, 0, 0 }, + { "polyin", 1, 3, 0, 0 }, /* LATER parse args for nouts */ + { "polyout", 3, 0, 0, 0 }, /* CHECKME nins */ + /* LATER poly~ */ + { "pong~", -1, 1, 0, (t_newmethod)dummy_pong_tilde_new }, + { "pp", 2, 2, 0, 0 }, /* CHECKME nins */ + { "pptempo", 2, 2, 0, 0 }, + { "pptime", 4, 4, 0, 0 }, + { "preset", 1, 3, 0, 0 }, + { "radiogroup", 1, 1, 0, 0 }, + { "rate~", 2, 1, 0, 0 }, /* CHECKME */ + /* LATER settable Receive? */ + { "rect", 6, 0, 0, 0 }, + { "relativepath", 1, 1, 0, 0 }, + { "reson~", 4, 1, 0, 0 }, + { "rewire~", 1, -1, 0, (t_newmethod)dummy_rewire_tilde_new }, + { "ring", 6, 0, 0, 0 }, + { "round~", 2, 1, 0, 0 }, + { "rslider", 2, 2, 0, 0 }, + { "rtin", 1, 1, 0, 0 }, + { "sampstoms~", 1, 2, 0, 0 }, + { "savedialog", 1, 3, 0, 0 }, + { "screensize", 1, 2, 0, 0 }, + { "selector~", -1, 1, 0, (t_newmethod)dummy_selector_tilde_new }, + { "seq~", 1, 2, 0, 0 }, + { "serial", 1, 2, 0, 0 }, + { "setclock", 2, 1, 0, 0 }, + { "sfinfo~", 1, 6, 0, 0 }, /* CHECKME nouts */ + { "sflist~", 1, 0, 0, 0 }, + { "sfplay~", 1, -1, 0, (t_newmethod)dummy_sfplay_tilde_new }, + { "sfrecord~", -1, 0, 0, (t_newmethod)dummy_sfrecord_tilde_new }, + { "sndmgrin~", 0, 2, 0, 0 }, /* CHECKME */ + { "strippath", 1, 2, 0, 0 }, + { "stutter~", -1, -1, 0, (t_newmethod)dummy_stutter_tilde_new }, + { "suspend", 0, 1, 0, 0 }, + { "svf~", 3, 4, 0, 0 }, + { "swatch", 3, 2, 0, 0 }, + { "sxformat", -1, 1, 0, (t_newmethod)dummy_sxformat_new }, + { "sysexin", 1, 1, 0, 0 }, + { "Table", 2, 2, 0, 0 }, + { "tapin~", 1, 1, 0, 0 }, + { "tapout~", -1, -1, 0, (t_newmethod)dummy_tapout_tilde_new }, + { "teeth~", 6, 1, 0, 0 }, + { "tempo", 4, 1, 0, 0 }, + { "Text", 1, 1, 0, 0 }, + { "textedit", 1, 3, 0, 0 }, + { "thisobject", 1, 3, 0, 0 }, /* CHECKME */ + { "thispatcher", 1, 2, 0, 0 }, + { "thisTimeline", 1, 1, 0, 0 }, + { "thisTrack", 1, 0, 0, 0 }, + { "thispoly~", 1, 1, 0, 0 }, + { "thresh~", 3, 1, 0, 0 }, + { "tiCmd", 0, -1, 0, (t_newmethod)dummy_tiCmd_new }, + { "timeline", 1, -1, 0, (t_newmethod)dummy_timeline_new }, + { "tiOut", 1, 0, 0, 0 }, + { "timein", 3, 4, 0, 0 }, + { "timeout", 4, 0, 0, 0 }, + /* LATER touchin's inlet (Touchin?) */ + { "trunc~", 1, 1, 0, 0 }, /* CHECKME */ + { "ubutton", 1, 4, 0, 0 }, + { "umenu", 1, 2, 0, 0 }, + { "vdp", 3, 4, 0, 0 }, + { "vexpr", -1, 1, 0, (t_newmethod)dummy_vexpr_new }, + { "vpicture", 0, 0, 0, 0 }, + { "vst~", -1, -1, 0, (t_newmethod)dummy_vst_tilde_new }, + { "waveform~", 5, 6, 0, 0 }, /* CHECKME */ + { "zerox~", 1, 2, 0, 0 }, + { "zigzag~", 2, 4, 0, 0 }, + { "_dummy", 0, 0, 0, 0 } +}; + +static void *dummy_new(t_symbol *s, int ac, t_atom *av) +{ + t_dummy_slot *sl; + t_object *x = dummy_newobject(s, &sl); + dummy_io(x, sl->s_nins, sl->s_nouts); + return (x); +} + +static void dummy_io(t_object *x, int nins, int nouts) +{ + nins = (nins > 0 ? nins - 1 : 0); + while (nins--) inlet_new(x, (t_pd *)x, 0, 0); + while (nouts--) outlet_new(x, &s_anything); +} + +static t_object *dummy_newobject(t_symbol *s, t_dummy_slot **slotp) +{ + t_object *x; + t_dummy_slot *sl; + int fnd; + for (fnd = 0; fnd < dummy_nclasses; fnd++) + /* LATER compare symbols, rather than strings */ + if (dummy_classes[fnd] /* empty slot: abstraction replacement */ + && !strcmp(class_getname(dummy_classes[fnd]), s->s_name)) + break; + x = (t_object *)pd_new(dummy_classes[fnd]); + sl = &dummy_slots[fnd]; + if (fnd == dummy_nclasses) + bug("dummy_newobject"); /* create a "_dummy" in this case */ + else if (!sl->s_warned) + { + loud_warning((t_pd *)x, "dummy substitution"); + sl->s_warned = 1; + } + if (slotp) *slotp = sl; + return (x); +} + +int dummy_nreplacements(void) +{ + return (dummy_nreps); +} + +void dummy_printreplacements(char *msg) +{ + int i, len = strlen(msg); + t_dummy_slot *sl; + startpost(msg); + for (i = 0, sl = dummy_slots; i < dummy_nclasses; i++, sl++) + { + if (!dummy_classes[i]) + { + int l = 1 + strlen(sl->s_name); + if ((len += l) > 66) + { + endpost(); + startpost(" "); + len = 3 + l; + } + poststring(sl->s_name); + } + } + endpost(); +} + +void alldummies_setup(void) +{ + t_dummy_slot *sl; + int i; + dummy_nclasses = sizeof(dummy_slots)/sizeof(*dummy_slots); + /* never freed: */ + dummy_classes = getbytes(dummy_nclasses * sizeof(*dummy_classes)); + for (i = 0, sl = dummy_slots; i < dummy_nclasses; i++, sl++) + { + int fd; + char dirbuf[MAXPDSTRING], *nameptr; + if ((fd = open_via_path("", sl->s_name, ".pd", + dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0) + { + close(fd); + dummy_nreps++; + } + else + dummy_classes[i] = + class_new(gensym(sl->s_name), + sl->s_method ? sl->s_method : (t_newmethod)dummy_new, + 0, sizeof(t_object), + (sl->s_nins ? 0 : CLASS_NOINLET), A_GIMME, 0); + } + dummy_nclasses--; /* use "_dummy" as a sentinel */ +} diff --git a/cyclone/shadow/nettles.c b/cyclone/shadow/nettles.c new file mode 100644 index 0000000..d7ccb87 --- /dev/null +++ b/cyclone/shadow/nettles.c @@ -0,0 +1,549 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include <math.h> +#include "m_pd.h" +#include "shared.h" +#include "sickle/sic.h" +#include "shadow.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define fmodf fmod +#endif + +/* Two remaining control binops have their inputs reversed. + LATER think about float-to-int conversion -- there is no point in making + the two below compatible, while all the others are not compatible... */ + +/* CHECKED left inlet causes output (refman's error -- a total rubbish) */ + +typedef struct _rbinop +{ + t_object x_ob; + t_float x_f1; /* left inlet value */ + t_float x_f2; +} t_rbinop; + +static t_class *rminus_class; + +static void rminus_bang(t_rbinop *x) +{ + outlet_float(((t_object *)x)->ob_outlet, x->x_f2 - x->x_f1); +} + +static void rminus_float(t_rbinop *x, t_float f) +{ + outlet_float(((t_object *)x)->ob_outlet, x->x_f2 - (x->x_f1 = f)); +} + +static void *rminus_new(t_floatarg f) +{ + t_rbinop *x = (t_rbinop *)pd_new(rminus_class); + floatinlet_new((t_object *)x, &x->x_f2); /* CHECKED */ + outlet_new((t_object *)x, &s_float); + x->x_f1 = 0; + x->x_f2 = f; /* CHECKED */ + return (x); +} + +static t_class *rdiv_class; + +static void rdiv_bang(t_rbinop *x) +{ + if (x->x_f1 != 0.) + outlet_float(((t_object *)x)->ob_outlet, x->x_f2 / x->x_f1); + else + /* CHECKED int mode: nonnegative/0 == 0, negative/0 == -1, + float mode: positive/0 == INT_MAX, nonpositive/0 == INT_MIN + LATER rethink -- why is it INT_MAX, not FLT_MAX? */ + outlet_float(((t_object *)x)->ob_outlet, + (x->x_f2 > 0 ? SHARED_INT_MAX : SHARED_INT_MIN)); +} + +static void rdiv_float(t_rbinop *x, t_float f) +{ + x->x_f1 = f; + rdiv_bang(x); +} + +static void *rdiv_new(t_floatarg f) +{ + t_rbinop *x = (t_rbinop *)pd_new(rdiv_class); + floatinlet_new((t_object *)x, &x->x_f2); + outlet_new((t_object *)x, &s_float); + x->x_f1 = 0; + x->x_f2 = f; /* CHECKED (refman's error) */ + return (x); +} + +/* The implementation of signal relational operators below has been tuned + somewhat, mostly in order to get rid of costly int->float conversions. + Loops are not hand-unrolled, because these have proven to be slower + in all the tests performed so far. LATER find a good soul willing to + make a serious profiling research... */ + +typedef struct _sigeq +{ + t_sic x_sic; + int x_algo; +} t_sigeq; + +static t_class *sigeq_class; + +static t_int *sigeq_perform0(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_shared_floatint fi; +#ifdef NETTLES_SAFE + int32 truebits; + fi.fi_f = 1.; + truebits = fi.fi_i; +#endif + while (nblock--) + { +#ifdef NETTLES_SAFE + fi.fi_i = ~((*in1++ == *in2++) - 1) & truebits; +#else + fi.fi_i = ~((*in1++ == *in2++) - 1) & SHARED_TRUEBITS; +#endif + *out++ = fi.fi_f; + } + return (w + 5); +} + +static t_int *sigeq_perform1(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + while (nblock--) *out++ = (*in1++ == *in2++); + return (w + 5); +} + +static t_int *sigeq_perform2(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + for (; nblock; nblock -= 8, in1 += 8, in2 += 8, out += 8) + { + float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; + float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; + float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; + float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; + out[0] = f0 == g0; out[1] = f1 == g1; + out[2] = f2 == g2; out[3] = f3 == g3; + out[4] = f4 == g4; out[5] = f5 == g5; + out[6] = f6 == g6; out[7] = f7 == g7; + } + return (w + 5); +} + +static void sigeq_dsp(t_sigeq *x, t_signal **sp) +{ + switch (x->x_algo) + { + case 1: + dsp_add(sigeq_perform1, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); + break; + case 2: + dsp_add(sigeq_perform2, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); + break; + default: + dsp_add(sigeq_perform0, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); + } +} + +static void sigeq__algo(t_sigeq *x, t_floatarg f) +{ + x->x_algo = f; +} + +static void *sigeq_new(t_symbol *s, int ac, t_atom *av) +{ + t_sigeq *x = (t_sigeq *)pd_new(sigeq_class); + if (s == gensym("_==1~")) + x->x_algo = 1; + else if (s == gensym("_==2~")) + x->x_algo = 2; + else + x->x_algo = 0; + sic_inlet((t_sic *)x, 1, 0, 0, ac, av); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +typedef t_sic t_signeq; +static t_class *signeq_class; + +static t_int *signeq_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_shared_floatint fi; + while (nblock--) + { + fi.fi_i = ~((*in1++ != *in2++) - 1) & SHARED_TRUEBITS; + *out++ = fi.fi_f; + } + return (w + 5); +} + +static void signeq_dsp(t_signeq *x, t_signal **sp) +{ + dsp_add(signeq_perform, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *signeq_new(t_symbol *s, int ac, t_atom *av) +{ + t_signeq *x = (t_signeq *)pd_new(signeq_class); + sic_inlet((t_sic *)x, 1, 0, 0, ac, av); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +typedef t_sic t_siglt; +static t_class *siglt_class; + +static t_int *siglt_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_shared_floatint fi; + while (nblock--) + { + fi.fi_i = ~((*in1++ < *in2++) - 1) & SHARED_TRUEBITS; + *out++ = fi.fi_f; + } + return (w + 5); +} + +static void siglt_dsp(t_siglt *x, t_signal **sp) +{ + dsp_add(siglt_perform, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *siglt_new(t_symbol *s, int ac, t_atom *av) +{ + t_siglt *x = (t_siglt *)pd_new(siglt_class); + sic_inlet((t_sic *)x, 1, 0, 0, ac, av); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +typedef t_sic t_siggt; +static t_class *siggt_class; + +static t_int *siggt_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_shared_floatint fi; + while (nblock--) + { + fi.fi_i = ~((*in1++ > *in2++) - 1) & SHARED_TRUEBITS; + *out++ = fi.fi_f; + } + return (w + 5); +} + +static void siggt_dsp(t_siggt *x, t_signal **sp) +{ + dsp_add(siggt_perform, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *siggt_new(t_symbol *s, int ac, t_atom *av) +{ + t_siggt *x = (t_siggt *)pd_new(siggt_class); + sic_inlet((t_sic *)x, 1, 0, 0, ac, av); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +typedef t_sic t_sigleq; +static t_class *sigleq_class; + +static t_int *sigleq_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_shared_floatint fi; + while (nblock--) + { + fi.fi_i = ~((*in1++ <= *in2++) - 1) & SHARED_TRUEBITS; + *out++ = fi.fi_f; + } + return (w + 5); +} + +static void sigleq_dsp(t_sigleq *x, t_signal **sp) +{ + dsp_add(sigleq_perform, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *sigleq_new(t_symbol *s, int ac, t_atom *av) +{ + t_sigleq *x = (t_sigleq *)pd_new(sigleq_class); + sic_inlet((t_sic *)x, 1, 0, 0, ac, av); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +typedef t_sic t_siggeq; +static t_class *siggeq_class; + +static t_int *siggeq_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_shared_floatint fi; + while (nblock--) + { + fi.fi_i = ~((*in1++ >= *in2++) - 1) & SHARED_TRUEBITS; + *out++ = fi.fi_f; + } + return (w + 5); +} + +static void siggeq_dsp(t_siggeq *x, t_signal **sp) +{ + dsp_add(siggeq_perform, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *siggeq_new(t_symbol *s, int ac, t_atom *av) +{ + t_siggeq *x = (t_siggeq *)pd_new(siggeq_class); + sic_inlet((t_sic *)x, 1, 0, 0, ac, av); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +typedef t_sic t_sigrminus; +static t_class *sigrminus_class; + +static t_int *sigrminus_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + while (nblock--) *out++ = *in2++ - *in1++; + return (w + 5); +} + +static void sigrminus_dsp(t_sigrminus *x, t_signal **sp) +{ + dsp_add(sigrminus_perform, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *sigrminus_new(t_symbol *s, int ac, t_atom *av) +{ + t_sigrminus *x = (t_sigrminus *)pd_new(sigrminus_class); + sic_inlet((t_sic *)x, 1, 0, 0, ac, av); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +typedef t_sic t_sigrover; +static t_class *sigrover_class; + +static t_int *sigrover_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + while (nblock--) + { + t_float f1 = *in1++; + /* CHECKED incompatible: c74 outputs NaNs. + The line below is consistent with Pd's /~, LATER rethink. */ + /* LATER multiply by reciprocal if in1 has no signal feeders */ + *out++ = (f1 == 0. ? 0. : *in2++ / f1); + } + return (w + 5); +} + +static void sigrover_dsp(t_sigrover *x, t_signal **sp) +{ + dsp_add(sigrover_perform, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *sigrover_new(t_symbol *s, int ac, t_atom *av) +{ + t_sigrover *x = (t_sigrover *)pd_new(sigrover_class); + /* CHECKED default 0 (refman's error), LATER rethink */ + sic_inlet((t_sic *)x, 1, 0, 0, ac, av); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +typedef t_sic t_sigmod; +static t_class *sigmod_class; + +static t_int *sigmod_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + while (nblock--) + { + t_float f1 = *in1++; + t_float f2 = *in2++; + /* LATER think about using ieee-754 normalization tricks */ + *out++ = (f2 == 0. ? 0. /* CHECKED */ + : fmod(f1, f2)); + } + return (w + 5); +} + +static void sigmod_dsp(t_sigmod *x, t_signal **sp) +{ + dsp_add(sigmod_perform, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *sigmod_new(t_symbol *s, int ac, t_atom *av) +{ + t_sigmod *x = (t_sigmod *)pd_new(sigmod_class); + /* CHECKED default 0 (refman's error), LATER rethink */ + sic_inlet((t_sic *)x, 1, 0, 0, ac, av); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +typedef struct _sigaccum +{ + t_sic x_sic; + t_float x_sum; +} t_sigaccum; + +static t_class *sigaccum_class; + +static t_int *sigaccum_perform(t_int *w) +{ + t_sigaccum *x = (t_sigaccum *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_float sum = x->x_sum; + while (nblock--) *out++ = (sum += *in++); + x->x_sum = sum; + return (w + 5); +} + +static void sigaccum_dsp(t_sigaccum *x, t_signal **sp) +{ + dsp_add(sigaccum_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void sigaccum_bang(t_sigaccum *x) +{ + x->x_sum = 0; +} + +static void sigaccum_set(t_sigaccum *x, t_floatarg f) +{ + x->x_sum = f; +} + +static void *sigaccum_new(t_floatarg f) +{ + t_sigaccum *x = (t_sigaccum *)pd_new(sigaccum_class); + x->x_sum = f; + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void allnettles_setup(void) +{ + rminus_class = class_new(gensym("!-"), + (t_newmethod)rminus_new, 0, + sizeof(t_rbinop), 0, A_DEFFLOAT, 0); + class_addbang(rminus_class, rminus_bang); + class_addfloat(rminus_class, rminus_float); + rdiv_class = class_new(gensym("!/"), + (t_newmethod)rdiv_new, 0, + sizeof(t_rbinop), 0, A_DEFFLOAT, 0); + class_addbang(rdiv_class, rdiv_bang); + class_addfloat(rdiv_class, rdiv_float); + + sigeq_class = class_new(gensym("==~"), + (t_newmethod)sigeq_new, 0, + sizeof(t_sigeq), 0, A_GIMME, 0); + class_addcreator((t_newmethod)sigeq_new, + gensym("_==1~"), A_GIMME, 0); + class_addcreator((t_newmethod)sigeq_new, + gensym("_==2~"), A_GIMME, 0); + sic_setup(sigeq_class, sigeq_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(sigeq_class, (t_method)sigeq__algo, + gensym("_algo"), A_FLOAT, 0); + + signeq_class = class_new(gensym("!=~"), + (t_newmethod)signeq_new, 0, + sizeof(t_signeq), 0, A_GIMME, 0); + sic_setup(signeq_class, signeq_dsp, SIC_FLOATTOSIGNAL); + siglt_class = class_new(gensym("<~"), + (t_newmethod)siglt_new, 0, + sizeof(t_siglt), 0, A_GIMME, 0); + sic_setup(siglt_class, siglt_dsp, SIC_FLOATTOSIGNAL); + siggt_class = class_new(gensym(">~"), + (t_newmethod)siggt_new, 0, + sizeof(t_siggt), 0, A_GIMME, 0); + sic_setup(siggt_class, siggt_dsp, SIC_FLOATTOSIGNAL); + sigleq_class = class_new(gensym("<=~"), + (t_newmethod)sigleq_new, 0, + sizeof(t_sigleq), 0, A_GIMME, 0); + sic_setup(sigleq_class, sigleq_dsp, SIC_FLOATTOSIGNAL); + siggeq_class = class_new(gensym(">=~"), + (t_newmethod)siggeq_new, 0, + sizeof(t_siggeq), 0, A_GIMME, 0); + sic_setup(siggeq_class, siggeq_dsp, SIC_FLOATTOSIGNAL); + sigrminus_class = class_new(gensym("!-~"), + (t_newmethod)sigrminus_new, 0, + sizeof(t_sigrminus), 0, A_GIMME, 0); + sic_setup(sigrminus_class, sigrminus_dsp, SIC_FLOATTOSIGNAL); + sigrover_class = class_new(gensym("!/~"), + (t_newmethod)sigrover_new, 0, + sizeof(t_sigrover), 0, A_GIMME, 0); + sic_setup(sigrover_class, sigrover_dsp, SIC_FLOATTOSIGNAL); + sigmod_class = class_new(gensym("%~"), + (t_newmethod)sigmod_new, 0, + sizeof(t_sigmod), 0, A_GIMME, 0); + sic_setup(sigmod_class, sigmod_dsp, SIC_FLOATTOSIGNAL); + sigaccum_class = class_new(gensym("+=~"), + (t_newmethod)sigaccum_new, 0, + sizeof(t_sigaccum), 0, A_DEFFLOAT, 0); + sic_setup(sigaccum_class, sigaccum_dsp, SIC_FLOATTOSIGNAL); + class_addbang(sigaccum_class, sigaccum_bang); + class_addmethod(sigaccum_class, (t_method)sigaccum_set, + gensym("set"), A_FLOAT, 0); +} diff --git a/cyclone/shadow/shadow.h b/cyclone/shadow/shadow.h new file mode 100644 index 0000000..aefc46e --- /dev/null +++ b/cyclone/shadow/shadow.h @@ -0,0 +1,13 @@ +/* Copyright (c) 2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#ifndef __SHADOW_H__ +#define __SHADOW_H__ + +void allnettles_setup(void); +void alldummies_setup(void); +int dummy_nreplacements(void); +void dummy_printreplacements(char *msg); + +#endif diff --git a/cyclone/sickle/Clip.c b/cyclone/sickle/Clip.c new file mode 100644 index 0000000..2888be1 --- /dev/null +++ b/cyclone/sickle/Clip.c @@ -0,0 +1,59 @@ +/* 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. */ + +/* Clip~ substitution is needed to handle signal input for lo and hi */ + +#include "m_pd.h" +#include "sickle/sic.h" + +#define CLIP_DEFLO 0. +#define CLIP_DEFHI 0. + +typedef t_sic t_clip; +static t_class *clip_class; + +static t_int *clip_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *in3 = (t_float *)(w[4]); + t_float *out = (t_float *)(w[5]); + while (nblock--) + { + float f = *in1++; + float lo = *in2++; + float hi = *in3++; + if (f < lo) + *out++ = lo; + else if (f > hi) + *out++ = hi; + else + *out++ = f; + } + return (w + 6); +} + +static void clip_dsp(t_clip *x, t_signal **sp) +{ + dsp_add(clip_perform, 5, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); +} + +static void *clip_new(t_symbol *s, int ac, t_atom *av) +{ + t_clip *x = (t_clip *)pd_new(clip_class); + sic_inlet((t_sic *)x, 1, CLIP_DEFLO, 0, ac, av); + sic_inlet((t_sic *)x, 2, CLIP_DEFHI, 1, ac, av); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void Clip_tilde_setup(void) +{ + clip_class = class_new(gensym("Clip~"), + (t_newmethod)clip_new, 0, + sizeof(t_clip), 0, A_GIMME, 0); + sic_setup(clip_class, clip_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/Line.c b/cyclone/sickle/Line.c new file mode 100644 index 0000000..f1d2b18 --- /dev/null +++ b/cyclone/sickle/Line.c @@ -0,0 +1,299 @@ +/* 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/grow.h" +#include "common/loud.h" +#include "sickle/sic.h" + +//#define LINE_DEBUG + +#ifndef PD_BADFLOAT +#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \ + (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000)) +#endif + +#define LINE_INISIZE 64 /* LATER rethink */ +#define LINE_MAXSIZE 64 + +typedef struct _lineseg +{ + float s_target; + float s_delta; +} t_lineseg; + +typedef struct _line +{ + t_sic x_sic; + float x_value; + float x_target; + float x_delta; + int x_deltaset; + float x_inc; + float x_biginc; + float x_ksr; + int x_nleft; + int x_retarget; + int x_size; /* as allocated */ + int x_nsegs; /* as used */ + t_lineseg *x_curseg; + t_lineseg *x_segs; + t_lineseg x_segini[LINE_INISIZE]; + t_clock *x_clock; + t_outlet *x_bangout; +#ifdef LINE_DEBUG + int dbg_nretargets; + int dbg_exitpoint; + int dbg_npoints; +#endif +} t_line; + +static t_class *line_class; + +static void line_tick(t_line *x) +{ + outlet_bang(x->x_bangout); +#ifdef LINE_DEBUG + post("exit point %d, after %d retarget calls", + x->dbg_exitpoint, x->dbg_nretargets); + post("at value %g, after last %d npoints, with inc %g, biginc %g", + x->x_value, x->dbg_npoints, x->x_inc, x->x_biginc); + x->dbg_nretargets = x->dbg_exitpoint = x->dbg_npoints = 0; +#endif +} + +static t_int *line_perform(t_int *w) +{ + t_line *x = (t_line *)(w[1]); + t_float *out = (t_float *)(w[2]); + int nblock = (int)(w[3]); + int nxfer = x->x_nleft; + float curval = x->x_value; + float inc = x->x_inc; + float biginc = x->x_biginc; + if (PD_BADFLOAT(curval)) /* LATER rethink */ + curval = x->x_value = 0; +retarget: + if (x->x_retarget) + { + float target = x->x_curseg->s_target; + float delta = x->x_curseg->s_delta; + int npoints = delta * x->x_ksr + 0.5; /* LATER rethink */ +#ifdef LINE_DEBUG + x->dbg_nretargets++; +#endif + x->x_nsegs--; + x->x_curseg++; + while (npoints <= 0) + { + curval = x->x_value = target; + if (x->x_nsegs) + { + target = x->x_curseg->s_target; + delta = x->x_curseg->s_delta; + npoints = delta * x->x_ksr + 0.5; /* LATER rethink */ + x->x_nsegs--; + x->x_curseg++; + } + else + { + while (nblock--) *out++ = curval; + x->x_nleft = 0; +#ifdef LINE_DEBUG + x->dbg_exitpoint = 1; +#endif + clock_delay(x->x_clock, 0); + x->x_retarget = 0; + return (w + 4); + } + } + nxfer = x->x_nleft = npoints; + inc = x->x_inc = (target - x->x_value) / (float)npoints; + x->x_biginc = (int)(w[3]) * inc; + biginc = nblock * inc; + x->x_target = target; + x->x_retarget = 0; +#ifdef LINE_DEBUG + x->dbg_npoints = npoints; +#endif + } + if (nxfer >= nblock) + { + if ((x->x_nleft -= nblock) == 0) + { + if (x->x_nsegs) x->x_retarget = 1; + else + { +#ifdef LINE_DEBUG + x->dbg_exitpoint = 2; +#endif + clock_delay(x->x_clock, 0); + } + x->x_value = x->x_target; + } + else x->x_value += biginc; + while (nblock--) + *out++ = curval, curval += inc; + } + else if (nxfer > 0) + { + nblock -= nxfer; + do + *out++ = curval, curval += inc; + while (--nxfer); + curval = x->x_value = x->x_target; + if (x->x_nsegs) + { + x->x_retarget = 1; + goto retarget; + } + else + { + while (nblock--) *out++ = curval; + x->x_nleft = 0; +#ifdef LINE_DEBUG + x->dbg_exitpoint = 3; +#endif + clock_delay(x->x_clock, 0); + } + } + else while (nblock--) *out++ = curval; + return (w + 4); +} + +static void line_float(t_line *x, t_float f) +{ + if (x->x_deltaset) + { + x->x_deltaset = 0; + x->x_target = f; + x->x_nsegs = 1; + x->x_curseg = x->x_segs; + x->x_curseg->s_target = f; + x->x_curseg->s_delta = x->x_delta; + x->x_retarget = 1; + } + else + { + x->x_value = x->x_target = f; + x->x_nsegs = 0; + x->x_curseg = 0; + x->x_nleft = 0; + x->x_retarget = 0; + } +} + +static void line_ft1(t_line *x, t_floatarg f) +{ + x->x_delta = f; + x->x_deltaset = (f > 0); +} + +static void line_list(t_line *x, t_symbol *s, int ac, t_atom *av) +{ + int natoms, nsegs, odd; + t_atom *ap; + t_lineseg *segp; + for (natoms = 0, ap = av; natoms < ac; natoms++, ap++) + if (ap->a_type != A_FLOAT) break; /* CHECKME */ + if (!natoms) + return; /* CHECKME */ + odd = natoms % 2; + nsegs = natoms / 2; + if (odd) nsegs++; + if (nsegs > x->x_size) + { + int ns = nsegs; + x->x_segs = grow_nodata(&ns, &x->x_size, x->x_segs, + LINE_INISIZE, x->x_segini, + sizeof(*x->x_segs)); + if (ns < nsegs) + { + natoms = ns * 2; + nsegs = ns; + } + } + x->x_nsegs = nsegs; +#ifdef LINE_DEBUG + post("%d segments:", x->x_nsegs); +#endif + segp = x->x_segs; + if (odd) nsegs--; + while (nsegs--) + { + segp->s_target = av++->a_w.w_float; + segp->s_delta = av++->a_w.w_float; +#ifdef LINE_DEBUG + post("%g %g", segp->s_target, segp->s_delta); +#endif + segp++; + } + if (odd) + { + segp->s_target = av->a_w.w_float; + segp->s_delta = 0; +#ifdef LINE_DEBUG + post("%g %g", segp->s_target, segp->s_delta); +#endif + } + x->x_deltaset = 0; + x->x_target = x->x_segs->s_target; + x->x_curseg = x->x_segs; + x->x_retarget = 1; +} + +/* CHECKED no stop, pity... */ +#if 0 +static void line_stop(t_line *x) +{ + x->x_target = x->x_value; + x->x_nleft = 0; + x->x_retarget = 0; + x->x_nsegs = 0; + x->x_curseg = 0; +} +#endif + +static void line_dsp(t_line *x, t_signal **sp) +{ + dsp_add(line_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); + x->x_ksr = sp[0]->s_sr * 0.001; +} + +static void line_free(t_line *x) +{ + if (x->x_segs != x->x_segini) + freebytes(x->x_segs, x->x_size * sizeof(*x->x_segs)); + if (x->x_clock) clock_free(x->x_clock); +} + +static void *line_new(t_floatarg f) +{ + t_line *x = (t_line *)pd_new(line_class); + x->x_value = x->x_target = f; + x->x_deltaset = 0; + x->x_nleft = 0; + x->x_retarget = 0; + x->x_size = LINE_INISIZE; + x->x_nsegs = 0; + x->x_segs = x->x_segini; + x->x_curseg = 0; + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); + outlet_new((t_object *)x, &s_signal); + x->x_bangout = outlet_new((t_object *)x, &s_bang); + x->x_clock = clock_new(x, (t_method)line_tick); + return (x); +} + +void Line_tilde_setup(void) +{ + line_class = class_new(gensym("Line~"), + (t_newmethod)line_new, 0, + sizeof(t_line), 0, A_DEFFLOAT, 0); + sic_setup(line_class, line_dsp, SIC_NOMAINSIGNALIN); + class_addfloat(line_class, line_float); + class_addlist(line_class, line_list); + class_addmethod(line_class, (t_method)line_ft1, + gensym("ft1"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/Makefile b/cyclone/sickle/Makefile new file mode 100644 index 0000000..61aa444 --- /dev/null +++ b/cyclone/sickle/Makefile @@ -0,0 +1,3 @@ +ROOT_DIR = ../.. +redefault: allsickles.c default +include $(ROOT_DIR)/Makefile.common diff --git a/cyclone/sickle/Makefile.objects b/cyclone/sickle/Makefile.objects new file mode 100644 index 0000000..2edb12c --- /dev/null +++ b/cyclone/sickle/Makefile.objects @@ -0,0 +1,11 @@ +SHARED_OBJECTS = \ +unstable/forky.o \ +unstable/fragile.o \ +common/loud.o \ +common/grow.o \ +common/vefl.o \ +common/binport.o \ +common/port.o \ +hammer/file.o \ +sickle/sic.o \ +sickle/arsic.o diff --git a/cyclone/sickle/Makefile.sources b/cyclone/sickle/Makefile.sources new file mode 100644 index 0000000..e807a06 --- /dev/null +++ b/cyclone/sickle/Makefile.sources @@ -0,0 +1,67 @@ +CX_SOURCES = \ +sickle.c + +OTHER_SOURCES = \ +allsickles.c \ +abs.c \ +acos.c \ +acosh.c \ +allpass.c \ +asin.c \ +asinh.c \ +atan.c \ +atan2.c \ +atanh.c \ +average.c \ +avg.c \ +bitand.c \ +bitnot.c \ +bitor.c \ +bitshift.c \ +bitxor.c \ +capture.c \ +cartopol.c \ +change.c \ +click.c \ +Clip.c \ +comb.c \ +cosh.c \ +cosx.c \ +count.c \ +cycle.c \ +delay.c \ +delta.c \ +deltaclip.c \ +edge.c \ +frameaccum.c \ +framedelta.c \ +index.c \ +kink.c \ +Line.c \ +linedrive.c \ +log.c \ +lookup.c \ +minmax.c \ +peakamp.c \ +peek.c \ +phasewrap.c \ +play.c \ +poltocar.c \ +pow.c \ +rand.c \ +rampsmooth.c \ +record.c \ +sah.c \ +Scope.c \ +sinh.c \ +sinx.c \ +slide.c \ +Snapshot.c \ +spike.c \ +tanh.c \ +tanx.c \ +train.c \ +trapezoid.c \ +triangle.c \ +vectral.c \ +wave.c diff --git a/cyclone/sickle/Scope.c b/cyclone/sickle/Scope.c new file mode 100644 index 0000000..75e825d --- /dev/null +++ b/cyclone/sickle/Scope.c @@ -0,0 +1,1043 @@ +/* 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 cache gui commands */ +/* LATER think about resizing scheme. Currently mouse events are not bound + to any part of Scope~'s 'widget' as such, but to a special item, which is + created only for a selected Scope~. For the other scheme see the 'comment' + class (no indicator there, though -- neither a handle, nor a pointer change). + One way or the other, the traffic from the gui layer should be kept possibly + low, at least in run-mode. */ + +#include <stdio.h> +#include <string.h> +#include "m_pd.h" +#include "g_canvas.h" +#include "common/loud.h" +#include "common/grow.h" +#include "unstable/forky.h" +#include "sickle/sic.h" + +//#define SCOPE_DEBUG + +/* these are powers of 2 + margins */ +#define SCOPE_DEFWIDTH 130 /* CHECKED */ +#define SCOPE_MINWIDTH 66 +#define SCOPE_DEFHEIGHT 130 /* CHECKED */ +#define SCOPE_MINHEIGHT 34 +#define SCOPE_DEFPERIOD 256 +#define SCOPE_MINPERIOD 2 +#define SCOPE_MAXPERIOD 8092 +#define SCOPE_DEFBUFSIZE 128 +#define SCOPE_MINBUFSIZE 8 +#define SCOPE_MAXBUFSIZE 800 /* LATER rethink */ +#define SCOPE_WARNBUFSIZE 256 +#define SCOPE_DEFMINVAL -1. +#define SCOPE_DEFMAXVAL 1. +#define SCOPE_DEFDELAY 0 +#define SCOPE_MINDELAY 0 +#define SCOPE_TRIGLINEMODE 0 +#define SCOPE_TRIGUPMODE 1 +#define SCOPE_TRIGDOWNMODE 2 +#define SCOPE_DEFTRIGMODE SCOPE_TRIGLINEMODE +#define SCOPE_MINTRIGMODE SCOPE_TRIGLINEMODE +#define SCOPE_MAXTRIGMODE SCOPE_TRIGDOWNMODE +#define SCOPE_DEFTRIGLEVEL 0. +#define SCOPE_MINCOLOR 0 +#define SCOPE_MAXCOLOR 255 +#define SCOPE_DEFFGRED 102 +#define SCOPE_DEFFGGREEN 255 +#define SCOPE_DEFFGBLUE 51 +#define SCOPE_DEFBGRED 135 +#define SCOPE_DEFBGGREEN 135 +#define SCOPE_DEFBGBLUE 135 +#define SCOPE_SELCOLOR "#8080ff" /* a bit lighter shade of blue */ +#define SCOPE_FGWIDTH 0.7 /* line width is float */ +#define SCOPE_GRIDWIDTH 0.9 +#define SCOPE_SELBDWIDTH 3.0 +#define SCOPEHANDLE_WIDTH 10 /* item size is int */ +#define SCOPEHANDLE_HEIGHT 10 +/* these are performance-related hacks, LATER investigate */ +#define SCOPE_GUICHUNKMONO 16 +#define SCOPE_GUICHUNKXY 32 + +typedef struct _scope +{ + t_sic x_sic; + t_glist *x_glist; + t_canvas *x_canvas; /* also an 'isvised' flag */ + char x_tag[64]; + char x_fgtag[64]; + char x_bgtag[64]; + char x_gridtag[64]; + int x_width; + int x_height; + float x_minval; + float x_maxval; + int x_delay; + int x_trigmode; + float x_triglevel; + unsigned char x_fgred; + unsigned char x_fggreen; + unsigned char x_fgblue; + unsigned char x_bgred; + unsigned char x_bggreen; + unsigned char x_bgblue; + int x_xymode; + float *x_xbuffer; + float *x_ybuffer; + float x_xbufini[SCOPE_DEFBUFSIZE]; + float x_ybufini[SCOPE_DEFBUFSIZE]; + int x_allocsize; + int x_bufsize; + int x_bufphase; + int x_period; + int x_phase; + int x_precount; + int x_retrigger; + float x_ksr; + float x_currx; + float x_curry; + float x_trigx; + int x_frozen; + t_clock *x_clock; + t_pd *x_handle; +} t_scope; + +typedef struct _scopehandle +{ + t_pd h_pd; + t_scope *h_master; + t_symbol *h_bindsym; + char h_pathname[64]; + char h_outlinetag[64]; + int h_dragon; + int h_dragx; + int h_dragy; +} t_scopehandle; + +static t_class *scope_class; +static t_class *scopehandle_class; + +static void scope_clear(t_scope *x, int withdelay) +{ + x->x_bufphase = 0; + x->x_phase = 0; + x->x_precount = (withdelay ? (int)(x->x_delay * x->x_ksr) : 0); + /* CHECKED delay does not matter (refman is wrong) */ + x->x_retrigger = (x->x_trigmode != SCOPE_TRIGLINEMODE); + x->x_trigx = x->x_triglevel; +} + +static t_int *scope_monoperform(t_int *w) +{ + t_scope *x = (t_scope *)(w[1]); + int bufphase = x->x_bufphase; + int bufsize = x->x_bufsize; + if (bufphase < bufsize) + { + int nblock = (int)(w[2]); + if (x->x_precount >= nblock) + x->x_precount -= nblock; + else + { + t_float *in = (t_float *)(w[3]); + int phase = x->x_phase; + int period = x->x_period; + float *bp1 = x->x_xbuffer + bufphase; + float *bp2 = x->x_ybuffer + bufphase; + float currx = x->x_currx; + if (x->x_precount > 0) + { + nblock -= x->x_precount; + in += x->x_precount; + x->x_precount = 0; + } + while (x->x_retrigger) + { + float triglevel = x->x_triglevel; + if (x->x_trigmode == SCOPE_TRIGUPMODE) + { + if (x->x_trigx < triglevel) + { + while (nblock--) if (*in++ >= triglevel) + { + x->x_retrigger = 0; + break; + } + } + else while (nblock--) if (*in++ < triglevel) + { + x->x_trigx = triglevel - 1.; + break; + } + } + else + { + if (x->x_trigx > triglevel) + { + while (nblock--) if (*in++ <= triglevel) + { + x->x_retrigger = 0; + break; + } + } + else while (nblock--) if (*in++ > triglevel) + { + x->x_trigx = triglevel + 1.; + break; + } + } + if (nblock <= 0) + return (w + 4); + } + while (nblock--) + { + if (phase) + { + float f = *in++; + /* CHECKED */ + if ((currx < 0 && (f < currx || f > -currx)) || + (currx > 0 && (f > currx || f < -currx))) + currx = f; + } + else currx = *in++; + if (currx != currx) + currx = 0.; /* CHECKED NaNs bashed to zeros */ + if (++phase == period) + { + phase = 0; + if (++bufphase == bufsize) + { + *bp1 = *bp2 = currx; + clock_delay(x->x_clock, 0); + break; + } + else *bp1++ = *bp2++ = currx; + } + } + x->x_currx = currx; + x->x_bufphase = bufphase; + x->x_phase = phase; + } + } + return (w + 4); +} + +static t_int *scope_xyperform(t_int *w) +{ + t_scope *x = (t_scope *)(w[1]); + int bufphase = x->x_bufphase; + int bufsize = x->x_bufsize; + if (bufphase < bufsize) + { + int nblock = (int)(w[2]); + if (x->x_precount >= nblock) + x->x_precount -= nblock; + else + { + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + int phase = x->x_phase; + int period = x->x_period; + float freq = 1. / period; + float *bp1 = x->x_xbuffer + bufphase; + float *bp2 = x->x_ybuffer + bufphase; + float currx = x->x_currx; + float curry = x->x_curry; + if (x->x_precount > 0) + { + nblock -= x->x_precount; + in1 += x->x_precount; + in2 += x->x_precount; + x->x_precount = 0; + } + if (x->x_retrigger) + { + /* CHECKME and FIXME */ + x->x_retrigger = 0; + } + while (nblock--) + { + if (phase) + { + /* CHECKME */ + currx += *in1++; + curry += *in2++; + } + else + { + currx = *in1++; + curry = *in2++; + } + if (currx != currx) + currx = 0.; /* CHECKME NaNs bashed to zeros */ + if (curry != curry) + curry = 0.; /* CHECKME NaNs bashed to zeros */ + if (++phase == period) + { + phase = 0; + if (++bufphase == bufsize) + { + *bp1 = currx * freq; + *bp2 = curry * freq; + clock_delay(x->x_clock, 0); + break; + } + else + { + *bp1++ = currx * freq; + *bp2++ = curry * freq; + } + } + } + x->x_currx = currx; + x->x_curry = curry; + x->x_bufphase = bufphase; + x->x_phase = phase; + } + } + return (w + 5); +} + +static void scope_setxymode(t_scope *x, int xymode); + +static void scope_dsp(t_scope *x, t_signal **sp) +{ + x->x_ksr = sp[0]->s_sr * 0.001; + scope_setxymode(x, + forky_hasfeeders((t_object *)x, x->x_glist, 1, &s_signal)); + if (x->x_xymode) + dsp_add(scope_xyperform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + else + dsp_add(scope_monoperform, 3, x, sp[0]->s_n, sp[0]->s_vec); +} + +static t_canvas *scope_getcanvas(t_scope *x, t_glist *glist) +{ + if (glist != x->x_glist) + { + bug("scope_getcanvas"); + x->x_glist = glist; + } + return (x->x_canvas = glist_getcanvas(glist)); +} + +/* answers the question: ``can we draw and where to?'' */ +static t_canvas *scope_isvisible(t_scope *x) +{ + return (glist_isvisible(x->x_glist) ? x->x_canvas : 0); +} + +static void scope_period(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float period = (s ? x->x_period : SCOPE_DEFPERIOD); + int result = loud_floatarg(*(t_pd *)x, (s ? 0 : 2), ac, av, &period, + SCOPE_MINPERIOD, SCOPE_MAXPERIOD, + /* LATER rethink warning rules */ + (s ? LOUD_CLIP : LOUD_CLIP | LOUD_WARN), + (s ? 0 : LOUD_WARN), "samples per element"); + if (!s || result == LOUD_ARGOK || result == LOUD_ARGOVER) + { + x->x_period = (int)period; + scope_clear(x, 0); + } +} + +static void scope_float(t_scope *x, t_float f) +{ + t_atom at; + SETFLOAT(&at, f); + scope_period(x, &s_float, 1, &at); +} + +static void scope_bufsize(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float bufsize = (s ? x->x_bufsize : SCOPE_DEFBUFSIZE); + int result = loud_floatarg(*(t_pd *)x, (s ? 0 : 4), ac, av, &bufsize, + SCOPE_MINBUFSIZE, SCOPE_WARNBUFSIZE, + /* LATER rethink warning rules */ + (s ? LOUD_CLIP : LOUD_CLIP | LOUD_WARN), + (s ? 0 : LOUD_WARN), "display elements"); + if (result == LOUD_ARGOVER) + { + bufsize = (s ? x->x_bufsize : SCOPE_DEFBUFSIZE); + result = loud_floatarg(*(t_pd *)x, (s ? 0 : 4), ac, av, &bufsize, + 0, SCOPE_MAXBUFSIZE, 0, LOUD_CLIP | LOUD_WARN, + "display elements"); + } + if (!s) + { + x->x_allocsize = SCOPE_DEFBUFSIZE; + x->x_bufsize = 0; + x->x_xbuffer = x->x_xbufini; + x->x_ybuffer = x->x_ybufini; + } + if (!s || result == LOUD_ARGOK) + { + int newsize = (int)bufsize; + if (newsize > x->x_allocsize) + { + int nrequested = newsize; + int allocsize = x->x_allocsize; + int oldsize = x->x_bufsize; + x->x_xbuffer = grow_withdata(&nrequested, &oldsize, + &allocsize, x->x_xbuffer, + SCOPE_DEFBUFSIZE, x->x_xbufini, + sizeof(*x->x_xbuffer)); + if (nrequested == newsize) + { + allocsize = x->x_allocsize; + oldsize = x->x_bufsize; + x->x_ybuffer = grow_withdata(&nrequested, &oldsize, + &allocsize, x->x_ybuffer, + SCOPE_DEFBUFSIZE, x->x_ybufini, + sizeof(*x->x_ybuffer)); + } + if (nrequested == newsize) + { + x->x_allocsize = allocsize; + x->x_bufsize = newsize; + } + else + { + if (x->x_xbuffer != x->x_xbufini) + freebytes(x->x_xbuffer, + x->x_allocsize * sizeof(*x->x_xbuffer)); + if (x->x_ybuffer != x->x_ybufini) + freebytes(x->x_ybuffer, + x->x_allocsize * sizeof(*x->x_ybuffer)); + x->x_allocsize = SCOPE_DEFBUFSIZE; + x->x_bufsize = SCOPE_DEFBUFSIZE; + x->x_xbuffer = x->x_xbufini; + x->x_ybuffer = x->x_ybufini; + } + } + else x->x_bufsize = newsize; + scope_clear(x, 0); + } +} + +static void scope_range(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float minval = (s ? x->x_minval : SCOPE_DEFMINVAL); + t_float maxval = (s ? x->x_maxval : SCOPE_DEFMAXVAL); + loud_floatarg(*(t_pd *)x, (s ? 0 : 5), ac, av, &minval, 0, 0, 0, 0, 0); + loud_floatarg(*(t_pd *)x, (s ? 1 : 6), ac, av, &maxval, 0, 0, 0, 0, 0); + /* CHECKME swapping, ignoring if equal */ + if (minval < maxval) + { + x->x_minval = minval; + x->x_maxval = maxval; + } + else if (minval > maxval) + { + x->x_minval = maxval; + x->x_maxval = minval; + } + else if (!s) + { + x->x_minval = SCOPE_DEFMINVAL; + x->x_maxval = SCOPE_DEFMAXVAL; + } +} + +static void scope_delay(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float delay = (s ? x->x_delay : SCOPE_DEFDELAY); + int result = loud_floatarg(*(t_pd *)x, (s ? 0 : 7), ac, av, &delay, + SCOPE_MINDELAY, 0, + LOUD_CLIP | LOUD_WARN, 0, "delay"); + if (!s || result == LOUD_ARGOK) + x->x_delay = delay; +} + +static void scope_trigger(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float trigmode = (s ? x->x_trigmode : SCOPE_DEFTRIGMODE); + loud_floatarg(*(t_pd *)x, (s ? 0 : 9), ac, av, &trigmode, + SCOPE_MINTRIGMODE, SCOPE_MAXTRIGMODE, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, + "trigger mode"); + x->x_trigmode = (int)trigmode; + if (x->x_trigmode == SCOPE_TRIGLINEMODE) + x->x_retrigger = 0; +} + +static void scope_triglevel(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float triglevel = (s ? x->x_triglevel : SCOPE_DEFTRIGLEVEL); + loud_floatarg(*(t_pd *)x, (s ? 0 : 10), ac, av, &triglevel, 0, 0, 0, 0, 0); + x->x_triglevel = triglevel; +} + +static void scope_frgb(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float fgred = (s ? x->x_fgred : SCOPE_DEFFGRED); + t_float fggreen = (s ? x->x_fggreen : SCOPE_DEFFGGREEN); + t_float fgblue = (s ? x->x_fgblue : SCOPE_DEFFGBLUE); + t_canvas *cv; + loud_floatarg(*(t_pd *)x, (s ? 0 : 11), ac, av, &fgred, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + loud_floatarg(*(t_pd *)x, (s ? 1 : 12), ac, av, &fggreen, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + loud_floatarg(*(t_pd *)x, (s ? 2 : 13), ac, av, &fgblue, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + x->x_fgred = (int)fgred; + x->x_fggreen = (int)fggreen; + x->x_fgblue = (int)fgblue; + if (cv = scope_isvisible(x)) + sys_vgui(".x%x.c itemconfigure %s -fill #%2.2x%2.2x%2.2x\n", + cv, x->x_fgtag, x->x_fgred, x->x_fggreen, x->x_fgblue); +} + +static void scope_brgb(t_scope *x, t_symbol *s, int ac, t_atom *av) +{ + t_float bgred = (s ? x->x_bgred : SCOPE_DEFBGRED); + t_float bggreen = (s ? x->x_bggreen : SCOPE_DEFBGGREEN); + t_float bgblue = (s ? x->x_bgblue : SCOPE_DEFBGBLUE); + t_canvas *cv; + loud_floatarg(*(t_pd *)x, (s ? 0 : 14), ac, av, &bgred, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + loud_floatarg(*(t_pd *)x, (s ? 1 : 15), ac, av, &bggreen, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + loud_floatarg(*(t_pd *)x, (s ? 2 : 16), ac, av, &bgblue, + SCOPE_MINCOLOR, SCOPE_MAXCOLOR, + LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color"); + x->x_bgred = (int)bgred; + x->x_bggreen = (int)bggreen; + x->x_bgblue = (int)bgblue; + if (cv = scope_isvisible(x)) + sys_vgui(".x%x.c itemconfigure %s -fill #%2.2x%2.2x%2.2x\n", + cv, x->x_bgtag, x->x_bgred, x->x_bggreen, x->x_bgblue); +} + +static void scope_getrect(t_gobj *z, t_glist *glist, + int *xp1, int *yp1, int *xp2, int *yp2) +{ + t_scope *x = (t_scope *)z; + float x1, y1, x2, y2; + x1 = text_xpix((t_text *)x, glist); + y1 = text_ypix((t_text *)x, glist); + x2 = x1 + x->x_width; + y2 = y1 + x->x_height; + *xp1 = x1; + *yp1 = y1; + *xp2 = x2; + *yp2 = y2; +} + +static void scope_displace(t_gobj *z, t_glist *glist, int dx, int dy) +{ + t_scope *x = (t_scope *)z; + t_text *t = (t_text *)z; + t->te_xpix += dx; + t->te_ypix += dy; + if (glist_isvisible(glist)) + { + t_canvas *cv = scope_getcanvas(x, glist); + sys_vgui(".x%x.c move %s %d %d\n", cv, x->x_tag, dx, dy); + canvas_fixlinesfor(cv, t); + } +} + +static void scope_select(t_gobj *z, t_glist *glist, int state) +{ + t_scope *x = (t_scope *)z; + t_canvas *cv = scope_getcanvas(x, glist); + t_scopehandle *sh = (t_scopehandle *)x->x_handle; + if (state) + { + int x1, y1, x2, y2; + scope_getrect(z, glist, &x1, &y1, &x2, &y2); + + sys_vgui(".x%x.c itemconfigure %s -outline blue -width %f -fill %s\n", + cv, x->x_bgtag, SCOPE_SELBDWIDTH, SCOPE_SELCOLOR); + + sys_vgui("canvas %s -width %d -height %d -bg #fedc00 -bd 0\n", + sh->h_pathname, SCOPEHANDLE_WIDTH, SCOPEHANDLE_HEIGHT); + sys_vgui(".x%x.c create window %f %f -anchor nw\ + -width %d -height %d -window %s -tags %s\n", + cv, x2 - (SCOPEHANDLE_WIDTH - SCOPE_SELBDWIDTH), + y2 - (SCOPEHANDLE_HEIGHT - SCOPE_SELBDWIDTH), + SCOPEHANDLE_WIDTH, SCOPEHANDLE_HEIGHT, + sh->h_pathname, x->x_tag); + sys_vgui("bind %s <Button> {pd [concat %s _click 1 \\;]}\n", + sh->h_pathname, sh->h_bindsym->s_name); + sys_vgui("bind %s <ButtonRelease> {pd [concat %s _click 0 \\;]}\n", + sh->h_pathname, sh->h_bindsym->s_name); + sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n", + sh->h_pathname, sh->h_bindsym->s_name); + } + else + { + sys_vgui(".x%x.c itemconfigure %s -outline black -width %f\ + -fill #%2.2x%2.2x%2.2x\n", cv, x->x_bgtag, SCOPE_GRIDWIDTH, + x->x_bgred, x->x_bggreen, x->x_bgblue); + sys_vgui("destroy %s\n", sh->h_pathname); + } +} + +static void scope_delete(t_gobj *z, t_glist *glist) +{ + canvas_deletelinesfor(glist, (t_text *)z); +} + +static void scope_drawfgmono(t_scope *x, t_canvas *cv, + int x1, int y1, int x2, int y2) +{ + int i; + float dx, dy, xx, yy, sc; + float *bp; + dx = (float)(x2 - x1) / (float)x->x_bufsize; + sc = ((float)x->x_height - 2.) / (float)(x->x_maxval - x->x_minval); + sys_vgui(".x%x.c create line \\\n", cv); + for (i = 0, xx = x1, bp = x->x_xbuffer; + i < x->x_bufsize; i++, xx += dx, bp++) + { + yy = (y2 - 1) - sc * (*bp - x->x_minval); +#ifndef SCOPE_DEBUG + if (yy > y2) yy = y2; else if (yy < y1) yy = y1; +#endif + sys_vgui("%d %d \\\n", (int)xx, (int)yy); + } + sys_vgui("-fill #%2.2x%2.2x%2.2x -width %f -tags {%s %s}\n", + x->x_fgred, x->x_fggreen, x->x_fgblue, + SCOPE_FGWIDTH, x->x_fgtag, x->x_tag); + + /* margin lines: masking overflows, so that they appear as gaps, + rather than clipped signal values, LATER rethink */ + sys_vgui(".x%x.c create line %d %d %d %d\ + -fill #%2.2x%2.2x%2.2x -width %f -tags {%s %s}\n", + cv, x1, y1, x2, y1, x->x_bgred, x->x_bggreen, x->x_bgblue, + 1., x->x_fgtag, x->x_tag); + sys_vgui(".x%x.c create line %d %d %d %d\ + -fill #%2.2x%2.2x%2.2x -width %f -tags {%s %s}\n", + cv, x1, y2, x2, y2, x->x_bgred, x->x_bggreen, x->x_bgblue, + 1., x->x_fgtag, x->x_tag); +} + +static void scope_drawfgxy(t_scope *x, t_canvas *cv, + int x1, int y1, int x2, int y2) +{ + int nleft = x->x_bufsize; + float *xbp = x->x_xbuffer, *ybp = x->x_ybuffer; + char chunk[200 * SCOPE_GUICHUNKXY]; /* LATER estimate */ + char *chunkp = chunk; + char cmd1[64], cmd2[64]; + float xx, yy, xsc, ysc; + xx = yy = 0; + /* subtract 1-pixel margins, see below */ + xsc = ((float)x->x_width - 2.) / (float)(x->x_maxval - x->x_minval); + ysc = ((float)x->x_height - 2.) / (float)(x->x_maxval - x->x_minval); + sprintf(cmd1, ".x%x.c create line", (int)cv); + sprintf(cmd2, "-fill #%2.2x%2.2x%2.2x -width %f -tags {%s %s}\n ", + x->x_fgred, x->x_fggreen, x->x_fgblue, + SCOPE_FGWIDTH, x->x_fgtag, x->x_tag); + while (nleft > SCOPE_GUICHUNKXY) + { + int i = SCOPE_GUICHUNKXY; + while (i--) + { + float oldx = xx, oldy = yy, dx, dy; + xx = x1 + xsc * (*xbp++ - x->x_minval); + yy = y2 - ysc * (*ybp++ - x->x_minval); + /* using 1-pixel margins */ + dx = (xx > oldx ? 1. : -1.); + dy = (yy > oldy ? 1. : -1.); +#ifndef SCOPE_DEBUG + if (xx < x1 || xx > x2 || yy < y1 || yy > y2) + continue; +#endif + sprintf(chunkp, "%s %d %d %d %d %s", cmd1, + (int)(xx - dx), (int)(yy - dy), + (int)(xx + dx), (int)(yy + dy), cmd2); + chunkp += strlen(chunkp); + } + if (chunkp > chunk) + sys_gui(chunk); + chunkp = chunk; + nleft -= SCOPE_GUICHUNKXY; + } + while (nleft--) + { + float oldx = xx, oldy = yy, dx, dy; + xx = x1 + xsc * (*xbp++ - x->x_minval); + yy = y2 - ysc * (*ybp++ - x->x_minval); + /* using 1-pixel margins */ + dx = (xx > oldx ? 1. : -1.); + dy = (yy > oldy ? 1. : -1.); +#ifndef SCOPE_DEBUG + if (xx < x1 || xx > x2 || yy < y1 || yy > y2) + continue; +#endif + sprintf(chunkp, "%s %d %d %d %d %s", cmd1, + (int)(xx - dx), (int)(yy - dy), + (int)(xx + dx), (int)(yy + dy), cmd2); + chunkp += strlen(chunkp); + } + if (chunkp > chunk) + sys_gui(chunk); +} + +static void scope_drawbg(t_scope *x, t_canvas *cv, + int x1, int y1, int x2, int y2) +{ + int i; + float dx, dy, xx, yy; + dx = (x2 - x1) * 0.125; + dy = (y2 - y1) * 0.25; + sys_vgui(".x%x.c create rectangle %d %d %d %d\ + -fill #%2.2x%2.2x%2.2x -width %f -tags {%s %s}\n", + cv, x1, y1, x2, y2, + x->x_bgred, x->x_bggreen, x->x_bgblue, + SCOPE_GRIDWIDTH, x->x_bgtag, x->x_tag); + for (i = 0, xx = x1 + dx; i < 7; i++, xx += dx) + sys_vgui(".x%x.c create line %f %d %f %d\ + -width %f -tags {%s %s}\n", cv, xx, y1, xx, y2, + SCOPE_GRIDWIDTH, x->x_gridtag, x->x_tag); + for (i = 0, yy = y1 + dy; i < 3; i++, yy += dy) + sys_vgui(".x%x.c create line %d %f %d %f\ + -width %f -tags {%s %s}\n", cv, x1, yy, x2, yy, + SCOPE_GRIDWIDTH, x->x_gridtag, x->x_tag); +} + +static void scope_drawmono(t_scope *x, t_canvas *cv) +{ + int x1, y1, x2, y2; + scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2); + scope_drawbg(x, cv, x1, y1, x2, y2); + scope_drawfgmono(x, cv, x1, y1, x2, y2); +} + +static void scope_redrawmono(t_scope *x, t_canvas *cv) +{ + int nleft = x->x_bufsize; + float *bp = x->x_xbuffer; + char chunk[32 * SCOPE_GUICHUNKMONO]; /* LATER estimate */ + char *chunkp = chunk; + int x1, y1, x2, y2; + float dx, dy, xx, yy, sc; + scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2); + dx = (float)(x2 - x1) / (float)x->x_bufsize; + sc = ((float)x->x_height - 2.) / (float)(x->x_maxval - x->x_minval); + xx = x1; + sys_vgui(".x%x.c coords %s \\\n", cv, x->x_fgtag); + while (nleft > SCOPE_GUICHUNKMONO) + { + int i = SCOPE_GUICHUNKMONO; + while (i--) + { + yy = (y2 - 1) - sc * (*bp++ - x->x_minval); +#ifndef SCOPE_DEBUG + if (yy > y2) yy = y2; else if (yy < y1) yy = y1; +#endif + sprintf(chunkp, "%d %d ", (int)xx, (int)yy); + chunkp += strlen(chunkp); + xx += dx; + } + strcpy(chunkp, "\\\n"); + sys_gui(chunk); + chunkp = chunk; + nleft -= SCOPE_GUICHUNKMONO; + } + while (nleft--) + { + yy = (y2 - 1) - sc * (*bp++ - x->x_minval); +#ifndef SCOPE_DEBUG + if (yy > y2) yy = y2; else if (yy < y1) yy = y1; +#endif + sprintf(chunkp, "%d %d ", (int)xx, (int)yy); + chunkp += strlen(chunkp); + xx += dx; + } + strcpy(chunkp, "\n"); + sys_gui(chunk); +} + +static void scope_drawxy(t_scope *x, t_canvas *cv) +{ + int x1, y1, x2, y2; + scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2); + scope_drawbg(x, cv, x1, y1, x2, y2); + scope_drawfgxy(x, cv, x1, y1, x2, y2); +} + +static void scope_redrawxy(t_scope *x, t_canvas *cv) +{ + int x1, y1, x2, y2; + scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2); + sys_vgui(".x%x.c delete %s\n", cv, x->x_fgtag); + scope_drawfgxy(x, cv, x1, y1, x2, y2); +} + +static void scope_revis(t_scope *x, t_canvas *cv) +{ + sys_vgui(".x%x.c delete %s\n", cv, x->x_tag); + if (x->x_xymode) + scope_drawxy(x, cv); + else + scope_drawmono(x, cv); +} + +static void scope_vis(t_gobj *z, t_glist *glist, int vis) +{ + t_scope *x = (t_scope *)z; + t_text *t = (t_text *)z; + t_canvas *cv = scope_getcanvas(x, glist); + if (vis) + { + t_scopehandle *sh = (t_scopehandle *)x->x_handle; +#ifndef PD_MINOR_VERSION + rtext_new(glist, t, glist->gl_editor->e_rtext, 0); +#endif + sprintf(sh->h_pathname, ".x%x.h%x", (int)cv, (int)sh); + if (x->x_xymode) + scope_drawxy(x, cv); + else + scope_drawmono(x, cv); + } + else + { +#ifndef PD_MINOR_VERSION + t_rtext *rt = glist_findrtext(glist, t); + if (rt) rtext_free(rt); +#endif + sys_vgui(".x%x.c delete %s\n", cv, x->x_tag); + x->x_canvas = 0; + } +} + +static int scope_click(t_gobj *z, t_glist *glist, + int xpix, int ypix, int shift, int alt, int dbl, + int doit) +{ + t_scope *x = (t_scope *)z; + x->x_frozen = doit; + return (CURSOR_RUNMODE_CLICKME); +} + +/* CHECKED there is only one copy of state variables, + the same, whether modified with messages, or in the inspector */ +static void scope_save(t_gobj *z, t_binbuf *b) +{ + t_scope *x = (t_scope *)z; + t_text *t = (t_text *)x; + binbuf_addv(b, "ssiisiiiiiffififiiiiiii;", gensym("#X"), gensym("obj"), + (int)t->te_xpix, (int)t->te_ypix, + gensym("Scope~"), + x->x_width, x->x_height, x->x_period, 3, x->x_bufsize, + x->x_minval, x->x_maxval, x->x_delay, 0., + x->x_trigmode, x->x_triglevel, + x->x_fgred, x->x_fggreen, x->x_fgblue, + x->x_bgred, x->x_bggreen, x->x_bgblue, 0); +} + +static t_widgetbehavior scope_widgetbehavior = +{ + scope_getrect, + scope_displace, + scope_select, + 0, + scope_delete, + scope_vis, + scope_click, + scope_save, + 0 +}; + +static void scope_setxymode(t_scope *x, int xymode) +{ + if (xymode != x->x_xymode) + { + t_canvas *cv; + if (cv = scope_isvisible(x)) + { + sys_vgui(".x%x.c delete %s\n", cv, x->x_fgtag); + if (!xymode) + { + int x1, y1, x2, y2; + scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2); + scope_drawfgmono(x, cv, x1, y1, x2, y2); + } + } + x->x_xymode = xymode; + scope_clear(x, 0); + } +} + +static void scope_tick(t_scope *x) +{ + t_canvas *cv; + if (!x->x_frozen && (cv = scope_isvisible(x))) + { + if (x->x_xymode) + scope_redrawxy(x, cv); + else + scope_redrawmono(x, cv); + } + scope_clear(x, 1); +} + +static void scopehandle__clickhook(t_scopehandle *sh, t_floatarg f) +{ + int newstate = (int)f; + if (sh->h_dragon && newstate == 0) + { + t_scope *x = sh->h_master; + t_canvas *cv; + x->x_width += sh->h_dragx; + x->x_height += sh->h_dragy; + if (cv = scope_isvisible(x)) + { + sys_vgui(".x%x.c delete %s\n", cv, sh->h_outlinetag); + scope_revis(x, cv); + sys_vgui("destroy %s\n", sh->h_pathname); + scope_select((t_gobj *)x, x->x_glist, 1); + canvas_fixlinesfor(x->x_glist, (t_text *)x); /* 2nd inlet */ + } + } + else if (!sh->h_dragon && newstate) + { + t_scope *x = sh->h_master; + t_canvas *cv; + if (cv = scope_isvisible(x)) + { + int x1, y1, x2, y2; + scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2); + sys_vgui("lower %s\n", sh->h_pathname); + sys_vgui(".x%x.c create rectangle %d %d %d %d\ + -outline blue -width %f -tags %s\n", + cv, x1, y1, x2, y2, SCOPE_SELBDWIDTH, sh->h_outlinetag); + } + sh->h_dragx = 0; + sh->h_dragy = 0; + } + sh->h_dragon = newstate; +} + +static void scopehandle__motionhook(t_scopehandle *sh, + t_floatarg f1, t_floatarg f2) +{ + if (sh->h_dragon) + { + t_scope *x = sh->h_master; + int dx = (int)f1, dy = (int)f2; + int x1, y1, x2, y2, newx, newy; + scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2); + newx = x2 + dx; + newy = y2 + dy; + if (newx > x1 + SCOPE_MINWIDTH && newy > y1 + SCOPE_MINHEIGHT) + { + t_canvas *cv; + if (cv = scope_isvisible(x)) + sys_vgui(".x%x.c coords %s %d %d %d %d\n", + cv, sh->h_outlinetag, x1, y1, newx, newy); + sh->h_dragx = dx; + sh->h_dragy = dy; + } + } +} + +static void scope_free(t_scope *x) +{ + if (x->x_clock) clock_free(x->x_clock); + if (x->x_xbuffer != x->x_xbufini) + freebytes(x->x_xbuffer, x->x_allocsize * sizeof(*x->x_xbuffer)); + if (x->x_ybuffer != x->x_ybufini) + freebytes(x->x_ybuffer, x->x_allocsize * sizeof(*x->x_ybuffer)); + if (x->x_handle) + { + pd_unbind(x->x_handle, ((t_scopehandle *)x->x_handle)->h_bindsym); + pd_free(x->x_handle); + } +} + +static void *scope_new(t_symbol *s, int ac, t_atom *av) +{ + t_scope *x = (t_scope *)pd_new(scope_class); + t_scopehandle *sh; + t_float width = SCOPE_DEFWIDTH; + t_float height = SCOPE_DEFHEIGHT; + char buf[64]; + x->x_glist = canvas_getcurrent(); + x->x_canvas = 0; + loud_floatarg(*(t_pd *)x, 0, ac, av, &width, + SCOPE_MINWIDTH, 0, + LOUD_CLIP | LOUD_WARN, 0, "width"); + x->x_width = (int)width; + loud_floatarg(*(t_pd *)x, 1, ac, av, &height, + SCOPE_MINHEIGHT, 0, + LOUD_CLIP | LOUD_WARN, 0, "height"); + x->x_height = (int)height; + scope_period(x, 0, ac, av); + /* CHECKME 6th argument (default 3 for mono, 1 for xy */ + scope_bufsize(x, 0, ac, av); + scope_range(x, 0, ac, av); + scope_delay(x, 0, ac, av); + /* CHECKME 11th argument (default 0.) */ + scope_trigger(x, 0, ac, av); + scope_triglevel(x, 0, ac, av); + scope_frgb(x, 0, ac, av); + scope_brgb(x, 0, ac, av); + /* CHECKME last argument (default 0) */ + + sprintf(x->x_tag, "all%x", (int)x); + sprintf(x->x_bgtag, "bg%x", (int)x); + sprintf(x->x_gridtag, "gr%x", (int)x); + sprintf(x->x_fgtag, "fg%x", (int)x); + x->x_xymode = 0; + x->x_ksr = sys_getsr() * 0.001; /* redundant */ + x->x_frozen = 0; + inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); + x->x_clock = clock_new(x, (t_method)scope_tick); + scope_clear(x, 0); + + x->x_handle = pd_new(scopehandle_class); + sh = (t_scopehandle *)x->x_handle; + sh->h_master = x; + sprintf(buf, "_h%x", (int)sh); + pd_bind(x->x_handle, sh->h_bindsym = gensym(buf)); + sprintf(sh->h_outlinetag, "h%x", (int)sh); + sh->h_dragon = 0; + return (x); +} + +void Scope_tilde_setup(void) +{ + scope_class = class_new(gensym("Scope~"), + (t_newmethod)scope_new, + (t_method)scope_free, + sizeof(t_scope), 0, A_GIMME, 0); + sic_setup(scope_class, scope_dsp, scope_float); + class_addmethod(scope_class, (t_method)scope_bufsize, + gensym("bufsize"), A_GIMME, 0); + class_addmethod(scope_class, (t_method)scope_range, + gensym("range"), A_GIMME, 0); + class_addmethod(scope_class, (t_method)scope_delay, + gensym("delay"), A_GIMME, 0); + class_addmethod(scope_class, (t_method)scope_trigger, + gensym("trigger"), A_GIMME, 0); + class_addmethod(scope_class, (t_method)scope_triglevel, + gensym("triglevel"), A_GIMME, 0); + class_addmethod(scope_class, (t_method)scope_frgb, + gensym("frgb"), A_GIMME, 0); + class_addmethod(scope_class, (t_method)scope_brgb, + gensym("brgb"), A_GIMME, 0); + class_addmethod(scope_class, (t_method)scope_click, + gensym("click"), + A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); + class_setwidget(scope_class, &scope_widgetbehavior); + scopehandle_class = class_new(gensym("_scopehandle"), 0, 0, + sizeof(t_scopehandle), CLASS_PD, 0); + class_addmethod(scopehandle_class, (t_method)scopehandle__clickhook, + gensym("_click"), A_FLOAT, 0); + class_addmethod(scopehandle_class, (t_method)scopehandle__motionhook, + gensym("_motion"), A_FLOAT, A_FLOAT, 0); +} diff --git a/cyclone/sickle/Snapshot.c b/cyclone/sickle/Snapshot.c new file mode 100644 index 0000000..7c7e974 --- /dev/null +++ b/cyclone/sickle/Snapshot.c @@ -0,0 +1,161 @@ +/* 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 "sickle/sic.h" + +/* CHECKME for a fixed minimum deltime, if any (5ms for c74's metro) */ + +typedef struct _snapshot +{ + t_sic x_sic; + t_float x_value; + int x_rqoffset; /* requested */ + int x_offset; /* effective (truncated) */ + int x_stopped; + int x_on; /* !stopped && deltime > 0 */ + float x_deltime; + int x_npoints; + int x_nleft; + int x_nblock; + float x_ksr; + t_clock *x_clock; +} t_snapshot; + +static t_class *snapshot_class; + +static void snapshot_tick(t_snapshot *x) +{ + outlet_float(((t_object *)x)->ob_outlet, x->x_value); +} + +static void snapshot_bang(t_snapshot *x) +{ + outlet_float(((t_object *)x)->ob_outlet, x->x_value); +} + +static void snapshot_correct(t_snapshot *x) +{ + int wason = x->x_on; + x->x_offset = + (x->x_rqoffset < x->x_nblock ? x->x_rqoffset : x->x_nblock - 1); + x->x_npoints = x->x_deltime * x->x_ksr - x->x_nblock + x->x_offset; + if (x->x_on = (!x->x_stopped && x->x_deltime > 0.)) + { + if (!wason) x->x_nleft = x->x_offset; /* CHECKME */ + } + else if (wason) clock_unset(x->x_clock); +} + +static void snapshot_start(t_snapshot *x) +{ + x->x_stopped = 0; + if (!x->x_on && x->x_deltime > 0.) /* CHECKED no default */ + { + x->x_nleft = x->x_offset; /* CHECKME */ + x->x_on = 1; + } +} + +static void snapshot_stop(t_snapshot *x) +{ + x->x_stopped = 1; + if (x->x_on) + { + clock_unset(x->x_clock); + x->x_on = 0; + } +} + +static void snapshot_float(t_snapshot *x, t_float f) +{ + /* CHECKED nonzero/zero, CHECKED incompatible: int only (float ignored) */ + if (f != 0.) + snapshot_start(x); + else + snapshot_stop(x); +} + +static void snapshot_ft1(t_snapshot *x, t_floatarg f) +{ + x->x_deltime = (f > 0. ? f : 0.); /* CHECKED */ + /* CHECKED setting deltime to a positive value starts the clock + only if it was stopped by setting deltime to zero */ + snapshot_correct(x); +} + +static void snapshot_offset(t_snapshot *x, t_floatarg f) +{ + int i = (int)f; /* CHECKME */ + x->x_rqoffset = (i >= 0 ? i : 0); /* CHECKME */ + /* CHECKME if the change has an effect prior to next dsp_add call */ + snapshot_correct(x); +} + +static t_int *snapshot_perform(t_int *w) +{ + t_snapshot *x = (t_snapshot *)(w[1]); + t_float *in = (t_float *)(w[2]); + x->x_value = in[x->x_offset]; + if (x->x_on) + { + /* CHECKME nleft vs offset */ + if (x->x_nleft < x->x_nblock) + { + clock_delay(x->x_clock, 0); + x->x_nleft = x->x_npoints; + } + else x->x_nleft -= x->x_nblock; + } + return (w + 3); +} + +static void snapshot_dsp(t_snapshot *x, t_signal **sp) +{ + x->x_nblock = sp[0]->s_n; + x->x_ksr = sp[0]->s_sr * 0.001; + snapshot_correct(x); + x->x_nleft = x->x_offset; /* CHECKME */ + dsp_add(snapshot_perform, 2, x, sp[0]->s_vec); +} + +static void snapshot_free(t_snapshot *x) +{ + if (x->x_clock) clock_free(x->x_clock); +} + +static void *snapshot_new(t_floatarg f1, t_floatarg f2) +{ + t_snapshot *x = (t_snapshot *)pd_new(snapshot_class); + x->x_stopped = 0; /* CHECKED */ + x->x_on = 0; + x->x_value = 0; + x->x_nblock = 64; /* redundant */ + x->x_ksr = 44.1; /* redundant */ + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); + outlet_new((t_object *)x, &s_float); + x->x_clock = clock_new(x, (t_method)snapshot_tick); + snapshot_offset(x, f2); /* CHECKME (this is fixed at nblock-1 in Pd) */ + snapshot_ft1(x, f1); + return (x); +} + +void Snapshot_tilde_setup(void) +{ + snapshot_class = class_new(gensym("Snapshot~"), + (t_newmethod)snapshot_new, + (t_method)snapshot_free, + sizeof(t_snapshot), 0, + A_DEFFLOAT, A_DEFFLOAT, 0); + sic_setup(snapshot_class, snapshot_dsp, snapshot_float); + class_addbang(snapshot_class, snapshot_bang); + class_addmethod(snapshot_class, (t_method)snapshot_ft1, + gensym("ft1"), A_FLOAT, 0); + class_addmethod(snapshot_class, (t_method)snapshot_offset, + gensym("offset"), A_FLOAT, 0); + class_addmethod(snapshot_class, (t_method)snapshot_start, + gensym("start"), 0); + class_addmethod(snapshot_class, (t_method)snapshot_stop, + gensym("stop"), 0); +} diff --git a/cyclone/sickle/abs.c b/cyclone/sickle/abs.c new file mode 100644 index 0000000..cde26a5 --- /dev/null +++ b/cyclone/sickle/abs.c @@ -0,0 +1,42 @@ +/* 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 "sickle/sic.h" + +typedef t_sic t_abs; +static t_class *abs_class; + +static t_int *abs_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = (f >= 0 ? f : -f); + } + return (w + 4); +} + +static void abs_dsp(t_abs *x, t_signal **sp) +{ + dsp_add(abs_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *abs_new(void) +{ + t_abs *x = (t_abs *)pd_new(abs_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void abs_tilde_setup(void) +{ + abs_class = class_new(gensym("abs~"), + (t_newmethod)abs_new, 0, + sizeof(t_abs), 0, 0); + sic_setup(abs_class, abs_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/acos.c b/cyclone/sickle/acos.c new file mode 100644 index 0000000..1dd5719 --- /dev/null +++ b/cyclone/sickle/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" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define acosf acos +#endif + +typedef t_sic t_acos; +static t_class *acos_class; + +static t_int *acos_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = acosf(f); /* CHECKED no protection against NaNs */ + } + return (w + 4); +} + +static void acos_dsp(t_acos *x, t_signal **sp) +{ + dsp_add(acos_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *acos_new(void) +{ + t_acos *x = (t_acos *)pd_new(acos_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void acos_tilde_setup(void) +{ + acos_class = class_new(gensym("acos~"), + (t_newmethod)acos_new, 0, + sizeof(t_acos), 0, 0); + sic_setup(acos_class, acos_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/acosh.c b/cyclone/sickle/acosh.c new file mode 100644 index 0000000..392ad97 --- /dev/null +++ b/cyclone/sickle/acosh.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" +#include "sickle/sic.h" + +/* LATER ask about osx */ +#if defined(NT) || defined(MACOSX) +#define acoshf(x) (log(x + sqrt(x * x - 1))) +#endif + +typedef t_sic t_acosh; +static t_class *acosh_class; + +static t_int *acosh_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = acoshf(f); /* CHECKME no protection against NaNs */ + } + return (w + 4); +} + +static void acosh_dsp(t_acosh *x, t_signal **sp) +{ + dsp_add(acosh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *acosh_new(void) +{ + t_acosh *x = (t_acosh *)pd_new(acosh_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void acosh_tilde_setup(void) +{ + acosh_class = class_new(gensym("acosh~"), + (t_newmethod)acosh_new, 0, + sizeof(t_acosh), 0, 0); + sic_setup(acosh_class, acosh_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/allpass.c b/cyclone/sickle/allpass.c new file mode 100644 index 0000000..761d0cc --- /dev/null +++ b/cyclone/sickle/allpass.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 <string.h> +#include "m_pd.h" +#include "sickle/sic.h" + +typedef struct _allpass +{ + t_sic x_sic; + float x_sr; + float x_ksr; + t_float *x_buf; + int x_bufsize; /* as allocated */ + int x_maxsize; /* as used */ + float x_maxdelay; /* same in ms */ + int x_phase; /* writing head */ +} t_allpass; + +static t_class *allpass_class; + +/* maximum delay defaults to 50 ms (cycling has 10 ms here) */ +#define ALLPASS_DEFMAXDELAY 50.0 + +/* LATER choose the best way (compare with comb~) */ +#define ALLPASS_MAXFEEDBACK 0.999 + +static void allpass_clear(t_allpass *x) +{ + memset(x->x_buf, 0, x->x_maxsize * sizeof(*x->x_buf)); + x->x_phase = 0; +} + +static void allpass_resize(t_allpass *x, int newsize) +{ + if (newsize > 0 && newsize != x->x_maxsize) + { + if (newsize > x->x_bufsize) + { + x->x_buf = resizebytes(x->x_buf, + x->x_bufsize * sizeof(*x->x_buf), + newsize * sizeof(*x->x_buf)); + /* LATER test for failure */ + x->x_bufsize = newsize; + } + x->x_maxsize = newsize; + } + allpass_clear(x); +} + +static t_int *allpass_perform(t_int *w) +{ + t_allpass *x = (t_allpass *)(w[1]); + int nblock = (int)(w[2]); + t_float *xin = (t_float *)(w[3]); + t_float *din = (t_float *)(w[4]); + t_float *gin = (t_float *)(w[5]); + t_float *out = (t_float *)(w[6]); + t_float *buf = x->x_buf; + int maxsize = x->x_maxsize; + int guardpoint = maxsize - 1; + float ksr = x->x_ksr; + int wph = x->x_phase; + while (nblock--) + { /* TDFII scheme */ + float xn = *xin++; + float delsize = ksr * *din++; + float gain = *gin++; + float yn; + float rph; /* reading head */ + if (gain < -ALLPASS_MAXFEEDBACK) gain = -ALLPASS_MAXFEEDBACK; + else if (gain > ALLPASS_MAXFEEDBACK) gain = ALLPASS_MAXFEEDBACK; + yn = -gain * xn; + if (delsize > 0) + { + int ndx; + float val; + rph = wph - (delsize > guardpoint ? guardpoint : delsize); + if (rph < 0) rph += guardpoint; + ndx = (int)rph; + val = buf[ndx]; + /* ``a cheezy linear interpolation'' ala msp, + (vd~ uses 4-point interpolation...) */ + yn += val + (buf[ndx+1] - val) * (rph - ndx); + } + *out++ = yn; + if (wph == guardpoint) + { + buf[wph] = *buf = xn + gain * yn; + wph = 1; + } + else buf[wph++] = xn + gain * yn; + } + x->x_phase = wph; + return (w + 7); +} + +static void allpass_dsp(t_allpass *x, t_signal **sp) +{ + float sr = sp[0]->s_sr; + if (sr != x->x_sr) + { + x->x_sr = sr; + x->x_ksr = sr * 0.001; + allpass_resize(x, x->x_ksr * x->x_maxdelay); + } + else allpass_clear(x); + dsp_add(allpass_perform, 6, x, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); +} + +static void *allpass_new(t_floatarg f1, t_floatarg f2, t_floatarg f3) +{ + t_allpass *x; + float maxdelay = (f1 > 0 ? f1 : ALLPASS_DEFMAXDELAY); + float sr = sys_getsr(); + float ksr = sr * 0.001; + int bufsize = ksr * maxdelay; + t_float *buf = (t_float *)getbytes(bufsize * sizeof(*buf)); + if (!buf) + return (0); + x = (t_allpass *)pd_new(allpass_class); + x->x_maxdelay = maxdelay; + x->x_sr = sr; + x->x_ksr = ksr; + x->x_bufsize = x->x_maxsize = bufsize; + x->x_buf = buf; + if (f2 < 0) f2 = 0; + if (f3 < -ALLPASS_MAXFEEDBACK) f3 = -ALLPASS_MAXFEEDBACK; + else if (f3 > ALLPASS_MAXFEEDBACK) f3 = ALLPASS_MAXFEEDBACK; + sic_newinlet((t_sic *)x, f2); + sic_newinlet((t_sic *)x, f3); + outlet_new((t_object *)x, &s_signal); + allpass_clear(x); + return (x); +} + +static void allpass_free(t_allpass *x) +{ + if (x->x_buf) freebytes(x->x_buf, x->x_bufsize * sizeof(*x->x_buf)); +} + +void allpass_tilde_setup(void) +{ + allpass_class = class_new(gensym("allpass~"), + (t_newmethod)allpass_new, + (t_method)allpass_free, + sizeof(t_allpass), 0, + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + sic_setup(allpass_class, allpass_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(allpass_class, (t_method)allpass_clear, gensym("clear"), 0); +} diff --git a/cyclone/sickle/allsickles.c b/cyclone/sickle/allsickles.c new file mode 100644 index 0000000..624a48d --- /dev/null +++ b/cyclone/sickle/allsickles.c @@ -0,0 +1,134 @@ +// 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 Clip_tilde_setup(void); +void Line_tilde_setup(void); +void Scope_tilde_setup(void); +void Snapshot_tilde_setup(void); +void abs_tilde_setup(void); +void acos_tilde_setup(void); +void acosh_tilde_setup(void); +void allpass_tilde_setup(void); +void asin_tilde_setup(void); +void asinh_tilde_setup(void); +void atan_tilde_setup(void); +void atan2_tilde_setup(void); +void atanh_tilde_setup(void); +void average_tilde_setup(void); +void avg_tilde_setup(void); +void bitand_tilde_setup(void); +void bitnot_tilde_setup(void); +void bitor_tilde_setup(void); +void bitshift_tilde_setup(void); +void bitxor_tilde_setup(void); +void capture_tilde_setup(void); +void cartopol_tilde_setup(void); +void change_tilde_setup(void); +void click_tilde_setup(void); +void comb_tilde_setup(void); +void cosh_tilde_setup(void); +void cosx_tilde_setup(void); +void count_tilde_setup(void); +void cycle_tilde_setup(void); +void delay_tilde_setup(void); +void delta_tilde_setup(void); +void deltaclip_tilde_setup(void); +void edge_tilde_setup(void); +void frameaccum_tilde_setup(void); +void framedelta_tilde_setup(void); +void index_tilde_setup(void); +void kink_tilde_setup(void); +void linedrive_setup(void); +void log_tilde_setup(void); +void lookup_tilde_setup(void); +void minmax_tilde_setup(void); +void peakamp_tilde_setup(void); +void peek_tilde_setup(void); +void phasewrap_tilde_setup(void); +void play_tilde_setup(void); +void poltocar_tilde_setup(void); +void pow_tilde_setup(void); +void rampsmooth_tilde_setup(void); +void rand_tilde_setup(void); +void record_tilde_setup(void); +void sah_tilde_setup(void); +void sinh_tilde_setup(void); +void sinx_tilde_setup(void); +void slide_tilde_setup(void); +void spike_tilde_setup(void); +void tanh_tilde_setup(void); +void tanx_tilde_setup(void); +void train_tilde_setup(void); +void trapezoid_tilde_setup(void); +void triangle_tilde_setup(void); +void vectral_tilde_setup(void); +void wave_tilde_setup(void); + +void allsickles_setup(void) +{ + Clip_tilde_setup(); + Line_tilde_setup(); + Scope_tilde_setup(); + Snapshot_tilde_setup(); + abs_tilde_setup(); + acos_tilde_setup(); + acosh_tilde_setup(); + allpass_tilde_setup(); + asin_tilde_setup(); + asinh_tilde_setup(); + atan_tilde_setup(); + atan2_tilde_setup(); + atanh_tilde_setup(); + average_tilde_setup(); + avg_tilde_setup(); + bitand_tilde_setup(); + bitnot_tilde_setup(); + bitor_tilde_setup(); + bitshift_tilde_setup(); + bitxor_tilde_setup(); + capture_tilde_setup(); + cartopol_tilde_setup(); + change_tilde_setup(); + click_tilde_setup(); + comb_tilde_setup(); + cosh_tilde_setup(); + cosx_tilde_setup(); + count_tilde_setup(); + cycle_tilde_setup(); + delay_tilde_setup(); + delta_tilde_setup(); + deltaclip_tilde_setup(); + edge_tilde_setup(); + frameaccum_tilde_setup(); + framedelta_tilde_setup(); + index_tilde_setup(); + kink_tilde_setup(); + linedrive_setup(); + log_tilde_setup(); + lookup_tilde_setup(); + minmax_tilde_setup(); + peakamp_tilde_setup(); + peek_tilde_setup(); + phasewrap_tilde_setup(); + play_tilde_setup(); + poltocar_tilde_setup(); + pow_tilde_setup(); + rampsmooth_tilde_setup(); + rand_tilde_setup(); + record_tilde_setup(); + sah_tilde_setup(); + sinh_tilde_setup(); + sinx_tilde_setup(); + slide_tilde_setup(); + spike_tilde_setup(); + tanh_tilde_setup(); + tanx_tilde_setup(); + train_tilde_setup(); + trapezoid_tilde_setup(); + triangle_tilde_setup(); + vectral_tilde_setup(); + wave_tilde_setup(); +} diff --git a/cyclone/sickle/asin.c b/cyclone/sickle/asin.c new file mode 100644 index 0000000..05e5c28 --- /dev/null +++ b/cyclone/sickle/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" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define asinf asin +#endif + +typedef t_sic t_asin; +static t_class *asin_class; + +static t_int *asin_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = asinf(f); /* CHECKME no protection against NaNs */ + } + return (w + 4); +} + +static void asin_dsp(t_asin *x, t_signal **sp) +{ + dsp_add(asin_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *asin_new(void) +{ + t_asin *x = (t_asin *)pd_new(asin_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void asin_tilde_setup(void) +{ + asin_class = class_new(gensym("asin~"), + (t_newmethod)asin_new, 0, + sizeof(t_asin), 0, 0); + sic_setup(asin_class, asin_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/asinh.c b/cyclone/sickle/asinh.c new file mode 100644 index 0000000..931cb1f --- /dev/null +++ b/cyclone/sickle/asinh.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" +#include "sickle/sic.h" + +/* LATER ask about osx */ +#if defined(NT) || defined(MACOSX) +#define asinhf(x) (log(x + sqrt(x * x + 1))) +#endif + +typedef t_sic t_asinh; +static t_class *asinh_class; + +static t_int *asinh_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = asinhf(f); /* CHECKME no protection against NaNs */ + } + return (w + 4); +} + +static void asinh_dsp(t_asinh *x, t_signal **sp) +{ + dsp_add(asinh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *asinh_new(void) +{ + t_asinh *x = (t_asinh *)pd_new(asinh_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void asinh_tilde_setup(void) +{ + asinh_class = class_new(gensym("asinh~"), + (t_newmethod)asinh_new, 0, + sizeof(t_asinh), 0, 0); + sic_setup(asinh_class, asinh_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/atan.c b/cyclone/sickle/atan.c new file mode 100644 index 0000000..f541fa4 --- /dev/null +++ b/cyclone/sickle/atan.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" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define atanf atan +#endif + +typedef t_sic t_atan; +static t_class *atan_class; + +static t_int *atan_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = atanf(f); /* CHECKME no protection against NaNs */ + } + return (w + 4); +} + +static void atan_dsp(t_atan *x, t_signal **sp) +{ + dsp_add(atan_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *atan_new(void) +{ + t_atan *x = (t_atan *)pd_new(atan_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void atan_tilde_setup(void) +{ + atan_class = class_new(gensym("atan~"), + (t_newmethod)atan_new, 0, + sizeof(t_atan), 0, 0); + sic_setup(atan_class, atan_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/atan2.c b/cyclone/sickle/atan2.c new file mode 100644 index 0000000..171fc17 --- /dev/null +++ b/cyclone/sickle/atan2.c @@ -0,0 +1,53 @@ +/* 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" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define atan2f atan2 +#endif + +typedef t_sic t_atan2; +static t_class *atan2_class; + +static t_int *atan2_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + while (nblock--) + { + float f1 = *in1++; + float f2 = *in2++; + /* CHECKED arg order, range (radians) */ + *out++ = atan2f(f1, f2); + } + return (w + 5); +} + +static void atan2_dsp(t_atan2 *x, t_signal **sp) +{ + dsp_add(atan2_perform, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *atan2_new(t_floatarg f) +{ + t_atan2 *x = (t_atan2 *)pd_new(atan2_class); + sic_newinlet((t_sic *)x, f); /* CHECKED x-value argument */ + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void atan2_tilde_setup(void) +{ + atan2_class = class_new(gensym("atan2~"), + (t_newmethod)atan2_new, 0, + sizeof(t_atan2), 0, A_DEFFLOAT, 0); + sic_setup(atan2_class, atan2_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/atanh.c b/cyclone/sickle/atanh.c new file mode 100644 index 0000000..464f955 --- /dev/null +++ b/cyclone/sickle/atanh.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" +#include "sickle/sic.h" + +/* LATER ask about osx */ +#if defined(NT) || defined(MACOSX) +#define atanhf(x) (log((1 + x) / (1 - x)) * 0.5) +#endif + +typedef t_sic t_atanh; +static t_class *atanh_class; + +static t_int *atanh_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = atanhf(f); /* CHECKME no protection against NaNs */ + } + return (w + 4); +} + +static void atanh_dsp(t_atanh *x, t_signal **sp) +{ + dsp_add(atanh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *atanh_new(void) +{ + t_atanh *x = (t_atanh *)pd_new(atanh_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void atanh_tilde_setup(void) +{ + atanh_class = class_new(gensym("atanh~"), + (t_newmethod)atanh_new, 0, + sizeof(t_atanh), 0, 0); + sic_setup(atanh_class, atanh_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/average.c b/cyclone/sickle/average.c new file mode 100644 index 0000000..ea330c1 --- /dev/null +++ b/cyclone/sickle/average.c @@ -0,0 +1,194 @@ +/* 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 no reset after changing of a window size? */ +/* CHECKME overlap */ + +#include <math.h> +#include "m_pd.h" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define sqrtf sqrt +#endif + +#define AVERAGE_DEFNPOINTS 100 /* CHECKME */ +#define AVERAGE_DEFMODE AVERAGE_BIPOLAR +enum { AVERAGE_BIPOLAR, AVERAGE_ABSOLUTE, AVERAGE_RMS }; + +typedef struct _average +{ + t_sic x_sic; + int x_mode; + float (*x_sumfn)(t_float*, int, float); + int x_phase; + int x_npoints; + float x_result; + float x_accum; + t_clock *x_clock; +} t_average; + +static t_class *average_class; + +static void average_tick(t_average *x) +{ + outlet_float(((t_object *)x)->ob_outlet, x->x_result); +} + +static float average_bipolarsum(t_float *in, int nxfer, float accum) +{ + while (nxfer--) + accum += *in++; + return (accum); +} + +static float average_absolutesum(t_float *in, int nxfer, float accum) +{ + while (nxfer--) + { + float f = *in++; + accum += (f >= 0 ? f : -f); + } + return (accum); +} + +static float average_rmssum(t_float *in, int nxfer, float accum) +{ + while (nxfer--) + { + float f = *in++; + accum += f * f; + } + return (accum); +} + +static void average_setmode(t_average *x, int mode) +{ + if (mode == AVERAGE_BIPOLAR) + x->x_sumfn = average_bipolarsum; + else if (mode == AVERAGE_ABSOLUTE) + x->x_sumfn = average_absolutesum; + else if (mode == AVERAGE_RMS) + x->x_sumfn = average_rmssum; + else + { + bug("average_setmode"); + return; + } + x->x_mode = mode; + x->x_phase = x->x_npoints; + x->x_accum = 0; +} + +static void average_float(t_average *x, t_float f) +{ + int i = (int)f; /* CHECKME noninteger */ + if (i > 0) /* CHECKME */ + { + x->x_npoints = i; + x->x_phase = x->x_npoints; + x->x_accum = 0; + } +} + +static void average_bipolar(t_average *x) +{ + average_setmode(x, AVERAGE_BIPOLAR); +} + +static void average_absolute(t_average *x) +{ + average_setmode(x, AVERAGE_ABSOLUTE); +} + +static void average_rms(t_average *x) +{ + average_setmode(x, AVERAGE_RMS); +} + +static t_int *average_perform(t_int *w) +{ + t_average *x = (t_average *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + float (*sumfn)(t_float*, int, float) = x->x_sumfn; + int phase = x->x_phase; + if (phase <= nblock) + { + float accum = (*sumfn)(in, phase, x->x_accum); + nblock -= phase; + if (x->x_mode == AVERAGE_RMS) + /* CHECKME scaling and FIXME */ + x->x_result = sqrtf(accum / x->x_npoints); + else + x->x_result = accum / x->x_npoints; + clock_delay(x->x_clock, 0); + x->x_accum = 0; + if (nblock < x->x_npoints) + x->x_phase = x->x_npoints - nblock; + else + { + x->x_phase = x->x_npoints; + return (w + 4); + } + } + else x->x_phase -= nblock; + x->x_accum = (*sumfn)(in, nblock, x->x_accum); + return (w + 4); +} + +static void average_dsp(t_average *x, t_signal **sp) +{ + dsp_add(average_perform, 3, x, sp[0]->s_n, sp[0]->s_vec); +} + +static void average_free(t_average *x) +{ + if (x->x_clock) clock_free(x->x_clock); +} + +static void *average_new(t_symbol *s, t_floatarg f) +{ + t_average *x = (t_average *)pd_new(average_class); + int i = (int)f; /* CHECKME noninteger */ + int mode; + /* CHECKED it looks like memory is allocated for the entire window, + in tune with the refman's note about ``maximum averaging interval'' -- + needed for dynamic control over window size, or what? LATER rethink */ + x->x_npoints = (i > 0 ? /* CHECKME */ + i : AVERAGE_DEFNPOINTS); + if (s == gensym("bipolar")) + mode = AVERAGE_BIPOLAR; + else if (s == gensym("absolute")) + mode = AVERAGE_ABSOLUTE; + else if (s == gensym("rms")) + mode = AVERAGE_RMS; + else + { + mode = AVERAGE_DEFMODE; + /* CHECKME a warning if (s && s != &s_) */ + } + average_setmode(x, mode); + /* CHECKME if not x->x_phase = 0 */ + outlet_new((t_object *)x, &s_float); + x->x_clock = clock_new(x, (t_method)average_tick); + return (x); +} + +void average_tilde_setup(void) +{ + average_class = class_new(gensym("average~"), + (t_newmethod)average_new, + (t_method)average_free, + sizeof(t_average), 0, + A_DEFFLOAT, A_DEFSYM, 0); + sic_setup(average_class, average_dsp, average_float); + class_addmethod(average_class, (t_method)average_bipolar, + gensym("bipolar"), 0); + class_addmethod(average_class, (t_method)average_absolute, + gensym("absolute"), 0); + class_addmethod(average_class, (t_method)average_rms, + gensym("rms"), 0); +} diff --git a/cyclone/sickle/avg.c b/cyclone/sickle/avg.c new file mode 100644 index 0000000..2ad214a --- /dev/null +++ b/cyclone/sickle/avg.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" +#include "sickle/sic.h" + +typedef struct _avg +{ + t_sic x_sic; + float x_count; + float x_accum; +} t_avg; + +static t_class *avg_class; + +static void avg_bang(t_avg *x) +{ + outlet_float(((t_object *)x)->ob_outlet, + (x->x_count ? x->x_accum / x->x_count : 0)); + x->x_count = 0; + x->x_accum = 0; +} + +static t_int *avg_perform(t_int *w) +{ + t_avg *x = (t_avg *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + float accum = 0; + x->x_count += nblock; /* LATER consider blockcount++ */ + while (nblock--) + { + float f = *in++; + accum += (f >= 0 ? f : -f); + } + x->x_accum += accum; + return (w + 4); +} + +static void avg_dsp(t_avg *x, t_signal **sp) +{ + dsp_add(avg_perform, 3, x, sp[0]->s_n, sp[0]->s_vec); +} + +static void *avg_new(void) +{ + t_avg *x = (t_avg *)pd_new(avg_class); + outlet_new((t_object *)x, &s_float); + x->x_count = 0; + x->x_accum = 0; + return (x); +} + +void avg_tilde_setup(void) +{ + avg_class = class_new(gensym("avg~"), + (t_newmethod)avg_new, 0, + sizeof(t_avg), 0, 0); + sic_setup(avg_class, avg_dsp, SIC_FLOATTOSIGNAL); + class_addbang(avg_class, avg_bang); +} diff --git a/cyclone/sickle/bitand.c b/cyclone/sickle/bitand.c new file mode 100644 index 0000000..a7cfeb7 --- /dev/null +++ b/cyclone/sickle/bitand.c @@ -0,0 +1,144 @@ +/* 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 find a way of setting a 32-bit mask in an argument */ + +#include "m_pd.h" +#include "unstable/forky.h" +#include "sickle/sic.h" + +typedef struct _bitand +{ + t_sic x_sic; + t_glist *x_glist; + t_int x_mask; /* set by a 'bits' message or a creation argument */ + int x_mode; + int x_convert1; +} t_bitand; + +static t_class *bitand_class; + +static t_int *bitand_perform(t_int *w) +{ + t_bitand *x = (t_bitand *)(w[1]); + int nblock = (int)(w[2]); + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + t_float *out = (t_float *)(w[5]); + t_int mask = x->x_mask; + switch (x->x_mode) + { + /* LATER think about performance */ + case 0: + /* CHECKED */ + while (nblock--) + { + t_int i = ((*(t_int *)(t_float *)in1++) & + (*(t_int *)(t_float *)in2++)); + *out++ = *(t_float *)&i; + } + break; + case 1: + /* CHECKED */ + while (nblock--) + { + t_int i = (((t_int)*in1++) & + ((t_int)*in2++)); + *out++ = (t_float)i; + } + break; + case 2: + /* CHECKED */ + while (nblock--) + { + t_int i = (*(t_int *)(t_float *)in1++) & ((t_int)*in2++); + *out++ = *(t_float *)&i; + } + break; + case 3: + /* CHECKED */ + while (nblock--) + { + t_int i = ((t_int)*in1++) & (*(t_int *)(t_float *)in2++); + *out++ = (t_float)i; + } + break; + } + return (w + 6); +} + +static t_int *bitand_perform_noin2(t_int *w) +{ + t_bitand *x = (t_bitand *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_int mask = x->x_mask; + /* LATER think about performance */ + if (x->x_convert1) while (nblock--) + { + /* CHECKED */ + t_int i = ((t_int)*in++) & mask; + *out++ = (t_float)i; + } + else while (nblock--) + { + /* CHECKED */ + t_int i = (*(t_int *)(t_float *)in++) & mask; + *out++ = *(t_float *)&i; + } + return (w + 5); +} + +static void bitand_dsp(t_bitand *x, t_signal **sp) +{ + if (forky_hasfeeders((t_object *)x, x->x_glist, 1, 0)) + /* use the mask set by a second inlet's signal or float, + CHECKED (incompatible) second inlet's int is persistent */ + dsp_add(bitand_perform, 5, x, sp[0]->s_n, sp[0]->s_vec, + sp[1]->s_vec, sp[2]->s_vec); + else /* use the mask set by a 'bits' message or a creation argument */ + dsp_add(bitand_perform_noin2, 4, x, sp[0]->s_n, sp[0]->s_vec, + sp[1]->s_vec); +} + +static void bitand_bits(t_bitand *x, t_symbol *s, int ac, t_atom *av) +{ + x->x_mask = forky_getbitmask(ac, av); +} + +static void bitand_mode(t_bitand *x, t_floatarg f) +{ + int i = (int)f; + if (i < 0) + i = 0; /* CHECKED */ + else if (i > 3) + i = 3; /* CHECKED */ + x->x_mode = i; + x->x_convert1 = (x->x_mode == 1 || x->x_mode == 3); +} + +static void *bitand_new(t_floatarg f1, t_floatarg f2) +{ + t_bitand *x = (t_bitand *)pd_new(bitand_class); + x->x_glist = canvas_getcurrent(); + inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); + outlet_new((t_object *)x, &s_signal); + x->x_mask = (t_int)f1; /* FIXME (how?) */ + bitand_mode(x, f2); + return (x); +} + +void bitand_tilde_setup(void) +{ + bitand_class = class_new(gensym("bitand~"), + (t_newmethod)bitand_new, 0, + sizeof(t_bitand), 0, + A_DEFFLOAT, A_DEFFLOAT, 0); + sic_setup(bitand_class, bitand_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(bitand_class, (t_method)bitand_bits, + gensym("bits"), A_GIMME, 0); + class_addmethod(bitand_class, (t_method)bitand_mode, + gensym("mode"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/bitnot.c b/cyclone/sickle/bitnot.c new file mode 100644 index 0000000..c2929e8 --- /dev/null +++ b/cyclone/sickle/bitnot.c @@ -0,0 +1,66 @@ +/* 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 "sickle/sic.h" + +typedef struct _bitnot +{ + t_sic x_sic; + int x_convert1; +} t_bitnot; + +static t_class *bitnot_class; + +static t_int *bitnot_perform(t_int *w) +{ + t_bitnot *x = (t_bitnot *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + /* LATER think about performance */ + if (x->x_convert1) while (nblock--) + { + /* CHECKME */ + t_int i = ~((t_int)*in++); + *out++ = (t_float)i; + } + else while (nblock--) + { + /* CHECKME */ + t_int i = ~(*(t_int *)(t_float *)in++); + *out++ = *(t_float *)&i; + } + return (w + 5); +} + +static void bitnot_dsp(t_bitnot *x, t_signal **sp) +{ + dsp_add(bitnot_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void bitnot_mode(t_bitnot *x, t_floatarg f) +{ + int i = (int)f; + x->x_convert1 = (i > 0); /* CHECKME */ +} + +static void *bitnot_new(t_floatarg f) +{ + t_bitnot *x = (t_bitnot *)pd_new(bitnot_class); + outlet_new((t_object *)x, &s_signal); + bitnot_mode(x, f); + return (x); +} + +void bitnot_tilde_setup(void) +{ + bitnot_class = class_new(gensym("bitnot~"), + (t_newmethod)bitnot_new, 0, + sizeof(t_bitnot), 0, + A_DEFFLOAT, 0); + sic_setup(bitnot_class, bitnot_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(bitnot_class, (t_method)bitnot_mode, + gensym("mode"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/bitor.c b/cyclone/sickle/bitor.c new file mode 100644 index 0000000..e5c887b --- /dev/null +++ b/cyclone/sickle/bitor.c @@ -0,0 +1,144 @@ +/* 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 find a way of setting a 32-bit mask in an argument */ + +#include "m_pd.h" +#include "unstable/forky.h" +#include "sickle/sic.h" + +typedef struct _bitor +{ + t_sic x_sic; + t_glist *x_glist; + t_int x_mask; /* set by a 'bits' message or a creation argument */ + int x_mode; + int x_convert1; +} t_bitor; + +static t_class *bitor_class; + +static t_int *bitor_perform(t_int *w) +{ + t_bitor *x = (t_bitor *)(w[1]); + int nblock = (int)(w[2]); + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + t_float *out = (t_float *)(w[5]); + t_int mask = x->x_mask; + switch (x->x_mode) + { + /* LATER think about performance */ + case 0: + /* CHECKED */ + while (nblock--) + { + t_int i = ((*(t_int *)(t_float *)in1++) | + (*(t_int *)(t_float *)in2++)); + *out++ = *(t_float *)&i; + } + break; + case 1: + /* CHECKED */ + while (nblock--) + { + t_int i = (((t_int)*in1++) | + ((t_int)*in2++)); + *out++ = (t_float)i; + } + break; + case 2: + /* CHECKED */ + while (nblock--) + { + t_int i = (*(t_int *)(t_float *)in1++) | ((t_int)*in2++); + *out++ = *(t_float *)&i; + } + break; + case 3: + /* CHECKED */ + while (nblock--) + { + t_int i = ((t_int)*in1++) | (*(t_int *)(t_float *)in2++); + *out++ = (t_float)i; + } + break; + } + return (w + 6); +} + +static t_int *bitor_perform_noin2(t_int *w) +{ + t_bitor *x = (t_bitor *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_int mask = x->x_mask; + /* LATER think about performance */ + if (x->x_convert1) while (nblock--) + { + /* CHECKED */ + t_int i = ((t_int)*in++) | mask; + *out++ = (t_float)i; + } + else while (nblock--) + { + /* CHECKED */ + t_int i = (*(t_int *)(t_float *)in++) | mask; + *out++ = *(t_float *)&i; + } + return (w + 5); +} + +static void bitor_dsp(t_bitor *x, t_signal **sp) +{ + if (forky_hasfeeders((t_object *)x, x->x_glist, 1, 0)) + /* use the mask set by a second inlet's signal or float, + CHECKED (incompatible) second inlet's int is persistent */ + dsp_add(bitor_perform, 5, x, sp[0]->s_n, sp[0]->s_vec, + sp[1]->s_vec, sp[2]->s_vec); + else /* use the mask set by a 'bits' message or a creation argument */ + dsp_add(bitor_perform_noin2, 4, x, sp[0]->s_n, sp[0]->s_vec, + sp[1]->s_vec); +} + +static void bitor_bits(t_bitor *x, t_symbol *s, int ac, t_atom *av) +{ + x->x_mask = forky_getbitmask(ac, av); +} + +static void bitor_mode(t_bitor *x, t_floatarg f) +{ + int i = (int)f; + if (i < 0) + i = 0; /* CHECKED */ + else if (i > 3) + i = 3; /* CHECKED */ + x->x_mode = i; + x->x_convert1 = (x->x_mode == 1 || x->x_mode == 3); +} + +static void *bitor_new(t_floatarg f1, t_floatarg f2) +{ + t_bitor *x = (t_bitor *)pd_new(bitor_class); + x->x_glist = canvas_getcurrent(); + inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); + outlet_new((t_object *)x, &s_signal); + x->x_mask = (t_int)f1; /* FIXME (how?) */ + bitor_mode(x, f2); + return (x); +} + +void bitor_tilde_setup(void) +{ + bitor_class = class_new(gensym("bitor~"), + (t_newmethod)bitor_new, 0, + sizeof(t_bitor), 0, + A_DEFFLOAT, A_DEFFLOAT, 0); + sic_setup(bitor_class, bitor_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(bitor_class, (t_method)bitor_bits, + gensym("bits"), A_GIMME, 0); + class_addmethod(bitor_class, (t_method)bitor_mode, + gensym("mode"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/bitshift.c b/cyclone/sickle/bitshift.c new file mode 100644 index 0000000..db30fcd --- /dev/null +++ b/cyclone/sickle/bitshift.c @@ -0,0 +1,130 @@ +/* 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. */ + +/* When bit-shifting 32-bit values, gcc (intel?) bashes the second operand + modulo 32. In msp x << 32 gives 0, x >> 32 gives a propagated sign bit + (as expected). Mimicking that is clumsy. LATER consider making the calcs + more generic (use long long values?) */ + +#include "m_pd.h" +#include "sickle/sic.h" + +//#define BITSHIFT_DEBUG + +typedef struct _bitshift +{ + t_sic x_sic; + int x_convert1; + int x_lshift; + int x_rshift; + int x_lover; +} t_bitshift; + +static t_class *bitshift_class; + +static t_int *bitshift_perform(t_int *w) +{ + t_bitshift *x = (t_bitshift *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + /* LATER think about performance */ + if (x->x_lshift) + { + unsigned int shift = x->x_lshift; + if (x->x_convert1) while (nblock--) + { + /* CHECKED */ + t_int i = ((t_int)*in++ << shift); + *out++ = (t_float)i; + } + else while (nblock--) + { + /* CHECKED */ + t_int i = (*(t_int *)(t_float *)in++ << shift); + *out++ = *(t_float *)&i; + } + } + else if (x->x_rshift) + { + unsigned int shift = x->x_rshift; + if (x->x_convert1) while (nblock--) + { + /* CHECKME */ + t_int i = ((t_int)*in++ >> shift); + *out++ = (t_float)i; + } + else while (nblock--) + { + /* CHECKME */ + t_int i = (*(t_int *)(t_float *)in++ >> shift); + *out++ = *(t_float *)&i; + } + } + else if (x->x_lover) + while (nblock--) *out++ = 0; /* CHECKED both modes */ + else + while (nblock--) *out++ = *in++; /* CHECKED both modes */ + return (w + 5); +} + +static void bitshift_dsp(t_bitshift *x, t_signal **sp) +{ + dsp_add(bitshift_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void bitshift_mode(t_bitshift *x, t_floatarg f) +{ + int i = (int)f; + x->x_convert1 = (i > 0); /* CHECKED */ +} + +static void bitshift_shift(t_bitshift *x, t_floatarg f) +{ + int i = (int)f; + int nbits = sizeof(t_int) * 8; + x->x_lshift = x->x_rshift = 0; + x->x_lover = 0; + if (i > 0) + { +#ifdef BITSHIFT_DEBUG + post("%.8x << %d == %.8x, %.8x << %d == %.8x", + 1, i, 1 << i, -1, i, -1 << i); +#endif + if (i < nbits) + x->x_lshift = i; + else + x->x_lover = 1; + } + else if (i < 0) + { +#ifdef BITSHIFT_DEBUG + post("%.8x >> %d == %.8x, %.8x >> %d == %.8x", + 0x7fffffff, -i, 0x7fffffff >> -i, -1, -i, -1 >> -i); +#endif + x->x_rshift = (i <= -nbits ? nbits - 1 : -i); + } +} + +static void *bitshift_new(t_floatarg f1, t_floatarg f2) +{ + t_bitshift *x = (t_bitshift *)pd_new(bitshift_class); + outlet_new((t_object *)x, &s_signal); + bitshift_shift(x, f1); + bitshift_mode(x, f2); + return (x); +} + +void bitshift_tilde_setup(void) +{ + bitshift_class = class_new(gensym("bitshift~"), + (t_newmethod)bitshift_new, 0, + sizeof(t_bitshift), 0, + A_DEFFLOAT, A_DEFFLOAT, 0); + sic_setup(bitshift_class, bitshift_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(bitshift_class, (t_method)bitshift_mode, + gensym("mode"), A_FLOAT, 0); + class_addmethod(bitshift_class, (t_method)bitshift_shift, + gensym("shift"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/bitxor.c b/cyclone/sickle/bitxor.c new file mode 100644 index 0000000..ce54843 --- /dev/null +++ b/cyclone/sickle/bitxor.c @@ -0,0 +1,144 @@ +/* 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 find a way of setting a 32-bit mask in an argument */ + +#include "m_pd.h" +#include "unstable/forky.h" +#include "sickle/sic.h" + +typedef struct _bitxor +{ + t_sic x_sic; + t_glist *x_glist; + t_int x_mask; /* set by a 'bits' message or a creation argument */ + int x_mode; + int x_convert1; +} t_bitxor; + +static t_class *bitxor_class; + +static t_int *bitxor_perform(t_int *w) +{ + t_bitxor *x = (t_bitxor *)(w[1]); + int nblock = (int)(w[2]); + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + t_float *out = (t_float *)(w[5]); + t_int mask = x->x_mask; + switch (x->x_mode) + { + /* LATER think about performance */ + case 0: + /* CHECKED */ + while (nblock--) + { + t_int i = ((*(t_int *)(t_float *)in1++) ^ + (*(t_int *)(t_float *)in2++)); + *out++ = *(t_float *)&i; + } + break; + case 1: + /* CHECKED */ + while (nblock--) + { + t_int i = (((t_int)*in1++) ^ + ((t_int)*in2++)); + *out++ = (t_float)i; + } + break; + case 2: + /* CHECKED */ + while (nblock--) + { + t_int i = (*(t_int *)(t_float *)in1++) ^ ((t_int)*in2++); + *out++ = *(t_float *)&i; + } + break; + case 3: + /* CHECKED */ + while (nblock--) + { + t_int i = ((t_int)*in1++) ^ (*(t_int *)(t_float *)in2++); + *out++ = (t_float)i; + } + break; + } + return (w + 6); +} + +static t_int *bitxor_perform_noin2(t_int *w) +{ + t_bitxor *x = (t_bitxor *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_int mask = x->x_mask; + /* LATER think about performance */ + if (x->x_convert1) while (nblock--) + { + /* CHECKED */ + t_int i = ((t_int)*in++) ^ mask; + *out++ = (t_float)i; + } + else while (nblock--) + { + /* CHECKED */ + t_int i = (*(t_int *)(t_float *)in++) ^ mask; + *out++ = *(t_float *)&i; + } + return (w + 5); +} + +static void bitxor_dsp(t_bitxor *x, t_signal **sp) +{ + if (forky_hasfeeders((t_object *)x, x->x_glist, 1, 0)) + /* use the mask set by a second inlet's signal or float, + CHECKED (incompatible) second inlet's int is persistent */ + dsp_add(bitxor_perform, 5, x, sp[0]->s_n, sp[0]->s_vec, + sp[1]->s_vec, sp[2]->s_vec); + else /* use the mask set by a 'bits' message or a creation argument */ + dsp_add(bitxor_perform_noin2, 4, x, sp[0]->s_n, sp[0]->s_vec, + sp[1]->s_vec); +} + +static void bitxor_bits(t_bitxor *x, t_symbol *s, int ac, t_atom *av) +{ + x->x_mask = forky_getbitmask(ac, av); +} + +static void bitxor_mode(t_bitxor *x, t_floatarg f) +{ + int i = (int)f; + if (i < 0) + i = 0; /* CHECKED */ + else if (i > 3) + i = 3; /* CHECKED */ + x->x_mode = i; + x->x_convert1 = (x->x_mode == 1 || x->x_mode == 3); +} + +static void *bitxor_new(t_floatarg f1, t_floatarg f2) +{ + t_bitxor *x = (t_bitxor *)pd_new(bitxor_class); + x->x_glist = canvas_getcurrent(); + inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); + outlet_new((t_object *)x, &s_signal); + x->x_mask = (t_int)f1; /* FIXME (how?) */ + bitxor_mode(x, f2); + return (x); +} + +void bitxor_tilde_setup(void) +{ + bitxor_class = class_new(gensym("bitxor~"), + (t_newmethod)bitxor_new, 0, + sizeof(t_bitxor), 0, + A_DEFFLOAT, A_DEFFLOAT, 0); + sic_setup(bitxor_class, bitxor_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(bitxor_class, (t_method)bitxor_bits, + gensym("bits"), A_GIMME, 0); + class_addmethod(bitxor_class, (t_method)bitxor_mode, + gensym("mode"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/capture.c b/cyclone/sickle/capture.c new file mode 100644 index 0000000..089c21e --- /dev/null +++ b/cyclone/sickle/capture.c @@ -0,0 +1,408 @@ +/* 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 list of indices */ + +#include <stdio.h> +#include "m_pd.h" +#include "g_canvas.h" +#include "common/loud.h" +#include "hammer/file.h" +#include "sickle/sic.h" + +#define CAPTURE_DEFSIZE 4096 +#define CAPTURE_DEFPRECISION 4 +#define CAPTURE_MAXPRECISION 99 /* format array protection */ +#define CAPTURE_MAXINDICES 4096 /* FIXME */ + +typedef struct _capture +{ + t_sic x_sic; + t_glist *x_glist; + char x_mode; /* 'f' for first or 0 for last */ + int x_precision; + char x_format[8]; + char *x_indices; + int x_szindices; /* size of x_indices array */ + int x_nindices; /* number of reported indices */ + int x_nblock; + 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_clear(t_capture *x) +{ + x->x_count = 0; + x->x_head = 0; +} + +static int capture_formatfloat(t_capture *x, float f, char *buf, int col, + int maxcol) +{ + char *bp = buf; + int cnt = 0; + if (col > 0) + *bp++ = ' ', cnt++; + if (x->x_precision) + cnt += sprintf(bp, x->x_format, f); + else + cnt += sprintf(bp, "%d", (int)f); + if (col + cnt > maxcol) + buf[0] = '\n', col = cnt; + else + col += cnt; + return (col); +} + +static int capture_writefloat(t_capture *x, float f, char *buf, int col, + FILE *fp) +{ + /* CHECKME linebreaks */ + col = capture_formatfloat(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(glist_getcanvas(x->x_glist), + fn->s_name, buf, MAXPDSTRING); + if (fp = fopen(buf, "w")) /* LATER ask if overwriting, CHECKME */ + { + int col = 0; + if (x->x_mode == 'f' || 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, int linebreak) +{ + /* CHECKME 80 columns */ + col = capture_formatfloat(x, f, buf, col, 80); + hammereditor_append(x->x_filehandle, buf); + if (linebreak) + { + if (col) + { + hammereditor_append(x->x_filehandle, "\n\n"); + col = 0; + } + else hammereditor_append(x->x_filehandle, "\n"); + } + return (col); +} + +/* CHECKED blank line between blocks */ +static void capture_open(t_capture *x) +{ + int count = x->x_count; + char buf[MAXPDSTRING]; + int nindices = (x->x_nindices > 0 ? x->x_nindices : x->x_nblock); + hammereditor_open(x->x_filehandle, "Signal Capture"); /* CHECKED */ + if (x->x_mode == 'f' || count < x->x_bufsize) + { + float *bp = x->x_buffer; + int col = 0, i; + for (i = 1; i <= count; i++) + col = capture_appendfloat(x, *bp++, buf, col, + ((i % nindices) == 0)); + } + else + { + float *bp = x->x_buffer + x->x_head; + int col = 0, i = x->x_bufsize; + count = x->x_bufsize - x->x_head; + while (count--) + col = capture_appendfloat(x, *bp++, buf, col, + ((--i % nindices) == 0)); + bp = x->x_buffer; + count = x->x_head; + while (count--) + col = capture_appendfloat(x, *bp++, buf, col, + ((count % nindices) == 0)); + } +} + +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 t_int *capture_perform_first(t_int *w) +{ + t_capture *x = (t_capture *)(w[1]); + int count = x->x_count; + int bufsize = x->x_bufsize; + if (count < bufsize) + { + t_float *in = (t_float *)(w[2]); + int nblock = (int)(w[3]); + float *bp = x->x_buffer + count; + char *ndxp = x->x_indices; + if (nblock > x->x_szindices) + nblock = x->x_szindices; + while (nblock--) + { + if (*ndxp++) + { + *bp++ = *in++; + if (++count == bufsize) + break; + } + else in++; + } + x->x_count = count; + } + return (w + 4); +} + +static t_int *capture_perform_allfirst(t_int *w) +{ + t_capture *x = (t_capture *)(w[1]); + int count = x->x_count; + int bufsize = x->x_bufsize; + if (count < bufsize) + { + t_float *in = (t_float *)(w[2]); + int nblock = (int)(w[3]); + float *bp = x->x_buffer + count; + while (nblock--) + { + *bp++ = *in++; + if (++count == bufsize) + break; + } + x->x_count = count; + } + return (w + 4); +} + +static t_int *capture_perform_last(t_int *w) +{ + t_capture *x = (t_capture *)(w[1]); + t_float *in = (t_float *)(w[2]); + int nblock = (int)(w[3]); + float *buffer = x->x_buffer; + int bufsize = x->x_bufsize; + int count = x->x_count; + int head = x->x_head; + char *ndxp = x->x_indices; + if (nblock > x->x_szindices) + nblock = x->x_szindices; + while (nblock--) + { + if (*ndxp++) + { + buffer[head++] = *in++; + if (head >= bufsize) + head = 0; + if (count < bufsize) + count++; + } + else in++; + } + x->x_count = count; + x->x_head = head; + return (w + 4); +} + +static t_int *capture_perform_alllast(t_int *w) +{ + t_capture *x = (t_capture *)(w[1]); + t_float *in = (t_float *)(w[2]); + int nblock = (int)(w[3]); + float *buffer = x->x_buffer; + int bufsize = x->x_bufsize; + int count = x->x_count; + int head = x->x_head; + while (nblock--) + { + buffer[head++] = *in++; + if (head >= bufsize) + head = 0; + if (count < bufsize) + count++; + } + x->x_count = count; + x->x_head = head; + return (w + 4); +} + +static void capture_dsp(t_capture *x, t_signal **sp) +{ + x->x_nblock = sp[0]->s_n; + if (x->x_indices) + dsp_add((x->x_mode == 'f' ? + capture_perform_first : capture_perform_last), + 3, x, sp[0]->s_vec, sp[0]->s_n); + else + dsp_add((x->x_mode == 'f' ? + capture_perform_allfirst : capture_perform_alllast), + 3, x, sp[0]->s_vec, sp[0]->s_n); +} + +static void capture_free(t_capture *x) +{ + hammerfile_free(x->x_filehandle); + if (x->x_indices) + freebytes(x->x_indices, x->x_szindices * sizeof(*x->x_indices)); + if (x->x_buffer) + freebytes(x->x_buffer, x->x_bufsize * sizeof(*x->x_buffer)); +} + +static void *capture_new(t_symbol *s, int ac, t_atom *av) +{ + t_capture *x = 0; + char mode = 0; + int precision = -1; + float *buffer; + int bufsize = 0; + char *indices = 0; + int szindices = 0, nindices = -1; + if (ac && av->a_type == A_SYMBOL) + { + t_symbol *s = av->a_w.w_symbol; + if (s && *s->s_name == 'f') /* CHECKME */ + mode = 'f'; + ac--; av++; + } + if (ac && av->a_type == A_FLOAT) + { + bufsize = (int)av->a_w.w_float; /* CHECKME */ + ac--; av++; + if (ac && av->a_type == A_FLOAT) + { + int i; + t_atom *ap; + precision = (int)av->a_w.w_float; /* CHECKME */ + ac--; av++; + for (i = 0, ap = av; i < ac; i++, ap++) + { + if (ap->a_type == A_FLOAT) + { + int ndx = (int)ap->a_w.w_float; + /* CHECKME noninteger, negative */ + ndx++; + if (ndx >= CAPTURE_MAXINDICES) + { + /* CHECKME complaint */ + szindices = CAPTURE_MAXINDICES; + break; + } + else if (ndx > szindices) + szindices = ndx; + } + else break; /* CHECKME */ + } + if (szindices && (indices = getbytes(szindices * sizeof(*indices)))) + { + nindices = 0; + while (i--) + { + int ndx = (int)av++->a_w.w_float; + /* CHECKME noninteger */ + if (ndx >= 0 && ndx < szindices) + indices[ndx] = 1, nindices++; + } + } + } + } + if (bufsize <= 0) /* CHECKME */ + bufsize = CAPTURE_DEFSIZE; + if (buffer = getbytes(bufsize * sizeof(*buffer))) + { + x = (t_capture *)pd_new(capture_class); + x->x_glist = canvas_getcurrent(); + x->x_mode = mode; + if (precision < 0) /* CHECKME */ + precision = CAPTURE_DEFPRECISION; + else if (precision > CAPTURE_MAXPRECISION) /* CHECKME */ + precision = CAPTURE_MAXPRECISION; + if (x->x_precision = precision) + sprintf(x->x_format, "%%.%dg", precision); + x->x_indices = indices; + x->x_szindices = szindices; + x->x_nindices = nindices; + x->x_nblock = 64; /* redundant */ + x->x_buffer = buffer; + x->x_bufsize = bufsize; + x->x_filehandle = hammerfile_new((t_pd *)x, 0, 0, capture_writehook, 0); + capture_clear(x); + } + else if (indices) + freebytes(indices, szindices * sizeof(*indices)); + return (x); +} + +void capture_tilde_setup(void) +{ + capture_class = class_new(gensym("capture~"), + (t_newmethod)capture_new, + (t_method)capture_free, + sizeof(t_capture), 0, A_GIMME, 0); + sic_setup(capture_class, capture_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(capture_class, (t_method)capture_clear, + gensym("clear"), 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/sickle/cartopol.c b/cyclone/sickle/cartopol.c new file mode 100644 index 0000000..4c25797 --- /dev/null +++ b/cyclone/sickle/cartopol.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 <math.h> +#include "m_pd.h" +#include "unstable/fragile.h" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define atan2f atan2 +#define hypotf hypot +#endif + +typedef struct _cartopol +{ + t_sic x_sic; + t_outlet *x_out2; +} t_cartopol; + +static t_class *cartopol_class; + +static t_int *cartopol_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out1 = (t_float *)(w[4]); + t_float *out2 = (t_float *)(w[5]); + while (nblock--) + { + float rl = *in1++, im = -*in2++; /* CHECKED */ + *out1++ = hypotf(rl, im); + *out2++ = atan2f(im, rl); + } + return (w + 6); +} + +static t_int *cartopol_perform_nophase(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out1 = (t_float *)(w[4]); + while (nblock--) + { + float rl = *in1++, im = -*in2++; /* CHECKED */ + *out1++ = hypotf(rl, im); + } + return (w + 5); +} + +static void cartopol_dsp(t_cartopol *x, t_signal **sp) +{ + if (fragile_outlet_connections(x->x_out2)) + dsp_add(cartopol_perform, 5, sp[0]->s_n, sp[0]->s_vec, + sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); + else + dsp_add(cartopol_perform_nophase, 4, sp[0]->s_n, sp[0]->s_vec, + sp[1]->s_vec, sp[2]->s_vec); +} + +static void *cartopol_new(void) +{ + t_cartopol *x = (t_cartopol *)pd_new(cartopol_class); + inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); + outlet_new((t_object *)x, &s_signal); + x->x_out2 = outlet_new((t_object *)x, &s_signal); + return (x); +} + +void cartopol_tilde_setup(void) +{ + cartopol_class = class_new(gensym("cartopol~"), + (t_newmethod)cartopol_new, 0, + sizeof(t_cartopol), 0, 0); + sic_setup(cartopol_class, cartopol_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/change.c b/cyclone/sickle/change.c new file mode 100644 index 0000000..fffc43a --- /dev/null +++ b/cyclone/sickle/change.c @@ -0,0 +1,52 @@ +/* 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 "sickle/sic.h" + +typedef struct _change +{ + t_sic x_sic; + t_float x_last; +} t_change; + +static t_class *change_class; + +static t_int *change_perform(t_int *w) +{ + t_change *x = (t_change *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_float last = x->x_last; + while (nblock--) + { + t_float f = *in++; + *out++ = (f > last ? 1. : (f < last ? -1. : 0.)); + last = f; + } + x->x_last = last; + return (w + 5); +} + +static void change_dsp(t_change *x, t_signal **sp) +{ + dsp_add(change_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *change_new(void) +{ + t_change *x = (t_change *)pd_new(change_class); + outlet_new((t_object *)x, &s_signal); + x->x_last = 0; /* CHECKME startup conditions */ + return (x); +} + +void change_tilde_setup(void) +{ + change_class = class_new(gensym("change~"), + (t_newmethod)change_new, 0, + sizeof(t_change), 0, 0); + sic_setup(change_class, change_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/click.c b/cyclone/sickle/click.c new file mode 100644 index 0000000..5734cfd --- /dev/null +++ b/cyclone/sickle/click.c @@ -0,0 +1,119 @@ +/* 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/grow.h" +#include "sickle/sic.h" + +#define CLICK_INISIZE 16 /* LATER rethink */ + +typedef struct _click +{ + t_sic x_sic; + int x_nsamples; /* as used */ + int x_bufsize; /* as allocated */ + t_float *x_buffer; + t_float x_bufini[CLICK_INISIZE]; + int x_nleft; + t_float *x_head; +} t_click; + +static t_class *click_class; + +static void click_bang(t_click *x) +{ + x->x_nleft = x->x_nsamples; + x->x_head = x->x_buffer; +} + +static void click_set(t_click *x, t_symbol *s, int ac, t_atom *av) +{ + int i, nsamples = 0; + t_atom *ap; + t_float *bp; + for (i = 0, ap = av; i < ac; i++, ap++) + { + if (ap->a_type == A_FLOAT) nsamples++; + /* CHECKED no restrictions (refman's error about 0.0-1.0 range) + CHECKED nonnumeric atoms silently ignored */ + } + if (nsamples > x->x_bufsize) + x->x_buffer = grow_nodata(&nsamples, &x->x_bufsize, x->x_buffer, + CLICK_INISIZE, x->x_bufini, + sizeof(*x->x_buffer)); + if (nsamples) + { + x->x_nsamples = nsamples; + bp = x->x_buffer; + while (nsamples--) *bp++ = av++->a_w.w_float; + } + else x->x_nsamples = 0; /* CHECKED, need to 'set 1' explicitly */ + x->x_nleft = 0; + x->x_head = x->x_buffer; +} + +static t_int *click_perform(t_int *w) +{ + t_click *x = (t_click *)(w[1]); + int nblock = (int)(w[2]); + t_float *out = (t_float *)(w[3]); + if (x->x_nleft) + { + int nleft = x->x_nleft; + t_float *head = x->x_head; + if (nleft >= nblock) + { + x->x_nleft -= nblock; + while (nblock--) *out++ = *head++; + x->x_head = head; + } + else + { + nblock -= nleft; + while (nleft--) *out++ = *head++; + while (nblock--) *out++ = 0.; + x->x_nleft = 0; + x->x_head = x->x_buffer; + } + } + else while (nblock--) *out++ = 0.; + return (w + 4); +} + +static void click_dsp(t_click *x, t_signal **sp) +{ + dsp_add(click_perform, 3, x, sp[0]->s_n, sp[0]->s_vec); +} + +static void click_free(t_click *x) +{ + if (x->x_buffer != x->x_bufini) + freebytes(x->x_buffer, x->x_bufsize * sizeof(*x->x_buffer)); +} + +static void *click_new(t_symbol *s, int ac, t_atom *av) +{ + t_click *x = (t_click *)pd_new(click_class); + x->x_nsamples = 1; /* CHECKED */ + x->x_bufsize = CLICK_INISIZE; + x->x_buffer = x->x_bufini; + x->x_buffer[0] = 1.; /* CHECKED */ + x->x_nleft = 0; + x->x_head = x->x_buffer; + outlet_new((t_object *)x, &s_signal); + if (ac) click_set(x, 0, ac, av); + return (x); +} + +void click_tilde_setup(void) +{ + click_class = class_new(gensym("click~"), + (t_newmethod)click_new, + (t_method)click_free, + sizeof(t_click), 0, A_GIMME, 0); + sic_setup(click_class, click_dsp, SIC_NOMAINSIGNALIN); + class_addbang(click_class, click_bang); + class_addmethod(click_class, (t_method)click_set, + gensym("set"), A_GIMME, 0); +} diff --git a/cyclone/sickle/comb.c b/cyclone/sickle/comb.c new file mode 100644 index 0000000..8d4c8b3 --- /dev/null +++ b/cyclone/sickle/comb.c @@ -0,0 +1,162 @@ +/* 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 "sickle/sic.h" + +typedef struct _comb +{ + t_sic x_sic; + float x_sr; + float x_ksr; + t_float *x_buf; + int x_bufsize; /* as allocated */ + int x_maxsize; /* as used */ + float x_maxdelay; /* same in ms */ + int x_phase; /* writing head */ +} t_comb; + +static t_class *comb_class; + +/* maximum delay defaults to 50 ms (cycling has 10 ms here) */ +#define COMB_DEFMAXDELAY 50.0 + +/* LATER choose the best way. From msp help patch: + no clipping is done on a, b, or c coefficient input */ +#define COMB_MAXFEEDBACK 0.999 + +static void comb_clear(t_comb *x) +{ + memset(x->x_buf, 0, x->x_maxsize * sizeof(*x->x_buf)); + x->x_phase = 0; +} + +static void comb_resize(t_comb *x, int newsize) +{ + if (newsize > 0 && newsize != x->x_maxsize) + { + if (newsize > x->x_bufsize) + { + x->x_buf = resizebytes(x->x_buf, + x->x_bufsize * sizeof(*x->x_buf), + newsize * sizeof(*x->x_buf)); + /* LATER test for failure */ + x->x_bufsize = newsize; + } + x->x_maxsize = newsize; + } + comb_clear(x); +} + +static t_int *comb_perform(t_int *w) +{ + t_comb *x = (t_comb *)(w[1]); + int nblock = (int)(w[2]); + t_float *xin = (t_float *)(w[3]); + t_float *din = (t_float *)(w[4]); + t_float *ain = (t_float *)(w[5]); + t_float *bin = (t_float *)(w[6]); + t_float *cin = (t_float *)(w[7]); + t_float *out = (t_float *)(w[8]); + t_float *buf = x->x_buf; + int maxsize = x->x_maxsize; + int guardpoint = maxsize - 1; + float ksr = x->x_ksr; + int wph = x->x_phase; + while (nblock--) + { /* TDFII scheme is used. Do not forget, that any signal value + read after writing to out has to be saved beforehand. */ + float xn = *xin++; + float delsize = ksr * *din++; + float bgain = *bin++; + float cgain = *cin++; + float yn = *ain++ * xn; + float rph; /* reading head */ + if (cgain < -COMB_MAXFEEDBACK) cgain = -COMB_MAXFEEDBACK; + else if (cgain > COMB_MAXFEEDBACK) cgain = COMB_MAXFEEDBACK; + if (delsize > 1.0) + { + int ndx; + float val; + rph = wph - (delsize > guardpoint ? guardpoint : delsize); + if (rph < 0) rph += guardpoint; + ndx = (int)rph; + val = buf[ndx]; + /* ``a cheezy linear interpolation'' ala msp, + (vd~ uses 4-point interpolation...) */ + yn += val + (buf[ndx+1] - val) * (rph - ndx); + } + *out++ = yn; + if (wph == guardpoint) + { + buf[wph] = *buf = bgain * xn + cgain * yn; + wph = 1; + } + else buf[wph++] = bgain * xn + cgain * yn; + } + x->x_phase = wph; + return (w + 9); +} + +static void comb_dsp(t_comb *x, t_signal **sp) +{ + float sr = sp[0]->s_sr; + if (sr != x->x_sr) + { + x->x_sr = sr; + x->x_ksr = sr * 0.001; + comb_resize(x, x->x_ksr * x->x_maxdelay); + } + else comb_clear(x); + dsp_add(comb_perform, 8, x, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, + sp[3]->s_vec, sp[4]->s_vec, sp[5]->s_vec); +} + +static void *comb_new(t_floatarg f1, t_floatarg f2, + t_floatarg f3, t_floatarg f4, t_floatarg f5) +{ + t_comb *x; + float maxdelay = (f1 > 0 ? f1 : COMB_DEFMAXDELAY); + float sr = sys_getsr(); + float ksr = sr * 0.001; + int bufsize = ksr * maxdelay; + t_float *buf = (t_float *)getbytes(bufsize * sizeof(*buf)); + if (!buf) + return (0); + x = (t_comb *)pd_new(comb_class); + x->x_maxdelay = maxdelay; + x->x_sr = sr; + x->x_ksr = ksr; + x->x_bufsize = x->x_maxsize = bufsize; + x->x_buf = buf; + if (f2 < 0) f2 = 0; + if (f5 < -COMB_MAXFEEDBACK) f5 = -COMB_MAXFEEDBACK; + else if (f5 > COMB_MAXFEEDBACK) f5 = COMB_MAXFEEDBACK; + sic_newinlet((t_sic *)x, f2); + sic_newinlet((t_sic *)x, f3); + sic_newinlet((t_sic *)x, f4); + sic_newinlet((t_sic *)x, f5); + outlet_new((t_object *)x, &s_signal); + comb_clear(x); + return (x); +} + +static void comb_free(t_comb *x) +{ + if (x->x_buf) freebytes(x->x_buf, x->x_bufsize * sizeof(*x->x_buf)); +} + +void comb_tilde_setup(void) +{ + comb_class = class_new(gensym("comb~"), + (t_newmethod)comb_new, + (t_method)comb_free, + sizeof(t_comb), 0, + A_DEFFLOAT, A_DEFFLOAT, + A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + sic_setup(comb_class, comb_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(comb_class, (t_method)comb_clear, gensym("clear"), 0); +} diff --git a/cyclone/sickle/cosh.c b/cyclone/sickle/cosh.c new file mode 100644 index 0000000..ae5f8cb --- /dev/null +++ b/cyclone/sickle/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" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define coshf cosh +#endif + +typedef t_sic t_cosh; +static t_class *cosh_class; + +static t_int *cosh_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = coshf(f); /* CHECKME no protection against overflow */ + } + return (w + 4); +} + +static void cosh_dsp(t_cosh *x, t_signal **sp) +{ + dsp_add(cosh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *cosh_new(void) +{ + t_cosh *x = (t_cosh *)pd_new(cosh_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void cosh_tilde_setup(void) +{ + cosh_class = class_new(gensym("cosh~"), + (t_newmethod)cosh_new, 0, + sizeof(t_cosh), 0, 0); + sic_setup(cosh_class, cosh_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/cosx.c b/cyclone/sickle/cosx.c new file mode 100644 index 0000000..b368559 --- /dev/null +++ b/cyclone/sickle/cosx.c @@ -0,0 +1,51 @@ +/* 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" +#include "sickle/sic.h" + +/* by definition, this is just an interface to the -lm call + (do not use costable) */ + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define cosf cos +#endif + +typedef t_sic t_cosx; +static t_class *cosx_class; + +static t_int *cosx_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = cosf(f); + } + return (w + 4); +} + +static void cosx_dsp(t_cosx *x, t_signal **sp) +{ + dsp_add(cosx_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *cosx_new(void) +{ + t_cosx *x = (t_cosx *)pd_new(cosx_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void cosx_tilde_setup(void) +{ + cosx_class = class_new(gensym("cosx~"), + (t_newmethod)cosx_new, 0, + sizeof(t_cosx), 0, 0); + sic_setup(cosx_class, cosx_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/count.c b/cyclone/sickle/count.c new file mode 100644 index 0000000..b2ed2cd --- /dev/null +++ b/cyclone/sickle/count.c @@ -0,0 +1,145 @@ +/* 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 "sickle/sic.h" + +typedef struct _count +{ + t_sic x_sic; + int x_min; + int x_max; + int x_limit; + int x_on; + int x_autoreset; + int x_count; /* MAYBE use 64 bits (if 13.5 hours is not enough...) */ +} t_count; + +static t_class *count_class; + +static void count_min(t_count *x, t_floatarg f) +{ + x->x_min = (int)f; +} + +static void count_max(t_count *x, t_floatarg f) +{ + x->x_max = (int)f; + /* MAYBE use 64 bits */ + x->x_limit = (x->x_max == 0 ? 0x7fffffff + : x->x_max - 1); /* CHECKED */ +} + +static void count_autoreset(t_count *x, t_floatarg f) +{ + x->x_autoreset = (f != 0); +} + +static void count_bang(t_count *x) +{ + x->x_count = x->x_min; + x->x_on = 1; +} + +static void count_float(t_count *x, t_floatarg f) +{ + x->x_count = x->x_min = (int)f; + x->x_on = 1; +} + +static void count_list(t_count *x, t_symbol *s, int ac, t_atom *av) +{ + int i; + if (ac > 4) ac = 4; + for (i = 0; i < ac; i++) + if (av[i].a_type != A_FLOAT) break; + switch (i) + { + case 4: + count_autoreset(x, av[3].a_w.w_float); + case 3: + x->x_on = (av[2].a_w.w_float != 0); + case 2: + count_max(x, av[1].a_w.w_float); + case 1: + count_min(x, av[0].a_w.w_float); + default: + x->x_count = x->x_min; + } +} + +static void count_set(t_count *x, t_symbol s, int ac, t_atom *av) +{ + if (av[0].a_type == A_FLOAT) count_min(x, av[0].a_w.w_float); + if (av[1].a_type == A_FLOAT) count_max(x, av[1].a_w.w_float); +} + +static void count_stop(t_count *x) +{ + x->x_count = x->x_min; + x->x_on = 0; +} + +static t_int *count_perform(t_int *w) +{ + t_count *x = (t_count *)(w[1]); + int nblock = (int)(w[2]); + t_float *out = (t_float *)(w[3]); + int count = x->x_count; + int limit = x->x_limit; + if (x->x_on) + { + while (nblock--) + { + if (count > limit) count = x->x_min; + *out++ = (t_float)count++; + } + } + else + while (nblock--) *out++ = count; + x->x_count = count; + return (w + 4); +} + +static void count_dsp(t_count *x, t_signal **sp) +{ + if (x->x_autoreset) count_bang(x); + dsp_add(count_perform, 3, x, sp[0]->s_n, sp[0]->s_vec); +} + +static void *count_new(t_floatarg minval, t_floatarg maxval, + t_floatarg onflag, t_floatarg autoflag) +{ + t_count *x = (t_count *)pd_new(count_class); + count_min(x, minval); + count_max(x, maxval); + x->x_on = (onflag != 0); + count_autoreset(x, autoflag); + x->x_count = x->x_min; + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void count_tilde_setup(void) +{ + count_class = class_new(gensym("count~"), + (t_newmethod)count_new, 0, + sizeof(t_count), 0, + A_DEFFLOAT, A_DEFFLOAT, + A_DEFFLOAT, A_DEFFLOAT, 0); + sic_setup(count_class, count_dsp, SIC_NOMAINSIGNALIN); + class_addbang(count_class, count_bang); + class_addfloat(count_class, count_float); + class_addlist(count_class, count_list); + class_addmethod(count_class, (t_method)count_max, + gensym("ft1"), A_FLOAT, 0); + class_addmethod(count_class, (t_method)count_autoreset, + gensym("autoreset"), A_FLOAT, 0); + class_addmethod(count_class, (t_method)count_min, + gensym("min"), A_FLOAT, 0); + class_addmethod(count_class, (t_method)count_set, + gensym("set"), A_GIMME, 0); + class_addmethod(count_class, (t_method)count_stop, gensym("stop"), 0); +} diff --git a/cyclone/sickle/cycle.c b/cyclone/sickle/cycle.c new file mode 100644 index 0000000..01500ba --- /dev/null +++ b/cyclone/sickle/cycle.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. */ + +#include <string.h> +#include "m_pd.h" +#include "shared.h" +#include "common/loud.h" +#include "common/vefl.h" +#include "sickle/sic.h" + +#define CYCLE_TABSIZE 512 + +typedef struct _cycle +{ + t_sic x_sic; + double x_phase; + double x_conv; + t_symbol *x_name; + int x_offset; + t_float *x_table; + t_float *x_costable; + t_float x_usertable[CYCLE_TABSIZE + 1]; +} t_cycle; + +static t_class *cycle_class; + +static void cycle_gettable(t_cycle *x) +{ + x->x_table = 0; + if (x->x_name) + { + int tabsize = 0; + t_float *table = vefl_get(x->x_name, &tabsize, 1, (t_pd *)x); + /* CHECKED buffer is copied */ + if (table) + { + int indx = x->x_offset + CYCLE_TABSIZE; + t_float *ptr = x->x_usertable + CYCLE_TABSIZE; + if (indx == tabsize) + { + *ptr-- = *table; + indx--; + } + if (indx < tabsize) + { + table += indx; + indx -= x->x_offset; + while (indx--) *ptr-- = *table--; + x->x_table = x->x_usertable; + } + /* CHECKED else no complaint */ + } + } + else x->x_table = x->x_costable; + if (!x->x_table) + { + /* CHECKED (incompatible) cycle~ is disabled -- garbage is output */ + x->x_table = x->x_usertable; + memset(x->x_table, 0, (CYCLE_TABSIZE + 1) * sizeof(*x->x_table)); + } +} + +static void cycle_set(t_cycle *x, t_symbol *s, t_floatarg f) +{ + if (s && s != &s_) + { + x->x_name = s; + if ((x->x_offset = (int)f) < 0) + x->x_offset = 0; + } + else x->x_name = 0; + cycle_gettable(x); +} + +static t_int *cycle_perform(t_int *w) +{ + t_cycle *x = (t_cycle *)(w[1]); + int nblock = (int)(w[2]); + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + t_float *out = (t_float *)(w[5]); + t_float *tab = x->x_table; + t_float *addr, f1, f2, frac; + double dphase = x->x_phase + SHARED_UNITBIT32; + double conv = x->x_conv; + int32 normhipart; + t_shared_wrappy wrappy; + + wrappy.w_d = SHARED_UNITBIT32; + normhipart = wrappy.w_i[SHARED_HIOFFSET]; + + wrappy.w_d = dphase + CYCLE_TABSIZE * *in2++; /* CHECKED */ + dphase += *in1++ * conv; + addr = tab + (wrappy.w_i[SHARED_HIOFFSET] & (CYCLE_TABSIZE-1)); + wrappy.w_i[SHARED_HIOFFSET] = normhipart; + frac = wrappy.w_d - SHARED_UNITBIT32; + + while (--nblock) + { + wrappy.w_d = dphase + CYCLE_TABSIZE * *in2++; /* CHECKED */ + dphase += *in1++ * conv; + f1 = addr[0]; + f2 = addr[1]; + addr = tab + (wrappy.w_i[SHARED_HIOFFSET] & (CYCLE_TABSIZE-1)); + wrappy.w_i[SHARED_HIOFFSET] = normhipart; + *out++ = f1 + frac * (f2 - f1); + frac = wrappy.w_d - SHARED_UNITBIT32; + } + f1 = addr[0]; + f2 = addr[1]; + *out++ = f1 + frac * (f2 - f1); + + wrappy.w_d = SHARED_UNITBIT32 * CYCLE_TABSIZE; + normhipart = wrappy.w_i[SHARED_HIOFFSET]; + wrappy.w_d = dphase + (SHARED_UNITBIT32 * CYCLE_TABSIZE - SHARED_UNITBIT32); + wrappy.w_i[SHARED_HIOFFSET] = normhipart; + x->x_phase = wrappy.w_d - (SHARED_UNITBIT32 * CYCLE_TABSIZE); + return (w + 6); +} + +static void cycle_dsp(t_cycle *x, t_signal **sp) +{ + cycle_gettable(x); + x->x_conv = CYCLE_TABSIZE / sp[0]->s_sr; + dsp_add(cycle_perform, 5, x, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *cycle_new(t_symbol *s, int ac, t_atom *av) +{ + t_cycle *x = (t_cycle *)pd_new(cycle_class); + int i = (ac && av->a_type == A_FLOAT ? 1 : 0); + int tabsize = CYCLE_TABSIZE; + x->x_costable = sic_makecostable(&tabsize); + if (tabsize != CYCLE_TABSIZE) + { + bug("cycle_new"); + pd_free((t_pd *)x); + return (0); + } + if (ac && av->a_type == A_FLOAT) + { + sic_inlet((t_sic *)x, 0, 0, 0, ac, av); + ac--, av++; + } + sic_newinlet((t_sic *)x, 0); + outlet_new((t_object *)x, &s_signal); + x->x_offset = 0; + if (ac && av->a_type == A_SYMBOL) + { + x->x_name = av->a_w.w_symbol; + ac--, av++; + if (ac && av->a_type == A_FLOAT) + if ((x->x_offset = (int)av->a_w.w_float) < 0) + x->x_offset = 0; + } + else x->x_name = 0; + x->x_table = 0; + x->x_phase = 0.; + x->x_conv = 0.; + return (x); +} + +void cycle_tilde_setup(void) +{ + cycle_class = class_new(gensym("cycle~"), + (t_newmethod)cycle_new, 0, + sizeof(t_cycle), 0, A_GIMME, 0); + sic_setup(cycle_class, cycle_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(cycle_class, (t_method)cycle_set, + gensym("set"), A_DEFSYMBOL, A_DEFFLOAT, 0); +} diff --git a/cyclone/sickle/delay.c b/cyclone/sickle/delay.c new file mode 100644 index 0000000..b0ddd9d --- /dev/null +++ b/cyclone/sickle/delay.c @@ -0,0 +1,101 @@ +/* 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 "sickle/sic.h" + +typedef struct _delay +{ + t_sic x_sic; + t_float *x_buf; + t_float *x_bufend; + t_float *x_whead; + int x_maxsize; + int x_delsize; +} t_delay; + +static t_class *delay_class; + +#define DELAY_DEFMAXSIZE 512 + +static void delay_ft1(t_delay *x, t_floatarg f) +{ + x->x_delsize = (f > 0 ? (int)f : 0); + if (x->x_delsize > x->x_maxsize) + x->x_delsize = x->x_maxsize; /* CHECKED */ + /* CHECKED: all buffered values should be available */ +} + +static t_int *delay_perform(t_int *w) +{ + t_delay *x = (t_delay *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_float *buf = x->x_buf; + t_float *ep = x->x_bufend; + t_float *wp = x->x_whead; + if (x->x_delsize) + { + t_float *rp = wp - x->x_delsize; + if (rp < buf) rp += x->x_maxsize; + while (nblock--) + { + float f = *in++; + *out++ = *rp; + if (rp++ == ep) rp = buf; + *wp = f; + if (wp++ == ep) wp = buf; + } + } + else while (nblock--) + { + *out++ = *wp = *in++; + if (wp++ == ep) wp = buf; + } + x->x_whead = wp; + return (w + 5); +} + +static void delay_dsp(t_delay *x, t_signal **sp) +{ + memset(x->x_buf, 0, x->x_maxsize * sizeof(*x->x_buf)); /* CHECKED */ + x->x_whead = x->x_buf; + dsp_add(delay_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *delay_new(t_floatarg f1, t_floatarg f2) +{ + t_delay *x; + int maxsize = (f1 > 0 ? (int)f1 : DELAY_DEFMAXSIZE); + t_float *buf = (t_float *)getbytes(maxsize * sizeof(*buf)); + if (!buf) + return (0); + x = (t_delay *)pd_new(delay_class); + x->x_maxsize = maxsize; + x->x_buf = x->x_whead = buf; + x->x_bufend = buf + maxsize - 1; + x->x_delsize = (f2 > 0 ? (int)f2 : 0); + if (x->x_delsize > maxsize) + x->x_delsize = maxsize; + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +static void delay_free(t_delay *x) +{ + if (x->x_buf) freebytes(x->x_buf, x->x_maxsize * sizeof(*x->x_buf)); +} + +void delay_tilde_setup(void) +{ + delay_class = class_new(gensym("delay~"), + (t_newmethod)delay_new, (t_method)delay_free, + sizeof(t_delay), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + sic_setup(delay_class, delay_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(delay_class, (t_method)delay_ft1, + gensym("ft1"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/delta.c b/cyclone/sickle/delta.c new file mode 100644 index 0000000..145d6b7 --- /dev/null +++ b/cyclone/sickle/delta.c @@ -0,0 +1,52 @@ +/* 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 "sickle/sic.h" + +typedef struct _delta +{ + t_sic x_sic; + t_float x_last; +} t_delta; + +static t_class *delta_class; + +static t_int *delta_perform(t_int *w) +{ + t_delta *x = (t_delta *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_float last = x->x_last; + while (nblock--) + { + t_float f = *in++; + *out++ = f - last; + last = f; + } + x->x_last = last; + return (w + 5); +} + +static void delta_dsp(t_delta *x, t_signal **sp) +{ + dsp_add(delta_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *delta_new(void) +{ + t_delta *x = (t_delta *)pd_new(delta_class); + outlet_new((t_object *)x, &s_signal); + x->x_last = 0; + return (x); +} + +void delta_tilde_setup(void) +{ + delta_class = class_new(gensym("delta~"), + (t_newmethod)delta_new, 0, + sizeof(t_delta), 0, 0); + sic_setup(delta_class, delta_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/deltaclip.c b/cyclone/sickle/deltaclip.c new file mode 100644 index 0000000..89c9321 --- /dev/null +++ b/cyclone/sickle/deltaclip.c @@ -0,0 +1,67 @@ +/* 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 "shared.h" +#include "sickle/sic.h" + +#define DELTACLIP_DEFLO 0. +#define DELTACLIP_DEFHI 0. + +typedef struct _deltaclip +{ + t_sic x_sic; + t_float x_last; +} t_deltaclip; + +static t_class *deltaclip_class; + +static t_int *deltaclip_perform(t_int *w) +{ + t_deltaclip *x = (t_deltaclip *)(w[1]); + int nblock = (int)(w[2]); + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + t_float *in3 = (t_float *)(w[5]); + t_float *out = (t_float *)(w[6]); + t_float last = x->x_last; + while (nblock--) + { + float f = *in1++; + float delta = f - last; + float lo = *in2++; + float hi = *in3++; + if (delta < lo) + f = last + lo; + else if (delta > hi) + f = last + hi; + *out++ = last = f; + } + x->x_last = last; + return (w + 7); +} + +static void deltaclip_dsp(t_deltaclip *x, t_signal **sp) +{ + dsp_add(deltaclip_perform, 6, x, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); +} + +static void *deltaclip_new(t_symbol *s, int ac, t_atom *av) +{ + t_deltaclip *x = (t_deltaclip *)pd_new(deltaclip_class); + sic_inlet((t_sic *)x, 1, DELTACLIP_DEFLO, 0, ac, av); + sic_inlet((t_sic *)x, 2, DELTACLIP_DEFHI, 1, ac, av); + outlet_new((t_object *)x, &s_signal); + x->x_last = 0; + return (x); +} + +void deltaclip_tilde_setup(void) +{ + deltaclip_class = class_new(gensym("deltaclip~"), + (t_newmethod)deltaclip_new, 0, + sizeof(t_deltaclip), 0, A_GIMME, 0); + sic_setup(deltaclip_class, deltaclip_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/edge.c b/cyclone/sickle/edge.c new file mode 100644 index 0000000..b206f6b --- /dev/null +++ b/cyclone/sickle/edge.c @@ -0,0 +1,106 @@ +/* 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 "sickle/sic.h" + +typedef struct _edge +{ + t_sic x_sic; + t_float x_last; + int x_zeroleft; + int x_zerohit; + t_outlet *x_out2; + t_clock *x_clock; +} t_edge; + +static t_class *edge_class; + +static void edge_tick(t_edge *x) +{ + /* CHECKED both may fire simultaneously */ + if (x->x_zeroleft) + { + outlet_bang(((t_object *)x)->ob_outlet); + x->x_zeroleft = 0; + } + if (x->x_zerohit) + { + outlet_bang(x->x_out2); + x->x_zerohit = 0; + } +} + +static t_int *edge_perform(t_int *w) +{ + t_edge *x = (t_edge *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float last = x->x_last; + while (nblock--) + { + float f = *in++; + if (last == 0.) + { + if (f != 0.) + { + x->x_zeroleft = 1; + if (x->x_zerohit) + { + clock_delay(x->x_clock, 0); + x->x_last = in[nblock - 1]; + return (w + 4); + } + } + } + else + { + if (f == 0.) + { + x->x_zerohit = 1; + if (x->x_zeroleft) + { + clock_delay(x->x_clock, 0); + x->x_last = in[nblock - 1]; + return (w + 4); + } + } + } + last = f; + } + if (x->x_zeroleft || x->x_zerohit) clock_delay(x->x_clock, 0); + x->x_last = last; + return (w + 4); +} + +static void edge_dsp(t_edge *x, t_signal **sp) +{ + dsp_add(edge_perform, 3, x, sp[0]->s_n, sp[0]->s_vec); +} + +static void edge_free(t_edge *x) +{ + if (x->x_clock) clock_free(x->x_clock); +} + +static void *edge_new(t_floatarg f) +{ + t_edge *x = (t_edge *)pd_new(edge_class); + x->x_last = 0.; /* CHECKED fires at startup */ + x->x_zeroleft = x->x_zerohit = 0; + outlet_new((t_object *)x, &s_bang); + x->x_out2 = outlet_new((t_object *)x, &s_bang); + x->x_clock = clock_new(x, (t_method)edge_tick); + return (x); +} + +void edge_tilde_setup(void) +{ + edge_class = class_new(gensym("edge~"), + (t_newmethod)edge_new, + (t_method)edge_free, + sizeof(t_edge), 0, + A_DEFFLOAT, 0); + sic_setup(edge_class, edge_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/frameaccum.c b/cyclone/sickle/frameaccum.c new file mode 100644 index 0000000..6038ae5 --- /dev/null +++ b/cyclone/sickle/frameaccum.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 <string.h> +#include "m_pd.h" +#include "common/grow.h" +#include "sickle/sic.h" + +#define FRAMEACCUM_INISIZE 512 + +typedef struct _frameaccum +{ + t_sic x_sic; + int x_size; + t_float *x_frame; + t_float x_frameini[FRAMEACCUM_INISIZE]; +} t_frameaccum; + +static t_class *frameaccum_class; + +static t_int *frameaccum_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *frame = (t_float *)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + while (nblock--) *out++ = (*frame++ += *in++); + return (w + 5); +} + +static void frameaccum_dsp(t_frameaccum *x, t_signal **sp) +{ + int nblock = sp[0]->s_n; + if (nblock > x->x_size) + x->x_frame = grow_nodata(&nblock, &x->x_size, x->x_frame, + FRAMEACCUM_INISIZE, x->x_frameini, + sizeof(*x->x_frame)); + memset(x->x_frame, 0, nblock * sizeof(*x->x_frame)); /* CHECKED */ + dsp_add(frameaccum_perform, 4, nblock, x->x_frame, + sp[0]->s_vec, sp[1]->s_vec); +} + +static void frameaccum_free(t_frameaccum *x) +{ + if (x->x_frame != x->x_frameini) + freebytes(x->x_frame, x->x_size * sizeof(*x->x_frame)); +} + +static void *frameaccum_new(t_symbol *s, int ac, t_atom *av) +{ + t_frameaccum *x = (t_frameaccum *)pd_new(frameaccum_class); + int size; + x->x_size = FRAMEACCUM_INISIZE; + x->x_frame = x->x_frameini; + if ((size = sys_getblksize()) > FRAMEACCUM_INISIZE) + x->x_frame = grow_nodata(&size, &x->x_size, x->x_frame, + FRAMEACCUM_INISIZE, x->x_frameini, + sizeof(*x->x_frame)); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void frameaccum_tilde_setup(void) +{ + frameaccum_class = class_new(gensym("frameaccum~"), + (t_newmethod)frameaccum_new, + (t_method)frameaccum_free, + sizeof(t_frameaccum), 0, 0); + sic_setup(frameaccum_class, frameaccum_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/framedelta.c b/cyclone/sickle/framedelta.c new file mode 100644 index 0000000..b898444 --- /dev/null +++ b/cyclone/sickle/framedelta.c @@ -0,0 +1,76 @@ +/* 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" +#include "sickle/sic.h" + +#define FRAMEDELTA_INISIZE 512 + +typedef struct _framedelta +{ + t_sic x_sic; + int x_size; + t_float *x_frame; + t_float x_frameini[FRAMEDELTA_INISIZE]; +} t_framedelta; + +static t_class *framedelta_class; + +static t_int *framedelta_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *frame = (t_float *)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + while (nblock--) + { + float f = *in++; + *out++ = f - *frame; /* CHECKME */ + *frame++ = f; + } + return (w + 5); +} + +static void framedelta_dsp(t_framedelta *x, t_signal **sp) +{ + int nblock = sp[0]->s_n; + if (nblock > x->x_size) + x->x_frame = grow_nodata(&nblock, &x->x_size, x->x_frame, + FRAMEDELTA_INISIZE, x->x_frameini, + sizeof(*x->x_frame)); + memset(x->x_frame, 0, nblock * sizeof(*x->x_frame)); /* CHECKME */ + dsp_add(framedelta_perform, 4, nblock, x->x_frame, + sp[0]->s_vec, sp[1]->s_vec); +} + +static void framedelta_free(t_framedelta *x) +{ + if (x->x_frame != x->x_frameini) + freebytes(x->x_frame, x->x_size * sizeof(*x->x_frame)); +} + +static void *framedelta_new(t_symbol *s, int ac, t_atom *av) +{ + t_framedelta *x = (t_framedelta *)pd_new(framedelta_class); + int size; + x->x_size = FRAMEDELTA_INISIZE; + x->x_frame = x->x_frameini; + if ((size = sys_getblksize()) > FRAMEDELTA_INISIZE) + x->x_frame = grow_nodata(&size, &x->x_size, x->x_frame, + FRAMEDELTA_INISIZE, x->x_frameini, + sizeof(*x->x_frame)); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void framedelta_tilde_setup(void) +{ + framedelta_class = class_new(gensym("framedelta~"), + (t_newmethod)framedelta_new, + (t_method)framedelta_free, + sizeof(t_framedelta), 0, 0); + sic_setup(framedelta_class, framedelta_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/index.c b/cyclone/sickle/index.c new file mode 100644 index 0000000..036e6fb --- /dev/null +++ b/cyclone/sickle/index.c @@ -0,0 +1,107 @@ +/* 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: 'click' method */ + +#include <string.h> +#include "m_pd.h" +#include "sickle/sic.h" +#include "sickle/arsic.h" + +#define INDEX_MAXCHANNELS 4 /* LATER implement arsic resizing feature */ + +typedef struct _index +{ + t_arsic x_arsic; + int x_maxchannels; + int x_effchannel; /* effective channel (clipped reqchannel) */ + int x_reqchannel; /* requested channel */ +} t_index; + +static t_class *index_class; + +static void index_set(t_index *x, t_symbol *s) +{ + arsic_setarray((t_arsic *)x, s, 1); +} + +static t_int *index_perform(t_int *w) +{ + t_arsic *sic = (t_arsic *)(w[1]); + int nblock = (int)(w[2]); + t_float *out = (t_float *)(w[4]); + if (sic->s_playable) + { + t_index *x = (t_index *)sic; + t_float *xin = (t_float *)(w[3]); + int index, maxindex = sic->s_vecsize - 1; + t_float *vp = sic->s_vectors[x->x_effchannel]; + if (vp) /* handle array swapping on the fly via ft1 */ + { + while (nblock--) + { + index = (int)(*xin++ + 0.5); + if (index < 0) + index = 0; + else if (index > maxindex) + index = maxindex; + *out++ = vp[index]; + } + } + else while (nblock--) *out++ = 0; + } + else while (nblock--) *out++ = 0; + return (w + 5); +} + +static void index_ft1(t_index *x, t_floatarg f) +{ + if ((x->x_reqchannel = (f > 1 ? (int)f - 1 : 0)) > x->x_maxchannels) + x->x_effchannel = x->x_maxchannels - 1; + else + x->x_effchannel = x->x_reqchannel; +} + +static void index_dsp(t_index *x, t_signal **sp) +{ + t_arsic *sic = (t_arsic *)x; + arsic_dsp(sic, sp, index_perform, sic->s_mononame != 0); +} + +static void index_free(t_index *x) +{ + arsic_free((t_arsic *)x); +} + +static void *index_new(t_symbol *s, t_floatarg f) +{ + int ch = (f > 0 ? (int)f : 0); + /* two signals: index input, value output */ + t_index *x = (t_index *)arsic_new(index_class, s, + (ch ? INDEX_MAXCHANNELS : 0), 2, 0); + if (x) + { + if (ch > INDEX_MAXCHANNELS) + ch = INDEX_MAXCHANNELS; + x->x_maxchannels = (ch ? INDEX_MAXCHANNELS : 1); + x->x_effchannel = x->x_reqchannel = (ch ? ch - 1 : 0); + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); + outlet_new((t_object *)x, &s_signal); + } + return (x); +} + +void index_tilde_setup(void) +{ + index_class = class_new(gensym("index~"), + (t_newmethod)index_new, + (t_method)index_free, + sizeof(t_index), 0, + A_DEFSYM, A_DEFFLOAT, 0); + arsic_setup(index_class, index_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(index_class, (t_method)index_set, + gensym("set"), A_SYMBOL, 0); + class_addmethod(index_class, (t_method)index_ft1, + gensym("ft1"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/kink.c b/cyclone/sickle/kink.c new file mode 100644 index 0000000..86bc81d --- /dev/null +++ b/cyclone/sickle/kink.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. */ + +/* CHECKED negative float in 2nd inlet: "illegal slope value %f", + but no complaints for signal input -- this is impossible in Pd. + The only thing we could do (and a bit stupid one) would be to + clock this exception out from the perf routine. */ + +#include "m_pd.h" +#include "sickle/sic.h" + +#define KINK_DEFSLOPE 1.0 + +typedef t_sic t_kink; +static t_class *kink_class; + +static t_int *kink_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + while (nblock--) + { + float iph = *in1++; + float slope = *in2++; + float oph = iph * slope; + if (oph > .5) + { + slope = 1. / (slope + slope); /* x(y=.5) */ + if (slope == 1.) + *out++ = 0; /* CHECKED */ + else + *out++ = (iph - slope) / (2. - (slope + slope)) + .5; + } + else *out++ = oph; + } + return (w + 5); +} + +static void kink_dsp(t_kink *x, t_signal **sp) +{ + dsp_add(kink_perform, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *kink_new(t_symbol *s, int ac, t_atom *av) +{ + t_kink *x = (t_kink *)pd_new(kink_class); + sic_inlet((t_sic *)x, 1, KINK_DEFSLOPE, 0, ac, av); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void kink_tilde_setup(void) +{ + kink_class = class_new(gensym("kink~"), + (t_newmethod)kink_new, 0, + sizeof(t_kink), 0, A_GIMME, 0); + sic_setup(kink_class, kink_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/linedrive.c b/cyclone/sickle/linedrive.c new file mode 100644 index 0000000..8b133ab --- /dev/null +++ b/cyclone/sickle/linedrive.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. */ + +/* CHECKME polarity */ + +#include <math.h> +#include "m_pd.h" + +#if defined(NT) || defined(MACOSX) +#define logf log +#define expf exp +#endif + +static t_class *linedrive_class; + +typedef struct _linedrive +{ + t_object x_ob; + t_float x_maxin; + t_float x_maxout; + t_float x_expcoef; + t_float x_lincoef; + t_atom x_vec[2]; + int x_linear; +} t_linedrive; + +static void linedrive_float(t_linedrive *x, t_floatarg f) +{ + float outval = f - x->x_maxin; + if (outval >= 0) + outval = x->x_maxout; /* CHECKED */ + else if (x->x_linear) + outval = x->x_maxout + outval * x->x_lincoef; + else + outval = expf(outval * x->x_expcoef) * x->x_maxout; + SETFLOAT(x->x_vec, outval); + outlet_list(((t_object *)x)->ob_outlet, 0, 2, x->x_vec); +} + +static void *linedrive_new(t_floatarg maxin, t_floatarg maxout, + t_floatarg curve, t_floatarg deltime) +{ + t_linedrive *x = (t_linedrive *)pd_new(linedrive_class); + x->x_maxin = (maxin < 1.0e-20f && maxin > -1e-20f ? 0 : maxin); + x->x_maxout = maxout; + if (curve < 1.0e-20f) curve = 1.0; /* a bug in msp? */ + if (curve == 1.0) + { + x->x_expcoef = 0; + x->x_lincoef = (x->x_maxin == 0 ? 0 : x->x_maxout / x->x_maxin); + x->x_linear = 1; + } + else { + x->x_expcoef = logf(curve); + x->x_lincoef = 0; + x->x_linear = 0; + } + SETFLOAT(&x->x_vec[1], deltime); /* CHECKED: any value accepted */ + floatinlet_new((t_object *)x, &x->x_vec[1].a_w.w_float); + outlet_new((t_object *)x, &s_list); + return (x); +} + +void linedrive_setup(void) +{ + linedrive_class = class_new(gensym("linedrive"), + (t_newmethod)linedrive_new, 0, + sizeof(t_linedrive), 0, + A_DEFFLOAT, A_DEFFLOAT, + A_DEFFLOAT, A_DEFFLOAT, 0); + class_addfloat(linedrive_class, linedrive_float); +} diff --git a/cyclone/sickle/log.c b/cyclone/sickle/log.c new file mode 100644 index 0000000..74e3e40 --- /dev/null +++ b/cyclone/sickle/log.c @@ -0,0 +1,74 @@ +/* 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" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define logf log +#endif + +#define LOG_MININPUT 1e-10 /* CHECKED */ + +typedef struct _log +{ + t_sic x_sic; + t_float x_rcplogbase; /* LATER consider using double (and log()) */ +} t_log; + +static t_class *log_class; + +static void log_ft1(t_log *x, t_floatarg f) +{ + x->x_rcplogbase = (f == 0. ? 1. : /* CHECKED no protection against NaNs */ + (f == 1. ? 0. : /* CHECKED */ + 1. / logf(f))); +} + +static t_int *log_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + t_float rcplogbase = *(t_float *)(w[4]); + if (rcplogbase != 0.) + { + while (nblock--) + { + float f = *in++; + if (f < LOG_MININPUT) + f = LOG_MININPUT; /* CHECKED */ + *out++ = logf(f) * rcplogbase; + } + } + else while (nblock--) *out++ = 0.; + return (w + 5); +} + +static void log_dsp(t_log *x, t_signal **sp) +{ + dsp_add(log_perform, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, + &x->x_rcplogbase); +} + +static void *log_new(t_floatarg f) +{ + t_log *x = (t_log *)pd_new(log_class); + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); + outlet_new((t_object *)x, &s_signal); + log_ft1(x, f); + return (x); +} + +void log_tilde_setup(void) +{ + log_class = class_new(gensym("log~"), + (t_newmethod)log_new, 0, + sizeof(t_log), 0, A_DEFFLOAT, 0); + sic_setup(log_class, log_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(log_class, (t_method)log_ft1, + gensym("ft1"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/lookup.c b/cyclone/sickle/lookup.c new file mode 100644 index 0000000..1c6a8af --- /dev/null +++ b/cyclone/sickle/lookup.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. */ + +/* LATER reconsider making float/int conversions + more compatible (and less useful). */ + +#include "m_pd.h" +#include "sickle/sic.h" +#include "sickle/arsic.h" + +typedef t_arsic t_lookup; +static t_class *lookup_class; + +#define LOOKUP_DEFSIZE 512 + +static void lookup_set(t_lookup *x, t_symbol *s) +{ + arsic_setarray((t_arsic *)x, s, 1); +} + +static t_int *lookup_perform(t_int *w) +{ + t_arsic *sic = (t_arsic *)(w[1]); + int nblock = (int)(w[2]); + t_float *out = (t_float *)(w[6]); + if (sic->s_playable) + { + t_float *xin = (t_float *)(w[3]); + t_float *oin = (t_float *)(w[4]); + t_float *sin = (t_float *)(w[5]); + int vecsize = sic->s_vecsize; + t_float *vec = sic->s_vectors[0]; /* playable implies nonzero (mono) */ + while (nblock--) + { + float off = *oin++; /* msp: converted to int (if not a signal) */ + int siz = (int)*sin++ - 1; /* msp: converted to int (signal too) */ + float pos = (siz > 0 ? off + siz * (*xin++ + 1.0) * 0.5 : off); + int ndx = (int)pos; + int ndx1 = ndx + 1; + if (ndx1 > 0 && ndx1 < vecsize) + { + float val = vec[ndx]; + *out++ = val + (vec[ndx1] - val) * (pos - ndx); + } + /* CHECKED: */ + else if (ndx1 == 0) *out++ = *vec * (pos + 1.0); + else if (ndx1 == vecsize) *out++ = vec[ndx] * (ndx1 - pos); + else *out++ = 0; + } + } + else while (nblock--) *out++ = 0; + return (w + 7); +} + +static void lookup_dsp(t_lookup *x, t_signal **sp) +{ + arsic_dsp((t_arsic *)x, sp, lookup_perform, 1); +} + +static void lookup_free(t_lookup *x) +{ + arsic_free((t_arsic *)x); +} + +static void *lookup_new(t_symbol *s, t_floatarg f1, t_floatarg f2) +{ + /* CHECKED: lookup~ always uses the first channel in a multi-channel buffer~ + (as the refman says). */ + /* three auxiliary signals: amplitude, offset and size inputs */ + t_lookup *x = (t_lookup *)arsic_new(lookup_class, s, 0, 0, 3); + if (x) + { + arsic_setminsize((t_arsic *)x, 2); + if (f1 < 0) f1 = 0; + if (f2 <= 0) f2 = LOOKUP_DEFSIZE; + sic_newinlet((t_sic *)x, f1); + sic_newinlet((t_sic *)x, f2); + outlet_new((t_object *)x, &s_signal); + } + return (x); +} + +void lookup_tilde_setup(void) +{ + lookup_class = class_new(gensym("lookup~"), + (t_newmethod)lookup_new, + (t_method)lookup_free, + sizeof(t_lookup), 0, + A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0); + arsic_setup(lookup_class, lookup_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(lookup_class, (t_method)lookup_set, + gensym("set"), A_SYMBOL, 0); +} diff --git a/cyclone/sickle/minmax.c b/cyclone/sickle/minmax.c new file mode 100644 index 0000000..5bd0e39 --- /dev/null +++ b/cyclone/sickle/minmax.c @@ -0,0 +1,78 @@ +/* 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 "sickle/sic.h" + +typedef struct _minmax +{ + t_sic x_sic; + t_float x_min; + t_float x_max; + t_outlet *x_minout; + t_outlet *x_maxout; +} t_minmax; + +static t_class *minmax_class; + +static void minmax_bang(t_minmax *x) +{ + outlet_float(x->x_maxout, x->x_max); + outlet_float(x->x_minout, x->x_min); +} + +static void minmax_reset(t_minmax *x) +{ + x->x_min = x->x_max = 0; /* CHECKME */ +} + +static t_int *minmax_perform(t_int *w) +{ + t_minmax *x = (t_minmax *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *outmin = (t_float *)(w[4]); + t_float *outmax = (t_float *)(w[5]); + t_float fmin = x->x_min; + t_float fmax = x->x_max; + while (nblock--) + { + t_float f = *in++; + if (f < fmin) fmin = f; + else if (f > fmax) fmax = f; + *outmin++ = fmin; + *outmax++ = fmax; + } + x->x_min = fmin; + x->x_max = fmax; + return (w + 6); +} + +static void minmax_dsp(t_minmax *x, t_signal **sp) +{ + dsp_add(minmax_perform, 5, x, sp[0]->s_n, sp[0]->s_vec, + sp[1]->s_vec, sp[2]->s_vec); +} + +static void *minmax_new(void) +{ + t_minmax *x = (t_minmax *)pd_new(minmax_class); + outlet_new((t_object *)x, &s_signal); + outlet_new((t_object *)x, &s_signal); + x->x_minout = outlet_new((t_object *)x, &s_float); + x->x_maxout = outlet_new((t_object *)x, &s_float); + minmax_reset(x); + return (x); +} + +void minmax_tilde_setup(void) +{ + minmax_class = class_new(gensym("minmax~"), + (t_newmethod)minmax_new, 0, + sizeof(t_minmax), 0, 0); + sic_setup(minmax_class, minmax_dsp, SIC_FLOATTOSIGNAL); + class_addbang(minmax_class, minmax_bang); + class_addmethod(minmax_class, (t_method)minmax_reset, + gensym("reset"), 0); +} diff --git a/cyclone/sickle/peakamp.c b/cyclone/sickle/peakamp.c new file mode 100644 index 0000000..67d1093 --- /dev/null +++ b/cyclone/sickle/peakamp.c @@ -0,0 +1,107 @@ +/* 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 "sickle/sic.h" + +typedef struct _peakamp +{ + t_sic x_sic; + t_float x_value; + int x_nwait; + int x_nleft; + int x_precount; + float x_waittime; + float x_ksr; + t_clock *x_clock; +} t_peakamp; + +static t_class *peakamp_class; + +static void peakamp_tick(t_peakamp *x) +{ + outlet_float(((t_object *)x)->ob_outlet, x->x_value); + x->x_value = 0; + if ((x->x_nleft = x->x_nwait - x->x_precount) < 0) /* CHECKME */ + x->x_nleft = 0; +} + +static void peakamp_bang(t_peakamp *x) +{ + peakamp_tick(x); /* CHECKME */ +} + +static void peakamp_ft1(t_peakamp *x, t_floatarg f) +{ + if ((x->x_waittime = f) < 0.) + x->x_waittime = 0.; + if ((x->x_nwait = (int)(x->x_waittime * x->x_ksr)) < 0) + x->x_nwait = 0; +} + +static t_int *peakamp_perform(t_int *w) +{ + t_peakamp *x = (t_peakamp *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float value = x->x_value; + if (x->x_nwait) + { + if (x->x_nleft < nblock) + { + clock_delay(x->x_clock, 0); + x->x_precount = nblock - x->x_nleft; + x->x_nleft = 0; /* LATER rethink */ + } + else x->x_nleft -= nblock; + } + while (nblock--) + { + t_float f = *in++; + if (f > value) + value = f; + else if (f < -value) + value = -f; + } + x->x_value = value; + return (w + 4); +} + +static void peakamp_dsp(t_peakamp *x, t_signal **sp) +{ + x->x_ksr = sp[0]->s_sr * 0.001; + x->x_nwait = (int)(x->x_waittime * x->x_ksr); + dsp_add(peakamp_perform, 3, x, sp[0]->s_n, sp[0]->s_vec); +} + +static void peakamp_free(t_peakamp *x) +{ + if (x->x_clock) clock_free(x->x_clock); +} + +static void *peakamp_new(t_floatarg f) +{ + t_peakamp *x = (t_peakamp *)pd_new(peakamp_class); + x->x_value = 0.; + x->x_nleft = 0; + x->x_ksr = sys_getsr() * 0.001; + peakamp_ft1(x, f); + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); + outlet_new((t_object *)x, &s_float); + x->x_clock = clock_new(x, (t_method)peakamp_tick); + return (x); +} + +void peakamp_tilde_setup(void) +{ + peakamp_class = class_new(gensym("peakamp~"), + (t_newmethod)peakamp_new, + (t_method)peakamp_free, + sizeof(t_peakamp), 0, + A_DEFFLOAT, 0); + sic_setup(peakamp_class, peakamp_dsp, SIC_FLOATTOSIGNAL); + class_addbang(peakamp_class, peakamp_bang); + class_addmethod(peakamp_class, (t_method)peakamp_ft1, + gensym("ft1"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/peek.c b/cyclone/sickle/peek.c new file mode 100644 index 0000000..7397577 --- /dev/null +++ b/cyclone/sickle/peek.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. */ + +/* LATER: 'click' method */ + +#include <string.h> +#include "m_pd.h" +#include "sickle/sic.h" +#include "sickle/arsic.h" + +#define PEEK_MAXCHANNELS 4 /* LATER implement arsic resizing feature */ + +typedef struct _peek +{ + t_arsic x_arsic; + int x_maxchannels; + int x_effchannel; /* effective channel (clipped reqchannel) */ + int x_reqchannel; /* requested channel */ + int x_clipmode; + int x_pokemode; + t_float x_value; + t_clock *x_clock; + double x_clocklasttick; + int x_clockset; +} t_peek; + +static t_class *peek_class; + +static void peek_tick(t_peek *x) +{ + arsic_redraw((t_arsic *)x); /* LATER redraw only dirty channel(s!) */ + x->x_clockset = 0; + x->x_clocklasttick = clock_getsystime(); +} + +static void peek_set(t_peek *x, t_symbol *s) +{ + arsic_setarray((t_arsic *)x, s, 1); +} + +#define peek_doclip(f) (f < -1. ? -1. : (f > 1. ? 1. : f)) + +/* CHECKED refman error: ``if the number received in the left inlet + specifies a sample index that does not exist in the buffer~ object's + currently allocated memory, nothing happens.'' This is plainly wrong, + at least for max/msp 4.0.7 bundle: the index is clipped (just like + in tabread/tabwrite). As a kind of an experiment, lets make this + the refman's way... */ +static void peek_float(t_peek *x, t_float f) +{ + t_arsic *sic = (t_arsic *)x; + t_float *vp; + arsic_validate(sic, 0); /* LATER rethink (efficiency, and complaining) */ + if (vp = sic->s_vectors[x->x_effchannel]) + { + int ndx = (int)f; + if (vp && ndx >= 0 && ndx < sic->s_vecsize) + { + if (x->x_pokemode) + { + double timesince; + t_float f = x->x_value; + vp[ndx] = (x->x_clipmode ? peek_doclip(f) : f); + x->x_pokemode = 0; + timesince = clock_gettimesince(x->x_clocklasttick); + if (timesince > 1000) peek_tick(x); + else if (!x->x_clockset) + { + clock_delay(x->x_clock, 1000 - timesince); + x->x_clockset = 1; + } + } + /* CHECKED: output not clipped */ + else outlet_float(((t_object *)x)->ob_outlet, vp[ndx]); + } + } +} + +static void peek_ft1(t_peek *x, t_floatarg f) +{ + x->x_value = f; + x->x_pokemode = 1; + /* CHECKED: poke-mode is reset only after receiving left inlet input + -- it is kept across 'ft2', 'clip', and 'set' inputs. */ +} + +static void peek_ft2(t_peek *x, t_floatarg f) +{ + if ((x->x_reqchannel = (f > 1 ? (int)f - 1 : 0)) > x->x_maxchannels) + x->x_effchannel = x->x_maxchannels - 1; + else + x->x_effchannel = x->x_reqchannel; +} + +static void peek_clip(t_peek *x, t_floatarg f) +{ + x->x_clipmode = ((int)f != 0); +} + +static void peek_free(t_peek *x) +{ + if (x->x_clock) clock_free(x->x_clock); + arsic_free((t_arsic *)x); +} + +static void *peek_new(t_symbol *s, t_floatarg f1, t_floatarg f2) +{ + int ch = (f1 > 0 ? (int)f1 : 0); + t_peek *x = (t_peek *)arsic_new(peek_class, s, + (ch ? PEEK_MAXCHANNELS : 0), 0, 0); + if (x) + { + if (ch > PEEK_MAXCHANNELS) + ch = PEEK_MAXCHANNELS; + x->x_maxchannels = (ch ? PEEK_MAXCHANNELS : 1); + x->x_effchannel = x->x_reqchannel = (ch ? ch - 1 : 0); + /* CHECKED (refman error) clipping is disabled by default */ + x->x_clipmode = ((int)f2 != 0); + x->x_pokemode = 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")); + outlet_new((t_object *)x, &s_float); + x->x_clock = clock_new(x, (t_method)peek_tick); + x->x_clocklasttick = clock_getsystime(); + x->x_clockset = 0; + } + return (x); +} + +void peek_tilde_setup(void) +{ + peek_class = class_new(gensym("peek~"), + (t_newmethod)peek_new, + (t_method)peek_free, + sizeof(t_peek), 0, + A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addfloat(peek_class, peek_float); + class_addmethod(peek_class, (t_method)peek_set, + gensym("set"), A_SYMBOL, 0); + class_addmethod(peek_class, (t_method)peek_ft1, + gensym("ft1"), A_FLOAT, 0); + class_addmethod(peek_class, (t_method)peek_ft2, + gensym("ft2"), A_FLOAT, 0); + class_addmethod(peek_class, (t_method)peek_clip, + gensym("clip"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/phasewrap.c b/cyclone/sickle/phasewrap.c new file mode 100644 index 0000000..535d5e8 --- /dev/null +++ b/cyclone/sickle/phasewrap.c @@ -0,0 +1,131 @@ +/* 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" +#include "shared.h" +#include "sickle/sic.h" + +typedef struct _phasewrap +{ + t_sic x_sic; + int x_algo; +} t_phasewrap; + +static t_class *phasewrap_class; + +static t_int *phasewrap_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + t_shared_wrappy wrappy; + while (nblock--) + { + /* FIXME here we have pi -> pi, 3pi -> -pi, -pi -> -pi, -3pi -> pi, + while in msp it is pi -> -pi, 3pi -> -pi, -pi -> pi, -3pi -> pi */ + + double dnorm = *in++ * (1. / SHARED_2PI); + wrappy.w_d = dnorm + SHARED_UNITBIT0; + /* Speeding up the int-to-double conversion below would be nice, + but all attempts failed. Even this is slower (which works only + for nonnegative input): + + wrappy.w_i[SHARED_HIOFFSET] = SHARED_UNITBIT0_HIPART; + *out++ = (dnorm - (wrappy.w_d - SHARED_UNITBIT0)) * SHARED_2PI; + */ + dnorm -= wrappy.w_i[SHARED_LOWOFFSET]; + *out++ = dnorm * SHARED_2PI; + } + return (w + 4); +} + +/* This is the slowest algo. It is slower than fmod in all cases, + except for input being zero. */ +static t_int *phasewrap_perform1(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + double dnorm; + if (f < -SHARED_PI) + { + dnorm = (double)f * (1. / SHARED_2PI) + .5; + *out++ = (dnorm - (int)dnorm) * SHARED_2PI + SHARED_PI; + } + else if (f > SHARED_PI) + { + dnorm = (double)f * (1. / SHARED_2PI) + .5; + *out++ = (dnorm - (int)dnorm) * SHARED_2PI - SHARED_PI; + } + else *out++ = f; + } + return (w + 4); +} + +static t_int *phasewrap_perform2(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + double dnorm = *in++ + SHARED_PI; + if (dnorm < 0) + *out++ = SHARED_PI - fmod(-dnorm, SHARED_2PI); + else + *out++ = fmod(dnorm, SHARED_2PI) - SHARED_PI; + } + return (w + 4); +} + +static void phasewrap_dsp(t_phasewrap *x, t_signal **sp) +{ + switch (x->x_algo) + { + case 1: + dsp_add(phasewrap_perform1, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + break; + case 2: + dsp_add(phasewrap_perform2, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + break; + default: + dsp_add(phasewrap_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); + } +} + +static void phasewrap__algo(t_phasewrap *x, t_floatarg f) +{ + x->x_algo = f; +} + +static void *phasewrap_new(t_symbol *s, int ac, t_atom *av) +{ + t_phasewrap *x = (t_phasewrap *)pd_new(phasewrap_class); + if (s == gensym("_phasewrap1~")) + x->x_algo = 1; + else if (s == gensym("_phasewrap2~")) + x->x_algo = 2; + else + x->x_algo = 0; + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void phasewrap_tilde_setup(void) +{ + phasewrap_class = class_new(gensym("phasewrap~"), + (t_newmethod)phasewrap_new, 0, + sizeof(t_phasewrap), 0, A_GIMME, 0); + class_addcreator((t_newmethod)phasewrap_new, + gensym("_phasewrap1~"), A_GIMME, 0); + class_addcreator((t_newmethod)phasewrap_new, + gensym("_phasewrap2~"), A_GIMME, 0); + sic_setup(phasewrap_class, phasewrap_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(phasewrap_class, (t_method)phasewrap__algo, + gensym("_algo"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/play.c b/cyclone/sickle/play.c new file mode 100644 index 0000000..9d2c303 --- /dev/null +++ b/cyclone/sickle/play.c @@ -0,0 +1,122 @@ +/* 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 "sickle/sic.h" +#include "sickle/arsic.h" + +/* CHECKME (the refman): if the buffer~ has more channels, channels are mixed */ + +typedef t_arsic t_play; +static t_class *play_class; + +static void play_set(t_play *x, t_symbol *s) +{ + arsic_setarray((t_arsic *)x, s, 1); +} + +/* LATER optimize */ +static t_int *play_perform(t_int *w) +{ + t_arsic *sic = (t_arsic *)(w[1]); + int nblock = (int)(w[2]); + int nch = sic->s_nchannels; + t_int *outp = w + 4; + if (sic->s_playable) + { + t_play *x = (t_play *)sic; + t_float *xin = (t_float *)(w[3]); + int vecsize = sic->s_vecsize; + t_float **vectable = sic->s_vectors; + float ksr = sic->s_ksr; + int nointerp = 0; + int maxindex = (nointerp ? vecsize - 1 : vecsize - 3); + int iblock; + + for (iblock = 0; iblock < nblock; iblock++) + { + float phase = *xin++ * ksr; + int ndx; + int ch = nch; + float frac, a, b, c, d, cminusb; + if (phase < 0 || phase > maxindex) + phase = 0; /* CHECKED: a value 0, not ndx 0 */ + ndx = (int)phase; + /* CHECKME: what kind of interpolation? (CHECKED: multi-point) */ + if (ndx < 1) + ndx = 1, frac = 0; + else if (ndx > maxindex) + ndx = maxindex, frac = 1; + else frac = phase - ndx; + while (ch--) + { + t_float *vp = vectable[ch]; + t_float *out = (t_float *)(outp[ch]); + if (vp) + { + vp += ndx; + a = vp[-1]; + b = vp[0]; + c = vp[1]; + d = vp[2]; + cminusb = c-b; + out[iblock] = b + frac * ( + cminusb - 0.1666667f * (1. - frac) * ( + (d - a - 3.0f * cminusb) * frac + + (d + 2.0f * a - 3.0f * b) + ) + ); + } + else out[iblock] = 0; + } + } + } + else + { + int ch = nch; + while (ch--) + { + t_float *out = (t_float *)outp[ch]; + int n = nblock; + while (n--) *out++ = 0; + } + } + return (w + sic->s_nperfargs + 1); +} + +static void play_dsp(t_play *x, t_signal **sp) +{ + arsic_dsp((t_arsic *)x, sp, play_perform, 1); +} + +static void play_free(t_play *x) +{ + arsic_free((t_arsic *)x); +} + +static void *play_new(t_symbol *s, t_floatarg f) +{ + /* one auxiliary signal: position input */ + t_play *x = (t_play *)arsic_new(play_class, s, (int)f, 0, 1); + if (x) + { + int nch = arsic_getnchannels((t_arsic *)x); + while (nch--) + outlet_new((t_object *)x, &s_signal); + } + return (x); +} + +void play_tilde_setup(void) +{ + play_class = class_new(gensym("play~"), + (t_newmethod)play_new, + (t_method)play_free, + sizeof(t_play), 0, + A_DEFSYM, A_DEFFLOAT, 0); + arsic_setup(play_class, play_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(play_class, (t_method)play_set, + gensym("set"), A_SYMBOL, 0); +} diff --git a/cyclone/sickle/poltocar.c b/cyclone/sickle/poltocar.c new file mode 100644 index 0000000..8d7f94c --- /dev/null +++ b/cyclone/sickle/poltocar.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 <math.h> +#include "m_pd.h" +#include "unstable/fragile.h" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define sinf sin +#define cosf cos +#endif + +typedef struct _poltocar +{ + t_sic x_sic; + t_outlet *x_out2; +} t_poltocar; + +static t_class *poltocar_class; + +static t_int *poltocar_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out1 = (t_float *)(w[4]); + t_float *out2 = (t_float *)(w[5]); + while (nblock--) + { + float am = *in1++, ph = *in2++; + *out1++ = am * cosf(ph); + *out2++ = -am * sinf(ph); /* CHECKED */ + } + return (w + 6); +} + +static t_int *poltocar_perform_noimag(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out1 = (t_float *)(w[4]); + while (nblock--) + { + float am = *in1++, ph = *in2++; + *out1++ = am * cosf(ph); + } + return (w + 5); +} + +static void poltocar_dsp(t_poltocar *x, t_signal **sp) +{ + if (fragile_outlet_connections(x->x_out2)) + dsp_add(poltocar_perform, 5, sp[0]->s_n, sp[0]->s_vec, + sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); + else + dsp_add(poltocar_perform_noimag, 4, sp[0]->s_n, sp[0]->s_vec, + sp[1]->s_vec, sp[2]->s_vec); +} + +static void *poltocar_new(void) +{ + t_poltocar *x = (t_poltocar *)pd_new(poltocar_class); + inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); + outlet_new((t_object *)x, &s_signal); + x->x_out2 = outlet_new((t_object *)x, &s_signal); + return (x); +} + +void poltocar_tilde_setup(void) +{ + poltocar_class = class_new(gensym("poltocar~"), + (t_newmethod)poltocar_new, 0, + sizeof(t_poltocar), 0, 0); + sic_setup(poltocar_class, poltocar_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/pow.c b/cyclone/sickle/pow.c new file mode 100644 index 0000000..11cd508 --- /dev/null +++ b/cyclone/sickle/pow.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 <math.h> +#include "m_pd.h" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define powf pow +#endif + +typedef t_sic t_pow; +static t_class *pow_class; + +static t_int *pow_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in1 = (t_float *)(w[2]); + t_float *in2 = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + while (nblock--) + { + float f1 = *in1++; + float f2 = *in2++; + /* CHECKED arg order, no protection against NaNs (negative base), + under-, and overflows */ + *out++ = powf(f2, f1); + } + return (w + 5); +} + +static void pow_dsp(t_pow *x, t_signal **sp) +{ + dsp_add(pow_perform, 4, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *pow_new(t_floatarg f) +{ + t_pow *x = (t_pow *)pd_new(pow_class); + sic_newinlet((t_sic *)x, f); /* CHECKED default 0 */ + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void pow_tilde_setup(void) +{ + pow_class = class_new(gensym("pow~"), + (t_newmethod)pow_new, 0, + sizeof(t_pow), 0, A_DEFFLOAT, 0); + sic_setup(pow_class, pow_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/rampsmooth.c b/cyclone/sickle/rampsmooth.c new file mode 100644 index 0000000..c2023d8 --- /dev/null +++ b/cyclone/sickle/rampsmooth.c @@ -0,0 +1,206 @@ +/* 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 "sickle/sic.h" + +#define RAMPSMOOTH_GEOMETRIC /* geometric series (same as slide~) CHECKED */ +#ifndef RAMPSMOOTH_GEOMETRIC +#define RAMPSMOOTH_LINEAR +#endif +#define RAMPSMOOTH_DEFNUP 0. +#define RAMPSMOOTH_DEFNDOWN 0. + +typedef struct _rampsmooth +{ + t_sic x_sic; + int x_nup; + int x_ndown; + double x_upcoef; + double x_downcoef; + t_float x_last; +#ifdef RAMPSMOOTH_LINEAR + t_float x_target; + double x_incr; + int x_nleft; +#endif +} t_rampsmooth; + +static t_class *rampsmooth_class; + +#ifdef RAMPSMOOTH_LINEAR +/* this is a true linear ramper */ +static t_int *rampsmooth_perform(t_int *w) +{ + t_rampsmooth *x = (t_rampsmooth *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_float last = x->x_last; + t_float target = x->x_target; + double incr = x->x_incr; + int nleft = x->x_nleft; + while (nblock--) + { + t_float f = *in++; + if (f != target) + { + target = f; + if (f > last) + { + if (x->x_nup > 1) + { + incr = (f - last) * x->x_upcoef; + nleft = x->x_nup; + *out++ = (last += incr); + continue; + } + } + else if (f < last) + { + if (x->x_ndown > 1) + { + incr = (f - last) * x->x_downcoef; + nleft = x->x_ndown; + *out++ = (last += incr); + continue; + } + } + incr = 0.; + nleft = 0; + *out++ = last = f; + } + else if (nleft > 0) + { + *out++ = (last += incr); + if (--nleft == 0) + { + incr = 0.; + last = target; + } + } + else *out++ = target; + } + x->x_last = last; + x->x_target = target; + x->x_incr = incr; + x->x_nleft = nleft; + return (w + 5); +} + +#else + +/* this ramper generates a geometric series output for a single step input */ +static t_int *rampsmooth_perform(t_int *w) +{ + t_rampsmooth *x = (t_rampsmooth *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + t_float last = x->x_last; + while (nblock--) + { + t_float f = *in++; + if (f > last) + { + if (x->x_nup > 1) + { + *out++ = (last += (f - last) * x->x_upcoef); + continue; + } + } + else if (f < last) + { + if (x->x_ndown > 1) + { + *out++ = (last += (f - last) * x->x_downcoef); + continue; + } + } + *out++ = last = f; + } + x->x_last = last; + return (w + 5); +} +#endif + +static void rampsmooth_dsp(t_rampsmooth *x, t_signal **sp) +{ + dsp_add(rampsmooth_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void rampsmooth_rampup(t_rampsmooth *x, t_floatarg f) +{ + int i = (int)f; + if (i > 1) /* CHECKME if 1 and 0 differ in any way */ + { + x->x_nup = i; + x->x_upcoef = 1. / (float)i; + } + else + { + x->x_nup = 0; + x->x_upcoef = 0.; + } +} + +static void rampsmooth_rampdown(t_rampsmooth *x, t_floatarg f) +{ + int i = (int)f; + if (i > 1) /* CHECKME if 1 and 0 differ in any way */ + { + x->x_ndown = i; + x->x_downcoef = 1. / (float)i; + } + else + { + x->x_ndown = 0; + x->x_downcoef = 0.; + } +} + +/* CHECKED */ +static void rampsmooth_ramp(t_rampsmooth *x, t_floatarg f) +{ + rampsmooth_rampup(x, f); + rampsmooth_rampdown(x, f); +} + +static void *rampsmooth_new(t_symbol *s, int ac, t_atom *av) +{ + t_rampsmooth *x = (t_rampsmooth *)pd_new(rampsmooth_class); + float f1 = RAMPSMOOTH_DEFNUP; + float f2 = RAMPSMOOTH_DEFNDOWN; + if (ac && av->a_type == A_FLOAT) + { + f1 = av->a_w.w_float; + ac--; av++; + if (ac && av->a_type == A_FLOAT) + f2 = av->a_w.w_float; + } + rampsmooth_rampup(x, f1); + rampsmooth_rampdown(x, f2); + x->x_last = 0.; +#ifdef RAMPSMOOTH_LINEAR + x->x_target = 0.; + x->x_incr = 0.; + x->x_nleft = 0; +#endif + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void rampsmooth_tilde_setup(void) +{ + rampsmooth_class = class_new(gensym("rampsmooth~"), + (t_newmethod)rampsmooth_new, 0, + sizeof(t_rampsmooth), 0, A_GIMME, 0); + sic_setup(rampsmooth_class, rampsmooth_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(rampsmooth_class, (t_method)rampsmooth_rampup, + gensym("rampup"), A_FLOAT, 0); + class_addmethod(rampsmooth_class, (t_method)rampsmooth_rampdown, + gensym("rampdown"), A_FLOAT, 0); + class_addmethod(rampsmooth_class, (t_method)rampsmooth_ramp, + gensym("ramp"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/rand.c b/cyclone/sickle/rand.c new file mode 100644 index 0000000..146cbc9 --- /dev/null +++ b/cyclone/sickle/rand.c @@ -0,0 +1,95 @@ +/* Copyright (c) 1997-2003 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. */ + +/* This is a compilation of phasor~ and noise~ code from d_osc.c. */ + +#include "m_pd.h" +#include "shared.h" +#include "sickle/sic.h" + +typedef struct _rand +{ + t_sic x_sic; + t_float x_rate; + double x_lastphase; + double x_nextphase; + float x_rcpsr; + int x_state; + float x_target; + float x_scaling; /* LATER use phase increment */ +} t_rand; + +static t_class *rand_class; + +static t_int *rand_perform(t_int *w) +{ + t_rand *x = (t_rand *)(w[1]); + int nblock = (int)(w[2]); + t_float *rin = (t_float *)(w[3]); + t_float *out = (t_float *)(w[4]); + double lastph = x->x_lastphase; + double ph = x->x_nextphase; + double tfph = ph + SHARED_UNITBIT32; + t_shared_wrappy wrappy; + int32 normhipart; + float rcpsr = x->x_rcpsr; + float target = x->x_target; + float scaling = x->x_scaling; + + wrappy.w_d = SHARED_UNITBIT32; + normhipart = wrappy.w_i[SHARED_HIOFFSET]; + + while (nblock--) + { + float rate = *rin++; + if (ph > lastph) + { + int state = x->x_state; + float newtarget = ((float)((state & 0x7fffffff) - 0x40000000)) + * (float)(1.0 / 0x40000000); + x->x_state = state * 435898247 + 382842987; + x->x_scaling = scaling = target - newtarget; + x->x_target = target = newtarget; + } + *out++ = ph * scaling + target; + lastph = ph; + if (rate > 0) rate = -rate; + tfph += rate * rcpsr; + wrappy.w_d = tfph; + wrappy.w_i[SHARED_HIOFFSET] = normhipart; + ph = wrappy.w_d - SHARED_UNITBIT32; + } + x->x_lastphase = lastph; + x->x_nextphase = ph; + return (w + 5); +} + +static void rand_dsp(t_rand *x, t_signal **sp) +{ + x->x_rcpsr = 1. / sp[0]->s_sr; + dsp_add(rand_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *rand_new(t_floatarg inirate) +{ + t_rand *x = (t_rand *)pd_new(rand_class); + /* borrowed from d_osc.c, LATER rethink */ + static int init = 307; + x->x_state = (init *= 1319); + x->x_lastphase = 0.; + x->x_nextphase = 1.; /* start from 0, force retargetting */ + x->x_target = x->x_scaling = 0; + x->x_rate = (inirate > 0 ? -inirate : 0); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void rand_tilde_setup(void) +{ + rand_class = class_new(gensym("rand~"), + (t_newmethod)rand_new, 0, + sizeof(t_rand), 0, + A_DEFFLOAT, 0); + sic_setup(rand_class, rand_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/record.c b/cyclone/sickle/record.c new file mode 100644 index 0000000..ba2e3b5 --- /dev/null +++ b/cyclone/sickle/record.c @@ -0,0 +1,242 @@ +/* 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 "shared.h" +#include "sickle/sic.h" +#include "sickle/arsic.h" + +typedef struct _record +{ + t_arsic x_arsic; + float x_startpoint; /* the inputs */ + float x_endpoint; + int x_appendmode; + int x_loopmode; + int x_startindex; + int x_endindex; /* (one past last record position) */ + int x_pauseindex; + int x_phase; /* writing head */ + float x_sync; + float x_syncincr; + int x_isrunning; /* to know if sync should be 0.0 or 1.0 */ + t_clock *x_clock; +} t_record; + +static t_class *record_class; + +static void record_tick(t_record *x) +{ + arsic_redraw((t_arsic *)x); +} + +static void record_setsync(t_record *x) +{ + /* CHECKED: clipped to array size -- using indices, not points */ + float range = (float)(x->x_endindex - x->x_startindex); + int phase = x->x_phase; + if (phase == SHARED_INT_MAX || range < 1.0) + { + x->x_sync = (x->x_isrunning ? 1.0 : 0); /* CHECKED */ + x->x_syncincr = 0; + } + else + { + x->x_sync = (float)(phase - x->x_startindex) / range; + x->x_syncincr = 1.0 / range; + } +} + +static void record_mstoindex(t_record *x) +{ + t_arsic *sic = (t_arsic *)x; + x->x_startindex = (int)(x->x_startpoint * sic->s_ksr); + if (x->x_startindex < 0) + x->x_startindex = 0; /* CHECKED */ + x->x_endindex = (int)(x->x_endpoint * sic->s_ksr); + if (x->x_endindex > sic->s_vecsize + || x->x_endindex <= 0) + x->x_endindex = sic->s_vecsize; /* CHECKED (both ways) */ + record_setsync(x); +} + +static void record_set(t_record *x, t_symbol *s) +{ + arsic_setarray((t_arsic *)x, s, 1); + record_mstoindex(x); +} + +static void record_startpoint(t_record *x, t_floatarg f) +{ + x->x_startpoint = f; + record_mstoindex(x); +} + +static void record_endpoint(t_record *x, t_floatarg f) +{ + x->x_endpoint = f; + record_mstoindex(x); +} + +static void record_float(t_record *x, t_float f) +{ + if (x->x_isrunning = (f != 0)) + { + /* CHECKED: no (re)start in append mode */ + /* LATER consider restart if x->x_pauseindex == SHARED_INT_MAX */ + x->x_phase = x->x_appendmode ? x->x_pauseindex : x->x_startindex; + if (x->x_phase >= x->x_endindex) x->x_phase = SHARED_INT_MAX; + } + else if (x->x_phase != SHARED_INT_MAX) /* CHECKED: no rewind */ + { + record_tick(x); + x->x_pauseindex = x->x_phase; + x->x_phase = SHARED_INT_MAX; + } + record_setsync(x); +} + +static void record_append(t_record *x, t_floatarg f) +{ + if (f != 0) + { + x->x_appendmode = 1; /* CHECKED: always allow appending */ + } + else x->x_appendmode = 0; +} + +static void record_loop(t_record *x, t_floatarg f) +{ + x->x_loopmode = (f != 0); +} + +static t_int *record_perform(t_int *w) +{ + t_arsic *sic = (t_arsic *)(w[1]); + int nblock = (int)(w[2]); + int nch = sic->s_nchannels; + t_float *out = (t_float *)(w[3 + nch]); + t_record *x = (t_record *)sic; + int phase = x->x_phase; + int endphase = x->x_endindex; + float sync = x->x_sync; + if (sic->s_playable && endphase > phase) + { + int vecsize = sic->s_vecsize; + float syncincr = x->x_syncincr; + int ch, over, i, nxfer; +loopover: + if ((nxfer = endphase - phase) > nblock) + { + nxfer = nblock; + over = 0; + } + else over = 1; + ch = nch; + while (ch--) + { + t_float *vp = sic->s_vectors[ch]; + if (vp) + { + t_float *ip = (t_float *)(w[3 + ch]); + vp += phase; + i = nxfer; + /* LATER consider handling under and overflows */ + while (i--) *vp++ = *ip++; + } + } + i = nxfer; + while (i--) + { + *out++ = sync; + sync += syncincr; + } + if (over) + { + nblock -= nxfer; + if (x->x_loopmode + && (phase = x->x_startindex) < endphase) + { + x->x_phase = phase; + x->x_sync = sync = 0; + if (nblock > 0) goto loopover; + goto done; + } + clock_delay(x->x_clock, 0); + /* CHECKED: no restart in append mode */ + x->x_pauseindex = SHARED_INT_MAX; + x->x_phase = SHARED_INT_MAX; + x->x_sync = 1.0; + x->x_syncincr = 0; + } + else + { + x->x_phase += nxfer; + x->x_sync = sync; + goto done; + } + } + while (nblock--) *out++ = sync; +done: + return (w + sic->s_nperfargs + 1); +} + +static void record_dsp(t_record *x, t_signal **sp) +{ + arsic_dsp((t_arsic *)x, sp, record_perform, 1); + record_mstoindex(x); +} + +static void record_free(t_record *x) +{ + arsic_free((t_arsic *)x); + if (x->x_clock) clock_free(x->x_clock); +} + +static void *record_new(t_symbol *s, t_floatarg f) +{ + /* one auxiliary signal: sync output */ + t_record *x = (t_record *)arsic_new(record_class, s, (int)f, 0, 1); + if (x) + { + int nch = arsic_getnchannels((t_arsic *)x); + arsic_setminsize((t_arsic *)x, 2); + x->x_startpoint = 0; + x->x_endpoint = 0; + x->x_appendmode = 0; + x->x_loopmode = 0; + x->x_pauseindex = SHARED_INT_MAX; + x->x_phase = SHARED_INT_MAX; + x->x_isrunning = 0; + record_mstoindex(x); + x->x_clock = clock_new(x, (t_method)record_tick); + while (--nch) + inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft-2")); + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft-1")); + outlet_new((t_object *)x, &s_signal); + } + return (x); +} + +void record_tilde_setup(void) +{ + record_class = class_new(gensym("record~"), + (t_newmethod)record_new, + (t_method)record_free, + sizeof(t_record), 0, + A_DEFSYM, A_DEFFLOAT, 0); + arsic_setup(record_class, record_dsp, record_float); + class_addmethod(record_class, (t_method)record_startpoint, + gensym("ft-2"), A_FLOAT, 0); + class_addmethod(record_class, (t_method)record_endpoint, + gensym("ft-1"), A_FLOAT, 0); + class_addmethod(record_class, (t_method)record_append, + gensym("append"), A_FLOAT, 0); + class_addmethod(record_class, (t_method)record_loop, + gensym("loop"), A_FLOAT, 0); + class_addmethod(record_class, (t_method)record_set, + gensym("set"), A_SYMBOL, 0); +} diff --git a/cyclone/sickle/sah.c b/cyclone/sickle/sah.c new file mode 100644 index 0000000..afac1e0 --- /dev/null +++ b/cyclone/sickle/sah.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 "sickle/sic.h" + +typedef struct _sah +{ + t_sic x_sic; + t_float x_threshold; + t_float x_lastin; + t_float x_lastout; +} t_sah; + +static t_class *sah_class; + +static t_int *sah_perform(t_int *w) +{ + t_sah *x = (t_sah *)(w[1]); + int nblock = (t_int)(w[2]); + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + t_float *out = (t_float *)(w[5]); + t_float threshold = x->x_threshold; + t_float lastin = x->x_lastin; + t_float lastout = x->x_lastout; + while (nblock--) + { + float f = *in2++; + if (lastin <= threshold && f > threshold) /* CHECKME <=, > */ + lastout = *in1; + in1++; + lastin = f; + *out++ = lastout; + } + x->x_lastin = lastin; + x->x_lastout = lastout; + return (w + 6); +} + +static void sah_dsp(t_sah *x, t_signal **sp) +{ + dsp_add(sah_perform, 5, x, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void sah_float(t_sah *x, t_float f) +{ + x->x_threshold = f; +} + +static void *sah_new(t_floatarg f) +{ + t_sah *x = (t_sah *)pd_new(sah_class); + x->x_threshold = f; + x->x_lastin = 0; + x->x_lastout = 0; + inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void sah_tilde_setup(void) +{ + sah_class = class_new(gensym("sah~"), + (t_newmethod)sah_new, 0, + sizeof(t_sah), 0, A_DEFFLOAT, 0); + sic_setup(sah_class, sah_dsp, sah_float); +} diff --git a/cyclone/sickle/sickle.c b/cyclone/sickle/sickle.c new file mode 100644 index 0000000..765209a --- /dev/null +++ b/cyclone/sickle/sickle.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 allsickles_setup(void); + +typedef struct _sickle +{ + t_object x_ob; + t_symbol *x_dir; + t_hammerfile *x_filehandle; +} t_sickle; + +static t_class *sickle_class; +static int sickle_firstndx; +static int sickle_lastndx; + +static void sickle_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av) +{ + import_max(fn->s_name, ""); +} + +static void sickle_import(t_sickle *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 sickle_click(t_sickle *x, t_floatarg xpos, t_floatarg ypos, + t_floatarg shift, t_floatarg ctrl, t_floatarg alt) +{ + sickle_import(x, 0, 0); +} + +static void sickle_bang(t_sickle *x) +{ + fragile_class_printnames("sickle classes are: ", + sickle_firstndx, sickle_lastndx); +} + +static void sickle_free(t_sickle *x) +{ + hammerfile_free(x->x_filehandle); +} + +static void *sickle_new(t_symbol *s) +{ + t_sickle *x = (t_sickle *)pd_new(sickle_class); + x->x_filehandle = hammerfile_new((t_pd *)x, 0, sickle_readhook, 0, 0); + x->x_dir = (s && s != &s_ ? s : canvas_getdir(x->x_filehandle->f_canvas)); + return (x); +} + +void sickle_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 'sickle' object"); + loud_errand(0, "without having sickle library preloaded"); + return; + } + if (!zgetfn(&pd_objectmaker, gensym("cyclone"))) + post("this is sickle %s, %s %s build", + CYCLONE_VERSION, loud_ordinal(CYCLONE_BUILD), CYCLONE_RELEASE); + sickle_class = class_new(gensym("sickle"), + (t_newmethod)sickle_new, + (t_method)sickle_free, + sizeof(t_sickle), 0, A_DEFSYM, 0); + class_addbang(sickle_class, sickle_bang); + class_addmethod(sickle_class, (t_method)sickle_import, + gensym("import"), A_DEFSYM, A_DEFSYM, 0); + class_addmethod(sickle_class, (t_method)sickle_click, + gensym("click"), + A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); + hammerfile_setup(sickle_class, 0); + sickle_firstndx = fragile_class_count(); + allsickles_setup(); + sickle_lastndx = fragile_class_count() - 1; +} diff --git a/cyclone/sickle/sinh.c b/cyclone/sickle/sinh.c new file mode 100644 index 0000000..523c28a --- /dev/null +++ b/cyclone/sickle/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" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define sinhf sinh +#endif + +typedef t_sic t_sinh; +static t_class *sinh_class; + +static t_int *sinh_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = sinhf(f); /* CHECKME no protection against overflow */ + } + return (w + 4); +} + +static void sinh_dsp(t_sinh *x, t_signal **sp) +{ + dsp_add(sinh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *sinh_new(void) +{ + t_sinh *x = (t_sinh *)pd_new(sinh_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void sinh_tilde_setup(void) +{ + sinh_class = class_new(gensym("sinh~"), + (t_newmethod)sinh_new, 0, + sizeof(t_sinh), 0, 0); + sic_setup(sinh_class, sinh_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/sinx.c b/cyclone/sickle/sinx.c new file mode 100644 index 0000000..b303024 --- /dev/null +++ b/cyclone/sickle/sinx.c @@ -0,0 +1,51 @@ +/* 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" +#include "sickle/sic.h" + +/* by definition, this is just an interface to the -lm call + (do not use costable) */ + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define sinf sin +#endif + +typedef t_sic t_sinx; +static t_class *sinx_class; + +static t_int *sinx_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = sinf(f); + } + return (w + 4); +} + +static void sinx_dsp(t_sinx *x, t_signal **sp) +{ + dsp_add(sinx_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *sinx_new(void) +{ + t_sinx *x = (t_sinx *)pd_new(sinx_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void sinx_tilde_setup(void) +{ + sinx_class = class_new(gensym("sinx~"), + (t_newmethod)sinx_new, 0, + sizeof(t_sinx), 0, 0); + sic_setup(sinx_class, sinx_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/slide.c b/cyclone/sickle/slide.c new file mode 100644 index 0000000..92001b2 --- /dev/null +++ b/cyclone/sickle/slide.c @@ -0,0 +1,77 @@ +/* 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 "sickle/sic.h" + +#define SLIDE_DEFUP 1. +#define SLIDE_DEFDN 1. + +typedef struct _slide +{ + t_sic x_sic; + t_float x_last; +} t_slide; + +static t_class *slide_class; + +static t_int *slide_perform(t_int *w) +{ + t_slide *x = (t_slide *)(w[1]); + int nblock = (int)(w[2]); + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + t_float *in3 = (t_float *)(w[5]); + t_float *out = (t_float *)(w[6]); + t_float last = x->x_last; + while (nblock--) + { + float f = *in1++; + if (f > last) + { + float up = *in2++; + if (up > 1.) /* CHECKED */ + last += (f - last) / up; + else + last = f; + in3++; + } + else if (f < last) + { + float dn = *in3++; + if (dn > 1.) /* CHECKED */ + last += (f - last) / dn; + else + last = f; + in2++; + } + *out++ = last; + } + x->x_last = last; + return (w + 7); +} + +static void slide_dsp(t_slide *x, t_signal **sp) +{ + dsp_add(slide_perform, 6, x, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); +} + +static void *slide_new(t_symbol *s, int ac, t_atom *av) +{ + t_slide *x = (t_slide *)pd_new(slide_class); + sic_inlet((t_sic *)x, 1, SLIDE_DEFUP, 0, ac, av); + sic_inlet((t_sic *)x, 2, SLIDE_DEFDN, 1, ac, av); + outlet_new((t_object *)x, &s_signal); + x->x_last = 0; + return (x); +} + +void slide_tilde_setup(void) +{ + slide_class = class_new(gensym("slide~"), + (t_newmethod)slide_new, 0, + sizeof(t_slide), 0, A_GIMME, 0); + sic_setup(slide_class, slide_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/spike.c b/cyclone/sickle/spike.c new file mode 100644 index 0000000..13f9361 --- /dev/null +++ b/cyclone/sickle/spike.c @@ -0,0 +1,109 @@ +/* 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 "sickle/sic.h" + +typedef struct _spike +{ + t_sic x_sic; + t_float x_last; + int x_count; + int x_precount; + int x_nwait; + float x_waittime; + float x_ksr; + float x_rcpksr; + t_clock *x_clock; +} t_spike; + +static t_class *spike_class; + +static void spike_tick(t_spike *x) +{ + outlet_float(((t_object *)x)->ob_outlet, x->x_count * x->x_rcpksr); + x->x_count = x->x_precount; +} + +static void spike_ft1(t_spike *x, t_floatarg f) +{ + if ((x->x_waittime = f) < 0.) + x->x_waittime = 0.; + x->x_nwait = (int)(x->x_waittime * x->x_ksr); +} + +static t_int *spike_perform(t_int *w) +{ + t_spike *x = (t_spike *)(w[1]); + int nblock = (int)(w[2]); + t_float *in = (t_float *)(w[3]); + t_float last = x->x_last; + int count = x->x_count; + int nwait = x->x_nwait; + if (count + nblock > nwait) + { + /* LATER efficiency tricks */ + while (nblock--) + { + float f = *in++; + if (last == 0. && f != 0. /* CHECKED zero-to-nonzero */ + && count /* CHECKED no firing at startup */ + && count >= nwait) + { + clock_delay(x->x_clock, 0); + x->x_last = in[nblock - 1]; + x->x_count = count; + x->x_precount = nblock; + return (w + 4); + } + count++; + last = f; + } + x->x_last = last; + x->x_count = count; + } + else + { + x->x_last = in[nblock - 1]; + x->x_count += nblock; + } + return (w + 4); +} + +static void spike_dsp(t_spike *x, t_signal **sp) +{ + x->x_ksr = sp[0]->s_sr * 0.001; + x->x_rcpksr = 1000.0 / sp[0]->s_sr; + x->x_nwait = (int)(x->x_waittime * x->x_ksr); + dsp_add(spike_perform, 3, x, sp[0]->s_n, sp[0]->s_vec); +} + +static void spike_free(t_spike *x) +{ + if (x->x_clock) clock_free(x->x_clock); +} + +static void *spike_new(t_floatarg f) +{ + t_spike *x = (t_spike *)pd_new(spike_class); + x->x_last = 0.; + x->x_ksr = sys_getsr() * 0.001; + spike_ft1(x, f); + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); + outlet_new((t_object *)x, &s_float); + x->x_clock = clock_new(x, (t_method)spike_tick); + return (x); +} + +void spike_tilde_setup(void) +{ + spike_class = class_new(gensym("spike~"), + (t_newmethod)spike_new, + (t_method)spike_free, + sizeof(t_spike), 0, + A_DEFFLOAT, 0); + sic_setup(spike_class, spike_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(spike_class, (t_method)spike_ft1, + gensym("ft1"), A_FLOAT, 0); +} diff --git a/cyclone/sickle/tanh.c b/cyclone/sickle/tanh.c new file mode 100644 index 0000000..7473dcf --- /dev/null +++ b/cyclone/sickle/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" +#include "sickle/sic.h" + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define tanhf tanh +#endif + +typedef t_sic t_tanh; +static t_class *tanh_class; + +static t_int *tanh_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = tanhf(f); /* CHECKME no protection against overflow */ + } + return (w + 4); +} + +static void tanh_dsp(t_tanh *x, t_signal **sp) +{ + dsp_add(tanh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *tanh_new(void) +{ + t_tanh *x = (t_tanh *)pd_new(tanh_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void tanh_tilde_setup(void) +{ + tanh_class = class_new(gensym("tanh~"), + (t_newmethod)tanh_new, 0, + sizeof(t_tanh), 0, 0); + sic_setup(tanh_class, tanh_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/tanx.c b/cyclone/sickle/tanx.c new file mode 100644 index 0000000..d2a1102 --- /dev/null +++ b/cyclone/sickle/tanx.c @@ -0,0 +1,51 @@ +/* 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" +#include "sickle/sic.h" + +/* by definition, this is just an interface to the -lm call + (do not use costable) */ + +#if defined(NT) || defined(MACOSX) +/* cf pd/src/x_arithmetic.c */ +#define tanf tan +#endif + +typedef t_sic t_tanx; +static t_class *tanx_class; + +static t_int *tanx_perform(t_int *w) +{ + int nblock = (int)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + while (nblock--) + { + float f = *in++; + *out++ = tanf(f); + } + return (w + 4); +} + +static void tanx_dsp(t_tanx *x, t_signal **sp) +{ + dsp_add(tanx_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); +} + +static void *tanx_new(void) +{ + t_tanx *x = (t_tanx *)pd_new(tanx_class); + outlet_new((t_object *)x, &s_signal); + return (x); +} + +void tanx_tilde_setup(void) +{ + tanx_class = class_new(gensym("tanx~"), + (t_newmethod)tanx_new, 0, + sizeof(t_tanx), 0, 0); + sic_setup(tanx_class, tanx_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/train.c b/cyclone/sickle/train.c new file mode 100644 index 0000000..b07ba9a --- /dev/null +++ b/cyclone/sickle/train.c @@ -0,0 +1,117 @@ +/* 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 "shared.h" +#include "sickle/sic.h" + +#define TRAIN_DEFPERIOD 1000 +#define TRAIN_DEFWIDTH 0.5 +#define TRAIN_DEFOFFSET 0 + +typedef struct _train +{ + t_sic x_sic; + int x_on; + double x_phase; + float x_rcpksr; + t_outlet *x_bangout; + t_clock *x_clock; +} t_train; + +static t_class *train_class; + +static void train_tick(t_train *x) +{ + outlet_bang(x->x_bangout); +} + +static t_int *train_perform(t_int *w) +{ + t_train *x = (t_train *)(w[1]); + int nblock = (int)(w[2]); + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + t_float *in3 = (t_float *)(w[5]); + t_float *out = (t_float *)(w[6]); + float rcpksr = x->x_rcpksr; + double ph = x->x_phase; + double tfph = ph + SHARED_UNITBIT32; + t_shared_wrappy wrappy; + int32 normhipart; + int on = x->x_on; + int edge = 0; + + wrappy.w_d = SHARED_UNITBIT32; + normhipart = wrappy.w_i[SHARED_HIOFFSET]; + + while (nblock--) + { + double onph, offph; + float period = *in1++; + + wrappy.w_d = *in3++ + SHARED_UNITBIT32; + wrappy.w_i[SHARED_HIOFFSET] = normhipart; + onph = wrappy.w_d - SHARED_UNITBIT32; + + wrappy.w_d = onph + *in2++ + SHARED_UNITBIT32; + wrappy.w_i[SHARED_HIOFFSET] = normhipart; + offph = wrappy.w_d - SHARED_UNITBIT32; + + if (offph > onph ? ph < offph && ph >= onph : ph < offph || ph >= onph) + { + if (!on) on = edge = 1; + *out++ = 1.; + } + else + { + on = 0; + *out++ = 0.; + } + if (period > rcpksr) /* LATER rethink */ + tfph += rcpksr / period; /* LATER revisit (profiling?) */ + wrappy.w_d = tfph; + wrappy.w_i[SHARED_HIOFFSET] = normhipart; + ph = wrappy.w_d - SHARED_UNITBIT32; + } + x->x_phase = ph; + x->x_on = on; + if (edge) clock_delay(x->x_clock, 0); + return (w + 7); +} + +static void train_dsp(t_train *x, t_signal **sp) +{ + x->x_rcpksr = 1000. / sp[0]->s_sr; + dsp_add(train_perform, 6, x, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); +} + +static void train_free(t_train *x) +{ + if (x->x_clock) clock_free(x->x_clock); +} + +static void *train_new(t_symbol *s, int ac, t_atom *av) +{ + t_train *x = (t_train *)pd_new(train_class); + x->x_on = 0; + x->x_phase = 0; + sic_inlet((t_sic *)x, 0, TRAIN_DEFPERIOD, 0, ac, av); + sic_inlet((t_sic *)x, 1, TRAIN_DEFWIDTH, 1, ac, av); + sic_inlet((t_sic *)x, 2, TRAIN_DEFOFFSET, 2, ac, av); + outlet_new((t_object *)x, &s_signal); + x->x_bangout = outlet_new((t_object *)x, &s_bang); + x->x_clock = clock_new(x, (t_method)train_tick); + return (x); +} + +void train_tilde_setup(void) +{ + train_class = class_new(gensym("train~"), + (t_newmethod)train_new, + (t_method)train_free, + sizeof(t_train), 0, A_GIMME, 0); + sic_setup(train_class, train_dsp, SIC_FLOATTOSIGNAL); +} diff --git a/cyclone/sickle/trapezoid.c b/cyclone/sickle/trapezoid.c new file mode 100644 index 0000000..b33cb02 --- /dev/null +++ b/cyclone/sickle/trapezoid.c @@ -0,0 +1,105 @@ +/* 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 "sickle/sic.h" + +#define TRAPEZOID_DEFUP 0.1 /* a bug? */ +#define TRAPEZOID_DEFDN 0.9 /* a bug? */ +#define TRAPEZOID_DEFLO 0.0 +#define TRAPEZOID_DEFHI 1.0 + +typedef struct _trapezoid +{ + t_sic x_sic; + float x_low; + float x_range; +} t_trapezoid; + +static t_class *trapezoid_class; + +static void trapezoid_lo(t_trapezoid *x, t_floatarg f) +{ + float high = x->x_low + x->x_range; + x->x_low = f; + x->x_range = high - x->x_low; +} + +static void trapezoid_hi(t_trapezoid *x, t_floatarg f) +{ + x->x_range = f - x->x_low; +} + +/* LATER optimize */ +static t_int *trapezoid_perform(t_int *w) +{ + t_trapezoid *x = (t_trapezoid *)(w[1]); + int nblock = (int)(w[2]); + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + t_float *in3 = (t_float *)(w[5]); + t_float *out = (t_float *)(w[6]); + float low = x->x_low; + float range = x->x_range; + while (nblock--) + { + float ph = *in1++; + float upph = *in2++; + float dnph = *in3++; + /* CHECKED ph wrapped */ + if (ph < 0.) + ph -= (int)ph - 1.; + else if (ph > 1.) + ph -= (int)ph; + /* CHECKED upph, dnph clipped */ + if (upph < 0.) + upph = 0.; + else if (upph > 1.) /* CHECKME */ + upph = 1.; + if (dnph < upph) + dnph = upph; + else if (dnph > 1.) + dnph = 1.; + + if (ph < upph) + ph /= upph; + else if (ph < dnph) + ph = 1.; + else if (dnph < 1.) + ph = (1. - ph) / (1. - dnph); + else + ph = 0.; + *out++ = low + ph * range; + } + return (w + 7); +} + +static void trapezoid_dsp(t_trapezoid *x, t_signal **sp) +{ + dsp_add(trapezoid_perform, 6, x, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); +} + +static void *trapezoid_new(t_symbol *s, int ac, t_atom *av) +{ + t_trapezoid *x = (t_trapezoid *)pd_new(trapezoid_class); + sic_inlet((t_sic *)x, 1, TRAPEZOID_DEFUP, 0, ac, av); + sic_inlet((t_sic *)x, 2, TRAPEZOID_DEFDN, 1, ac, av); + outlet_new((t_object *)x, &s_signal); + x->x_low = TRAPEZOID_DEFLO; + x->x_range = (TRAPEZOID_DEFHI - TRAPEZOID_DEFLO); + return (x); +} + +void trapezoid_tilde_setup(void) +{ + trapezoid_class = class_new(gensym("trapezoid~"), + (t_newmethod)trapezoid_new, 0, + sizeof(t_trapezoid), 0, A_GIMME, 0); + sic_setup(trapezoid_class, trapezoid_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(trapezoid_class, (t_method)trapezoid_lo, + gensym("lo"), A_DEFFLOAT, 0); /* CHECKME */ + class_addmethod(trapezoid_class, (t_method)trapezoid_hi, + gensym("hi"), A_DEFFLOAT, 0); /* CHECKME */ +} diff --git a/cyclone/sickle/triangle.c b/cyclone/sickle/triangle.c new file mode 100644 index 0000000..703e5ba --- /dev/null +++ b/cyclone/sickle/triangle.c @@ -0,0 +1,95 @@ +/* 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 "sickle/sic.h" + +#define TRIANGLE_DEFPHASE 0.5 +#define TRIANGLE_DEFLO -1.0 +#define TRIANGLE_DEFHI 1.0 + +typedef struct _triangle +{ + t_sic x_sic; + float x_low; + float x_range; +} t_triangle; + +static t_class *triangle_class; + +static void triangle_lo(t_triangle *x, t_floatarg f) +{ + float high = x->x_low + x->x_range; + x->x_low = f; + x->x_range = high - x->x_low; +} + +static void triangle_hi(t_triangle *x, t_floatarg f) +{ + x->x_range = f - x->x_low; +} + +/* LATER optimize */ +static t_int *triangle_perform(t_int *w) +{ + t_triangle *x = (t_triangle *)(w[1]); + int nblock = (int)(w[2]); + t_float *in1 = (t_float *)(w[3]); + t_float *in2 = (t_float *)(w[4]); + t_float *out = (t_float *)(w[5]); + float low = x->x_low; + float range = x->x_range; + while (nblock--) + { + float ph = *in1++; + float peakph = *in2++; + /* CHECKED ph wrapped */ + if (ph < 0.) + ph -= (int)ph - 1.; + else if (ph > 1.) + ph -= (int)ph; + /* CHECKED peakph clipped */ + if (peakph < 0.) + peakph = 0.; + else if (peakph > 1.) + peakph = 1.; + + if (ph < peakph) + ph /= peakph; + else if (peakph < 1.) + ph = (1. - ph) / (1. - peakph); + else + ph = 0.; + *out++ = low + ph * range; + } + return (w + 6); +} + +static void triangle_dsp(t_triangle *x, t_signal **sp) +{ + dsp_add(triangle_perform, 5, x, sp[0]->s_n, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); +} + +static void *triangle_new(t_symbol *s, int ac, t_atom *av) +{ + t_triangle *x = (t_triangle *)pd_new(triangle_class); + sic_inlet((t_sic *)x, 1, TRIANGLE_DEFPHASE, 0, ac, av); + outlet_new((t_object *)x, &s_signal); + x->x_low = TRIANGLE_DEFLO; + x->x_range = (TRIANGLE_DEFHI - TRIANGLE_DEFLO); + return (x); +} + +void triangle_tilde_setup(void) +{ + triangle_class = class_new(gensym("triangle~"), + (t_newmethod)triangle_new, 0, + sizeof(t_triangle), 0, A_GIMME, 0); + sic_setup(triangle_class, triangle_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(triangle_class, (t_method)triangle_lo, + gensym("lo"), A_DEFFLOAT, 0); /* CHECKED */ + class_addmethod(triangle_class, (t_method)triangle_hi, + gensym("hi"), A_DEFFLOAT, 0); /* CHECKED */ +} diff --git a/cyclone/sickle/vectral.c b/cyclone/sickle/vectral.c new file mode 100644 index 0000000..b9cdf69 --- /dev/null +++ b/cyclone/sickle/vectral.c @@ -0,0 +1,235 @@ +/* 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 "sickle/sic.h" + +#define VECTRAL_DEFSIZE 512 + +struct _vectral; +typedef void (*t_vectral_perform)(struct _vectral *, int, + t_float *, t_float *, t_float *, t_float *); + +typedef struct _vectral +{ + t_sic x_sic; + t_vectral_perform x_perform; + int x_bufsize; + t_float *x_buffer; + t_float *x_lastframe; + /* rampsmooth and slide state */ + double x_upcoef; + double x_downcoef; + /* deltaclip state */ + float x_lo; + float x_hi; +} t_vectral; + +static t_class *vectral_class; + +/* LATER after any modification make sure about syncing other variants + of perform routine to the bypassing version */ +/* this is: for i in [0..nblock) buf[in2[i]] = in3[i], out[i] = buf[in1[i]] */ +static void vectral_perform_bypass(t_vectral *x, int nblock, + t_float *in1, t_float *in2, t_float *in3, + t_float *out) +{ + t_float *buf = x->x_buffer; + int bufsize = x->x_bufsize; + t_float *last = x->x_lastframe; + int blocksize = nblock; + while (nblock--) + { + int indx = (int)*in2++; + /* CHECKED buffer not zeroed out (the buffer's garbage remains) */ + if (indx >= 0 && indx < bufsize) + buf[indx] = *in3; + in3++; + } + while (blocksize--) + { + int ondx = (int)*in1++; + if (ondx >= 0 && ondx < bufsize) + *out++ = *last++ = buf[ondx]; + else + /* CHECKED garbage in the output vector is cleared */ + *out++ = *last++ = 0.; + } +} + +/* this one is used for rampsmooth mode as well (see rampsmooth.c) + LATER recheck */ +static void vectral_perform_slide(t_vectral *x, int nblock, + t_float *in1, t_float *in2, t_float *in3, + t_float *out) +{ + t_float *buf = x->x_buffer; + int bufsize = x->x_bufsize; + double upcoef = x->x_upcoef; + double downcoef = x->x_downcoef; + t_float *last = x->x_lastframe; + int blocksize = nblock; + while (nblock--) + { + int indx = (int)*in2++; + if (indx >= 0 && indx < bufsize) + buf[indx] = *in3; + in3++; + } + while (blocksize--) + { + int ondx = (int)*in1++; + if (ondx >= 0 && ondx < bufsize) + { + /* CHECKME what is smoothed, and FIXME */ + float delta = buf[ondx] - *last; + *out++ = + (*last++ += (delta > 0 ? delta * upcoef : delta * downcoef)); + } + else *out++ = *last++ = 0.; + } +} + +static void vectral_perform_clip(t_vectral *x, int nblock, + t_float *in1, t_float *in2, t_float *in3, + t_float *out) +{ + t_float *buf = x->x_buffer; + int bufsize = x->x_bufsize; + float lo = x->x_lo; + float hi = x->x_hi; + t_float *last = x->x_lastframe; + int blocksize = nblock; + while (nblock--) + { + int indx = (int)*in2++; + if (indx >= 0 && indx < bufsize) + buf[indx] = *in3; + in3++; + } + while (blocksize--) + { + int ondx = (int)*in1++; + if (ondx >= 0 && ondx < bufsize) + { + /* CHECKME what is smoothed, and FIXME */ + float delta = buf[ondx] - *last; + if (delta < lo) + *out++ = (*last++ += lo); + else if (delta > hi) + *out++ = (*last++ += hi); + else + *out++ = *last++ = buf[ondx]; + } + else *out++ = *last++ = 0.; + } +} + +static t_int *vectral_perform(t_int *w) +{ + t_vectral *x = (t_vectral *)(w[1]); + (*x->x_perform)(x, (int)(w[2]), (t_float *)(w[3]), (t_float *)(w[4]), + (t_float *)(w[5]), (t_float *)(w[6])); + return (w + 7); +} + +static void vectral_dsp(t_vectral *x, t_signal **sp) +{ + int nblock = sp[0]->s_n; + if (nblock > x->x_bufsize) + nblock = x->x_bufsize; /* CHECKME */ + dsp_add(vectral_perform, 6, x, nblock, + sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); +} + +static void vectral_rampsmooth(t_vectral *x, t_symbol *s, int ac, t_atom *av) +{ + if (ac && av->a_type == A_FLOAT) + { + int i; + x->x_upcoef = ((i = (int)av->a_w.w_float) > 1 ? 1. / (double)i : 1.); + ac--; av++; + if (ac && av->a_type == A_FLOAT) + x->x_downcoef = + ((i = (int)av->a_w.w_float) > 1 ? 1. / (double)i : 1.); + else + x->x_downcoef = 1.; /* CHECKED */ + x->x_perform = vectral_perform_slide; /* see above */ + } + else x->x_perform = vectral_perform_bypass; /* CHECKED */ +} + +static void vectral_slide(t_vectral *x, t_symbol *s, int ac, t_atom *av) +{ + if (ac && av->a_type == A_FLOAT) + { + double d; + x->x_upcoef = ((d = av->a_w.w_float) > 1. ? 1. / d : 1.); + ac--; av++; + if (ac && av->a_type == A_FLOAT) + x->x_downcoef = ((d = av->a_w.w_float) > 1. ? 1. / d : 1.); + else + x->x_downcoef = 1.; /* CHECKED */ + x->x_perform = vectral_perform_slide; + } + else x->x_perform = vectral_perform_bypass; /* CHECKED */ +} + +/* CHECKED 'deltaclip <hi> <lo>' (deltaclip~'s args are swapped) */ +static void vectral_deltaclip(t_vectral *x, t_symbol *s, int ac, t_atom *av) +{ + if (ac && av->a_type == A_FLOAT) + { + x->x_hi = av->a_w.w_float; + ac--; av++; + if (ac && av->a_type == A_FLOAT) + x->x_lo = av->a_w.w_float; + else + x->x_lo = 0.; /* CHECKED */ + } + else x->x_lo = x->x_hi = 0.; /* CHECKED */ + x->x_perform = vectral_perform_clip; +} + +static void vectral_free(t_vectral *x) +{ + if (x->x_buffer) + freebytes(x->x_buffer, x->x_bufsize * sizeof(*x->x_buffer)); + if (x->x_lastframe) + freebytes(x->x_lastframe, x->x_bufsize * sizeof(*x->x_lastframe)); +} + +static void *vectral_new(t_floatarg f) +{ + t_vectral *x = (t_vectral *)pd_new(vectral_class); + int i = (int)f; + x->x_bufsize = (i > 0 ? i : VECTRAL_DEFSIZE); + if (!(x->x_buffer = getbytes(x->x_bufsize * sizeof(*x->x_buffer)))) + goto failure; + if (!(x->x_lastframe = getbytes(x->x_bufsize * sizeof(*x->x_lastframe)))) + goto failure; + x->x_perform = vectral_perform_bypass; + inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); + inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); + outlet_new((t_object *)x, &s_signal); + return (x); +failure: + pd_free((t_pd *)x); + return (0); +} + +void vectral_tilde_setup(void) +{ + vectral_class = class_new(gensym("vectral~"), + (t_newmethod)vectral_new, + (t_method)vectral_free, + sizeof(t_vectral), 0, A_DEFFLOAT, 0); + sic_setup(vectral_class, vectral_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(vectral_class, (t_method)vectral_rampsmooth, + gensym("rampsmooth"), A_GIMME, 0); + class_addmethod(vectral_class, (t_method)vectral_slide, + gensym("slide"), A_GIMME, 0); + class_addmethod(vectral_class, (t_method)vectral_deltaclip, + gensym("deltaclip"), A_GIMME, 0); +} diff --git a/cyclone/sickle/wave.c b/cyclone/sickle/wave.c new file mode 100644 index 0000000..7804c88 --- /dev/null +++ b/cyclone/sickle/wave.c @@ -0,0 +1,161 @@ +/* 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 "sickle/sic.h" +#include "sickle/arsic.h" + +/* CHECKME (the refman): the extra channels are not played */ + +typedef struct _wave +{ + t_arsic x_arsic; + int x_nointerp; +} t_wave; + +static t_class *wave_class; + +static void wave_interp(t_wave *x, t_floatarg f) +{ + x->x_nointerp = (f == 0); + arsic_setminsize((t_arsic *)x, (x->x_nointerp ? 1 : 4)); + arsic_check((t_arsic *)x); +} + +static void wave_set(t_wave *x, t_symbol *s) +{ + arsic_setarray((t_arsic *)x, s, 1); +} + +static t_int *wave_perform(t_int *w) +{ + t_arsic *sic = (t_arsic *)(w[1]); + int nblock = (int)(w[2]); + int nch = sic->s_nchannels; + t_int *outp = w + 6; + if (sic->s_playable) + { + t_wave *x = (t_wave *)sic; + t_float *xin = (t_float *)(w[3]); + t_float *sin = (t_float *)(w[4]); + t_float *ein = (t_float *)(w[5]); + int vecsize = sic->s_vecsize; + t_float **vectable = sic->s_vectors; + float ksr = sic->s_ksr; + int nointerp = x->x_nointerp; + int maxindex = (nointerp ? vecsize - 1 : vecsize - 3); + int iblock; + + for (iblock = 0; iblock < nblock; iblock++) + { + float spos = *sin++ * ksr; + float xpos = *ein++ * ksr; + /* msp seems to be buggy here, but CHECKME again */ + int siz = (int)((xpos > 0 ? xpos : maxindex) - spos); + float phase = *xin++; + int ndx; + int ch = nch; + /* CHECKED: phase is clipped, not wrapped */ + if (phase < 0) phase = 0; + else if (phase > 1.0) phase = 1.0; + xpos = (siz > 0 ? spos + siz * phase : spos); + ndx = (int)xpos; + if (nointerp) + { + if (ndx < 0) ndx = 0; + else if (ndx > maxindex) ndx = maxindex; + while (ch--) + { + t_float *vp = vectable[ch]; + t_float *out = (t_float *)(outp[ch]); + out[iblock] = (vp ? vp[ndx] : 0); + } + } + else + { + float frac, a, b, c, d, cminusb; + if (ndx < 1) + ndx = 1, frac = 0; + else if (ndx > maxindex) + ndx = maxindex, frac = 1; + else frac = xpos - ndx; + while (ch--) + { + t_float *vp = vectable[ch]; + t_float *out = (t_float *)(outp[ch]); + if (vp) + { + vp += ndx; + a = vp[-1]; + b = vp[0]; + c = vp[1]; + d = vp[2]; + cminusb = c-b; + out[iblock] = b + frac * ( + cminusb - 0.1666667f * (1. - frac) * ( + (d - a - 3.0f * cminusb) * frac + + (d + 2.0f * a - 3.0f * b) + ) + ); + } + else out[iblock] = 0; + } + } + } + } + else + { + int ch = nch; + while (ch--) + { + t_float *out = (t_float *)outp[ch]; + int n = nblock; + while (n--) *out++ = 0; + } + } + return (w + sic->s_nperfargs + 1); +} + +static void wave_dsp(t_wave *x, t_signal **sp) +{ + arsic_dsp((t_arsic *)x, sp, wave_perform, 1); +} + +static void wave_free(t_wave *x) +{ + arsic_free((t_arsic *)x); +} + +static void *wave_new(t_symbol *s, t_floatarg f1, t_floatarg f2, t_floatarg f3) +{ + /* three auxiliary signals: phase, clipstart, and clipend inputs */ + t_wave *x = (t_wave *)arsic_new(wave_class, s, (int)f3, 0, 3); + if (x) + { + int nch = arsic_getnchannels((t_arsic *)x); + if (f1 < 0) f1 = 0; + if (f2 < 0) f2 = 0; + sic_newinlet((t_sic *)x, f1); + sic_newinlet((t_sic *)x, f2); + while (nch--) + outlet_new((t_object *)x, &s_signal); + wave_interp(x, 1); + } + return (x); +} + +void wave_tilde_setup(void) +{ + wave_class = class_new(gensym("wave~"), + (t_newmethod)wave_new, + (t_method)wave_free, + sizeof(t_wave), 0, + A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + arsic_setup(wave_class, wave_dsp, SIC_FLOATTOSIGNAL); + class_addmethod(wave_class, (t_method)wave_set, + gensym("set"), A_SYMBOL, 0); + class_addmethod(wave_class, (t_method)wave_interp, + gensym("interp"), A_FLOAT, 0); +} |