1
/* Copyright (c) 1997-1999 Miller Puckette.
2
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
3
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5
/* this file handles Max-style patchable objects, i.e., objects which
6
can interconnect via inlets and outlets; also, the (terse) generic
7
behavior for "gobjs" appears at the end of this file. */
15
t_gpointer *iu_pointerslot;
16
t_float *iu_floatslot;
17
t_symbol **iu_symslot;
18
t_float iu_floatsignalvalue;
24
struct _inlet *i_next;
28
union inletunion i_un;
31
#define i_symto i_un.iu_symto
32
#define i_pointerslot i_un.iu_pointerslot
33
#define i_floatslot i_un.iu_floatslot
34
#define i_symslot i_un.iu_symslot
36
static t_class *inlet_class, *pointerinlet_class, *floatinlet_class,
39
#define ISINLET(pd) ((*(pd) == inlet_class) || \
40
(*(pd) == pointerinlet_class) || \
41
(*(pd) == floatinlet_class) || \
42
(*(pd) == symbolinlet_class))
44
/* --------------------- generic inlets ala max ------------------ */
46
t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2)
48
t_inlet *x = (t_inlet *)pd_new(inlet_class), *y, *y2;
52
x->i_un.iu_floatsignalvalue = 0;
56
if (y = owner->ob_inlet)
58
while (y2 = y->i_next) y = y2;
61
else owner->ob_inlet = x;
65
t_inlet *signalinlet_new(t_object *owner, t_float f)
67
t_inlet *x = inlet_new(owner, &owner->ob_pd, &s_signal, &s_signal);
68
x->i_un.iu_floatsignalvalue = f;
72
static void inlet_wrong(t_inlet *x, t_symbol *s)
74
pd_error(x->i_owner, "inlet: expected '%s' but got '%s'",
75
x->i_symfrom->s_name, s->s_name);
78
/* LATER figure out how to make these efficient: */
79
static void inlet_bang(t_inlet *x)
81
if (x->i_symfrom == &s_bang)
82
pd_vmess(x->i_dest, x->i_symto, "");
83
else if (!x->i_symfrom) pd_bang(x->i_dest);
84
else inlet_wrong(x, &s_bang);
87
static void inlet_pointer(t_inlet *x, t_gpointer *gp)
89
if (x->i_symfrom == &s_pointer)
90
pd_vmess(x->i_dest, x->i_symto, "p", gp);
91
else if (!x->i_symfrom) pd_pointer(x->i_dest, gp);
92
else inlet_wrong(x, &s_pointer);
95
static void inlet_float(t_inlet *x, t_float f)
97
if (x->i_symfrom == &s_float)
98
pd_vmess(x->i_dest, x->i_symto, "f", (t_floatarg)f);
99
else if (x->i_symfrom == &s_signal)
100
x->i_un.iu_floatsignalvalue = f;
101
else if (!x->i_symfrom)
102
pd_float(x->i_dest, f);
103
else inlet_wrong(x, &s_float);
106
static void inlet_symbol(t_inlet *x, t_symbol *s)
108
if (x->i_symfrom == &s_symbol)
109
pd_vmess(x->i_dest, x->i_symto, "s", s);
110
else if (!x->i_symfrom) pd_symbol(x->i_dest, s);
111
else inlet_wrong(x, &s_symbol);
114
static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
117
if (x->i_symfrom == &s_list || x->i_symfrom == &s_float
118
|| x->i_symfrom == &s_symbol || x->i_symfrom == &s_pointer)
119
typedmess(x->i_dest, x->i_symto, argc, argv);
120
else if (!x->i_symfrom) pd_list(x->i_dest, s, argc, argv);
121
else inlet_wrong(x, &s_list);
124
static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
126
if (x->i_symfrom == s)
127
typedmess(x->i_dest, x->i_symto, argc, argv);
128
else if (!x->i_symfrom)
129
typedmess(x->i_dest, s, argc, argv);
130
else inlet_wrong(x, s);
133
void inlet_free(t_inlet *x)
135
t_object *y = x->i_owner;
137
if (y->ob_inlet == x) y->ob_inlet = x->i_next;
138
else for (x2 = y->ob_inlet; x2; x2 = x2->i_next)
141
x2->i_next = x->i_next;
144
t_freebytes(x, sizeof(*x));
147
/* ----- pointerinlets, floatinlets, syminlets: optimized inlets ------- */
149
static void pointerinlet_pointer(t_inlet *x, t_gpointer *gp)
151
gpointer_unset(x->i_pointerslot);
152
*(x->i_pointerslot) = *gp;
153
if (gp->gp_stub) gp->gp_stub->gs_refcount++;
156
t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp)
158
t_inlet *x = (t_inlet *)pd_new(pointerinlet_class), *y, *y2;
161
x->i_symfrom = &s_pointer;
162
x->i_pointerslot = gp;
164
if (y = owner->ob_inlet)
166
while (y2 = y->i_next) y = y2;
169
else owner->ob_inlet = x;
173
static void floatinlet_float(t_inlet *x, t_float f)
175
*(x->i_floatslot) = f;
178
t_inlet *floatinlet_new(t_object *owner, t_float *fp)
180
t_inlet *x = (t_inlet *)pd_new(floatinlet_class), *y, *y2;
183
x->i_symfrom = &s_float;
186
if (y = owner->ob_inlet)
188
while (y2 = y->i_next) y = y2;
191
else owner->ob_inlet = x;
195
static void symbolinlet_symbol(t_inlet *x, t_symbol *s)
200
t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp)
202
t_inlet *x = (t_inlet *)pd_new(symbolinlet_class), *y, *y2;
205
x->i_symfrom = &s_symbol;
208
if (y = owner->ob_inlet)
210
while (y2 = y->i_next) y = y2;
213
else owner->ob_inlet = x;
217
/* ---------------------- routine to handle lists ---------------------- */
219
/* objects interpret lists by feeding them to the individual inlets.
220
Before you call this check that the object doesn't have a more
221
specific way to handle lists. */
222
void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv)
226
t_inlet *ip = ((t_object *)x)->ob_inlet;
228
for (count = argc-1, ap = argv+1; ip && count--; ap++, ip = ip->i_next)
230
if (ap->a_type == A_POINTER) pd_pointer(&ip->i_pd, ap->a_w.w_gpointer);
231
else if (ap->a_type == A_FLOAT) pd_float(&ip->i_pd, ap->a_w.w_float);
232
else pd_symbol(&ip->i_pd, ap->a_w.w_symbol);
234
if (argv->a_type == A_POINTER) pd_pointer(&x->ob_pd, argv->a_w.w_gpointer);
235
else if (argv->a_type == A_FLOAT) pd_float(&x->ob_pd, argv->a_w.w_float);
236
else pd_symbol(&x->ob_pd, argv->a_w.w_symbol);
241
inlet_class = class_new(gensym("inlet"), 0, 0,
242
sizeof(t_inlet), CLASS_PD, 0);
243
class_addbang(inlet_class, inlet_bang);
244
class_addpointer(inlet_class, inlet_pointer);
245
class_addfloat(inlet_class, inlet_float);
246
class_addsymbol(inlet_class, inlet_symbol);
247
class_addlist(inlet_class, inlet_list);
248
class_addanything(inlet_class, inlet_anything);
250
pointerinlet_class = class_new(gensym("inlet"), 0, 0,
251
sizeof(t_inlet), CLASS_PD, 0);
252
class_addpointer(pointerinlet_class, pointerinlet_pointer);
253
class_addanything(pointerinlet_class, inlet_wrong);
255
floatinlet_class = class_new(gensym("inlet"), 0, 0,
256
sizeof(t_inlet), CLASS_PD, 0);
257
class_addfloat(floatinlet_class, (t_method)floatinlet_float);
258
class_addanything(floatinlet_class, inlet_wrong);
260
symbolinlet_class = class_new(gensym("inlet"), 0, 0,
261
sizeof(t_inlet), CLASS_PD, 0);
262
class_addsymbol(symbolinlet_class, symbolinlet_symbol);
263
class_addanything(symbolinlet_class, inlet_wrong);
267
/* --------------------------- outlets ------------------------------ */
269
static int stackcount = 0; /* iteration counter */
270
#define STACKITER 1000 /* maximum iterations allowed */
272
static int outlet_eventno;
274
/* set a stack limit (on each incoming event that can set off messages)
275
for the outlet functions to check to prevent stack overflow from message
278
void outlet_setstacklim(void)
283
/* get a number unique to the (clock, MIDI, GUI, etc.) event we're on */
284
int sched_geteventno( void)
286
return (outlet_eventno);
291
struct _outconnect *oc_next;
298
struct _outlet *o_next;
299
t_outconnect *o_connections;
303
t_outlet *outlet_new(t_object *owner, t_symbol *s)
305
t_outlet *x = (t_outlet *)getbytes(sizeof(*x)), *y, *y2;
308
if (y = owner->ob_outlet)
310
while (y2 = y->o_next) y = y2;
313
else owner->ob_outlet = x;
314
x->o_connections = 0;
319
static void outlet_stackerror(t_outlet *x)
321
pd_error(x->o_owner, "stack overflow");
324
void outlet_bang(t_outlet *x)
327
if(++stackcount >= STACKITER)
328
outlet_stackerror(x);
330
for (oc = x->o_connections; oc; oc = oc->oc_next)
335
void outlet_pointer(t_outlet *x, t_gpointer *gp)
339
if(++stackcount >= STACKITER)
340
outlet_stackerror(x);
344
for (oc = x->o_connections; oc; oc = oc->oc_next)
345
pd_pointer(oc->oc_to, &gpointer);
350
void outlet_float(t_outlet *x, t_float f)
353
if(++stackcount >= STACKITER)
354
outlet_stackerror(x);
356
for (oc = x->o_connections; oc; oc = oc->oc_next)
357
pd_float(oc->oc_to, f);
361
void outlet_symbol(t_outlet *x, t_symbol *s)
364
if(++stackcount >= STACKITER)
365
outlet_stackerror(x);
367
for (oc = x->o_connections; oc; oc = oc->oc_next)
368
pd_symbol(oc->oc_to, s);
372
void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
375
if(++stackcount >= STACKITER)
376
outlet_stackerror(x);
378
for (oc = x->o_connections; oc; oc = oc->oc_next)
379
pd_list(oc->oc_to, s, argc, argv);
383
void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
386
if(++stackcount >= STACKITER)
387
outlet_stackerror(x);
389
for (oc = x->o_connections; oc; oc = oc->oc_next)
390
typedmess(oc->oc_to, s, argc, argv);
394
/* get the outlet's declared symbol */
395
t_symbol *outlet_getsymbol(t_outlet *x)
400
void outlet_free(t_outlet *x)
402
t_object *y = x->o_owner;
404
if (y->ob_outlet == x) y->ob_outlet = x->o_next;
405
else for (x2 = y->ob_outlet; x2; x2 = x2->o_next)
408
x2->o_next = x->o_next;
411
t_freebytes(x, sizeof(*x));
414
t_outconnect *obj_connect(t_object *source, int outno,
415
t_object *sink, int inno)
420
t_outconnect *oc, *oc2;
422
for (o = source->ob_outlet; o && outno; o = o->o_next, outno--) ;
425
if (sink->ob_pd->c_firstin)
434
for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
438
oc = (t_outconnect *)t_getbytes(sizeof(*oc));
441
/* append it to the end of the list */
442
/* LATER we might cache the last "oc" to make this faster. */
443
if ((oc2 = o->o_connections))
445
while (oc2->oc_next) oc2 = oc2->oc_next;
448
else o->o_connections = oc;
449
if (o->o_sym == &s_signal) canvas_update_dsp();
454
void obj_disconnect(t_object *source, int outno, t_object *sink, int inno)
459
t_outconnect *oc, *oc2;
461
for (o = source->ob_outlet; o && outno; o = o->o_next, outno--)
463
if (sink->ob_pd->c_firstin)
472
for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
476
if (!(oc = o->o_connections)) return;
479
o->o_connections = oc->oc_next;
480
freebytes(oc, sizeof(*oc));
483
while (oc2 = oc->oc_next)
485
if (oc2->oc_to == to)
487
oc->oc_next = oc2->oc_next;
488
freebytes(oc2, sizeof(*oc2));
494
if (o->o_sym == &s_signal) canvas_update_dsp();
497
/* ------ traversal routines for code that can't see our structures ------ */
499
int obj_noutlets(t_object *x)
503
for (o = x->ob_outlet, n = 0; o; o = o->o_next) n++;
507
int obj_ninlets(t_object *x)
511
for (i = x->ob_inlet, n = 0; i; i = i->i_next) n++;
512
if (x->ob_pd->c_firstin) n++;
516
t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout)
518
t_outlet *o = x->ob_outlet;
519
while (nout-- && o) o = o->o_next;
521
if (o) return (o->o_connections);
525
t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect,
526
t_object **destp, t_inlet **inletp, int *whichp)
529
y = lastconnect->oc_to;
533
t_inlet *i = (t_inlet *)y, *i2;
534
t_object *dest = i->i_owner;
535
for (n = dest->ob_pd->c_firstin, i2 = dest->ob_inlet;
536
i2 && i2 != i; i2 = i2->i_next) n++;
545
*destp = ((t_object *)y);
547
return (lastconnect->oc_next);
550
/* this one checks that a pd is indeed a patchable object, and returns
551
it, correctly typed, or zero if the check failed. */
552
t_object *pd_checkobject(t_pd *x)
554
if ((*x)->c_patchable) return ((t_object *)x);
558
/* move an inlet or outlet to the head of the list */
559
void obj_moveinletfirst(t_object *x, t_inlet *i)
562
if (x->ob_inlet == i) return;
563
else for (i2 = x->ob_inlet; i2; i2 = i2->i_next)
566
i2->i_next = i->i_next;
567
i->i_next = x->ob_inlet;
573
void obj_moveoutletfirst(t_object *x, t_outlet *o)
576
if (x->ob_outlet == o) return;
577
else for (o2 = x->ob_outlet; o2; o2 = o2->o_next)
580
o2->o_next = o->o_next;
581
o->o_next = x->ob_outlet;
587
/* routines for DSP sorting, which are used in d_ugen.c and g_canvas.c */
588
/* LATER try to consolidate all the slightly different routines. */
590
int obj_nsiginlets(t_object *x)
594
for (i = x->ob_inlet, n = 0; i; i = i->i_next)
595
if (i->i_symfrom == &s_signal) n++;
596
if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin) n++;
600
/* get the index, among signal inlets, of the mth inlet overall */
601
int obj_siginletindex(t_object *x, int m)
605
if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
607
if (!m--) return (0);
610
for (i = x->ob_inlet; i; i = i->i_next, m--)
611
if (i->i_symfrom == &s_signal)
613
if (m == 0) return (n);
619
int obj_issignalinlet(t_object *x, int m)
622
if (x->ob_pd->c_firstin)
625
return (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin);
628
for (i = x->ob_inlet; i && m; i = i->i_next, m--)
630
return (i && (i->i_symfrom == &s_signal));
633
int obj_nsigoutlets(t_object *x)
637
for (o = x->ob_outlet, n = 0; o; o = o->o_next)
638
if (o->o_sym == &s_signal) n++;
642
int obj_sigoutletindex(t_object *x, int m)
646
for (o2 = x->ob_outlet, n = 0; o2; o2 = o2->o_next, m--)
647
if (o2->o_sym == &s_signal)
649
if (m == 0) return (n);
655
int obj_issignaloutlet(t_object *x, int m)
659
for (o2 = x->ob_outlet, n = 0; o2 && m--; o2 = o2->o_next);
660
return (o2 && (o2->o_sym == &s_signal));
663
t_float *obj_findsignalscalar(t_object *x, int m)
667
if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
670
return (x->ob_pd->c_floatsignalin > 0 ?
671
(t_float *)(((char *)x) + x->ob_pd->c_floatsignalin) : 0);
674
for (i = x->ob_inlet; i; i = i->i_next, m--)
675
if (i->i_symfrom == &s_signal)
678
return (&i->i_un.iu_floatsignalvalue);
684
/* and these are only used in g_io.c... */
686
int inlet_getsignalindex(t_inlet *x)
690
if (x->i_symfrom != &s_signal)
691
bug("inlet_getsignalindex");
692
for (i = x->i_owner->ob_inlet, n = 0; i && i != x; i = i->i_next)
693
if (i->i_symfrom == &s_signal) n++;
697
int outlet_getsignalindex(t_outlet *x)
701
for (o = x->o_owner->ob_outlet, n = 0; o && o != x; o = o->o_next)
702
if (o->o_sym == &s_signal) n++;