diff options
-rw-r--r-- | riddle/rdremote.c | 814 | ||||
-rw-r--r-- | riddle/riddle.c | 1317 | ||||
-rw-r--r-- | riddle/riddle.h | 131 | ||||
-rw-r--r-- | riddle/riddleguts.h | 35 |
4 files changed, 1449 insertions, 848 deletions
diff --git a/riddle/rdremote.c b/riddle/rdremote.c new file mode 100644 index 0000000..689e079 --- /dev/null +++ b/riddle/rdremote.c @@ -0,0 +1,814 @@ +/* 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" +#include "riddleguts.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, vinlet_class */ +#include "g_canvas.h" + +EXTERN_STRUCT _rdpool; +#define t_rdpool struct _rdpool + +typedef struct _rdenvironment +{ + t_pd en_pd; + t_rdpool *en_graphpools; + t_rdremote *en_writers; + t_rdremote *en_readers; /* list of orphaned readers */ + t_clock *en_updatedspclock; +} t_rdenvironment; + +static t_class *rdenvironment_class = 0; + +#define RDREMOTE_INISIZE 1024 + +struct _rdremote +{ + int re_id; /* positive for readers, otherwise zero */ + t_symbol *re_name; + t_riddle *re_owner; + int re_phase; + t_rdremote *re_portlink; /* slist of object i/o */ + t_rdremote *re_prev; /* double-linked list of readers or writers */ + t_rdremote *re_next; + + /* common part, copied from writer to all its readers + immediately after any change */ + int re_nframes; + int re_framesize; + int re_npoints; + int re_maxphase; + t_float *re_data; + + /* writer-specific part */ + t_rdremote *re_readers; + int re_datasize; + t_float *re_inidata; +}; + +#define RDPICKER_INISIZE 64 + +struct _rdpool +{ + t_canvas *po_graph; + int po_refcount; + t_rdpicker *po_pickstore; + t_rdpool *po_prev; + t_rdpool *po_next; +}; + +struct _rdpicker +{ + t_symbol *pi_key; + int pi_refcount; + t_rdpool *pi_graphpool; + int pi_size; + int pi_maxsize; + t_float *pi_data; + t_float pi_inidata[RDPICKER_INISIZE]; + t_rdpicker *pi_prev; + t_rdpicker *pi_next; +}; + +typedef struct _rdfeeder +{ + t_rdpicker *fe_picker; + struct _rdfeeder *fe_next; +} t_rdfeeder; + +struct _rdfeedchain +{ + t_rdfeeder *ch_head; + int ch_outno; +}; + +static t_symbol *rdps__idle = 0; + +static void rdenvironment_updatedsptick(t_rdenvironment *en) +{ + canvas_update_dsp(); +} + +static void rdenvironment_anything(t_rdenvironment *en, + t_symbol *s, int ac, t_atom *av) +{ + /* FIXME */ +} + +static t_rdenvironment *rdenvironment_provide(void) +{ + t_rdenvironment *en; + t_symbol *ps__riddle = gensym("_riddle"); /* class name */ + t_symbol *ps_hashriddle = gensym("#riddle"); /* instance binding */ + 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); + } + } + rdps__idle = gensym("_idle"); + rdenvironment_class = class_new(ps__riddle, 0, 0, + sizeof(t_rdenvironment), + CLASS_PD | CLASS_NOINLET, 0); + class_addanything(rdenvironment_class, rdenvironment_anything); + en = (t_rdenvironment *)pd_new(rdenvironment_class); /* never freed */ + en->en_graphpools = 0; + en->en_writers = 0; + en->en_readers = 0; + en->en_updatedspclock = + clock_new(en, (t_method)rdenvironment_updatedsptick); + pd_bind((t_pd *)en, ps_hashriddle); /* never unbound */ + return (en); +} + +t_pd *riddle_getenvironment(void) +{ + return ((t_pd *)rdenvironment_provide()); +} + + +/* subgraph-localized remote connections: feeders and pickers + LATER should become a kind of rdremote writers and readers */ + +t_rdpicker *rdpicker_attach(t_riddle *rd, t_symbol *key) +{ + t_rdenvironment *en = rdenvironment_provide(); + /* FIXME protect against calling outside of the constructor */ + t_canvas *graph = canvas_getcurrent(); + t_rdpool *po; + t_rdpicker *pi; + for (po = en->en_graphpools; po; po = po->po_next) + { + if (po->po_graph == graph) + { + for (pi = po->po_pickstore; pi; pi = pi->pi_next) + { + if (pi->pi_key == key) + { + pi->pi_refcount++; + return (pi); + } + } + } + } + + if (po) + po->po_refcount++; + else + { + po = getbytes(sizeof(*po)); + po->po_graph = graph; + po->po_refcount = 1; + po->po_pickstore = 0; + po->po_prev = 0; + if (en->en_graphpools) + en->en_graphpools->po_prev = po; + po->po_next = en->en_graphpools; + en->en_graphpools = po; + } + + pi = getbytes(sizeof(*pi)); + pi->pi_key = key; + pi->pi_refcount = 1; + pi->pi_graphpool = po; + pi->pi_size = 0; + pi->pi_maxsize = RDPICKER_INISIZE; + pi->pi_data = pi->pi_inidata; + pi->pi_prev = 0; + if (po->po_pickstore) + po->po_pickstore->pi_prev = pi; + pi->pi_next = po->po_pickstore; + po->po_pickstore = pi; + return (pi); +} + +void rdpicker_detach(t_rdpicker *pi, t_riddle *rd) +{ + if (pi->pi_refcount > 1) + pi->pi_refcount--; + else + { + if (pi->pi_data && pi->pi_data != pi->pi_inidata) + freebytes(pi->pi_data, pi->pi_maxsize * sizeof(*pi->pi_data)); + if (pi->pi_prev) + pi->pi_prev->pi_next = pi->pi_next; + else if (pi->pi_graphpool) + pi->pi_graphpool->po_pickstore = pi->pi_next; + else + loudbug_bug("rdpicker_detach 1"); + if (pi->pi_next) + pi->pi_next->pi_prev = pi->pi_prev; + if (pi->pi_graphpool) + { + t_rdpool *po = pi->pi_graphpool; + t_rdenvironment *en = rdenvironment_provide(); + if (po->po_refcount > 1) + po->po_refcount--; + else + { + if (po->po_pickstore) + loudbug_bug("rdpicker_detach 2"); + if (po->po_prev) + po->po_prev->po_next = po->po_next; + else + en->en_graphpools = po->po_next; + if (po->po_next) + po->po_next->po_prev = po->po_prev; + freebytes(po, sizeof(*po)); + } + } + freebytes(pi, sizeof(*pi)); + } +} + +t_float *rdpicker_pick(t_rdpicker *pi, int *sizep) +{ + *sizep = pi->pi_size; + return (pi->pi_data); +} + +t_float rdpicker_pick1(t_rdpicker *pi) +{ + return (*pi->pi_data); +} + +static t_rdpicker *rdpool_linkpicker(t_rdpool *po, t_symbol *key, int size) +{ + t_rdpicker *pi; + for (pi = po->po_pickstore; pi; pi = pi->pi_next) + { + if (pi->pi_key == key) + { + if (size > pi->pi_maxsize) + pi->pi_data = grow_nodata(&size, &pi->pi_maxsize, pi->pi_data, + RDPICKER_INISIZE, pi->pi_inidata, + sizeof(*pi->pi_data)); + pi->pi_size = size; + return (pi); + } + } + return (0); +} + +/* LATER think about rdpool_unlinkpicker() */ + +static void rdfeedchain_proliferate(t_rdfeedchain *ch, t_rdpool *pohead, + t_gobj *g, t_symbol *key, int size) +{ + int result = 0; + for (; g; g = g->g_next) + { + if (pd_class((t_pd *)g) == canvas_class) + { + t_canvas *graph = (t_canvas *)g; + t_rdpool *po; + t_rdpicker *pi; + for (po = pohead; po; po = po->po_next) + if (po->po_graph == graph) + break; + if (po && (pi = rdpool_linkpicker(po, key, size))) + { + t_rdfeeder *fe = getbytes(sizeof(*fe)); /* FIXME reuse */ + fe->fe_picker = pi; + fe->fe_next = ch->ch_head; + ch->ch_head = fe; + } + rdfeedchain_proliferate(ch, pohead, graph->gl_list, key, size); + } + } +} + +void rdfeedchain_free(t_rdfeedchain *ch) +{ + t_rdfeeder *fe, *fenext; + for (fe = ch->ch_head; fe; fe = fenext) + { + fenext = fe->fe_next; + freebytes(fe, sizeof(*fe)); + } +} + +t_rdfeedchain *rdfeedchain_new(int outno) +{ + t_rdfeedchain *ch = getbytes(sizeof(*ch)); + ch->ch_head = 0; + ch->ch_outno = outno; +} + +t_rdfeedchain *riddle_usefeedchain(t_riddle *rd, + int sigoutno, t_symbol *key, int size) +{ + t_rdfeedchain *ch; + if (ch = riddle_getfeedchain(rd, sigoutno)) + { + t_canvas *graph; + t_rdfeeder *fe, *fenext; + /* LATER reuse */ + for (fe = ch->ch_head; fe; fe = fenext) + { + fenext = fe->fe_next; + freebytes(fe, sizeof(*fe)); + } + for (graph = riddle_firstgraph(rd, ch->ch_outno); + graph; graph = riddle_nextgraph(rd)) + { + t_rdenvironment *en = rdenvironment_provide(); + t_rdpool *po; + t_rdpicker *pi; + for (po = en->en_graphpools; po; po = po->po_next) + if (po->po_graph == graph) + break; + if (po && (pi = rdpool_linkpicker(po, key, size))) + { + t_rdfeeder *fe = getbytes(sizeof(*fe)); + fe->fe_picker = pi; + fe->fe_next = 0; + ch->ch_head = fe; + } + else ch->ch_head = 0; + rdfeedchain_proliferate(ch, en->en_graphpools, + (t_gobj *)graph, key, size); + } + } + return (ch); +} + +t_rdfeedchain *riddle_useidlechain(t_riddle *rd, int sigoutno) +{ + return (riddle_usefeedchain(rd, sigoutno, rdps__idle, 1)); +} + +void rdfeedchain_feed(t_rdfeedchain *ch, int size, t_float *data) +{ + t_rdfeeder *fe; + for (fe = ch->ch_head; fe; fe = fe->fe_next) + { + t_rdpicker *pi = fe->fe_picker; + if (size > pi->pi_size) + size = pi->pi_size; + memcpy(pi->pi_data, data, size * sizeof(*pi->pi_data)); + } +} + +void rdfeedchain_feed1(t_rdfeedchain *ch, t_float v) +{ + t_rdfeeder *fe; + for (fe = ch->ch_head; fe; fe = fe->fe_next) + *fe->fe_picker->pi_data = v; +} + +int riddle_isidle(t_riddle *rd) +{ + return (rd->rd_idlepicker && *rd->rd_idlepicker->pi_data > .5); +} + +void riddle_updatedsp(void) +{ + t_rdenvironment *en = rdenvironment_provide(); + loud_warning((t_pd *)en, 0, "...trying to reconstruct the dsp chain"); + clock_delay(en->en_updatedspclock, 0); +} + + +/* rdremote: global named writers, global named readers, + and private anonymous bidirectional buffers */ + + +static t_rdremote *rdenvironment_getbuffer(t_rdenvironment *en, t_symbol *name) +{ + t_rdremote *re = en->en_writers; + while (re) + { + if (re->re_name == name) + return (re); + re = re->re_next; + } + return (0); +} + +t_rdremote *rdremote_getwriter(t_rdremote *re) +{ + t_rdenvironment *en = rdenvironment_provide(); + return (rdenvironment_getbuffer(en, re->re_name)); +} + +t_rdremote *rdremote_nextreader(t_rdremote *re) +{ + while (re && !re->re_id) + re = re->re_portlink; + return (re); +} + +int rdremote_getsourceblock(t_rdremote *re) +{ + if (re->re_owner && re->re_id > 0) + return (riddle_getsourceblock(re->re_owner, -re->re_id)); + else + { + loudbug_bug("rdremote_getsourceblock"); + return (0); + } +} + +t_symbol *rdremote_getsourcelayout(t_rdremote *re, int *maxblockp) +{ + if (re->re_owner && re->re_id > 0) + return (riddle_getsourcelayout(re->re_owner, -re->re_id, maxblockp)); + else + { + loudbug_bug("rdremote_getsourcelayout"); + return (0); + } +} + +int rdremote_getsourceflags(t_rdremote *re) +{ + if (re->re_owner && re->re_id > 0) + return (riddle_getsourceflags(re->re_owner, -re->re_id)); + else + { + loudbug_bug("rdremote_getsourceflags"); + return (0); + } +} + +/* this call reallocates memory if necessary, so the caller should check + for failures: the number of frames and/ot framesize may decrease + (the actually available framesize is returned by the call) */ +/* LATER optionally use old contents by zero-padding, interpolating, etc. */ +static int rdremote_setframesize(t_rdremote *re, int framesize) +{ + t_rdremote *reader; + if (re->re_inidata == 0) + { + /* not a writer */ + loudbug_bug("rdremote_setframesize 1"); + return (0); + } + if (framesize <= 0) + { + if (re->re_owner) + framesize = re->re_owner->rd_graphblock; + else + { + loudbug_bug("rdremote_setframesize 2"); + return (0); + } + } + re->re_npoints = framesize * re->re_nframes; + if (re->re_npoints > re->re_datasize) + { + int reqsize = re->re_npoints; + /* LATER use grow_withdata() */ + re->re_data = grow_nodata(&re->re_npoints, &re->re_datasize, + re->re_data, RDREMOTE_INISIZE, + re->re_inidata, sizeof(*re->re_data)); + if (re->re_npoints != reqsize) + { + re->re_nframes = re->re_npoints / framesize; + if (re->re_nframes < 1) + { + loudbug_bug("rdremote_setframesize 3"); + re->re_nframes = 1; + framesize = re->re_npoints; + } + } + } + /* LATER convert old buffer's contents of re->re_framesize * re->re_nframes + points into the new buffer of framesize * re->re_nframes points */ + memset(re->re_data, 0, re->re_npoints * sizeof(*re->re_data)); + re->re_phase = 0; /* LATER adjust */ + re->re_maxphase = re->re_npoints - framesize; + re->re_framesize = framesize; + + for (reader = re->re_readers; reader; reader = reader->re_next) + { + reader->re_nframes = re->re_nframes; + reader->re_framesize = re->re_framesize; + reader->re_npoints = re->re_npoints; + reader->re_maxphase = re->re_maxphase; + reader->re_data = re->re_data; + reader->re_phase = 0; /* LATER adjust */ + } + return (framesize); +} + +void rdremote_setoutblock(t_rdremote *re, int nblock) +{ + if (nblock = rdremote_setframesize(re, nblock)) + { + t_rdremote *reader; + for (reader = re->re_readers; reader; reader = reader->re_next) + if (reader->re_owner && reader->re_id > 0) + riddle_setsourceblock(reader->re_owner, -reader->re_id, + re->re_framesize); + } +} + +void rdremote_setoutlayout(t_rdremote *re, t_symbol *pattern, int maxblock) +{ + if (maxblock = rdremote_setframesize(re, maxblock)) + { + t_rdremote *reader; + for (reader = re->re_readers; reader; reader = reader->re_next) + if (reader->re_owner && reader->re_id > 0) + riddle_setsourcelayout(reader->re_owner, -reader->re_id, + pattern, re->re_framesize); + } +} + +void rdremote_setoutflags(t_rdremote *re, int flags) +{ + t_rdremote *reader; + for (reader = re->re_readers; reader; reader = reader->re_next) + if (reader->re_owner && reader->re_id > 0) + riddle_setsourceflags(reader->re_owner, -reader->re_id, flags); +} + +void rdremote_reset(t_rdremote *re) +{ + if (re->re_inidata) + { + memset(re->re_data, 0, re->re_npoints * sizeof(*re->re_data)); + re->re_phase = 0; + } + else + { + t_rdremote *writer = rdremote_getwriter(re); + if (writer) + re->re_phase = writer->re_phase; + else + re->re_phase = 0; + } +} + +t_float *rdremote_gethead(t_rdremote *re) +{ + return (re->re_data + re->re_phase); +} + +void rdremote_stephead(t_rdremote *re) +{ + re->re_phase += re->re_framesize; + if (re->re_phase > re->re_maxphase) + re->re_phase = 0; +} + +void rdremote_movehead(t_rdremote *re, int nframes) +{ + if (re->re_nframes <= 0) + { + loudbug_bug("rdremote_movehead"); + } + else if (nframes > 0) + { + if (nframes >= re->re_nframes) + nframes = re->re_nframes - 1; + re->re_phase += nframes * re->re_framesize; + while (re->re_phase > re->re_maxphase) + re->re_phase -= re->re_npoints; + } + else if (nframes < 0) + { + nframes = -nframes; + if (nframes >= re->re_nframes) + nframes = re->re_nframes - 1; + re->re_phase -= nframes * re->re_framesize; + while (re->re_phase < 0) + re->re_phase += re->re_npoints; + } +} + +void rdremote_delayhead(t_rdremote *re, int nframes) +{ + if (re->re_inidata) + loudbug_bug("rdremote_delayhead"); /* not a reader */ + else + { + t_rdremote *writer = rdremote_getwriter(re); + if (writer) + { + re->re_phase = writer->re_phase; + rdremote_movehead(re, -nframes); + } + } +} + +static void rdremote_free(t_rdremote *re) +{ + if (re->re_inidata) + { + if (re->re_data != re->re_inidata) + freebytes(re->re_data, re->re_datasize * sizeof(*re->re_data)); + if (re->re_name) + { + t_rdremote *reader; + t_rdenvironment *en = rdenvironment_provide(); + /* remove from the environment */ + if (re->re_next) + re->re_next->re_prev = re->re_prev; + if (re->re_prev) + re->re_prev->re_next = re->re_next; + else + en->en_writers = re->re_next; + /* move all readers to the orphanage */ + if (reader = re->re_readers) + { + while (reader->re_next) + reader = reader->re_next; + if (en->en_readers) + en->en_readers->re_prev = reader; + reader->re_next = en->en_readers; + en->en_readers = re->re_readers; + } + } + } + else + { + if (re->re_name) + { + /* remove from writer's list or orphanage */ + if (re->re_next) + re->re_next->re_prev = re->re_prev; + if (re->re_prev) + re->re_prev->re_next = re->re_next; + else + { + t_rdenvironment *en = rdenvironment_provide(); + t_rdremote *writer = rdenvironment_getbuffer(en, re->re_name); + if (writer) + writer->re_readers = re->re_next; + else + en->en_readers = re->re_next; + } + } + } + freebytes(re, sizeof(*re)); +} + +void rdremote_freeports(t_rdremote *re) +{ + while (re) + { + t_rdremote *nxt = re->re_portlink; + rdremote_free(re); + re = nxt; + } +} + +/* FIXME do not rely on pd_new() callocing owner->rd_nremoteslots + and owner->rd_remoteports to zero... one option is to traverse + environment in riddle_new() after newfn call */ +static t_rdremote *rdremote_newany(t_riddle *owner, t_symbol *name, int nframes) +{ + t_rdremote *re = (t_rdremote *)getbytes(sizeof(*re)); + if (name && !nframes) + { + owner->rd_nremoteslots++; + re->re_id = owner->rd_nremoteslots; /* starting from 1 */ + } + else re->re_id = 0; + re->re_name = 0; + re->re_owner = owner; + re->re_phase = 0; + re->re_nframes = nframes; + re->re_framesize = 0; + re->re_npoints = 0; + re->re_maxphase = 0; + if (nframes) + { + re->re_datasize = RDREMOTE_INISIZE; + re->re_inidata = getbytes(re->re_datasize * sizeof(*re->re_inidata)); + re->re_data = re->re_inidata; + } + else + { + re->re_datasize = 0; + re->re_inidata = 0; + re->re_data = 0; + } + re->re_readers = 0; + re->re_prev = 0; + re->re_next = 0; + if (owner->rd_remoteports) + { + t_rdremote *prv = owner->rd_remoteports; + while (prv->re_portlink) + prv = prv->re_portlink; + prv->re_portlink = re; + } + else owner->rd_remoteports = re; + re->re_portlink = 0; + return (re); +} + +t_rdremote *rdremote_newwriter(t_riddle *owner, t_symbol *name, int nframes) +{ + if (name && *name->s_name) + { + t_rdremote *re = + rdremote_newany(owner, name, (nframes > 1 ? nframes : 1)); + t_rdenvironment *en = rdenvironment_provide(); + if (rdenvironment_getbuffer(en, re->re_name)) + { + /* LATER accumulating writers case */ + loud_error((t_pd *)owner, "duplicate buffer name \"%s\"", + re->re_name->s_name); + /* FIXME put on the namesakes queue */ + } + else + { + t_rdremote *reader; + /* store in the environment */ + if (en->en_writers) + en->en_writers->re_prev = re; + re->re_next = en->en_writers; + en->en_writers = re; + /* recover readers from the orphanage */ + for (reader = en->en_readers; reader; reader = reader->re_next) + { + if (reader->re_name == re->re_name) + { + if (reader->re_next) + reader->re_next->re_prev = reader->re_prev; + if (reader->re_prev) + reader->re_prev->re_next = reader->re_next; + else + en->en_readers = reader->re_next; + if (re->re_readers) + re->re_readers->re_prev = reader; + reader->re_next = re->re_readers; + re->re_readers = reader; + } + } + } + return (re); + } + else + { + loudbug_bug("rdremote_newwriter"); + return (0); + } +} + +t_rdremote *rdremote_newreader(t_riddle *owner, t_symbol *name) +{ + if (name && *name->s_name) + { + t_rdremote *re = rdremote_newany(owner, name, 0); + t_rdenvironment *en = rdenvironment_provide(); + t_rdremote *writer = rdenvironment_getbuffer(en, name); + if (writer) + { + /* register to the writer */ + if (writer->re_readers) + writer->re_readers->re_prev = re; + re->re_next = writer->re_readers; + writer->re_readers = re; + } + else + { + /* store in the orphanage */ + if (en->en_readers) + en->en_readers->re_prev = re; + re->re_next = en->en_readers; + en->en_readers = re; + } + return (re); + } + else + { + loudbug_bug("rdremote_newreader"); + return (0); + } +} + +t_rdremote *rdremote_newbuffer(t_riddle *owner, int nframes) +{ + return (rdremote_newany(owner, 0, (nframes > 1 ? nframes : 1))); +} diff --git a/riddle/riddle.c b/riddle/riddle.c index 26e17e7..1348413 100644 --- a/riddle/riddle.c +++ b/riddle/riddle.c @@ -11,97 +11,70 @@ #include "common/grow.h" #include "sickle/sic.h" #include "riddle.h" +#include "riddleguts.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 */ +/* struct _glist, canvas_class, vinlet_class */ #include "g_canvas.h" -#define RIDDLE_DEBUG +/* it is horrible, but we need x_canvas and x_parentoutlet and o_next for + pushing through an outlet~, which is here for the completeness of the tests; + LATER remove from library version, unless there is an API way to do it... */ -typedef struct _rdenvironment +/* from g_io.c */ +typedef struct _rdvoutlet { - 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_object x_obj; + t_canvas *x_canvas; + t_outlet *x_parentoutlet; + /* ... */ +} t_rdvoutlet; + +/* from m_obj.c */ +typedef struct _rdoutlet { - 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; -}; + t_object *o_owner; + struct _rdoutlet *o_next; + /* ... */ +} t_rdoutlet; -struct _rdsink +#define RIDDLE_DEBUG + +struct _rdprivate { - 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 */ + t_outconnect *pr_oc; }; -#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 +struct _rdsource { - t_canvas *rp_graph; - int rp_refcount; - t_rdlink *rp_links; - t_rdpool *rp_prev; - t_rdpool *rp_next; + t_riddle *so_riddle; + t_rdremote *so_remote; + int so_sourcecount; + t_symbol *so_pattern; + t_symbol *so_newpattern; + int so_block; /* if non-zero pattern: largest expected block */ + int so_newblock; + int so_flags; }; -#define RDBUFFER_INISIZE 1024 - -struct _rdbuffer +struct _rdsink { - 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; + t_riddle *si_riddle; + int si_outno; + t_symbol *si_pattern; + int si_block; /* if non-zero pattern: largest expected block */ + int si_flags; + t_atom si_outbuf[4]; /* siginno, pattern, block, flags */ + t_rdfeedchain *si_feedchain; + int si_isready; }; /* 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, ...) @@ -123,221 +96,6 @@ void riddlebug_post(t_riddle *rd, char *pfx, char *fmt, ...) #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); @@ -357,58 +115,49 @@ int riddle_getsourceblock(t_riddle *rd, int siginno) } else { - t_rdsource *slot = (siginno >= 0 ? - rd->rd_inslots + siginno : - rd->rd_remoteslots - ++siginno); - return (slot->ri_pattern ? 0 : slot->ri_block); + t_rdsource *so = (siginno >= 0 ? + rd->rd_inslots + siginno : + rd->rd_remoteslots - ++siginno); + return (so->so_pattern ? 0 : so->so_block); /* FIXME disable? */ } } -t_symbol *riddle_getsourcepattern(t_riddle *rd, int siginno, int *maxblockp) +t_symbol *riddle_getsourcelayout(t_riddle *rd, int siginno, int *maxblockp) { if (siginno >= rd->rd_nsiginlets || -siginno > rd->rd_nremoteslots) { - loudbug_bug("riddle_getsourcepattern"); + loudbug_bug("riddle_getsourcelayout"); return (0); } else { - t_rdsource *slot = (siginno >= 0 ? - rd->rd_inslots + siginno : - rd->rd_remoteslots - ++siginno); + t_rdsource *so = (siginno >= 0 ? + rd->rd_inslots + siginno : + rd->rd_remoteslots - ++siginno); if (maxblockp) - *maxblockp = slot->ri_block; - return (slot->ri_pattern); + *maxblockp = so->so_block; + return (so->so_pattern); } } -int riddle_getoutblock(t_riddle *rd, int sigoutno) +int riddle_getsourceflags(t_riddle *rd, int siginno) { - 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) + if (siginno >= rd->rd_nsiginlets || -siginno > rd->rd_nremoteslots) { - loudbug_bug("riddle_getoutpattern"); + loudbug_bug("riddle_getsourceflags"); return (0); } else { - if (maxblockp) - *maxblockp = rd->rd_outslots[sigoutno].ro_block; - return (rd->rd_outslots[sigoutno].ro_pattern); + t_rdsource *so = (siginno >= 0 ? + rd->rd_inslots + siginno : + rd->rd_remoteslots - ++siginno); + return (so->so_flags); } } -static void riddle_setsourceblock(t_riddle *rd, int siginno, int newblock) +/* LATER rethink the remote case */ +void riddle_setsourceblock(t_riddle *rd, int siginno, int newblock) { int slotno = (siginno < 0 ? rd->rd_nsiginlets - siginno - 1 : siginno); #ifdef RIDDLE_DEBUG @@ -422,128 +171,186 @@ static void riddle_setsourceblock(t_riddle *rd, int siginno, int newblock) "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) + t_rdsource *so = rd->rd_inslots + slotno; + /* LATER if (so->so_newpattern) complain */ + if (newblock == so->so_newblock) + so->so_sourcecount++; + else if (so->so_sourcecount > 0) loud_error((t_pd *)rd, "source block mismatch on inlet %d: %d != %d", - siginno, newblock, slot->ri_newblock); + siginno, newblock, so->so_newblock); else { - slot->ri_newblock = newblock; - slot->ri_sourcecount = 1; - if (siginno < 0) - rd->rd_remotesource = 1; + so->so_newblock = newblock; + so->so_sourcecount = 1; } } } -/* LATER pattern validation and normalization (e.g. xXXX -> aAAA */ -static void riddle_setsourcepattern(t_riddle *rd, int siginno, - t_symbol *newpattern, int maxblock) +#define RDLAYOUT_MAXNVECTORS 32 + +/* apart from normalization, this is used only as a sanity check; patterns + are never interpreted, they just have to match (after normalization) */ +static t_symbol *riddle_validatepattern(t_symbol *pattern) +{ + char *p = pattern->s_name, lc, uc; + switch (*p) + { + case 'a': + case 'A': + lc = 'b'; uc = 'A'; break; + case 'b': + lc = 'c'; uc = 'B'; break; + default: + lc = 0; + } + if (lc) + { + /* we require at least one vector for each size element */ + int vused[RDLAYOUT_MAXNVECTORS], i; + for (i = 0; i < RDLAYOUT_MAXNVECTORS; i++) + vused[i] = 0; + if (*p == 'A') + vused[0] = 1; + for (p++; *p; p++) + { + if (*p == lc) + { + if (lc - 'a' < RDLAYOUT_MAXNVECTORS) + lc++, uc++; + else + break; + } + else if (*p >= 'A' && *p <= uc) + vused[*p - 'A'] = 1; + else + break; + } + if (!*p) + { + for (i = 0; i < lc - 'a'; i++) + if (!vused[i]) + break; + if (i == lc - 'a') + { + if (*pattern->s_name == 'a') /* normalization */ + pattern = gensym(pattern->s_name + 1); + return (pattern); + } + } + } + loudbug_bug("riddle_validatepattern"); + return (0); +} + +void riddle_setsourcelayout(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", + riddlebug_post(rd, "setsourcelayout", "%d (%d) %s %d", siginno, slotno, newpattern->s_name, maxblock); #endif if (siginno >= rd->rd_nsiginlets || -siginno > rd->rd_nremoteslots) - loudbug_bug("riddle_setsourcepattern"); + loudbug_bug("riddle_setsourcelayout"); else { - t_rdsource *slot = rd->rd_inslots + slotno; - if (newpattern == slot->ri_newpattern) - slot->ri_sourcecount++; - else if (slot->ri_sourcecount > 0) + t_rdsource *so = rd->rd_inslots + slotno; + if (newpattern == so->so_newpattern) + so->so_sourcecount++; + else if (so->so_sourcecount > 0) { - if (slot->ri_newpattern) + if (so->so_newpattern) loud_error((t_pd *)rd, - "source pattern mismatch on inlet %d: %s != %s", + "source layout mismatch on inlet %d: %s != %s", siginno, newpattern->s_name, - slot->ri_newpattern->s_name); + so->so_newpattern->s_name); else loud_error((t_pd *)rd, - "source pattern/block mismatch on inlet %d"); + "source layout/block mismatch on inlet %d"); } - else + else if (newpattern = riddle_validatepattern(newpattern)) { - slot->ri_newpattern = newpattern; + so->so_newpattern = newpattern; if (maxblock) { - if (maxblock > slot->ri_newblock) - slot->ri_newblock = maxblock; + if (maxblock > so->so_newblock) + so->so_newblock = maxblock; } - else slot->ri_newblock = rd->rd_graphblock; - slot->ri_sourcecount = 1; - if (siginno < 0) - rd->rd_remotesource = 1; + else so->so_newblock = rd->rd_graphblock; + so->so_sourcecount = 1; } } } +void riddle_setsourceflags(t_riddle *rd, int siginno, int flags) +{ + int slotno = (siginno < 0 ? rd->rd_nsiginlets - siginno - 1 : siginno); +#ifdef RIDDLE_DEBUG + riddlebug_post(rd, "setsourceflags", "%d (%d) %d", + siginno, slotno, flags); +#endif + if (siginno >= rd->rd_nsiginlets || -siginno > rd->rd_nremoteslots) + loudbug_bug("riddle_setsourceflags"); + else + { + t_rdsource *so = rd->rd_inslots + slotno; + so->so_flags = flags; + } +} + 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) + if (sigoutno < 0 || 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; + t_rdsink *si = rd->rd_outslots + sigoutno; + si->si_pattern = 0; + si->si_block = block; + si->si_outbuf[1].a_w.w_symbol = rdps__; + si->si_outbuf[2].a_w.w_float = (t_float)block; + si->si_isready = 1; } } -void riddle_setoutpattern(t_riddle *rd, int sigoutno, - t_symbol *pattern, int maxblock) +void riddle_setoutlayout(t_riddle *rd, int sigoutno, + t_symbol *pattern, int maxblock) { - t_rdsink *slot; #ifdef RIDDLE_DEBUG - riddlebug_post(rd, "setoutpattern", "%d %s %d", + riddlebug_post(rd, "setoutlayout", "%d %s %d", sigoutno, pattern->s_name, maxblock); #endif - if (sigoutno >= rd->rd_nsigoutlets) - loudbug_bug("riddle_setoutpattern"); - else if (sigoutno < 0) + if (sigoutno < 0 || sigoutno >= rd->rd_nsigoutlets) + loudbug_bug("riddle_setoutlayout"); + else if (pattern = riddle_validatepattern(pattern)) { - 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; - } + t_rdsink *si = rd->rd_outslots + sigoutno; + if (maxblock <= 0) + maxblock = rd->rd_graphblock; + si->si_pattern = pattern; + si->si_block = maxblock; + si->si_outbuf[1].a_w.w_symbol = pattern; + si->si_outbuf[2].a_w.w_float = (t_float)maxblock; + si->si_isready = 1; } +} + +void riddle_setoutflags(t_riddle *rd, int sigoutno, int flags) +{ +#ifdef RIDDLE_DEBUG + riddlebug_post(rd, "setoutflags", "%d %d", sigoutno, flags); +#endif + if (sigoutno < 0 || sigoutno >= rd->rd_nsigoutlets) + loudbug_bug("riddle_setoutflags"); 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; + t_rdsink *si = rd->rd_outslots + sigoutno; + si->si_flags = flags; + si->si_outbuf[3].a_w.w_float = (t_float)flags; } } @@ -554,7 +361,7 @@ int riddle_checksourceblock(t_riddle *rd, int siginno, int reqblock) return (1); else { - if (!rd->rd_wasdisabled && rd->rd_inslots[siginno].ri_sourcecount) + if (!rd->rd_wasdisabled && rd->rd_inslots[siginno].so_sourcecount) loud_error((t_pd *)rd, "invalid source block on inlet %d: %d (%d expected)", siginno, block, reqblock); @@ -563,24 +370,24 @@ int riddle_checksourceblock(t_riddle *rd, int siginno, int reqblock) } } -/* LATER pattern normalization (e.g. xXXX -> aAAA */ -int riddle_checksourcepattern(t_riddle *rd, int siginno, - t_symbol *reqpattern, int *maxblockp) +int riddle_checksourcelayout(t_riddle *rd, int siginno, + t_symbol *reqpattern, int *maxblockp) { - t_symbol *pattern = riddle_getsourcepattern(rd, siginno, maxblockp); - if (pattern == reqpattern) + t_symbol *pattern = riddle_getsourcelayout(rd, siginno, maxblockp); + if (reqpattern == pattern || + riddle_validatepattern(reqpattern) == pattern) return (1); else { - if (!rd->rd_wasdisabled && rd->rd_inslots[siginno].ri_sourcecount) + if (!rd->rd_wasdisabled && rd->rd_inslots[siginno].so_sourcecount) { if (pattern) loud_error((t_pd *)rd, - "wrong source pattern on inlet %d: %s (%s expected)", + "wrong source layout 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", + "invalid source on inlet %d: layout %s expected", siginno, reqpattern->s_name); } rd->rd_disabled = 1; @@ -594,10 +401,10 @@ int riddle_checkanysource(t_riddle *rd, int siginno) loudbug_bug("riddle_checkanysource"); else { - t_rdsource *slot = (siginno >= 0 ? - rd->rd_inslots + siginno : - rd->rd_remoteslots - ++siginno); - if (slot->ri_sourcecount > 0) + t_rdsource *so = (siginno >= 0 ? + rd->rd_inslots + siginno : + rd->rd_remoteslots - ++siginno); + if (so->so_sourcecount > 0) return (1); } rd->rd_disabled = 1; @@ -611,9 +418,35 @@ int riddle_isdisabled(t_riddle *rd) void riddle_disable(t_riddle *rd) { + /* FIXME allow calling from the dsp routine (mute then) */ rd->rd_disabled = 1; } +t_rdfeedchain *riddle_getfeedchain(t_riddle *rd, int sigoutno) +{ + if (sigoutno < 0 || sigoutno >= rd->rd_nsigoutlets) + { + loudbug_bug("riddle_getfeedchain 1"); + return (0); + } + else + { + t_rdsink *si = rd->rd_outslots + sigoutno; + if (si->si_outno >= 0) + { + /* LATER update ch_outno */ + return (si->si_feedchain); + } + else + { + loudbug_bug("riddle_getfeedchain 2"); + return (0); + } + } +} + +/* ensures that sinks match signal outlets -- this is needed in the constructor, + but is called before each push, perhaps too defensively... LATER rethink */ static int riddle_validatesinks(t_riddle *rd) { t_object *x = (t_object *)rd; @@ -624,10 +457,10 @@ static int riddle_validatesinks(t_riddle *rd) { if (sigoutno < rd->rd_nsigoutlets) { - if (rd->rd_outslots[sigoutno].ro_outno != outno) + if (rd->rd_outslots[sigoutno].si_outno != outno) { - if (rd->rd_outslots[sigoutno].ro_outno < 0) - rd->rd_outslots[sigoutno].ro_outno = outno; + if (rd->rd_outslots[sigoutno].si_outno < 0) + rd->rd_outslots[sigoutno].si_outno = outno; else { loudbug_bug("riddle_validatesinks 1"); @@ -653,12 +486,46 @@ static int riddle_validatesinks(t_riddle *rd) return (1); } -static int rdsink_push(t_rdsink *slot) +t_canvas *riddle_nextgraph(t_riddle *rd) +{ + while (rd->rd_private->pr_oc) + { + t_object *dst; + t_inlet *ip; + int inno; + rd->rd_private->pr_oc = + obj_nexttraverseoutlet(rd->rd_private->pr_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); +} + +t_canvas *riddle_firstgraph(t_riddle *rd, int outno) +{ + t_outlet *op; + rd->rd_private->pr_oc = obj_starttraverseoutlet((t_object *)rd, &op, outno); + return (rd->rd_private->pr_oc ? riddle_nextgraph(rd) : 0); +} + +static int rdsink_push(t_rdsink *si, t_object *x, int outno) { int result = 1; - t_object *x = (t_object *)slot->ro_riddle; t_outlet *op; - t_outconnect *oc = obj_starttraverseoutlet(x, &op, slot->ro_outno); + t_outconnect *oc = obj_starttraverseoutlet(x, &op, outno); while (oc) { t_object *dst; @@ -672,18 +539,83 @@ static int rdsink_push(t_rdsink *slot) { /* 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); + si->si_outbuf->a_w.w_float = (t_float)siginno; + typedmess((t_pd *)dst, rdps__reblock, 4, si->si_outbuf); } - else if (slot->ro_isstrict) + else if (pd_class((t_pd *)dst) == canvas_class) + { + t_gobj *ob; + int i; + for (i = 0, ob = ((t_canvas *)dst)->gl_list; + ob; ob = ob->g_next) + { + if (pd_class((t_pd *)ob) == vinlet_class) + { + if (i == inno) + break; + else + i++; + } + } + if (ob) + { +#ifdef RIDDLE_DEBUG + riddlebug_post(si->si_riddle, "PUSH-SUBCANVAS", + "vinlet %d (\"%s\")", + inno, class_getname(*(t_pd *)ob)); +#endif + rdsink_push(si, (t_object *)ob, 0); + } + else loudbug_bug("rdsink_push 1"); + } + else if (pd_class((t_pd *)dst) == voutlet_class) + { + t_rdvoutlet *vout = (t_rdvoutlet *)dst; + if (vout->x_canvas) + { + int n; + t_outlet *o; + for (o = ((t_object *)vout->x_canvas)->ob_outlet, n = 0; + o; o = (t_outlet *)(((t_rdoutlet *)o)->o_next), n++) + if (o == vout->x_parentoutlet) + break; + if (o) + { +#ifdef RIDDLE_DEBUG + riddlebug_post(si->si_riddle, "PUSH-OUTLET", + "outno %d, graph %x", + n, (int)vout->x_canvas); +#endif + rdsink_push(si, (t_object *)vout->x_canvas, n); + } + else loudbug_bug("rdsink_push 2"); + } +#ifdef RIDDLE_DEBUG + else riddlebug_post(si->si_riddle, "PUSH-OUTLET", + "void canvas..."); +#endif + } + else { char *dstname = class_getname(*(t_pd *)dst); - if (strcmp(dstname, "print~")) +#ifdef RIDDLE_DEBUG + riddlebug_post(si->si_riddle, "PUSH-RIDDLESS", + "inlet %d (\"%s\")", inno, dstname); +#endif + if (si->si_flags & RIDDLE_STRICTNESSMASK) { - loud_error((t_pd *)x, "not a riddle: \"%s\"", dstname); + if (strcmp(dstname, "print~")) + { + loud_error((t_pd *)x, "not a riddle: \"%s\"", dstname); + result = 0; + } + } + else if (!strcmp(dstname, "send~") || + !strcmp(dstname, "throw~")) + { + loud_error((t_pd *)x, "bad destination: \"%s\"", dstname); result = 0; } } @@ -692,10 +624,10 @@ static int rdsink_push(t_rdsink *slot) return (result); } -void riddle_mute(t_riddle *rd, t_signal **sp) +static void riddle_mute(t_riddle *rd, t_signal **sp) { int i, j, nouts = obj_nsigoutlets((t_object *)rd); - t_rdsink *slot = rd->rd_outslots; + t_rdsink *si = rd->rd_outslots; #ifdef RIDDLE_DEBUG riddlebug_post(rd, "MUTE", 0); #endif @@ -710,14 +642,14 @@ void riddle_mute(t_riddle *rd, t_signal **sp) 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; + si->si_pattern = 0; + si->si_block = sp[j]->s_n; + si->si_outbuf[1].a_w.w_symbol = rdps__; + si->si_outbuf[2].a_w.w_float = (t_float)si->si_block; + si->si_isready = 1; dsp_add_zero(sp[j]->s_vec, sp[j]->s_n); i++; j++; - slot++; + si++; } } @@ -736,13 +668,14 @@ static void riddle_dsp(t_riddle *rd, t_signal **sp) 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); + inslotno, inslot->so_sourcecount, + inslot->so_block, inslot->so_newblock); #endif rd->rd_graphsr = (int)sp[0]->s_sr; rd->rd_graphblock = sp[0]->s_n; + /* this belongs to step 2., but should precede all "muteandreset" gotos */ if (rd->rd_wasdisabled = rd->rd_disabled) { rd->rd_disabled = 0; @@ -750,53 +683,71 @@ static void riddle_dsp(t_riddle *rd, t_signal **sp) doreblock = 1; else { - loudbug_bug("riddle_dsp 2"); + loudbug_bug("riddle_dsp 1"); goto muteandreset; } } - /* verify all source slots */ + /* step 1: verify all source slots */ + for (inslotno = 0, inslot = rd->rd_inslots; inslotno < ninslots; inslotno++, inslot++) { - if (inslot->ri_newblock > rd->rd_graphblock) + if (inslot->so_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; + if (inslotno < rd->rd_nsiginlets) + { + loud_error((t_pd *)rd, + "inslot %d: source block too large (%d > %d)", + inslotno, inslot->so_newblock, rd->rd_graphblock); + failed = 1; + } } - else if (inslot->ri_sourcecount <= 0) + else if (inslot->so_sourcecount <= 0) { - if (rd->rd_remotesource) /* this is an `issticky' flag -- it tells - if unconfirmed sourceblock should be - preserved or bashed to graphblock */ + if (inslotno < rd->rd_nsiginlets) { - inslot->ri_newpattern = inslot->ri_pattern; - if (inslot->ri_block > 0) - inslot->ri_newblock = inslot->ri_block; - else - inslot->ri_newblock = rd->rd_graphblock; + /* bash unconfirmed declarations to graphblock */ + inslot->so_newpattern = 0; + inslot->so_newblock = rd->rd_graphblock; } - else + else if (inslot->so_remote) { - inslot->ri_newpattern = 0; - inslot->ri_newblock = rd->rd_graphblock; + if (rdremote_getwriter(inslot->so_remote)) + { + loud_warning((t_pd *)rd, 0, "misplaced buffer reader..."); + riddle_updatedsp(); + failed = 1; /* LATER rethink */ + } + else + { + loud_warning((t_pd *)rd, 0, "orphaned buffer reader"); + + /* remote slots preserve unconfirmed declarations */ + inslot->so_newpattern = inslot->so_pattern; + if (inslot->so_block > 0) + inslot->so_newblock = inslot->so_block; + else + inslot->so_newblock = rd->rd_graphblock; + } } + else loudbug_bug("riddle_dsp 2"); } - else if (inslot->ri_newblock <= 0) /* should not happen */ + else if (inslot->so_newblock <= 0) /* should not happen */ { - loudbug_bug("riddle_dsp 1"); + loudbug_bug("riddle_dsp 3"); 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... */ + /* step 2: determine outslot sizes/layouts -- 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 the pros + and cons of performing the reblocking during every dsp call */ + + /* 2a: was there any change of inslot size/layout or graph block/sr? */ if (!doreblock && rd->rd_blockfn) { if (rd->rd_graphsr != oldgraphsr || @@ -805,8 +756,8 @@ static void riddle_dsp(t_riddle *rd, t_signal **sp) 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) + if (inslot->so_newpattern != inslot->so_pattern || + inslot->so_newblock != inslot->so_block) { doreblock = 1; break; @@ -814,23 +765,25 @@ static void riddle_dsp(t_riddle *rd, t_signal **sp) } } + /* 2b: update the inslots, reset the outslots */ 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; + inslot->so_pattern = inslot->so_newpattern; + inslot->so_block = inslot->so_newblock; + } + for (outslotno = 0, outslot = rd->rd_outslots; + outslotno < rd->rd_nsigoutlets; outslotno++, outslot++) + { + outslot->si_pattern = 0; + outslot->si_block = 0; + outslot->si_isready = 0; } } + /* 2c: call the instance-specific method which redeclares the outslots */ if (doreblock) { #ifdef RIDDLE_DEBUG @@ -841,20 +794,24 @@ static void riddle_dsp(t_riddle *rd, t_signal **sp) goto muteandreset; } + /* 2d: assign defaults to undeclared outslots */ for (outslotno = 0, outslot = rd->rd_outslots; outslotno < rd->rd_nsigoutlets; outslotno++, outslot++) { - if (outslot->ro_block < 0) + if (outslot->si_block < 0) { - loudbug_bug("riddle_dsp 3"); + loudbug_bug("riddle_dsp 4"); failed = 1; } - else if (outslot->ro_block == 0) - outslot->ro_block = rd->rd_graphblock; + else if (outslot->si_block == 0) + outslot->si_block = rd->rd_graphblock; } + /* LATER think about not redeclared remote writers */ if (failed) goto muteandreset; + /* step 3: transfer outslot declarations down to destination objects */ + #ifdef RIDDLE_DEBUG riddlebug_post(rd, "PUSH", 0); #endif @@ -862,19 +819,27 @@ static void riddle_dsp(t_riddle *rd, t_signal **sp) { for (outslotno = 0, outslot = rd->rd_outslots; outslotno < rd->rd_nsigoutlets; outslotno++, outslot++) - if (outslot->ro_isready && rdsink_push(outslot) == 0) + if (outslot->si_isready && + rdsink_push(outslot, (t_object *)rd, outslot->si_outno) == 0) failed = 1; } else failed = 1; + /* remote declarations are propagated directly from within + rdremote_setoutblock/layout(), cf. rdremote_pushblock/layout() */ if (failed) goto muteandreset; + + /* step 4: call the wrappee */ + if (rd->rd_dspfn) { rd->rd_dspfn(rd, sp); unarmed = 0; } - else loudbug_bug("riddle_dsp 4"); + else loudbug_bug("riddle_dsp 5"); + + /* step 5: mute if disabled, then reset the inslots */ muteandreset: if (unarmed) @@ -885,40 +850,54 @@ muteandreset: for (inslotno = 0, inslot = rd->rd_inslots; inslotno < ninslots; inslotno++, inslot++) { - inslot->ri_newpattern = 0; - inslot->ri_newblock = 0; - inslot->ri_sourcecount = 0; + inslot->so_newpattern = 0; + inslot->so_newblock = 0; + inslot->so_sourcecount = 0; } - rd->rd_remotesource = 0; } -static void riddle__reblock(t_riddle *rd, - t_symbol *pattern, t_floatarg f1, t_floatarg f2) +static void riddle__reblock(t_riddle *rd, t_symbol *pattern, + t_floatarg f1, t_floatarg f2, t_floatarg f3) { + riddle_setsourceflags(rd, (int)f1, (int)f3); 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 if (pattern) + riddle_setsourcelayout(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()); + if (rd->rd_private) + freebytes(rd->rd_private, sizeof(*rd->rd_private)); - nslots = rd->rd_nsiginlets + rd->rd_nremoteslots; if (rd->rd_inslots) + { + int nslots = rd->rd_nsiginlets + rd->rd_nremoteslots; freebytes(rd->rd_inslots, nslots * sizeof(*rd->rd_inslots)); + } + if (rd->rd_outslots) + { + t_rdsink *si; + int i; + for (i = 0, si = rd->rd_outslots; i < rd->rd_nsigoutlets; i++, si++) + if (si->si_feedchain) + rdfeedchain_free(si->si_feedchain); freebytes(rd->rd_outslots, rd->rd_nsigoutlets * sizeof(*rd->rd_outslots)); + } + + rdremote_freeports(rd->rd_remoteports); + + if (rd->rd_idlepicker) + rdpicker_detach(rd->rd_idlepicker, rd); } typedef t_pd *(*t_newgimme)(t_symbol *s, int argc, t_atom *argv); @@ -926,8 +905,8 @@ 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); + t_pd *en = riddle_getenvironment(); + t_newgimme newfn = (t_newgimme)zgetfn(en, s); if (!newfn) { loudbug_bug("riddle_new 1"); @@ -939,8 +918,12 @@ static void *riddle_new(t_symbol *s, int ac, t_atom *av) int i, nslots; t_rdsource *inslot; t_rdsink *outslot; + t_rdremote *re; if (!rd) return (0); + + rd->rd_private = getbytes(sizeof(*rd->rd_private)); + rd->rd_disabled = 0; rd->rd_wasdisabled = 0; rd->rd_blockfn = (t_rdblockfn)zgetfn((t_pd *)rd, gensym("dspblock")); @@ -948,53 +931,77 @@ static void *riddle_new(t_symbol *s, int ac, t_atom *av) 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; + /* currently, rd_nremoteslots is incremented in rdbuffer_newreader(), + which relies on calloc in pd_new(), LATER rethink */ + + 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; + inslot->so_riddle = rd; + inslot->so_remote = 0; + inslot->so_sourcecount = 0; + inslot->so_pattern = 0; + inslot->so_newpattern = 0; + inslot->so_block = 0; + inslot->so_newblock = 0; + inslot->so_flags = 0; } rd->rd_remoteslots = rd->rd_inslots + rd->rd_nsiginlets; + for (i = 0, inslot = rd->rd_remoteslots, re = rd->rd_remoteports; + i < rd->rd_nremoteslots; i++, inslot++) + { + if (re = rdremote_nextreader(re)) + inslot->so_remote = re; + else + { + loudbug_bug("riddle_new 3"); + break; /* FIXME this is fatal */ + } + } + 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 */ + outslot->si_riddle = rd; + outslot->si_outno = -1; + outslot->si_pattern = 0; + outslot->si_block = 0; + outslot->si_flags = 0; + outslot->si_outbuf[0].a_type = A_FLOAT; + outslot->si_outbuf[1].a_type = A_SYMBOL; + outslot->si_outbuf[1].a_w.w_symbol = rdps__; + outslot->si_outbuf[2].a_type = A_FLOAT; + outslot->si_outbuf[3].a_type = A_FLOAT; + outslot->si_outbuf[3].a_w.w_float = 0.; + outslot->si_feedchain = 0; + outslot->si_isready = 0; } + riddle_validatesinks(rd); - /* currently, rd->rd_nremoteslots is incremented in - rdbuffer_newreader(), LATER rethink */ + for (i = 0, outslot = rd->rd_outslots; + i < rd->rd_nsigoutlets; i++, outslot++) + if (outslot->si_outno >= 0) + outslot->si_feedchain = rdfeedchain_new(outslot->si_outno); + + rd->rd_idlepicker = rdpicker_attach(rd, gensym("_idle")); - rd->rd_remotesource = 0; return (rd); } } /* IFBUILTIN remove: classes would use explicit class_addmethod calls */ +/* obligatory: newfn, dspfn */ +/* optional: freefn, blockfn, floatfn */ 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) @@ -1003,327 +1010,43 @@ t_class *riddle_setup(t_symbol *name, t_newmethod newfn, t_method freefn, (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); + t_pd *en = riddle_getenvironment(); + class_addmethod(*en, (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); + class_addmethod(*en, (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); + if (blockfn) + 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); + if (freefn) + 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); + rdps__reblock, A_FLOAT, A_SYMBOL, A_FLOAT, 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) +/* Fills an array of band sizes, in bins, which partition an nbins-point power + spectrum into nbands or less ERB bands (nbands is a requested number of + bands, the actual number is returned). The buffer is then zero-terminated + (and zero-padded if necessary), so its size has to be at least nbands+1. */ +int riddle_erbfill(int nbands, int *buf, int nbins, int sr) { static double coef = 9.293902; /* 21.4 / log(10) */ - double df = (double)sr / (double)nblock; - double fmax = .5 * (nblock + 1) * df; + double df = (double)sr / (double)nbins; + double fmax = .5 * (nbins + 1) * df; double fc = df; int i, erbcount = 0, bincount = 0, lastbin = 0; int bufsize = nbands + 1; diff --git a/riddle/riddle.h b/riddle/riddle.h index 12d5907..0795f5f 100644 --- a/riddle/riddle.h +++ b/riddle/riddle.h @@ -2,103 +2,132 @@ * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ +/* these are the riddle external API declarations */ + #ifndef __RIDDLE_H__ #define __RIDDLE_H__ EXTERN_STRUCT _riddle; #define t_riddle struct _riddle +EXTERN_STRUCT _rdprivate; +#define t_rdprivate struct _rdprivate + EXTERN_STRUCT _rdsource; #define t_rdsource struct _rdsource EXTERN_STRUCT _rdsink; #define t_rdsink struct _rdsink -EXTERN_STRUCT _rdpool; -#define t_rdpool struct _rdpool +EXTERN_STRUCT _rdpicker; +#define t_rdpicker struct _rdpicker + +EXTERN_STRUCT _rdfeedchain; +#define t_rdfeedchain struct _rdfeedchain -EXTERN_STRUCT _rdbuffer; -#define t_rdbuffer struct _rdbuffer +EXTERN_STRUCT _rdremote; +#define t_rdremote struct _rdremote typedef void (*t_rdblockfn)(t_riddle *); typedef void (*t_rddspfn)(t_riddle *, t_signal **); struct _riddle { - t_sic rd_sic; + t_sic rd_sic; + + /* LATER rethink: indirection cost vs. abi stability */ + t_rdprivate *rd_private; /* designed for system-level control: block mismatches, etc. - (user-level control via '_idle' slot in graphpool) */ - int rd_disabled; - int rd_wasdisabled; + (user-level control possible via the '_idle' slot in graphpool) */ + int rd_disabled; + int rd_wasdisabled; t_rdblockfn rd_blockfn; t_rddspfn rd_dspfn; - t_rdpool *rd_graphpool; - - int rd_graphsr; - int rd_graphblock; + int rd_graphsr; + int rd_graphblock; int rd_nsiginlets; int rd_nremoteslots; - t_rdsource *rd_inslots; /* rd_nsiginlets + rd_nremoteslots elements */ - t_rdsource *rd_remoteslots; /* == rd_inslots + rd_nsiginlets */ + t_rdsource *rd_inslots; /* nsiginlets + nremoteslots elements */ + t_rdsource *rd_remoteslots; /* == inslots + nsiginlets (readers only) */ + t_rdremote *rd_remoteports; /* the list of all remotes */ - int rd_nsigoutlets; - t_rdsink *rd_outslots; /* rd_nsigoutlets elements */ + int rd_nsigoutlets; + t_rdsink *rd_outslots; /* nsigoutlets elements */ - int rd_remotesource; /* LATER consider storing remote sources here */ + t_rdpicker *rd_idlepicker; }; -void riddlebug_post(t_riddle *rd, char *pfx, char *fmt, ...); +#define RIDDLE_STRICTNESSMASK 1 /* if set: non-riddle sinks are rejected */ -int riddle_getsr(t_riddle *rd); -int riddle_getgraphblock(t_riddle *rd); +/* the main part of the API */ int riddle_getsourceblock(t_riddle *rd, int siginno); -t_symbol *riddle_getsourcepattern(t_riddle *rd, int siginno, int *maxblockp); -int riddle_getoutblock(t_riddle *rd, int sigoutno); -t_symbol *riddle_getoutpattern(t_riddle *rd, int sigoutno, int *maxblockp); +t_symbol *riddle_getsourcelayout(t_riddle *rd, int siginno, int *maxblockp); +int riddle_getsourceflags(t_riddle *rd, int siginno); +/* or perhaps, IFBUILTIN, int inlet_getblock(t_inlet *)... */ void riddle_setoutblock(t_riddle *rd, int sigoutno, int newblock); -void riddle_setoutpattern(t_riddle *rd, int sigoutno, - t_symbol *pattern, int maxblock); +void riddle_setoutlayout(t_riddle *rd, int sigoutno, + t_symbol *pattern, int maxblock); +void riddle_setoutflags(t_riddle *rd, int sigoutno, int flags); +/* or perhaps, IFBUILTIN, void outlet_setblock(t_outlet *, int)... */ int riddle_checksourceblock(t_riddle *rd, int siginno, int reqblock); -int riddle_checksourcepattern(t_riddle *rd, int siginno, - t_symbol *reqpattern, int *maxblockp); -int riddle_checkanysource(t_riddle *rd, int siginno); +int riddle_checksourcelayout(t_riddle *rd, int siginno, + t_symbol *reqpattern, int *maxblockp); int riddle_isdisabled(t_riddle *rd); void riddle_disable(t_riddle *rd); -void riddle_mute(t_riddle *rd, t_signal **sp); + +/* this part is specific to the library implementation */ 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); -void riddle_updatedsp(void); - -void rdpool_set(t_rdpool *rp, t_symbol *key, int size, t_float *data); -void rdpool_setbygraph(t_canvas *graph, t_symbol *key, int size, t_float *data); -t_float *rdpool_get(t_rdpool *rp, t_symbol *key, int *sizep); -t_float *riddle_getlink(t_riddle *rd, t_symbol *key, int *sizep); -t_canvas *riddle_getgraph(t_riddle *rd, int sigoutno); - -t_rdbuffer *riddle_getbuffer(t_symbol *name); -t_rdbuffer *rdbuffer_getwriter(t_rdbuffer *rb); -void rdbuffer_validate(t_rdbuffer *rb, int nblock); -void rdbuffer_reset(t_rdbuffer *rb); -int rdbuffer_getframesize(t_rdbuffer *rb); -t_float *rdbuffer_gethead(t_rdbuffer *rb); -void rdbuffer_stephead(t_rdbuffer *rb); -void rdbuffer_movehead(t_rdbuffer *rb, int nframes); -void rdbuffer_delayhead(t_rdbuffer *rb, int nframes); -void rdbuffer_free(t_rdbuffer *rb); -t_rdbuffer *rdbuffer_new(t_riddle *owner, t_symbol *name, int nframes); -t_rdbuffer *rdbuffer_newreader(t_riddle *owner, t_symbol *name); - -int riddle_erbfill(int nbands, int *buf, int nblock, int sr); +/* this part is very experimental: remote connections */ + +t_rdremote *rdremote_newwriter(t_riddle *owner, t_symbol *name, int nframes); +t_rdremote *rdremote_newreader(t_riddle *owner, t_symbol *name); +t_rdremote *rdremote_newbuffer(t_riddle *owner, int nframes); + +int rdremote_getsourceblock(t_rdremote *re); +t_symbol *rdremote_getsourcelayout(t_rdremote *re, int *maxblockp); +int rdremote_getsourceflags(t_rdremote *re); + +void rdremote_setoutblock(t_rdremote *re, int nblock); +void rdremote_setoutlayout(t_rdremote *re, t_symbol *pattern, int maxblock); +void rdremote_setoutflags(t_rdremote *re, int flags); + +void rdremote_reset(t_rdremote *re); +t_float *rdremote_gethead(t_rdremote *re); +void rdremote_stephead(t_rdremote *re); +void rdremote_movehead(t_rdremote *re, int nframes); +void rdremote_delayhead(t_rdremote *re, int nframes); + +t_rdpicker *rdpicker_attach(t_riddle *rd, t_symbol *key); +void rdpicker_detach(t_rdpicker *pi, t_riddle *rd); +t_float *rdpicker_pick(t_rdpicker *pi, int *sizep); +t_float rdpicker_pick1(t_rdpicker *pi); +int riddle_isidle(t_riddle *rd); + +t_rdfeedchain *riddle_usefeedchain(t_riddle *rd, + int sigoutno, t_symbol *key, int size); +t_rdfeedchain *riddle_useidlechain(t_riddle *rd, int sigoutno); +void rdfeedchain_feed(t_rdfeedchain *ch, int size, t_float *data); +void rdfeedchain_feed1(t_rdfeedchain *ch, t_float v); + +/* utilities */ + +void riddlebug_post(t_riddle *rd, char *pfx, char *fmt, ...); + +int riddle_getsr(t_riddle *rd); +int riddle_getgraphblock(t_riddle *rd); + +int riddle_erbfill(int nbands, int *buf, int nbins, int sr); #endif diff --git a/riddle/riddleguts.h b/riddle/riddleguts.h new file mode 100644 index 0000000..b6354e2 --- /dev/null +++ b/riddle/riddleguts.h @@ -0,0 +1,35 @@ +/* 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. */ + +/* these declarations do not belong to the riddle API + and should not be used by riddle externals */ + +#ifndef __RIDDLEGUTS_H__ +#define __RIDDLEGUTS_H__ + +/* from riddle.c */ + +void riddle_setsourceblock(t_riddle *rd, int siginno, int newblock); +void riddle_setsourcelayout(t_riddle *rd, int siginno, + t_symbol *newpattern, int maxblock); +void riddle_setsourceflags(t_riddle *rd, int siginno, int flags); + +t_canvas *riddle_nextgraph(t_riddle *rd); +t_canvas *riddle_firstgraph(t_riddle *rd, int outno); + +t_rdfeedchain *riddle_getfeedchain(t_riddle *rd, int sigoutno); + +/* from rdremote.c */ + +t_pd *riddle_getenvironment(void); +void riddle_updatedsp(void); + +void rdfeedchain_free(t_rdfeedchain *ch); +t_rdfeedchain *rdfeedchain_new(int outno); + +t_rdremote *rdremote_getwriter(t_rdremote *re); +t_rdremote *rdremote_nextreader(t_rdremote *re); +void rdremote_freeports(t_rdremote *re); + +#endif |