summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/m_obj.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/m_obj.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/m_obj.c1394
1 files changed, 1394 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/m_obj.c b/apps/plugins/pdbox/PDa/src/m_obj.c
new file mode 100644
index 0000000000..d53da5722e
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/m_obj.c
@@ -0,0 +1,1394 @@
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. */
4
5/* this file handles Max-style patchable objects, i.e., objects which
6can interconnect via inlets and outlets; also, the (terse) generic
7behavior for "gobjs" appears at the end of this file. */
8
9#include "m_pd.h"
10#include "m_imp.h"
11
12union inletunion
13{
14 t_symbol *iu_symto;
15 t_gpointer *iu_pointerslot;
16 t_float *iu_floatslot;
17 t_symbol **iu_symslot;
18 t_sample iu_floatsignalvalue;
19};
20
21struct _inlet
22{
23 t_pd i_pd;
24 struct _inlet *i_next;
25 t_object *i_owner;
26 t_pd *i_dest;
27 t_symbol *i_symfrom;
28 union inletunion i_un;
29};
30
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
35
36static t_class *inlet_class, *pointerinlet_class, *floatinlet_class,
37 *symbolinlet_class;
38
39#define ISINLET(pd) ((*(pd) == inlet_class) || \
40 (*(pd) == pointerinlet_class) || \
41 (*(pd) == floatinlet_class) || \
42 (*(pd) == symbolinlet_class))
43
44/* --------------------- generic inlets ala max ------------------ */
45
46t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2)
47{
48 t_inlet *x = (t_inlet *)pd_new(inlet_class), *y, *y2;
49 x->i_owner = owner;
50 x->i_dest = dest;
51 if (s1 == &s_signal)
52 x->i_un.iu_floatsignalvalue = 0;
53 else x->i_symto = s2;
54 x->i_symfrom = s1;
55 x->i_next = 0;
56 if (y = owner->ob_inlet)
57 {
58 while (y2 = y->i_next) y = y2;
59 y->i_next = x;
60 }
61 else owner->ob_inlet = x;
62 return (x);
63}
64
65static void inlet_wrong(t_inlet *x, t_symbol *s)
66{
67 pd_error(x->i_owner, "inlet: expected '%s' but got '%s'",
68 x->i_symfrom->s_name, s->s_name);
69}
70
71 /* LATER figure out how to make these efficient: */
72static void inlet_bang(t_inlet *x)
73{
74 if (x->i_symfrom == &s_bang)
75 pd_vmess(x->i_dest, x->i_symto, "");
76 else if (!x->i_symfrom) pd_bang(x->i_dest);
77 else inlet_wrong(x, &s_bang);
78}
79
80static void inlet_pointer(t_inlet *x, t_gpointer *gp)
81{
82 if (x->i_symfrom == &s_pointer)
83 pd_vmess(x->i_dest, x->i_symto, "p", gp);
84 else if (!x->i_symfrom) pd_pointer(x->i_dest, gp);
85 else inlet_wrong(x, &s_pointer);
86}
87
88static void inlet_float(t_inlet *x, t_float f)
89{
90 if (x->i_symfrom == &s_float)
91 pd_vmess(x->i_dest, x->i_symto, "f", (t_floatarg)f);
92 else if (x->i_symfrom == &s_signal)
93 x->i_un.iu_floatsignalvalue = ftofix(f);
94 else if (!x->i_symfrom)
95 pd_float(x->i_dest, f);
96 else inlet_wrong(x, &s_float);
97}
98
99static void inlet_symbol(t_inlet *x, t_symbol *s)
100{
101 if (x->i_symfrom == &s_symbol)
102 pd_vmess(x->i_dest, x->i_symto, "s", s);
103 else if (!x->i_symfrom) pd_symbol(x->i_dest, s);
104 else inlet_wrong(x, &s_symbol);
105}
106
107static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
108{
109 t_atom at;
110 if (x->i_symfrom == &s_list || x->i_symfrom == &s_float
111 || x->i_symfrom == &s_symbol || x->i_symfrom == &s_pointer)
112 typedmess(x->i_dest, x->i_symto, argc, argv);
113 else if (!x->i_symfrom) pd_list(x->i_dest, s, argc, argv);
114 else inlet_wrong(x, &s_list);
115}
116
117static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
118{
119 if (x->i_symfrom == s)
120 typedmess(x->i_dest, x->i_symto, argc, argv);
121 else if (!x->i_symfrom)
122 typedmess(x->i_dest, s, argc, argv);
123 else inlet_wrong(x, s);
124}
125
126void inlet_free(t_inlet *x)
127{
128 t_object *y = x->i_owner;
129 t_inlet *x2;
130 if (y->ob_inlet == x) y->ob_inlet = x->i_next;
131 else for (x2 = y->ob_inlet; x2; x2 = x2->i_next)
132 if (x2->i_next == x)
133 {
134 x2->i_next = x->i_next;
135 break;
136 }
137 t_freebytes(x, sizeof(*x));
138}
139
140/* ----- pointerinlets, floatinlets, syminlets: optimized inlets ------- */
141
142static void pointerinlet_pointer(t_inlet *x, t_gpointer *gp)
143{
144 gpointer_unset(x->i_pointerslot);
145 *(x->i_pointerslot) = *gp;
146 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
147}
148
149t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp)
150{
151 t_inlet *x = (t_inlet *)pd_new(pointerinlet_class), *y, *y2;
152 x->i_owner = owner;
153 x->i_dest = 0;
154 x->i_symfrom = &s_pointer;
155 x->i_pointerslot = gp;
156 x->i_next = 0;
157 if (y = owner->ob_inlet)
158 {
159 while (y2 = y->i_next) y = y2;
160 y->i_next = x;
161 }
162 else owner->ob_inlet = x;
163 return (x);
164}
165
166static void floatinlet_float(t_inlet *x, t_float f)
167{
168 *(x->i_floatslot) = f;
169}
170
171t_inlet *floatinlet_new(t_object *owner, t_float *fp)
172{
173 t_inlet *x = (t_inlet *)pd_new(floatinlet_class), *y, *y2;
174 x->i_owner = owner;
175 x->i_dest = 0;
176 x->i_symfrom = &s_float;
177 x->i_floatslot = fp;
178 x->i_next = 0;
179 if (y = owner->ob_inlet)
180 {
181 while (y2 = y->i_next) y = y2;
182 y->i_next = x;
183 }
184 else owner->ob_inlet = x;
185 return (x);
186}
187
188static void symbolinlet_symbol(t_inlet *x, t_symbol *s)
189{
190 *(x->i_symslot) = s;
191}
192
193t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp)
194{
195 t_inlet *x = (t_inlet *)pd_new(symbolinlet_class), *y, *y2;
196 x->i_owner = owner;
197 x->i_dest = 0;
198 x->i_symfrom = &s_symbol;
199 x->i_symslot = sp;
200 x->i_next = 0;
201 if (y = owner->ob_inlet)
202 {
203 while (y2 = y->i_next) y = y2;
204 y->i_next = x;
205 }
206 else owner->ob_inlet = x;
207 return (x);
208}
209
210/* ---------------------- routine to handle lists ---------------------- */
211
212 /* objects interpret lists by feeding them to the individual inlets.
213 Before you call this check that the object doesn't have a more
214 specific way to handle lists. */
215void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv)
216{
217 t_atom *ap;
218 int count;
219 t_inlet *ip = ((t_object *)x)->ob_inlet;
220 if (!argc) return;
221 for (count = argc-1, ap = argv+1; ip && count--; ap++, ip = ip->i_next)
222 {
223 if (ap->a_type == A_POINTER) pd_pointer(&ip->i_pd, ap->a_w.w_gpointer);
224 else if (ap->a_type == A_FLOAT) pd_float(&ip->i_pd, ap->a_w.w_float);
225 else pd_symbol(&ip->i_pd, ap->a_w.w_symbol);
226 }
227 if (argv->a_type == A_POINTER) pd_pointer(&x->ob_pd, argv->a_w.w_gpointer);
228 else if (argv->a_type == A_FLOAT) pd_float(&x->ob_pd, argv->a_w.w_float);
229 else pd_symbol(&x->ob_pd, argv->a_w.w_symbol);
230}
231
232void obj_init(void)
233{
234 inlet_class = class_new(gensym("inlet"), 0, 0,
235 sizeof(t_inlet), CLASS_PD, 0);
236 class_addbang(inlet_class, inlet_bang);
237 class_addpointer(inlet_class, inlet_pointer);
238 class_addfloat(inlet_class, inlet_float);
239 class_addsymbol(inlet_class, inlet_symbol);
240 class_addlist(inlet_class, inlet_list);
241 class_addanything(inlet_class, inlet_anything);
242
243 pointerinlet_class = class_new(gensym("inlet"), 0, 0,
244 sizeof(t_inlet), CLASS_PD, 0);
245 class_addpointer(pointerinlet_class, pointerinlet_pointer);
246
247 floatinlet_class = class_new(gensym("inlet"), 0, 0,
248 sizeof(t_inlet), CLASS_PD, 0);
249 class_addfloat(floatinlet_class, (t_method)floatinlet_float);
250
251 symbolinlet_class = class_new(gensym("inlet"), 0, 0,
252 sizeof(t_inlet), CLASS_PD, 0);
253 class_addsymbol(symbolinlet_class, symbolinlet_symbol);
254
255}
256
257/* --------------------------- outlets ------------------------------ */
258
259static char *stacklimit, *topstack;
260#define STACKSIZE 1000000
261static int outlet_eventno;
262
263 /* set a stack limit (on each incoming event that can set off messages)
264 for the outlet functions to check to prevent stack overflow from message
265 recursion */
266void outlet_setstacklim(void)
267{
268 char c;
269 topstack = &c;
270 stacklimit = (&c) - STACKSIZE;
271 outlet_eventno++;
272}
273
274 /* get a number unique to the (clock, MIDI, GUI, etc.) event we're on */
275int sched_geteventno( void)
276{
277 return (outlet_eventno);
278}
279
280struct _outconnect
281{
282 struct _outconnect *oc_next;
283 t_pd *oc_to;
284};
285
286struct _outlet
287{
288 t_object *o_owner;
289 struct _outlet *o_next;
290 t_outconnect *o_connections;
291 t_symbol *o_sym;
292};
293
294t_outlet *outlet_new(t_object *owner, t_symbol *s)
295{
296 t_outlet *x = (t_outlet *)getbytes(sizeof(*x)), *y, *y2;
297 x->o_owner = owner;
298 x->o_next = 0;
299 if (y = owner->ob_outlet)
300 {
301 while (y2 = y->o_next) y = y2;
302 y->o_next = x;
303 }
304 else owner->ob_outlet = x;
305 x->o_connections = 0;
306 x->o_sym = s;
307 return (x);
308}
309
310static void outlet_stackerror(t_outlet *x)
311{
312 pd_error(x->o_owner, "stack overflow");
313 stacklimit = topstack;
314}
315
316void outlet_bang(t_outlet *x)
317{
318 t_outconnect *oc;
319 char c;
320 if (&c < stacklimit)
321 outlet_stackerror(x);
322 else for (oc = x->o_connections; oc; oc = oc->oc_next)
323 pd_bang(oc->oc_to);
324}
325
326void outlet_pointer(t_outlet *x, t_gpointer *gp)
327{
328 t_outconnect *oc;
329 t_gpointer gpointer;
330 char c;
331 if (&c < stacklimit)
332 outlet_stackerror(x);
333 else
334 {
335#if 0
336 gpointer_copy(gp, &gpointer);
337 for (oc = x->o_connections; oc; oc = oc->oc_next)
338 pd_pointer(oc->oc_to, &gpointer);
339 gpointer_unset(&gpointer);
340#else
341 gpointer = *gp;
342 for (oc = x->o_connections; oc; oc = oc->oc_next)
343 pd_pointer(oc->oc_to, &gpointer);
344#endif
345 }
346}
347
348void outlet_float(t_outlet *x, t_float f)
349{
350 t_outconnect *oc;
351 char c;
352 if (&c < stacklimit)
353 outlet_stackerror(x);
354 else for (oc = x->o_connections; oc; oc = oc->oc_next)
355 pd_float(oc->oc_to, f);
356}
357
358void outlet_symbol(t_outlet *x, t_symbol *s)
359{
360 t_outconnect *oc;
361 char c;
362 if (&c < stacklimit)
363 outlet_stackerror(x);
364 else for (oc = x->o_connections; oc; oc = oc->oc_next)
365 pd_symbol(oc->oc_to, s);
366}
367
368void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
369{
370 t_outconnect *oc;
371 char c;
372 if (&c < stacklimit)
373 outlet_stackerror(x);
374 else for (oc = x->o_connections; oc; oc = oc->oc_next)
375 pd_list(oc->oc_to, s, argc, argv);
376}
377
378void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
379{
380 t_outconnect *oc;
381 char c;
382 if (&c < stacklimit)
383 outlet_stackerror(x);
384 else for (oc = x->o_connections; oc; oc = oc->oc_next)
385 typedmess(oc->oc_to, s, argc, argv);
386}
387
388 /* get the outlet's declared symbol */
389t_symbol *outlet_getsymbol(t_outlet *x)
390{
391 return (x->o_sym);
392}
393
394void outlet_free(t_outlet *x)
395{
396 t_object *y = x->o_owner;
397 t_outlet *x2;
398 if (y->ob_outlet == x) y->ob_outlet = x->o_next;
399 else for (x2 = y->ob_outlet; x2; x2 = x2->o_next)
400 if (x2->o_next == x)
401 {
402 x2->o_next = x->o_next;
403 break;
404 }
405 t_freebytes(x, sizeof(*x));
406}
407
408t_outconnect *obj_connect(t_object *source, int outno,
409 t_object *sink, int inno)
410{
411 t_inlet *i;
412 t_outlet *o;
413 t_pd *to;
414 t_outconnect *oc, *oc2;
415
416 for (o = source->ob_outlet; o && outno; o = o->o_next, outno--) ;
417 if (!o) return (0);
418
419 if (sink->ob_pd->c_firstin)
420 {
421 if (!inno)
422 {
423 to = &sink->ob_pd;
424 goto doit;
425 }
426 else inno--;
427 }
428 for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
429 if (!i) return (0);
430 to = &i->i_pd;
431doit:
432 oc = (t_outconnect *)t_getbytes(sizeof(*oc));
433 oc->oc_next = 0;
434 oc->oc_to = to;
435 /* append it to the end of the list */
436 /* LATER we might cache the last "oc" to make this faster. */
437 if ((oc2 = o->o_connections))
438 {
439 while (oc2->oc_next) oc2 = oc2->oc_next;
440 oc2->oc_next = oc;
441 }
442 else o->o_connections = oc;
443 if (o->o_sym == &s_signal) canvas_update_dsp();
444
445 return (oc);
446}
447
448void obj_disconnect(t_object *source, int outno, t_object *sink, int inno)
449{
450 t_inlet *i;
451 t_outlet *o;
452 t_pd *to;
453 t_outconnect *oc, *oc2;
454
455 for (o = source->ob_outlet; o && outno; o = o->o_next, outno--)
456 if (!o) return;
457 if (sink->ob_pd->c_firstin)
458 {
459 if (!inno)
460 {
461 to = &sink->ob_pd;
462 goto doit;
463 }
464 else inno--;
465 }
466 for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
467 if (!i) return;
468 to = &i->i_pd;
469doit:
470 if (!(oc = o->o_connections)) return;
471 if (oc->oc_to == to)
472 {
473 o->o_connections = oc->oc_next;
474 freebytes(oc, sizeof(*oc));
475 goto done;
476 }
477 while (oc2 = oc->oc_next)
478 {
479 if (oc2->oc_to == to)
480 {
481 oc->oc_next = oc2->oc_next;
482 freebytes(oc2, sizeof(*oc2));
483 goto done;
484 }
485 oc = oc2;
486 }
487done:
488 if (o->o_sym == &s_signal) canvas_update_dsp();
489}
490
491/* ------ traversal routines for code that can't see our structures ------ */
492
493int obj_noutlets(t_object *x)
494{
495 int n;
496 t_outlet *o;
497 for (o = x->ob_outlet, n = 0; o; o = o->o_next) n++;
498 return (n);
499}
500
501int obj_ninlets(t_object *x)
502{
503 int n;
504 t_inlet *i;
505 for (i = x->ob_inlet, n = 0; i; i = i->i_next) n++;
506 if (x->ob_pd->c_firstin) n++;
507 return (n);
508}
509
510t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout)
511{
512 t_outlet *o = x->ob_outlet;
513 while (nout-- && o) o = o->o_next;
514 *op = o;
515 if (o) return (o->o_connections);
516 else return (0);
517}
518
519t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect,
520 t_object **destp, t_inlet **inletp, int *whichp)
521{
522 t_pd *y;
523 y = lastconnect->oc_to;
524 if (ISINLET(y))
525 {
526 int n;
527 t_inlet *i = (t_inlet *)y, *i2;
528 t_object *dest = i->i_owner;
529 for (n = dest->ob_pd->c_firstin, i2 = dest->ob_inlet;
530 i2 && i2 != i; i2 = i2->i_next) n++;
531 *whichp = n;
532 *destp = dest;
533 *inletp = i;
534 }
535 else
536 {
537 *whichp = 0;
538 *inletp = 0;
539 *destp = ((t_object *)y);
540 }
541 return (lastconnect->oc_next);
542}
543
544 /* this one checks that a pd is indeed a patchable object, and returns
545 it, correctly typed, or zero if the check failed. */
546t_object *pd_checkobject(t_pd *x)
547{
548 if ((*x)->c_patchable) return ((t_object *)x);
549 else return (0);
550}
551
552 /* move an inlet or outlet to the head of the list */
553void obj_moveinletfirst(t_object *x, t_inlet *i)
554{
555 t_inlet *i2;
556 if (x->ob_inlet == i) return;
557 else for (i2 = x->ob_inlet; i2; i2 = i2->i_next)
558 if (i2->i_next == i)
559 {
560 i2->i_next = i->i_next;
561 i->i_next = x->ob_inlet;
562 x->ob_inlet = i;
563 return;
564 }
565}
566
567void obj_moveoutletfirst(t_object *x, t_outlet *o)
568{
569 t_outlet *o2;
570 if (x->ob_outlet == o) return;
571 else for (o2 = x->ob_outlet; o2; o2 = o2->o_next)
572 if (o2->o_next == o)
573 {
574 o2->o_next = o->o_next;
575 o->o_next = x->ob_outlet;
576 x->ob_outlet = o;
577 return;
578 }
579}
580
581 /* routines for DSP sorting, which are used in d_ugen.c and g_canvas.c */
582 /* LATER try to consolidate all the slightly different routines. */
583
584int obj_nsiginlets(t_object *x)
585{
586 int n;
587 t_inlet *i;
588 for (i = x->ob_inlet, n = 0; i; i = i->i_next)
589 if (i->i_symfrom == &s_signal) n++;
590 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin) n++;
591 return (n);
592}
593
594 /* get the index, among signal inlets, of the mth inlet overall */
595int obj_siginletindex(t_object *x, int m)
596{
597 int n = 0;
598 t_inlet *i;
599 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
600 {
601 if (!m--) return (0);
602 n++;
603 }
604 for (i = x->ob_inlet; i; i = i->i_next, m--)
605 if (i->i_symfrom == &s_signal)
606 {
607 if (m == 0) return (n);
608 n++;
609 }
610 return (-1);
611}
612
613int obj_issignalinlet(t_object *x, int m)
614{
615 t_inlet *i;
616 if (x->ob_pd->c_firstin)
617 {
618 if (!m)
619 return (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin);
620 else m--;
621 }
622 for (i = x->ob_inlet; i && m; i = i->i_next, m--)
623 ;
624 return (i && (i->i_symfrom == &s_signal));
625}
626
627int obj_nsigoutlets(t_object *x)
628{
629 int n;
630 t_outlet *o;
631 for (o = x->ob_outlet, n = 0; o; o = o->o_next)
632 if (o->o_sym == &s_signal) n++;
633 return (n);
634}
635
636int obj_sigoutletindex(t_object *x, int m)
637{
638 int n;
639 t_outlet *o2;
640 for (o2 = x->ob_outlet, n = 0; o2; o2 = o2->o_next, m--)
641 if (o2->o_sym == &s_signal)
642 {
643 if (m == 0) return (n);
644 n++;
645 }
646 return (-1);
647}
648
649int obj_issignaloutlet(t_object *x, int m)
650{
651 int n;
652 t_outlet *o2;
653 for (o2 = x->ob_outlet, n = 0; o2 && m--; o2 = o2->o_next);
654 return (o2 && (o2->o_sym == &s_signal));
655}
656
657t_sample *obj_findsignalscalar(t_object *x, int m)
658{
659 int n = 0;
660 t_inlet *i;
661 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
662 {
663 if (!m--)
664 return (x->ob_pd->c_floatsignalin > 0 ?
665 (t_sample *)(((char *)x) + x->ob_pd->c_floatsignalin) : 0);
666 n++;
667 }
668 for (i = x->ob_inlet; i; i = i->i_next, m--)
669 if (i->i_symfrom == &s_signal)
670 {
671 if (m == 0)
672 return (&i->i_un.iu_floatsignalvalue);
673 n++;
674 }
675 return (0);
676}
677
678/* and these are only used in g_io.c... */
679
680int inlet_getsignalindex(t_inlet *x)
681{
682 int n = 0;
683 t_inlet *i;
684 for (i = x->i_owner->ob_inlet, n = 0; i && i != x; i = i->i_next)
685 if (i->i_symfrom == &s_signal) n++;
686 return (n);
687}
688
689int outlet_getsignalindex(t_outlet *x)
690{
691 int n = 0;
692 t_outlet *o;
693 for (o = x->o_owner->ob_outlet, n = 0; o && o != x; o = o->o_next)
694 if (o->o_sym == &s_signal) n++;
695 return (n);
696}
697
698/* Copyright (c) 1997-1999 Miller Puckette.
699* For information on usage and redistribution, and for a DISCLAIMER OF ALL
700* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
701
702/* this file handles Max-style patchable objects, i.e., objects which
703can interconnect via inlets and outlets; also, the (terse) generic
704behavior for "gobjs" appears at the end of this file. */
705
706#include "m_pd.h"
707#include "m_imp.h"
708
709union inletunion
710{
711 t_symbol *iu_symto;
712 t_gpointer *iu_pointerslot;
713 t_float *iu_floatslot;
714 t_symbol **iu_symslot;
715 t_sample iu_floatsignalvalue;
716};
717
718struct _inlet
719{
720 t_pd i_pd;
721 struct _inlet *i_next;
722 t_object *i_owner;
723 t_pd *i_dest;
724 t_symbol *i_symfrom;
725 union inletunion i_un;
726};
727
728#define i_symto i_un.iu_symto
729#define i_pointerslot i_un.iu_pointerslot
730#define i_floatslot i_un.iu_floatslot
731#define i_symslot i_un.iu_symslot
732
733static t_class *inlet_class, *pointerinlet_class, *floatinlet_class,
734 *symbolinlet_class;
735
736#define ISINLET(pd) ((*(pd) == inlet_class) || \
737 (*(pd) == pointerinlet_class) || \
738 (*(pd) == floatinlet_class) || \
739 (*(pd) == symbolinlet_class))
740
741/* --------------------- generic inlets ala max ------------------ */
742
743t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2)
744{
745 t_inlet *x = (t_inlet *)pd_new(inlet_class), *y, *y2;
746 x->i_owner = owner;
747 x->i_dest = dest;
748 if (s1 == &s_signal)
749 x->i_un.iu_floatsignalvalue = 0;
750 else x->i_symto = s2;
751 x->i_symfrom = s1;
752 x->i_next = 0;
753 if (y = owner->ob_inlet)
754 {
755 while (y2 = y->i_next) y = y2;
756 y->i_next = x;
757 }
758 else owner->ob_inlet = x;
759 return (x);
760}
761
762static void inlet_wrong(t_inlet *x, t_symbol *s)
763{
764 pd_error(x->i_owner, "inlet: expected '%s' but got '%s'",
765 x->i_symfrom->s_name, s->s_name);
766}
767
768 /* LATER figure out how to make these efficient: */
769static void inlet_bang(t_inlet *x)
770{
771 if (x->i_symfrom == &s_bang)
772 pd_vmess(x->i_dest, x->i_symto, "");
773 else if (!x->i_symfrom) pd_bang(x->i_dest);
774 else inlet_wrong(x, &s_bang);
775}
776
777static void inlet_pointer(t_inlet *x, t_gpointer *gp)
778{
779 if (x->i_symfrom == &s_pointer)
780 pd_vmess(x->i_dest, x->i_symto, "p", gp);
781 else if (!x->i_symfrom) pd_pointer(x->i_dest, gp);
782 else inlet_wrong(x, &s_pointer);
783}
784
785static void inlet_float(t_inlet *x, t_float f)
786{
787 if (x->i_symfrom == &s_float)
788 pd_vmess(x->i_dest, x->i_symto, "f", (t_floatarg)f);
789 else if (x->i_symfrom == &s_signal)
790 x->i_un.iu_floatsignalvalue = ftofix(f);
791 else if (!x->i_symfrom)
792 pd_float(x->i_dest, f);
793 else inlet_wrong(x, &s_float);
794}
795
796static void inlet_symbol(t_inlet *x, t_symbol *s)
797{
798 if (x->i_symfrom == &s_symbol)
799 pd_vmess(x->i_dest, x->i_symto, "s", s);
800 else if (!x->i_symfrom) pd_symbol(x->i_dest, s);
801 else inlet_wrong(x, &s_symbol);
802}
803
804static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
805{
806 t_atom at;
807 if (x->i_symfrom == &s_list || x->i_symfrom == &s_float
808 || x->i_symfrom == &s_symbol || x->i_symfrom == &s_pointer)
809 typedmess(x->i_dest, x->i_symto, argc, argv);
810 else if (!x->i_symfrom) pd_list(x->i_dest, s, argc, argv);
811 else inlet_wrong(x, &s_list);
812}
813
814static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
815{
816 if (x->i_symfrom == s)
817 typedmess(x->i_dest, x->i_symto, argc, argv);
818 else if (!x->i_symfrom)
819 typedmess(x->i_dest, s, argc, argv);
820 else inlet_wrong(x, s);
821}
822
823void inlet_free(t_inlet *x)
824{
825 t_object *y = x->i_owner;
826 t_inlet *x2;
827 if (y->ob_inlet == x) y->ob_inlet = x->i_next;
828 else for (x2 = y->ob_inlet; x2; x2 = x2->i_next)
829 if (x2->i_next == x)
830 {
831 x2->i_next = x->i_next;
832 break;
833 }
834 t_freebytes(x, sizeof(*x));
835}
836
837/* ----- pointerinlets, floatinlets, syminlets: optimized inlets ------- */
838
839static void pointerinlet_pointer(t_inlet *x, t_gpointer *gp)
840{
841 gpointer_unset(x->i_pointerslot);
842 *(x->i_pointerslot) = *gp;
843 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
844}
845
846t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp)
847{
848 t_inlet *x = (t_inlet *)pd_new(pointerinlet_class), *y, *y2;
849 x->i_owner = owner;
850 x->i_dest = 0;
851 x->i_symfrom = &s_pointer;
852 x->i_pointerslot = gp;
853 x->i_next = 0;
854 if (y = owner->ob_inlet)
855 {
856 while (y2 = y->i_next) y = y2;
857 y->i_next = x;
858 }
859 else owner->ob_inlet = x;
860 return (x);
861}
862
863static void floatinlet_float(t_inlet *x, t_float f)
864{
865 *(x->i_floatslot) = f;
866}
867
868t_inlet *floatinlet_new(t_object *owner, t_float *fp)
869{
870 t_inlet *x = (t_inlet *)pd_new(floatinlet_class), *y, *y2;
871 x->i_owner = owner;
872 x->i_dest = 0;
873 x->i_symfrom = &s_float;
874 x->i_floatslot = fp;
875 x->i_next = 0;
876 if (y = owner->ob_inlet)
877 {
878 while (y2 = y->i_next) y = y2;
879 y->i_next = x;
880 }
881 else owner->ob_inlet = x;
882 return (x);
883}
884
885static void symbolinlet_symbol(t_inlet *x, t_symbol *s)
886{
887 *(x->i_symslot) = s;
888}
889
890t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp)
891{
892 t_inlet *x = (t_inlet *)pd_new(symbolinlet_class), *y, *y2;
893 x->i_owner = owner;
894 x->i_dest = 0;
895 x->i_symfrom = &s_symbol;
896 x->i_symslot = sp;
897 x->i_next = 0;
898 if (y = owner->ob_inlet)
899 {
900 while (y2 = y->i_next) y = y2;
901 y->i_next = x;
902 }
903 else owner->ob_inlet = x;
904 return (x);
905}
906
907/* ---------------------- routine to handle lists ---------------------- */
908
909 /* objects interpret lists by feeding them to the individual inlets.
910 Before you call this check that the object doesn't have a more
911 specific way to handle lists. */
912void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv)
913{
914 t_atom *ap;
915 int count;
916 t_inlet *ip = ((t_object *)x)->ob_inlet;
917 if (!argc) return;
918 for (count = argc-1, ap = argv+1; ip && count--; ap++, ip = ip->i_next)
919 {
920 if (ap->a_type == A_POINTER) pd_pointer(&ip->i_pd, ap->a_w.w_gpointer);
921 else if (ap->a_type == A_FLOAT) pd_float(&ip->i_pd, ap->a_w.w_float);
922 else pd_symbol(&ip->i_pd, ap->a_w.w_symbol);
923 }
924 if (argv->a_type == A_POINTER) pd_pointer(&x->ob_pd, argv->a_w.w_gpointer);
925 else if (argv->a_type == A_FLOAT) pd_float(&x->ob_pd, argv->a_w.w_float);
926 else pd_symbol(&x->ob_pd, argv->a_w.w_symbol);
927}
928
929void obj_init(void)
930{
931 inlet_class = class_new(gensym("inlet"), 0, 0,
932 sizeof(t_inlet), CLASS_PD, 0);
933 class_addbang(inlet_class, inlet_bang);
934 class_addpointer(inlet_class, inlet_pointer);
935 class_addfloat(inlet_class, inlet_float);
936 class_addsymbol(inlet_class, inlet_symbol);
937 class_addlist(inlet_class, inlet_list);
938 class_addanything(inlet_class, inlet_anything);
939
940 pointerinlet_class = class_new(gensym("inlet"), 0, 0,
941 sizeof(t_inlet), CLASS_PD, 0);
942 class_addpointer(pointerinlet_class, pointerinlet_pointer);
943
944 floatinlet_class = class_new(gensym("inlet"), 0, 0,
945 sizeof(t_inlet), CLASS_PD, 0);
946 class_addfloat(floatinlet_class, (t_method)floatinlet_float);
947
948 symbolinlet_class = class_new(gensym("inlet"), 0, 0,
949 sizeof(t_inlet), CLASS_PD, 0);
950 class_addsymbol(symbolinlet_class, symbolinlet_symbol);
951
952}
953
954/* --------------------------- outlets ------------------------------ */
955
956static char *stacklimit, *topstack;
957#define STACKSIZE 1000000
958static int outlet_eventno;
959
960 /* set a stack limit (on each incoming event that can set off messages)
961 for the outlet functions to check to prevent stack overflow from message
962 recursion */
963void outlet_setstacklim(void)
964{
965 char c;
966 topstack = &c;
967 stacklimit = (&c) - STACKSIZE;
968 outlet_eventno++;
969}
970
971 /* get a number unique to the (clock, MIDI, GUI, etc.) event we're on */
972int sched_geteventno( void)
973{
974 return (outlet_eventno);
975}
976
977struct _outconnect
978{
979 struct _outconnect *oc_next;
980 t_pd *oc_to;
981};
982
983struct _outlet
984{
985 t_object *o_owner;
986 struct _outlet *o_next;
987 t_outconnect *o_connections;
988 t_symbol *o_sym;
989};
990
991t_outlet *outlet_new(t_object *owner, t_symbol *s)
992{
993 t_outlet *x = (t_outlet *)getbytes(sizeof(*x)), *y, *y2;
994 x->o_owner = owner;
995 x->o_next = 0;
996 if (y = owner->ob_outlet)
997 {
998 while (y2 = y->o_next) y = y2;
999 y->o_next = x;
1000 }
1001 else owner->ob_outlet = x;
1002 x->o_connections = 0;
1003 x->o_sym = s;
1004 return (x);
1005}
1006
1007static void outlet_stackerror(t_outlet *x)
1008{
1009 pd_error(x->o_owner, "stack overflow");
1010 stacklimit = topstack;
1011}
1012
1013void outlet_bang(t_outlet *x)
1014{
1015 t_outconnect *oc;
1016 char c;
1017 if (&c < stacklimit)
1018 outlet_stackerror(x);
1019 else for (oc = x->o_connections; oc; oc = oc->oc_next)
1020 pd_bang(oc->oc_to);
1021}
1022
1023void outlet_pointer(t_outlet *x, t_gpointer *gp)
1024{
1025 t_outconnect *oc;
1026 t_gpointer gpointer;
1027 char c;
1028 if (&c < stacklimit)
1029 outlet_stackerror(x);
1030 else
1031 {
1032#if 0
1033 gpointer_copy(gp, &gpointer);
1034 for (oc = x->o_connections; oc; oc = oc->oc_next)
1035 pd_pointer(oc->oc_to, &gpointer);
1036 gpointer_unset(&gpointer);
1037#else
1038 gpointer = *gp;
1039 for (oc = x->o_connections; oc; oc = oc->oc_next)
1040 pd_pointer(oc->oc_to, &gpointer);
1041#endif
1042 }
1043}
1044
1045void outlet_float(t_outlet *x, t_float f)
1046{
1047 t_outconnect *oc;
1048 char c;
1049 if (&c < stacklimit)
1050 outlet_stackerror(x);
1051 else for (oc = x->o_connections; oc; oc = oc->oc_next)
1052 pd_float(oc->oc_to, f);
1053}
1054
1055void outlet_symbol(t_outlet *x, t_symbol *s)
1056{
1057 t_outconnect *oc;
1058 char c;
1059 if (&c < stacklimit)
1060 outlet_stackerror(x);
1061 else for (oc = x->o_connections; oc; oc = oc->oc_next)
1062 pd_symbol(oc->oc_to, s);
1063}
1064
1065void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
1066{
1067 t_outconnect *oc;
1068 char c;
1069 if (&c < stacklimit)
1070 outlet_stackerror(x);
1071 else for (oc = x->o_connections; oc; oc = oc->oc_next)
1072 pd_list(oc->oc_to, s, argc, argv);
1073}
1074
1075void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
1076{
1077 t_outconnect *oc;
1078 char c;
1079 if (&c < stacklimit)
1080 outlet_stackerror(x);
1081 else for (oc = x->o_connections; oc; oc = oc->oc_next)
1082 typedmess(oc->oc_to, s, argc, argv);
1083}
1084
1085 /* get the outlet's declared symbol */
1086t_symbol *outlet_getsymbol(t_outlet *x)
1087{
1088 return (x->o_sym);
1089}
1090
1091void outlet_free(t_outlet *x)
1092{
1093 t_object *y = x->o_owner;
1094 t_outlet *x2;
1095 if (y->ob_outlet == x) y->ob_outlet = x->o_next;
1096 else for (x2 = y->ob_outlet; x2; x2 = x2->o_next)
1097 if (x2->o_next == x)
1098 {
1099 x2->o_next = x->o_next;
1100 break;
1101 }
1102 t_freebytes(x, sizeof(*x));
1103}
1104
1105t_outconnect *obj_connect(t_object *source, int outno,
1106 t_object *sink, int inno)
1107{
1108 t_inlet *i;
1109 t_outlet *o;
1110 t_pd *to;
1111 t_outconnect *oc, *oc2;
1112
1113 for (o = source->ob_outlet; o && outno; o = o->o_next, outno--) ;
1114 if (!o) return (0);
1115
1116 if (sink->ob_pd->c_firstin)
1117 {
1118 if (!inno)
1119 {
1120 to = &sink->ob_pd;
1121 goto doit;
1122 }
1123 else inno--;
1124 }
1125 for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
1126 if (!i) return (0);
1127 to = &i->i_pd;
1128doit:
1129 oc = (t_outconnect *)t_getbytes(sizeof(*oc));
1130 oc->oc_next = 0;
1131 oc->oc_to = to;
1132 /* append it to the end of the list */
1133 /* LATER we might cache the last "oc" to make this faster. */
1134 if ((oc2 = o->o_connections))
1135 {
1136 while (oc2->oc_next) oc2 = oc2->oc_next;
1137 oc2->oc_next = oc;
1138 }
1139 else o->o_connections = oc;
1140 if (o->o_sym == &s_signal) canvas_update_dsp();
1141
1142 return (oc);
1143}
1144
1145void obj_disconnect(t_object *source, int outno, t_object *sink, int inno)
1146{
1147 t_inlet *i;
1148 t_outlet *o;
1149 t_pd *to;
1150 t_outconnect *oc, *oc2;
1151
1152 for (o = source->ob_outlet; o && outno; o = o->o_next, outno--)
1153 if (!o) return;
1154 if (sink->ob_pd->c_firstin)
1155 {
1156 if (!inno)
1157 {
1158 to = &sink->ob_pd;
1159 goto doit;
1160 }
1161 else inno--;
1162 }
1163 for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
1164 if (!i) return;
1165 to = &i->i_pd;
1166doit:
1167 if (!(oc = o->o_connections)) return;
1168 if (oc->oc_to == to)
1169 {
1170 o->o_connections = oc->oc_next;
1171 freebytes(oc, sizeof(*oc));
1172 goto done;
1173 }
1174 while (oc2 = oc->oc_next)
1175 {
1176 if (oc2->oc_to == to)
1177 {
1178 oc->oc_next = oc2->oc_next;
1179 freebytes(oc2, sizeof(*oc2));
1180 goto done;
1181 }
1182 oc = oc2;
1183 }
1184done:
1185 if (o->o_sym == &s_signal) canvas_update_dsp();
1186}
1187
1188/* ------ traversal routines for code that can't see our structures ------ */
1189
1190int obj_noutlets(t_object *x)
1191{
1192 int n;
1193 t_outlet *o;
1194 for (o = x->ob_outlet, n = 0; o; o = o->o_next) n++;
1195 return (n);
1196}
1197
1198int obj_ninlets(t_object *x)
1199{
1200 int n;
1201 t_inlet *i;
1202 for (i = x->ob_inlet, n = 0; i; i = i->i_next) n++;
1203 if (x->ob_pd->c_firstin) n++;
1204 return (n);
1205}
1206
1207t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout)
1208{
1209 t_outlet *o = x->ob_outlet;
1210 while (nout-- && o) o = o->o_next;
1211 *op = o;
1212 if (o) return (o->o_connections);
1213 else return (0);
1214}
1215
1216t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect,
1217 t_object **destp, t_inlet **inletp, int *whichp)
1218{
1219 t_pd *y;
1220 y = lastconnect->oc_to;
1221 if (ISINLET(y))
1222 {
1223 int n;
1224 t_inlet *i = (t_inlet *)y, *i2;
1225 t_object *dest = i->i_owner;
1226 for (n = dest->ob_pd->c_firstin, i2 = dest->ob_inlet;
1227 i2 && i2 != i; i2 = i2->i_next) n++;
1228 *whichp = n;
1229 *destp = dest;
1230 *inletp = i;
1231 }
1232 else
1233 {
1234 *whichp = 0;
1235 *inletp = 0;
1236 *destp = ((t_object *)y);
1237 }
1238 return (lastconnect->oc_next);
1239}
1240
1241 /* this one checks that a pd is indeed a patchable object, and returns
1242 it, correctly typed, or zero if the check failed. */
1243t_object *pd_checkobject(t_pd *x)
1244{
1245 if ((*x)->c_patchable) return ((t_object *)x);
1246 else return (0);
1247}
1248
1249 /* move an inlet or outlet to the head of the list */
1250void obj_moveinletfirst(t_object *x, t_inlet *i)
1251{
1252 t_inlet *i2;
1253 if (x->ob_inlet == i) return;
1254 else for (i2 = x->ob_inlet; i2; i2 = i2->i_next)
1255 if (i2->i_next == i)
1256 {
1257 i2->i_next = i->i_next;
1258 i->i_next = x->ob_inlet;
1259 x->ob_inlet = i;
1260 return;
1261 }
1262}
1263
1264void obj_moveoutletfirst(t_object *x, t_outlet *o)
1265{
1266 t_outlet *o2;
1267 if (x->ob_outlet == o) return;
1268 else for (o2 = x->ob_outlet; o2; o2 = o2->o_next)
1269 if (o2->o_next == o)
1270 {
1271 o2->o_next = o->o_next;
1272 o->o_next = x->ob_outlet;
1273 x->ob_outlet = o;
1274 return;
1275 }
1276}
1277
1278 /* routines for DSP sorting, which are used in d_ugen.c and g_canvas.c */
1279 /* LATER try to consolidate all the slightly different routines. */
1280
1281int obj_nsiginlets(t_object *x)
1282{
1283 int n;
1284 t_inlet *i;
1285 for (i = x->ob_inlet, n = 0; i; i = i->i_next)
1286 if (i->i_symfrom == &s_signal) n++;
1287 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin) n++;
1288 return (n);
1289}
1290
1291 /* get the index, among signal inlets, of the mth inlet overall */
1292int obj_siginletindex(t_object *x, int m)
1293{
1294 int n = 0;
1295 t_inlet *i;
1296 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
1297 {
1298 if (!m--) return (0);
1299 n++;
1300 }
1301 for (i = x->ob_inlet; i; i = i->i_next, m--)
1302 if (i->i_symfrom == &s_signal)
1303 {
1304 if (m == 0) return (n);
1305 n++;
1306 }
1307 return (-1);
1308}
1309
1310int obj_issignalinlet(t_object *x, int m)
1311{
1312 t_inlet *i;
1313 if (x->ob_pd->c_firstin)
1314 {
1315 if (!m)
1316 return (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin);
1317 else m--;
1318 }
1319 for (i = x->ob_inlet; i && m; i = i->i_next, m--)
1320 ;
1321 return (i && (i->i_symfrom == &s_signal));
1322}
1323
1324int obj_nsigoutlets(t_object *x)
1325{
1326 int n;
1327 t_outlet *o;
1328 for (o = x->ob_outlet, n = 0; o; o = o->o_next)
1329 if (o->o_sym == &s_signal) n++;
1330 return (n);
1331}
1332
1333int obj_sigoutletindex(t_object *x, int m)
1334{
1335 int n;
1336 t_outlet *o2;
1337 for (o2 = x->ob_outlet, n = 0; o2; o2 = o2->o_next, m--)
1338 if (o2->o_sym == &s_signal)
1339 {
1340 if (m == 0) return (n);
1341 n++;
1342 }
1343 return (-1);
1344}
1345
1346int obj_issignaloutlet(t_object *x, int m)
1347{
1348 int n;
1349 t_outlet *o2;
1350 for (o2 = x->ob_outlet, n = 0; o2 && m--; o2 = o2->o_next);
1351 return (o2 && (o2->o_sym == &s_signal));
1352}
1353
1354t_sample *obj_findsignalscalar(t_object *x, int m)
1355{
1356 int n = 0;
1357 t_inlet *i;
1358 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
1359 {
1360 if (!m--)
1361 return (x->ob_pd->c_floatsignalin > 0 ?
1362 (t_sample *)(((char *)x) + x->ob_pd->c_floatsignalin) : 0);
1363 n++;
1364 }
1365 for (i = x->ob_inlet; i; i = i->i_next, m--)
1366 if (i->i_symfrom == &s_signal)
1367 {
1368 if (m == 0)
1369 return (&i->i_un.iu_floatsignalvalue);
1370 n++;
1371 }
1372 return (0);
1373}
1374
1375/* and these are only used in g_io.c... */
1376
1377int inlet_getsignalindex(t_inlet *x)
1378{
1379 int n = 0;
1380 t_inlet *i;
1381 for (i = x->i_owner->ob_inlet, n = 0; i && i != x; i = i->i_next)
1382 if (i->i_symfrom == &s_signal) n++;
1383 return (n);
1384}
1385
1386int outlet_getsignalindex(t_outlet *x)
1387{
1388 int n = 0;
1389 t_outlet *o;
1390 for (o = x->o_owner->ob_outlet, n = 0; o && o != x; o = o->o_next)
1391 if (o->o_sym == &s_signal) n++;
1392 return (n);
1393}
1394