/* Copyright (c) 2002-2003 krzYszcz and others. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ /* LATER revisit buffer handling (maxsize, reentrancy) */ /* LATER rethink handling of symbols */ /* CHECKED: if 'n' argument is given, then store whole messages, instead of distributing atoms across successive slots. This is a new, buddy-like behaviour. */ /* CHECKED: without 'n' argument, 'symbol test' is parsed as two symbol atoms, but 'float 1' (or 'list 1') as a single float. */ #include #include "m_pd.h" #include "common/grow.h" #define BONDO_MINSLOTS 2 #define BONDO_INISIZE 4 /* LATER rethink (useful only in multiatom mode) */ typedef struct _bondo { t_object x_ob; t_float x_delay; int x_multiatom; int x_nslots; int x_nproxies; /* as requested (and allocated) */ t_pd **x_proxies; t_outlet **x_outs; t_clock *x_clock; } t_bondo; typedef struct _bondo_proxy { t_object p_ob; t_bondo *p_master; int p_id; t_symbol *p_selector; t_float p_float; t_symbol *p_symbol; t_gpointer *p_pointer; int p_size; /* as allocated */ int p_natoms; /* as used */ t_atom *p_message; t_atom p_messini[BONDO_INISIZE]; } t_bondo_proxy; static t_class *bondo_class; static t_class *bondo_proxy_class; static void bondo_doit(t_bondo *x) { t_bondo_proxy **p = (t_bondo_proxy **)x->x_proxies; int i = x->x_nslots; p = (t_bondo_proxy **)x->x_proxies; i = x->x_nslots; while (i--) { t_symbol *s = p[i]->p_selector; /* LATER consider complaining about extra arguments (CHECKED) */ if (s == &s_bang) outlet_bang(x->x_outs[i]); else if (s == &s_float) outlet_float(x->x_outs[i], p[i]->p_float); else if (s == &s_symbol && p[i]->p_symbol) { /* LATER rethink */ if (x->x_multiatom) outlet_symbol(x->x_outs[i], p[i]->p_symbol); else outlet_anything(x->x_outs[i], p[i]->p_symbol, 0, 0); } else if (s == &s_pointer) { /* LATER */ } else if (s == &s_list) outlet_list(x->x_outs[i], s, p[i]->p_natoms, p[i]->p_message); else if (s) /* CHECKED: a slot may be inactive (in multiatom mode) */ outlet_anything(x->x_outs[i], s, p[i]->p_natoms, p[i]->p_message); } } static void bondo_arm(t_bondo *x) { if (x->x_delay <= 0) bondo_doit(x); else clock_delay(x->x_clock, x->x_delay); } static void bondo_proxy_bang(t_bondo_proxy *x) { bondo_arm(x->p_master); /* CHECKED: bang in any inlet works in this way */ } static void bondo_proxy_dofloat(t_bondo_proxy *x, t_float f, int doit) { x->p_selector = &s_float; x->p_float = f; x->p_natoms = 0; /* defensive */ if (doit) bondo_arm(x->p_master); } static void bondo_proxy_float(t_bondo_proxy *x, t_float f) { bondo_proxy_dofloat(x, f, 1); } static void bondo_proxy_dosymbol(t_bondo_proxy *x, t_symbol *s, int doit) { x->p_selector = &s_symbol; x->p_symbol = s; x->p_natoms = 0; /* defensive */ if (doit) bondo_arm(x->p_master); } static void bondo_proxy_symbol(t_bondo_proxy *x, t_symbol *s) { bondo_proxy_dosymbol(x, s, 1); } static void bondo_proxy_dopointer(t_bondo_proxy *x, t_gpointer *gp, int doit) { x->p_selector = &s_pointer; x->p_pointer = gp; x->p_natoms = 0; /* defensive */ if (doit) bondo_arm(x->p_master); } static void bondo_proxy_pointer(t_bondo_proxy *x, t_gpointer *gp) { bondo_proxy_dopointer(x, gp, 1); } /* CHECKED: the slots fire in right-to-left order, but they trigger only once (refman error) */ static void bondo_distribute(t_bondo *x, int startid, t_symbol *s, int ac, t_atom *av, int doit) { t_atom *ap = av; t_bondo_proxy **pp; int id = startid + ac; if (s) id++; if (id > x->x_nslots) id = x->x_nslots; ap += id - startid; pp = (t_bondo_proxy **)(x->x_proxies + id); if (s) ap--; while (ap-- > av) { pp--; if (ap->a_type == A_FLOAT) bondo_proxy_dofloat(*pp, ap->a_w.w_float, 0); else if (ap->a_type == A_SYMBOL) bondo_proxy_dosymbol(*pp, ap->a_w.w_symbol, 0); else if (ap->a_type == A_POINTER) bondo_proxy_dopointer(*pp, ap->a_w.w_gpointer, 0); } if (s) bondo_proxy_dosymbol((t_bondo_proxy *)x->x_proxies[startid], s, 0); if (doit) bondo_arm(x); } static void bondo_proxy_domultiatom(t_bondo_proxy *x, int ac, t_atom *av, int doit) { if (ac > x->p_size) { /* LATER consider using BONDO_MAXSIZE (and warning if exceeded) */ x->p_message = grow_nodata(&ac, &x->p_size, x->p_message, BONDO_INISIZE, x->p_messini, sizeof(*x->p_message)); } x->p_natoms = ac; memcpy(x->p_message, av, ac * sizeof(*x->p_message)); if (doit) bondo_arm(x->p_master); } static void bondo_proxy_dolist(t_bondo_proxy *x, int ac, t_atom *av, int doit) { if (x->p_master->x_multiatom) { x->p_selector = &s_list; bondo_proxy_domultiatom(x, ac, av, doit); } else bondo_distribute(x->p_master, x->p_id, 0, ac, av, doit); } static void bondo_proxy_list(t_bondo_proxy *x, t_symbol *s, int ac, t_atom *av) { bondo_proxy_dolist(x, ac, av, 1); } static void bondo_proxy_doanything(t_bondo_proxy *x, t_symbol *s, int ac, t_atom *av, int doit) { if (x->p_master->x_multiatom) { /* LATER rethink and CHECKME */ if (s == &s_symbol) { if (ac && av->a_type == A_SYMBOL) bondo_proxy_dosymbol(x, av->a_w.w_symbol, doit); else bondo_proxy_dosymbol(x, &s_symbol, doit); } else { x->p_selector = s; bondo_proxy_domultiatom(x, ac, av, doit); } } else bondo_distribute(x->p_master, x->p_id, s, ac, av, doit); } static void bondo_proxy_anything(t_bondo_proxy *x, t_symbol *s, int ac, t_atom *av) { bondo_proxy_doanything(x, s, ac, av, 1); } static void bondo_proxy_set(t_bondo_proxy *x, t_symbol *s, int ac, t_atom *av) { if (ac) { if (av->a_type == A_FLOAT) { if (ac > 1) bondo_proxy_dolist(x, ac, av, 0); else bondo_proxy_dofloat(x, av->a_w.w_float, 0); } else if (av->a_type == A_SYMBOL) /* CHECKED: no tests for 'set float ...' and 'set list...' -- the parsing is made in an output routine */ bondo_proxy_doanything(x, av->a_w.w_symbol, ac-1, av+1, 0); else if (av->a_type == A_POINTER) bondo_proxy_dopointer(x, av->a_w.w_gpointer, 0); } /* CHECKED: 'set' without arguments makes a slot inactive, if multiatom, but is ignored, if !multiatom */ else if (x->p_master->x_multiatom) x->p_selector = 0; } static void bondo_bang(t_bondo *x) { bondo_proxy_bang((t_bondo_proxy *)x->x_proxies[0]); } static void bondo_float(t_bondo *x, t_float f) { bondo_proxy_dofloat((t_bondo_proxy *)x->x_proxies[0], f, 1); } static void bondo_symbol(t_bondo *x, t_symbol *s) { bondo_proxy_dosymbol((t_bondo_proxy *)x->x_proxies[0], s, 1); } static void bondo_pointer(t_bondo *x, t_gpointer *gp) { bondo_proxy_dopointer((t_bondo_proxy *)x->x_proxies[0], gp, 1); } static void bondo_list(t_bondo *x, t_symbol *s, int ac, t_atom *av) { bondo_proxy_dolist((t_bondo_proxy *)x->x_proxies[0], ac, av, 1); } static void bondo_anything(t_bondo *x, t_symbol *s, int ac, t_atom *av) { bondo_proxy_doanything((t_bondo_proxy *)x->x_proxies[0], s, ac, av, 1); } static void bondo_set(t_bondo *x, t_symbol *s, int ac, t_atom *av) { bondo_proxy_set((t_bondo_proxy *)x->x_proxies[0], s, ac, av); } static void bondo_free(t_bondo *x) { if (x->x_clock) clock_free(x->x_clock); if (x->x_proxies) { int i = x->x_nslots; while (i--) { t_bondo_proxy *y = (t_bondo_proxy *)x->x_proxies[i]; if (y->p_message != y->p_messini) freebytes(y->p_message, y->p_size * sizeof(*y->p_message)); pd_free((t_pd *)y); } freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies)); } if (x->x_outs) freebytes(x->x_outs, x->x_nslots * sizeof(*x->x_outs)); } static void *bondo_new(t_symbol *s, int ac, t_atom *av) { t_bondo *x; int i, nslots, nproxies = BONDO_MINSLOTS; int multiatom = 0; t_float delay = 0; t_pd **proxies; t_outlet **outs; i = 0; while (ac--) { /* CHECKED: no warnings */ if (av->a_type == A_FLOAT) { if (i == 0) nproxies = (int)av->a_w.w_float; else if (i == 1) delay = av->a_w.w_float; i++; } else if (av->a_type == A_SYMBOL) { if (av->a_w.w_symbol == gensym("n")) multiatom = 1; /* CHECKED: 'n' has to be the last argument given; the arguments after any symbol are silently ignored -- LATER decide if we should comply and break here */ } av++; } if (nproxies < BONDO_MINSLOTS) nproxies = BONDO_MINSLOTS; if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies)))) return (0); for (nslots = 0; nslots < nproxies; nslots++) if (!(proxies[nslots] = pd_new(bondo_proxy_class))) break; if (nslots < BONDO_MINSLOTS || !(outs = (t_outlet **)getbytes(nslots * sizeof(*outs)))) { i = nslots; while (i--) pd_free(proxies[i]); freebytes(proxies, nproxies * sizeof(*proxies)); return (0); } x = (t_bondo *)pd_new(bondo_class); x->x_delay = delay; x->x_multiatom = multiatom; x->x_nslots = nslots; x->x_nproxies = nproxies; x->x_proxies = proxies; x->x_outs = outs; for (i = 0; i < nslots; i++) { t_bondo_proxy *y = (t_bondo_proxy *)proxies[i]; y->p_master = x; y->p_id = i; y->p_selector = &s_float; /* CHECKED: it is so in multiatom mode too */ y->p_float = 0; y->p_symbol = 0; y->p_pointer = 0; y->p_size = BONDO_INISIZE; y->p_natoms = 0; y->p_message = y->p_messini; if (i) inlet_new((t_object *)x, (t_pd *)y, 0, 0); x->x_outs[i] = outlet_new((t_object *)x, &s_anything); } x->x_clock = clock_new(x, (t_method)bondo_doit); return (x); } void bondo_setup(void) { bondo_class = class_new(gensym("bondo"), (t_newmethod)bondo_new, (t_method)bondo_free, sizeof(t_bondo), 0, A_GIMME, 0); class_addbang(bondo_class, bondo_bang); class_addfloat(bondo_class, bondo_float); class_addsymbol(bondo_class, bondo_symbol); class_addpointer(bondo_class, bondo_pointer); class_addlist(bondo_class, bondo_list); class_addanything(bondo_class, bondo_anything); class_addmethod(bondo_class, (t_method)bondo_set, gensym("set"), A_GIMME, 0); bondo_proxy_class = class_new(gensym("_bondo_proxy"), 0, 0, sizeof(t_bondo_proxy), CLASS_PD | CLASS_NOINLET, 0); class_addbang(bondo_proxy_class, bondo_proxy_bang); class_addfloat(bondo_proxy_class, bondo_proxy_float); class_addsymbol(bondo_proxy_class, bondo_proxy_symbol); class_addpointer(bondo_proxy_class, bondo_proxy_pointer); class_addlist(bondo_proxy_class, bondo_proxy_list); class_addanything(bondo_proxy_class, bondo_proxy_anything); class_addmethod(bondo_proxy_class, (t_method)bondo_proxy_set, gensym("set"), A_GIMME, 0); }