aboutsummaryrefslogtreecommitdiff
path: root/cyclone/hammer/counter.c
diff options
context:
space:
mode:
Diffstat (limited to 'cyclone/hammer/counter.c')
-rw-r--r--cyclone/hammer/counter.c399
1 files changed, 399 insertions, 0 deletions
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);
+}