aboutsummaryrefslogtreecommitdiff
path: root/riddle/riddle.c
diff options
context:
space:
mode:
Diffstat (limited to 'riddle/riddle.c')
-rw-r--r--riddle/riddle.c1346
1 files changed, 1346 insertions, 0 deletions
diff --git a/riddle/riddle.c b/riddle/riddle.c
new file mode 100644
index 0000000..26e17e7
--- /dev/null
+++ b/riddle/riddle.c
@@ -0,0 +1,1346 @@
+/* Copyright (c) 2007 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 <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/grow.h"
+#include "sickle/sic.h"
+#include "riddle.h"
+
+/* obj_starttraverseoutlet, obj_nexttraverseoutlet, obj_noutlets,
+ obj_nsiginlets, obj_nsigoutlets, obj_siginletindex, obj_sigoutletindex,
+ obj_issignalinlet, obj_issignaloutlet */
+#include "m_imp.h"
+
+/* struct _glist, canvas_class */
+#include "g_canvas.h"
+
+#define RIDDLE_DEBUG
+
+typedef struct _rdenvironment
+{
+ t_pd re_pd;
+ t_rdpool *re_graphpools;
+ t_rdbuffer *re_writers;
+ t_rdbuffer *re_readers; /* list of orphaned readers */
+ t_clock *re_updatedspclock;
+} t_rdenvironment;
+
+static t_class *rdenvironment_class = 0;
+
+struct _rdsource
+{
+ t_riddle *ri_riddle;
+ int ri_sourcecount;
+ t_symbol *ri_pattern;
+ t_symbol *ri_newpattern;
+ int ri_block; /* if non-zero pattern: largest expected block */
+ int ri_newblock;
+};
+
+struct _rdsink
+{
+ t_riddle *ro_riddle;
+ int ro_outno;
+ t_symbol *ro_pattern;
+ int ro_block; /* if non-zero pattern: largest expected block */
+ t_atom ro_outbuf[3]; /* siginno, pattern, block */
+ int ro_isready;
+ int ro_isstrict; /* if set: non-riddle sinks are rejected */
+};
+
+#define RDPOOL_INISIZE 64
+
+typedef struct _rdlink
+{
+ t_symbol *rl_key;
+ int rl_size;
+ int rl_maxsize;
+ t_float *rl_data;
+ t_float rl_inidata[RDPOOL_INISIZE];
+ struct _rdlink *rl_next;
+} t_rdlink;
+
+struct _rdpool
+{
+ t_canvas *rp_graph;
+ int rp_refcount;
+ t_rdlink *rp_links;
+ t_rdpool *rp_prev;
+ t_rdpool *rp_next;
+};
+
+#define RDBUFFER_INISIZE 1024
+
+struct _rdbuffer
+{
+ t_symbol *rb_name;
+ t_riddle *rb_owner;
+ int rb_phase;
+ t_rdbuffer *rb_prev;
+ t_rdbuffer *rb_next;
+
+ /* common part, copied from writer to all its readers
+ immediately after any change */
+ int rb_nframes;
+ int rb_framesize;
+ int rb_npoints;
+ int rb_maxphase;
+ t_float *rb_buf;
+
+ /* writer-specific part */
+ t_rdbuffer *rb_readers;
+ int rb_bufsize;
+ t_float *rb_bufini;
+};
+
+/* these are filled in riddle_setup() */
+static t_symbol *rdps__reblock = 0;
+static t_symbol *rdps__idle = 0;
+static t_symbol *rdps__ = 0;
+
+void riddlebug_post(t_riddle *rd, char *pfx, char *fmt, ...)
+{
+ char buf[MAXPDSTRING];
+ va_list ap;
+ if (fmt)
+ {
+ va_start(ap, fmt);
+ vsnprintf(buf, MAXPDSTRING-1, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "%s \"%s\" (%x): %s\n",
+ pfx, class_getname(*(t_pd *)rd), (int)rd, buf);
+ }
+ else fprintf(stderr, "%s \"%s\" (%x)\n",
+ pfx, class_getname(*(t_pd *)rd), (int)rd);
+#ifdef MSW
+ fflush(stderr);
+#endif
+}
+
+static void riddle_updatedsptick(t_rdenvironment *re)
+{
+ canvas_update_dsp();
+}
+
+static void rdenvironment_anything(t_rdenvironment *re,
+ t_symbol *s, int ac, t_atom *av)
+{
+ /* FIXME */
+}
+
+static t_rdenvironment *rdenvironment_provide(void)
+{
+ t_rdenvironment *re;
+ t_symbol *ps__riddle = gensym("_riddle");
+ t_symbol *ps_hashriddle = gensym("#riddle");
+ if (ps_hashriddle->s_thing)
+ {
+ char *cname = class_getname(*ps_hashriddle->s_thing);
+ if (strcmp(cname, ps__riddle->s_name))
+ {
+ /* FIXME protect against the danger of someone else
+ (e.g. receive) binding to #riddle */
+ loudbug_bug("rdenvironment_provide");
+ }
+ else
+ {
+ /* FIXME compatibility test */
+ rdenvironment_class = *ps_hashriddle->s_thing;
+ return ((t_rdenvironment *)ps_hashriddle->s_thing);
+ }
+ }
+ rdenvironment_class = class_new(ps__riddle, 0, 0,
+ sizeof(t_rdenvironment),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addanything(rdenvironment_class, rdenvironment_anything);
+ re = (t_rdenvironment *)pd_new(rdenvironment_class); /* never freed */
+ re->re_graphpools = 0;
+ re->re_writers = 0;
+ re->re_readers = 0;
+ re->re_updatedspclock = clock_new(re, (t_method)riddle_updatedsptick);
+ pd_bind((t_pd *)re, ps_hashriddle); /* never unbound */
+ return (re);
+}
+
+static t_rdpool *rdpool_attach(t_rdenvironment *re, t_canvas *graph)
+{
+ t_rdpool *rp;
+ for (rp = re->re_graphpools; rp; rp = rp->rp_next)
+ if (rp->rp_graph == graph)
+ break;
+ if (rp)
+ rp->rp_refcount++;
+ else
+ {
+ rp = getbytes(sizeof(*rp));
+ rp->rp_graph = graph;
+ rp->rp_refcount = 1;
+ rp->rp_links = 0;
+ rp->rp_prev = 0;
+ if (re->re_graphpools)
+ re->re_graphpools->rp_prev = rp;
+ rp->rp_next = re->re_graphpools;
+ re->re_graphpools = rp;
+ }
+ return (rp);
+}
+
+static void rdpool_detach(t_rdpool *rp, t_rdenvironment *re)
+{
+ if (rp->rp_refcount > 1)
+ rp->rp_refcount--;
+ else
+ {
+ while (rp->rp_links)
+ {
+ t_rdlink *rl = rp->rp_links;
+ rp->rp_links = rl->rl_next;
+ if (rl->rl_data)
+ freebytes(rl->rl_data, rl->rl_size * sizeof(*rl->rl_data));
+ freebytes(rl, sizeof(*rl));
+ }
+ if (rp->rp_prev)
+ rp->rp_prev->rp_next = rp->rp_next;
+ else
+ re->re_graphpools = rp->rp_next;
+ if (rp->rp_next)
+ rp->rp_next->rp_prev = rp->rp_prev;
+ freebytes(rp, sizeof(*rp));
+ }
+}
+
+static void rdpool_setthis(t_rdpool *rp,
+ t_symbol *key, int size, t_float *data)
+{
+ t_rdlink *rl;
+ for (rl = rp->rp_links; rl; rl = rl->rl_next)
+ if (rl->rl_key == key)
+ break;
+ if (!rl)
+ {
+ rl = getbytes(sizeof(*rl));
+ rl->rl_key = key;
+ rl->rl_maxsize = RDPOOL_INISIZE;
+ rl->rl_data = rl->rl_inidata;
+ rl->rl_next = rp->rp_links;
+ rp->rp_links = rl;
+ }
+ if (size > rl->rl_maxsize)
+ rl->rl_data = grow_nodata(&size, &rl->rl_maxsize, rl->rl_data,
+ RDPOOL_INISIZE, rl->rl_inidata,
+ sizeof(*rl->rl_data));
+ rl->rl_size = size;
+ memcpy(rl->rl_data, data, size * sizeof(*rl->rl_data));
+}
+
+static void rdpool_proliferate(t_rdpool *rphead, t_gobj *g,
+ t_symbol *key, int size, t_float *data)
+{
+ for (; g; g = g->g_next)
+ {
+ if (pd_class((t_pd *)g) == canvas_class)
+ {
+ t_canvas *graph = (t_canvas *)g;
+ t_rdpool *rp;
+ for (rp = rphead; rp; rp = rp->rp_next)
+ if (rp->rp_graph == graph)
+ break;
+ if (rp)
+ rdpool_setthis(rp, key, size, data);
+ rdpool_proliferate(rphead, graph->gl_list, key, size, data);
+ }
+ }
+}
+
+/* LATER setcache */
+void rdpool_set(t_rdpool *rp, t_symbol *key, int size, t_float *data)
+{
+ t_rdenvironment *re = rdenvironment_provide();
+ rdpool_setthis(rp, key, size, data);
+ rdpool_proliferate(re->re_graphpools, (t_gobj *)rp->rp_graph,
+ key, size, data);
+}
+
+/* LATER setcache */
+void rdpool_setbygraph(t_canvas *graph, t_symbol *key, int size, t_float *data)
+{
+ t_rdenvironment *re = rdenvironment_provide();
+ t_rdpool *rp;
+ for (rp = re->re_graphpools; rp; rp = rp->rp_next)
+ if (rp->rp_graph == graph)
+ break;
+ if (rp)
+ rdpool_setthis(rp, key, size, data);
+ rdpool_proliferate(re->re_graphpools, (t_gobj *)graph, key, size, data);
+}
+
+t_float *rdpool_get(t_rdpool *rp, t_symbol *key, int *sizep)
+{
+ t_rdlink *rl;
+ for (rl = rp->rp_links; rl; rl = rl->rl_next)
+ {
+ if (rl->rl_key == key)
+ {
+ *sizep = rl->rl_size;
+ return (rl->rl_data);
+ }
+ }
+ return (0);
+}
+
+t_float *riddle_getlink(t_riddle *rd, t_symbol *key, int *sizep)
+{
+ return (rdpool_get(rd->rd_graphpool, key, sizep));
+}
+
+/* LATER traversal api */
+t_canvas *riddle_getgraph(t_riddle *rd, int sigoutno)
+{
+ t_outlet *op;
+ int outno = rd->rd_outslots[sigoutno].ro_outno;
+ t_outconnect *oc = obj_starttraverseoutlet((t_object *)rd, &op, outno);
+ while (oc)
+ {
+ t_object *dst;
+ t_inlet *ip;
+ int inno;
+ oc = obj_nexttraverseoutlet(oc, &dst, &ip, &inno);
+ if (dst)
+ {
+ int siginno = obj_siginletindex(dst, inno);
+ if (siginno < 0)
+ {
+ /* should not happen, LATER rethink */
+ break;
+ }
+ else if (pd_class((t_pd *)dst) != canvas_class)
+ {
+ loud_error((t_pd *)rd, "invalid connection (not to a canvas)");
+ break;
+ }
+ else return ((t_canvas *)dst);
+ }
+ }
+ return (0);
+}
+
+
+void riddle_updatedsp(void)
+{
+ t_rdenvironment *re = rdenvironment_provide();
+ loud_warning((t_pd *)re, 0, "...trying to reconstruct the dsp chain");
+ clock_delay(re->re_updatedspclock, 0);
+}
+
+int riddle_getsr(t_riddle *rd)
+{
+ return (rd->rd_graphsr);
+}
+
+int riddle_getgraphblock(t_riddle *rd)
+{
+ return (rd->rd_graphblock);
+}
+
+int riddle_getsourceblock(t_riddle *rd, int siginno)
+{
+ if (siginno >= rd->rd_nsiginlets || -siginno > rd->rd_nremoteslots)
+ {
+ loudbug_bug("riddle_getsourceblock");
+ return (0);
+ }
+ else
+ {
+ t_rdsource *slot = (siginno >= 0 ?
+ rd->rd_inslots + siginno :
+ rd->rd_remoteslots - ++siginno);
+ return (slot->ri_pattern ? 0 : slot->ri_block);
+ }
+}
+
+t_symbol *riddle_getsourcepattern(t_riddle *rd, int siginno, int *maxblockp)
+{
+ if (siginno >= rd->rd_nsiginlets || -siginno > rd->rd_nremoteslots)
+ {
+ loudbug_bug("riddle_getsourcepattern");
+ return (0);
+ }
+ else
+ {
+ t_rdsource *slot = (siginno >= 0 ?
+ rd->rd_inslots + siginno :
+ rd->rd_remoteslots - ++siginno);
+ if (maxblockp)
+ *maxblockp = slot->ri_block;
+ return (slot->ri_pattern);
+ }
+}
+
+int riddle_getoutblock(t_riddle *rd, int sigoutno)
+{
+ if (sigoutno >= rd->rd_nsigoutlets || sigoutno < 0)
+ {
+ loudbug_bug("riddle_getoutblock");
+ return (0);
+ }
+ else return (rd->rd_outslots[sigoutno].ro_pattern ?
+ 0 : rd->rd_outslots[sigoutno].ro_block);
+}
+
+t_symbol *riddle_getoutpattern(t_riddle *rd, int sigoutno, int *maxblockp)
+{
+ if (sigoutno >= rd->rd_nsigoutlets || sigoutno < 0)
+ {
+ loudbug_bug("riddle_getoutpattern");
+ return (0);
+ }
+ else
+ {
+ if (maxblockp)
+ *maxblockp = rd->rd_outslots[sigoutno].ro_block;
+ return (rd->rd_outslots[sigoutno].ro_pattern);
+ }
+}
+
+static void riddle_setsourceblock(t_riddle *rd, int siginno, int newblock)
+{
+ int slotno = (siginno < 0 ? rd->rd_nsiginlets - siginno - 1 : siginno);
+#ifdef RIDDLE_DEBUG
+ riddlebug_post(rd, "setsourceblock", "%d (%d) %d",
+ siginno, slotno, newblock);
+#endif
+ if (siginno >= rd->rd_nsiginlets || -siginno > rd->rd_nremoteslots)
+ loudbug_bug("riddle_setsourceblock");
+ else if (newblock <= 0)
+ loud_error((t_pd *)rd,
+ "invalid source block on inlet %d: %d", siginno, newblock);
+ else
+ {
+ t_rdsource *slot = rd->rd_inslots + slotno;
+ /* LATER if (slot->ri_newpattern) complain */
+ if (newblock == slot->ri_newblock)
+ slot->ri_sourcecount++;
+ else if (slot->ri_sourcecount > 0)
+ loud_error((t_pd *)rd,
+ "source block mismatch on inlet %d: %d != %d",
+ siginno, newblock, slot->ri_newblock);
+ else
+ {
+ slot->ri_newblock = newblock;
+ slot->ri_sourcecount = 1;
+ if (siginno < 0)
+ rd->rd_remotesource = 1;
+ }
+ }
+}
+
+/* LATER pattern validation and normalization (e.g. xXXX -> aAAA */
+static void riddle_setsourcepattern(t_riddle *rd, int siginno,
+ t_symbol *newpattern, int maxblock)
+{
+ int slotno = (siginno < 0 ? rd->rd_nsiginlets - siginno - 1 : siginno);
+#ifdef RIDDLE_DEBUG
+ riddlebug_post(rd, "setsourcepattern", "%d (%d) %s %d",
+ siginno, slotno, newpattern->s_name, maxblock);
+#endif
+ if (siginno >= rd->rd_nsiginlets || -siginno > rd->rd_nremoteslots)
+ loudbug_bug("riddle_setsourcepattern");
+ else
+ {
+ t_rdsource *slot = rd->rd_inslots + slotno;
+ if (newpattern == slot->ri_newpattern)
+ slot->ri_sourcecount++;
+ else if (slot->ri_sourcecount > 0)
+ {
+ if (slot->ri_newpattern)
+ loud_error((t_pd *)rd,
+ "source pattern mismatch on inlet %d: %s != %s",
+ siginno, newpattern->s_name,
+ slot->ri_newpattern->s_name);
+ else
+ loud_error((t_pd *)rd,
+ "source pattern/block mismatch on inlet %d");
+ }
+ else
+ {
+ slot->ri_newpattern = newpattern;
+ if (maxblock)
+ {
+ if (maxblock > slot->ri_newblock)
+ slot->ri_newblock = maxblock;
+ }
+ else slot->ri_newblock = rd->rd_graphblock;
+ slot->ri_sourcecount = 1;
+ if (siginno < 0)
+ rd->rd_remotesource = 1;
+ }
+ }
+}
+
+void riddle_setoutblock(t_riddle *rd, int sigoutno, int block)
+{
+ t_rdsink *slot;
+#ifdef RIDDLE_DEBUG
+ riddlebug_post(rd, "setoutblock", "%d %d", sigoutno, block);
+#endif
+ if (sigoutno >= rd->rd_nsigoutlets)
+ loudbug_bug("riddle_setoutblock");
+ else if (sigoutno < 0)
+ {
+ for (sigoutno = 0, slot = rd->rd_outslots;
+ sigoutno < rd->rd_nsigoutlets; sigoutno++, slot++)
+ {
+ slot->ro_pattern = 0;
+ slot->ro_block = block;
+ slot->ro_outbuf[1].a_w.w_symbol = rdps__;
+ slot->ro_outbuf[2].a_w.w_float = (t_float)block;
+ slot->ro_isready = 1;
+ }
+ }
+ else
+ {
+ slot = rd->rd_outslots + sigoutno;
+ slot->ro_pattern = 0;
+ slot->ro_block = block;
+ slot->ro_outbuf[1].a_w.w_symbol = rdps__;
+ slot->ro_outbuf[2].a_w.w_float = (t_float)block;
+ slot->ro_isready = 1;
+ }
+}
+
+void riddle_setoutpattern(t_riddle *rd, int sigoutno,
+ t_symbol *pattern, int maxblock)
+{
+ t_rdsink *slot;
+#ifdef RIDDLE_DEBUG
+ riddlebug_post(rd, "setoutpattern", "%d %s %d",
+ sigoutno, pattern->s_name, maxblock);
+#endif
+ if (sigoutno >= rd->rd_nsigoutlets)
+ loudbug_bug("riddle_setoutpattern");
+ else if (sigoutno < 0)
+ {
+ for (sigoutno = 0, slot = rd->rd_outslots;
+ sigoutno < rd->rd_nsigoutlets; sigoutno++, slot++)
+ {
+ slot->ro_pattern = pattern;
+ slot->ro_block = maxblock;
+ slot->ro_outbuf[1].a_w.w_symbol = pattern;
+ slot->ro_outbuf[2].a_w.w_float = (t_float)maxblock;
+ slot->ro_isready = 1;
+ }
+ }
+ else
+ {
+ slot = rd->rd_outslots;
+ slot->ro_pattern = pattern;
+ slot->ro_block = maxblock;
+ slot->ro_outbuf[1].a_w.w_symbol = pattern;
+ slot->ro_outbuf[2].a_w.w_float = (t_float)maxblock;
+ slot->ro_isready = 1;
+ }
+}
+
+int riddle_checksourceblock(t_riddle *rd, int siginno, int reqblock)
+{
+ int block = riddle_getsourceblock(rd, siginno);
+ if (block == reqblock)
+ return (1);
+ else
+ {
+ if (!rd->rd_wasdisabled && rd->rd_inslots[siginno].ri_sourcecount)
+ loud_error((t_pd *)rd,
+ "invalid source block on inlet %d: %d (%d expected)",
+ siginno, block, reqblock);
+ rd->rd_disabled = 1;
+ return (0);
+ }
+}
+
+/* LATER pattern normalization (e.g. xXXX -> aAAA */
+int riddle_checksourcepattern(t_riddle *rd, int siginno,
+ t_symbol *reqpattern, int *maxblockp)
+{
+ t_symbol *pattern = riddle_getsourcepattern(rd, siginno, maxblockp);
+ if (pattern == reqpattern)
+ return (1);
+ else
+ {
+ if (!rd->rd_wasdisabled && rd->rd_inslots[siginno].ri_sourcecount)
+ {
+ if (pattern)
+ loud_error((t_pd *)rd,
+ "wrong source pattern on inlet %d: %s (%s expected)",
+ siginno, pattern->s_name, reqpattern->s_name);
+ else
+ loud_error((t_pd *)rd,
+ "invalid source on inlet %d: pattern %s expected",
+ siginno, reqpattern->s_name);
+ }
+ rd->rd_disabled = 1;
+ return (0);
+ }
+}
+
+int riddle_checkanysource(t_riddle *rd, int siginno)
+{
+ if (siginno >= rd->rd_nsiginlets || -siginno > rd->rd_nremoteslots)
+ loudbug_bug("riddle_checkanysource");
+ else
+ {
+ t_rdsource *slot = (siginno >= 0 ?
+ rd->rd_inslots + siginno :
+ rd->rd_remoteslots - ++siginno);
+ if (slot->ri_sourcecount > 0)
+ return (1);
+ }
+ rd->rd_disabled = 1;
+ return (0);
+}
+
+int riddle_isdisabled(t_riddle *rd)
+{
+ return (rd->rd_disabled);
+}
+
+void riddle_disable(t_riddle *rd)
+{
+ rd->rd_disabled = 1;
+}
+
+static int riddle_validatesinks(t_riddle *rd)
+{
+ t_object *x = (t_object *)rd;
+ int sigoutno, outno, nouts = obj_noutlets(x);
+ for (sigoutno = 0, outno = 0; outno < nouts; outno++)
+ {
+ if (obj_issignaloutlet(x, outno))
+ {
+ if (sigoutno < rd->rd_nsigoutlets)
+ {
+ if (rd->rd_outslots[sigoutno].ro_outno != outno)
+ {
+ if (rd->rd_outslots[sigoutno].ro_outno < 0)
+ rd->rd_outslots[sigoutno].ro_outno = outno;
+ else
+ {
+ loudbug_bug("riddle_validatesinks 1");
+ return (0);
+ }
+ }
+ }
+ else
+ {
+ loudbug_bug("riddle_validatesinks 2");
+ /* LATER grow */
+ return (0);
+ }
+ sigoutno++;
+ }
+ }
+ if (sigoutno < rd->rd_nsigoutlets)
+ {
+ loudbug_bug("riddle_validatesinks 3");
+ /* LATER shrink */
+ return (0);
+ }
+ return (1);
+}
+
+static int rdsink_push(t_rdsink *slot)
+{
+ int result = 1;
+ t_object *x = (t_object *)slot->ro_riddle;
+ t_outlet *op;
+ t_outconnect *oc = obj_starttraverseoutlet(x, &op, slot->ro_outno);
+ while (oc)
+ {
+ t_object *dst;
+ t_inlet *ip;
+ int inno;
+ oc = obj_nexttraverseoutlet(oc, &dst, &ip, &inno);
+ if (dst)
+ {
+ int siginno = obj_siginletindex(dst, inno);
+ if (siginno < 0)
+ {
+ /* should not happen, LATER rethink */
+ }
+ /* LATER unify isriddle test as zgetfn(..., gensym("dspblock")) */
+ else if (zgetfn((t_pd *)dst, rdps__reblock))
+ {
+ slot->ro_outbuf->a_w.w_float = (t_float)siginno;
+ typedmess((t_pd *)dst, rdps__reblock, 3, slot->ro_outbuf);
+ }
+ else if (slot->ro_isstrict)
+ {
+ char *dstname = class_getname(*(t_pd *)dst);
+ if (strcmp(dstname, "print~"))
+ {
+ loud_error((t_pd *)x, "not a riddle: \"%s\"", dstname);
+ result = 0;
+ }
+ }
+ }
+ }
+ return (result);
+}
+
+void riddle_mute(t_riddle *rd, t_signal **sp)
+{
+ int i, j, nouts = obj_nsigoutlets((t_object *)rd);
+ t_rdsink *slot = rd->rd_outslots;
+#ifdef RIDDLE_DEBUG
+ riddlebug_post(rd, "MUTE", 0);
+#endif
+ if (rd->rd_nsigoutlets != nouts)
+ {
+ loudbug_bug("riddle_mute");
+ riddle_validatesinks(rd);
+ if (rd->rd_nsigoutlets != nouts)
+ return;
+ }
+ i = 0;
+ j = obj_nsiginlets((t_object *)rd);
+ while (nouts--)
+ {
+ slot->ro_pattern = 0;
+ slot->ro_block = sp[j]->s_n;
+ slot->ro_outbuf[1].a_w.w_symbol = rdps__;
+ slot->ro_outbuf[2].a_w.w_float = (t_float)slot->ro_block;
+ slot->ro_isready = 1;
+ dsp_add_zero(sp[j]->s_vec, sp[j]->s_n);
+ i++; j++;
+ slot++;
+ }
+}
+
+static void riddle_dsp(t_riddle *rd, t_signal **sp)
+{
+ int failed = 0, unarmed = 1, doreblock = 0;
+ int oldgraphsr = rd->rd_graphsr;
+ int oldgraphblock = rd->rd_graphblock;
+ int inslotno, ninslots = rd->rd_nsiginlets + rd->rd_nremoteslots;
+ int outslotno;
+ t_rdsource *inslot;
+ t_rdsink *outslot;
+
+#ifdef RIDDLE_DEBUG
+ riddlebug_post(rd, "\nriddle_dsp", 0);
+ for (inslotno = 0, inslot = rd->rd_inslots;
+ inslotno < ninslots; inslotno++, inslot++)
+ loudbug_post("%d sources: %d reblocks of %d -> %d",
+ inslotno, inslot->ri_sourcecount,
+ inslot->ri_block, inslot->ri_newblock);
+#endif
+
+ rd->rd_graphsr = (int)sp[0]->s_sr;
+ rd->rd_graphblock = sp[0]->s_n;
+
+ if (rd->rd_wasdisabled = rd->rd_disabled)
+ {
+ rd->rd_disabled = 0;
+ if (rd->rd_blockfn)
+ doreblock = 1;
+ else
+ {
+ loudbug_bug("riddle_dsp 2");
+ goto muteandreset;
+ }
+ }
+
+ /* verify all source slots */
+ for (inslotno = 0, inslot = rd->rd_inslots;
+ inslotno < ninslots; inslotno++, inslot++)
+ {
+ if (inslot->ri_newblock > rd->rd_graphblock)
+ {
+ loud_error((t_pd *)rd,
+ "inslot %d: source block too large (%d > %d)",
+ inslotno, inslot->ri_newblock, rd->rd_graphblock);
+ failed = 1;
+ }
+ else if (inslot->ri_sourcecount <= 0)
+ {
+ if (rd->rd_remotesource) /* this is an `issticky' flag -- it tells
+ if unconfirmed sourceblock should be
+ preserved or bashed to graphblock */
+ {
+ inslot->ri_newpattern = inslot->ri_pattern;
+ if (inslot->ri_block > 0)
+ inslot->ri_newblock = inslot->ri_block;
+ else
+ inslot->ri_newblock = rd->rd_graphblock;
+ }
+ else
+ {
+ inslot->ri_newpattern = 0;
+ inslot->ri_newblock = rd->rd_graphblock;
+ }
+ }
+ else if (inslot->ri_newblock <= 0) /* should not happen */
+ {
+ loudbug_bug("riddle_dsp 1");
+ failed = 1;
+ }
+ }
+ if (failed)
+ goto muteandreset;
+
+ /* determine outblock sizes -- blockfn fires on the very first call
+ to riddle_dsp(), and then after any change of block or sr,
+ and each time the object is disabled...
+ LATER reconsider reblocking during every dsp call... */
+ if (!doreblock && rd->rd_blockfn)
+ {
+ if (rd->rd_graphsr != oldgraphsr ||
+ rd->rd_graphblock != oldgraphblock)
+ doreblock = 1;
+ else for (inslotno = 0, inslot = rd->rd_inslots;
+ inslotno < ninslots; inslotno++, inslot++)
+ {
+ if (inslot->ri_newpattern != inslot->ri_pattern ||
+ inslot->ri_newblock != inslot->ri_block)
+ {
+ doreblock = 1;
+ break;
+ }
+ }
+ }
+
+ if (doreblock || !rd->rd_blockfn)
+ {
+ for (outslotno = 0, outslot = rd->rd_outslots;
+ outslotno < rd->rd_nsigoutlets; outslotno++, outslot++)
+ {
+ outslot->ro_pattern = 0;
+ outslot->ro_block = 0;
+ outslot->ro_isready = 0;
+ }
+ for (inslotno = 0, inslot = rd->rd_inslots;
+ inslotno < ninslots; inslotno++, inslot++)
+ {
+ inslot->ri_pattern = inslot->ri_newpattern;
+ inslot->ri_block = inslot->ri_newblock;
+ }
+ }
+
+ if (doreblock)
+ {
+#ifdef RIDDLE_DEBUG
+ riddlebug_post(rd, "REBLOCK", 0);
+#endif
+ rd->rd_blockfn(rd);
+ if (rd->rd_disabled)
+ goto muteandreset;
+ }
+
+ for (outslotno = 0, outslot = rd->rd_outslots;
+ outslotno < rd->rd_nsigoutlets; outslotno++, outslot++)
+ {
+ if (outslot->ro_block < 0)
+ {
+ loudbug_bug("riddle_dsp 3");
+ failed = 1;
+ }
+ else if (outslot->ro_block == 0)
+ outslot->ro_block = rd->rd_graphblock;
+ }
+ if (failed)
+ goto muteandreset;
+
+#ifdef RIDDLE_DEBUG
+ riddlebug_post(rd, "PUSH", 0);
+#endif
+ if (riddle_validatesinks(rd))
+ {
+ for (outslotno = 0, outslot = rd->rd_outslots;
+ outslotno < rd->rd_nsigoutlets; outslotno++, outslot++)
+ if (outslot->ro_isready && rdsink_push(outslot) == 0)
+ failed = 1;
+ }
+ else failed = 1;
+ if (failed)
+ goto muteandreset;
+
+ if (rd->rd_dspfn)
+ {
+ rd->rd_dspfn(rd, sp);
+ unarmed = 0;
+ }
+ else loudbug_bug("riddle_dsp 4");
+
+muteandreset:
+ if (unarmed)
+ {
+ rd->rd_disabled = 1;
+ riddle_mute(rd, sp);
+ }
+ for (inslotno = 0, inslot = rd->rd_inslots;
+ inslotno < ninslots; inslotno++, inslot++)
+ {
+ inslot->ri_newpattern = 0;
+ inslot->ri_newblock = 0;
+ inslot->ri_sourcecount = 0;
+ }
+ rd->rd_remotesource = 0;
+}
+
+static void riddle__reblock(t_riddle *rd,
+ t_symbol *pattern, t_floatarg f1, t_floatarg f2)
+{
+ if (pattern == rdps__)
+ riddle_setsourceblock(rd, (int)f1, (int)f2);
+ /* LATER replace with full validation done in riddle_setsourcepattern() */
+ else if (pattern && *pattern->s_name == 'a')
+ riddle_setsourcepattern(rd, (int)f1, pattern, (int)f2);
+ else
+ loud_error((t_pd *)rd, "bad arguments to '_reblock'");
+}
+
+static void riddle_free(t_riddle *rd)
+{
+ int nslots;
+ t_gotfn freefn = zgetfn((t_pd *)rd, gensym("_free"));
+ if (freefn)
+ freefn(rd);
+
+ rdpool_detach(rd->rd_graphpool, rdenvironment_provide());
+
+ nslots = rd->rd_nsiginlets + rd->rd_nremoteslots;
+ if (rd->rd_inslots)
+ freebytes(rd->rd_inslots, nslots * sizeof(*rd->rd_inslots));
+ if (rd->rd_outslots)
+ freebytes(rd->rd_outslots,
+ rd->rd_nsigoutlets * sizeof(*rd->rd_outslots));
+}
+
+typedef t_pd *(*t_newgimme)(t_symbol *s, int argc, t_atom *argv);
+
+static void *riddle_new(t_symbol *s, int ac, t_atom *av)
+{
+ /* IFBUILTIN remove: this is a bad hack */
+ t_rdenvironment *re = rdenvironment_provide();
+ t_newgimme newfn = (t_newgimme)zgetfn((t_pd *)re, s);
+ if (!newfn)
+ {
+ loudbug_bug("riddle_new 1");
+ return (0);
+ }
+ else
+ {
+ t_riddle *rd = (t_riddle *)newfn(s, ac, av);
+ int i, nslots;
+ t_rdsource *inslot;
+ t_rdsink *outslot;
+ if (!rd)
+ return (0);
+ rd->rd_disabled = 0;
+ rd->rd_wasdisabled = 0;
+ rd->rd_blockfn = (t_rdblockfn)zgetfn((t_pd *)rd, gensym("dspblock"));
+ rd->rd_dspfn = (t_rddspfn)zgetfn((t_pd *)rd, gensym("_dsp"));
+ if (!rd->rd_dspfn)
+ loudbug_bug("riddle_new 2");
+
+ rd->rd_graphpool = rdpool_attach(re, canvas_getcurrent());
+
+ rd->rd_graphsr = (int)sys_getsr();
+ rd->rd_graphblock = sys_getblksize();
+ rd->rd_nsiginlets = obj_nsiginlets((t_object *)rd);
+ rd->rd_nsigoutlets = obj_nsigoutlets((t_object *)rd);
+ nslots = rd->rd_nsiginlets + rd->rd_nremoteslots;
+
+ rd->rd_inslots = getbytes(nslots * sizeof(*rd->rd_inslots));
+ for (i = 0, inslot = rd->rd_inslots; i < nslots; i++, inslot++)
+ {
+ inslot->ri_riddle = rd;
+ inslot->ri_sourcecount = 0;
+ inslot->ri_pattern = 0;
+ inslot->ri_newpattern = 0;
+ inslot->ri_block = 0;
+ inslot->ri_newblock = 0;
+ }
+ rd->rd_remoteslots = rd->rd_inslots + rd->rd_nsiginlets;
+
+ rd->rd_outslots =
+ getbytes(rd->rd_nsigoutlets * sizeof(*rd->rd_outslots));
+ for (i = 0, outslot = rd->rd_outslots;
+ i < rd->rd_nsigoutlets; i++, outslot++)
+ {
+ outslot->ro_riddle = rd;
+ outslot->ro_outno = -1;
+ outslot->ro_pattern = 0;
+ outslot->ro_block = 0;
+ outslot->ro_outbuf[0].a_type = A_FLOAT;
+ outslot->ro_outbuf[1].a_type = A_SYMBOL;
+ outslot->ro_outbuf[1].a_w.w_symbol = rdps__;
+ outslot->ro_outbuf[2].a_type = A_FLOAT;
+ outslot->ro_isready = 0;
+ outslot->ro_isstrict = 0; /* LATER rethink */
+ }
+ riddle_validatesinks(rd);
+
+ /* currently, rd->rd_nremoteslots is incremented in
+ rdbuffer_newreader(), LATER rethink */
+
+ rd->rd_remotesource = 0;
+ return (rd);
+ }
+}
+
+/* IFBUILTIN remove: classes would use explicit class_addmethod calls */
+t_class *riddle_setup(t_symbol *name, t_newmethod newfn, t_method freefn,
+ size_t sz, t_method floatfn,
+ t_rdblockfn blockfn, t_rddspfn dspfn)
+{
+ t_class *c = class_new(name, (t_newmethod)riddle_new,
+ (t_method)riddle_free, sz, 0, A_GIMME, 0);
+
+ /* IFBUILTIN remove: this is a bad hack */
+ t_rdenvironment *re = rdenvironment_provide();
+ class_addmethod(*(t_pd *)re, (t_method)newfn, name, 0);
+
+ if (strlen(name->s_name) < 60)
+ {
+ char rdstr[64];
+ sprintf(rdstr, "rd.%s", name->s_name);
+ class_addcreator((t_newmethod)riddle_new, gensym(rdstr), A_GIMME, 0);
+ class_addmethod(*(t_pd *)re, (t_method)newfn, gensym(rdstr), 0);
+ }
+
+ rdps__reblock = gensym("_reblock");
+ rdps__idle = gensym("_idle");
+ rdps__ = gensym("_");
+
+ sic_setup(c, riddle_dsp, floatfn);
+ class_addmethod(c, (t_method)blockfn, gensym("dspblock"), 0);
+ /* IFBUILTIN "_dsp" -> "dsp" */
+ class_addmethod(c, (t_method)dspfn, gensym("_dsp"), 0);
+ /* IFBUILTIN remove these two */
+ class_addmethod(c, (t_method)newfn, gensym("_new"), 0);
+ class_addmethod(c, (t_method)freefn, gensym("_free"), 0);
+ class_addmethod(c, (t_method)riddle__reblock,
+ rdps__reblock, A_FLOAT, A_SYMBOL, A_FLOAT, 0);
+ return (c);
+}
+
+static t_rdbuffer *rdenvironment_getbuffer(t_rdenvironment *re, t_symbol *name)
+{
+ t_rdbuffer *rb = re->re_writers;
+ while (rb)
+ {
+ if (rb->rb_name == name)
+ return (rb);
+ rb = rb->rb_next;
+ }
+ return (0);
+}
+
+t_rdbuffer *riddle_getbuffer(t_symbol *name)
+{
+ t_rdenvironment *re = rdenvironment_provide();
+ return (rdenvironment_getbuffer(re, name));
+}
+
+t_rdbuffer *rdbuffer_getwriter(t_rdbuffer *rb)
+{
+ t_rdenvironment *re = rdenvironment_provide();
+ return (rdenvironment_getbuffer(re, rb->rb_name));
+}
+
+static void rdbuffer_updatereaders(t_rdbuffer *rb)
+{
+ t_rdbuffer *reader;
+ for (reader = rb->rb_readers; reader; reader = reader->rb_next)
+ {
+ reader->rb_nframes = rb->rb_nframes;
+ reader->rb_framesize = rb->rb_framesize;
+ reader->rb_npoints = rb->rb_npoints;
+ reader->rb_maxphase = rb->rb_maxphase;
+ reader->rb_buf = rb->rb_buf;
+ reader->rb_phase = 0; /* LATER adjust */
+ if (reader->rb_owner)
+ /* FIXME -1 - reader->rb_slotno */
+ riddle_setsourceblock(reader->rb_owner, -1, rb->rb_framesize);
+ }
+}
+
+/* FIXME return the actually allocated size */
+/* LATER optionally use old contents by zero-padding, interpolating, etc. */
+void rdbuffer_validate(t_rdbuffer *rb, int nblock)
+{
+ if (rb->rb_bufini == 0)
+ {
+ loudbug_bug("rdbuffer_validate 1");
+ return;
+ }
+ rb->rb_npoints = nblock * rb->rb_nframes;
+ if (rb->rb_npoints > rb->rb_bufsize)
+ {
+ int reqsize = rb->rb_npoints;
+ /* LATER use grow_withdata() */
+ rb->rb_buf = grow_nodata(&rb->rb_npoints, &rb->rb_bufsize, rb->rb_buf,
+ RDBUFFER_INISIZE, rb->rb_bufini,
+ sizeof(*rb->rb_buf));
+ if (rb->rb_npoints != reqsize)
+ {
+ rb->rb_nframes = rb->rb_npoints / nblock;
+ if (rb->rb_nframes < 1)
+ {
+ loudbug_bug("rdbuffer_validate 2");
+ rb->rb_nframes = 1;
+ nblock = rb->rb_npoints;
+ }
+ }
+ }
+ /* LATER convert old buffer's contents of rb->rb_framesize * rb->rb_nframes
+ points into the new buffer of nblock * rb->rb_nframes points */
+ memset(rb->rb_buf, 0, rb->rb_npoints * sizeof(*rb->rb_buf));
+ rb->rb_phase = 0; /* LATER adjust */
+ rb->rb_maxphase = rb->rb_npoints - nblock;
+ rb->rb_framesize = nblock;
+ rdbuffer_updatereaders(rb);
+}
+
+void rdbuffer_reset(t_rdbuffer *rb)
+{
+ if (rb->rb_bufini)
+ memset(rb->rb_buf, 0, rb->rb_npoints * sizeof(*rb->rb_buf));
+ rb->rb_phase = 0;
+}
+
+int rdbuffer_getframesize(t_rdbuffer *rb)
+{
+ return (rb->rb_framesize);
+}
+
+t_float *rdbuffer_gethead(t_rdbuffer *rb)
+{
+ return (rb->rb_buf + rb->rb_phase);
+}
+
+void rdbuffer_stephead(t_rdbuffer *rb)
+{
+ rb->rb_phase += rb->rb_framesize;
+ if (rb->rb_phase > rb->rb_maxphase)
+ rb->rb_phase = 0;
+}
+
+void rdbuffer_movehead(t_rdbuffer *rb, int nframes)
+{
+ if (rb->rb_nframes <= 0)
+ {
+ loudbug_bug("rdbuffer_movehead");
+ }
+ else if (nframes > 0)
+ {
+ if (nframes >= rb->rb_nframes)
+ nframes = rb->rb_nframes - 1;
+ rb->rb_phase += nframes * rb->rb_framesize;
+ while (rb->rb_phase > rb->rb_maxphase)
+ rb->rb_phase -= rb->rb_npoints;
+ }
+ else if (nframes < 0)
+ {
+ nframes = -nframes;
+ if (nframes >= rb->rb_nframes)
+ nframes = rb->rb_nframes - 1;
+ rb->rb_phase -= nframes * rb->rb_framesize;
+ while (rb->rb_phase < 0)
+ rb->rb_phase += rb->rb_npoints;
+ }
+}
+
+void rdbuffer_delayhead(t_rdbuffer *rb, int nframes)
+{
+ if (rb->rb_bufini)
+ loudbug_bug("rdbuffer_delayhead 1");
+ else
+ {
+ t_rdbuffer *writer = riddle_getbuffer(rb->rb_name);
+ if (writer)
+ {
+ rb->rb_phase = writer->rb_phase;
+ rdbuffer_movehead(rb, -nframes);
+ }
+ else loudbug_bug("rdbuffer_delayhead 2");
+ }
+}
+
+void rdbuffer_free(t_rdbuffer *rb)
+{
+ if (rb->rb_bufini)
+ {
+ if (rb->rb_buf != rb->rb_bufini)
+ freebytes(rb->rb_buf, rb->rb_bufsize * sizeof(*rb->rb_buf));
+ if (rb->rb_name)
+ {
+ t_rdbuffer *reader;
+ t_rdenvironment *re = rdenvironment_provide();
+ /* remove from the environment */
+ if (rb->rb_next)
+ rb->rb_next->rb_prev = rb->rb_prev;
+ if (rb->rb_prev)
+ rb->rb_prev->rb_next = rb->rb_next;
+ else
+ re->re_writers = rb->rb_next;
+ /* move all readers to the orphanage */
+ if (reader = rb->rb_readers)
+ {
+ while (reader->rb_next)
+ reader = reader->rb_next;
+ if (re->re_readers)
+ re->re_readers->rb_prev = reader;
+ reader->rb_next = re->re_readers;
+ re->re_readers = rb->rb_readers;
+ }
+ }
+ }
+ else
+ {
+ if (rb->rb_name)
+ {
+ /* remove from writer's list or orphanage */
+ if (rb->rb_next)
+ rb->rb_next->rb_prev = rb->rb_prev;
+ if (rb->rb_prev)
+ rb->rb_prev->rb_next = rb->rb_next;
+ else
+ {
+ t_rdenvironment *re = rdenvironment_provide();
+ t_rdbuffer *writer = rdenvironment_getbuffer(re, rb->rb_name);
+ if (writer)
+ writer->rb_readers = rb->rb_next;
+ else
+ re->re_readers = rb->rb_next;
+ }
+ }
+ }
+ freebytes(rb, sizeof(*rb));
+}
+
+t_rdbuffer *rdbuffer_new(t_riddle *owner, t_symbol *name, int nframes)
+{
+ t_rdbuffer *rb = (t_rdbuffer *)getbytes(sizeof(*rb));
+ rb->rb_name = (name && *name->s_name ? name : 0);
+ rb->rb_owner = owner;
+ rb->rb_phase = 0;
+ rb->rb_nframes = (nframes > 1 ? nframes : 1);
+ rb->rb_framesize = 0;
+ rb->rb_npoints = 0;
+ rb->rb_maxphase = 0;
+ rb->rb_bufsize = RDBUFFER_INISIZE;
+ rb->rb_bufini = getbytes(rb->rb_bufsize * sizeof(*rb->rb_bufini));
+ rb->rb_buf = rb->rb_bufini;
+ rb->rb_readers = 0;
+ rb->rb_prev = 0;
+ rb->rb_next = 0;
+ if (rb->rb_name)
+ {
+ t_rdenvironment *re = rdenvironment_provide();
+ if (rdenvironment_getbuffer(re, rb->rb_name))
+ {
+ loud_error((t_pd *)owner, "duplicate buffer name \"%s\"",
+ rb->rb_name->s_name);
+ }
+ else
+ {
+ t_rdbuffer *reader;
+ /* store in the environment */
+ if (re->re_writers)
+ re->re_writers->rb_prev = rb;
+ rb->rb_next = re->re_writers;
+ re->re_writers = rb;
+ /* recover readers from the orphanage */
+ for (reader = re->re_readers; reader; reader = reader->rb_next)
+ {
+ if (reader->rb_name == rb->rb_name)
+ {
+ if (reader->rb_next)
+ reader->rb_next->rb_prev = reader->rb_prev;
+ if (reader->rb_prev)
+ reader->rb_prev->rb_next = reader->rb_next;
+ else
+ re->re_readers = reader->rb_next;
+ if (rb->rb_readers)
+ rb->rb_readers->rb_prev = reader;
+ reader->rb_next = rb->rb_readers;
+ rb->rb_readers = reader;
+ }
+ }
+ }
+ }
+ return (rb);
+}
+
+t_rdbuffer *rdbuffer_newreader(t_riddle *owner, t_symbol *name)
+{
+ t_rdbuffer *rb = (t_rdbuffer *)getbytes(sizeof(*rb));
+ /* FIXME do not rely on pd_new() callocing owner->rd_nremoteslots to zero */
+ owner->rd_nremoteslots++;
+ rb->rb_name = (name && *name->s_name ? name : 0);
+ rb->rb_owner = owner;
+ rb->rb_phase = 0;
+ rb->rb_nframes = 0;
+ rb->rb_framesize = 0;
+ rb->rb_npoints = 0;
+ rb->rb_maxphase = 0;
+ rb->rb_buf = 0;
+ rb->rb_bufini = 0;
+ rb->rb_prev = 0;
+ rb->rb_next = 0;
+ if (rb->rb_name)
+ {
+ t_rdenvironment *re = rdenvironment_provide();
+ t_rdbuffer *writer = rdenvironment_getbuffer(re, rb->rb_name);
+ if (writer)
+ {
+ /* register to the writer */
+ if (writer->rb_readers)
+ writer->rb_readers->rb_prev = rb;
+ rb->rb_next = writer->rb_readers;
+ writer->rb_readers = rb;
+ }
+ else
+ {
+ /* store in the orphanage */
+ if (re->re_readers)
+ re->re_readers->rb_prev = rb;
+ rb->rb_next = re->re_readers;
+ re->re_readers = rb;
+ }
+ }
+ return (rb);
+}
+
+int riddle_erbfill(int nbands, int *buf, int nblock, int sr)
+{
+ static double coef = 9.293902; /* 21.4 / log(10) */
+ double df = (double)sr / (double)nblock;
+ double fmax = .5 * (nblock + 1) * df;
+ double fc = df;
+ int i, erbcount = 0, bincount = 0, lastbin = 0;
+ int bufsize = nbands + 1;
+ while (erbcount < nbands && fc < fmax)
+ {
+ /* the formula is taken from ~jos/bbt
+ (the results slightly differ from moore-glasberg's demos) */
+ double erbnumber = coef * log(.00437 * fc + 1.);
+ bincount++;
+ if ((int)erbnumber > erbcount) /* LATER rethink */
+ {
+ buf[erbcount++] = bincount - lastbin;
+ lastbin = bincount;
+ }
+ fc += df;
+ }
+ for (i = erbcount; i < bufsize; i++)
+ buf[i] = 0;
+ return (erbcount);
+}