Fix some greedy sed changes in imported code. Also provide a sys/types.h for compatib...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / m_obj.c
blobfa17a9052bdbbb3ddb8145181c949d7d7d0f70ef
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. */
9 #include "m_pd.h"
10 #include "m_imp.h"
12 union inletunion
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;
21 struct _inlet
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;
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,
37 *symbolinlet_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;
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))
58 while((y2 = y->i_next)) y = y2;
59 y->i_next = x;
61 else owner->ob_inlet = x;
62 return (x);
65 static void inlet_wrong(t_inlet *x, t_symbol *s)
67 pd_error(x->i_owner, "inlet: expected '%s' but got '%s'",
68 x->i_symfrom->s_name, s->s_name);
71 /* LATER figure out how to make these efficient: */
72 static void inlet_bang(t_inlet *x)
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);
80 static void inlet_pointer(t_inlet *x, t_gpointer *gp)
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);
88 static void inlet_float(t_inlet *x, t_float f)
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);
99 static void inlet_symbol(t_inlet *x, t_symbol *s)
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);
107 static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
109 #ifndef ROCKBOX
110 t_atom at;
111 #endif
112 if (x->i_symfrom == &s_list || x->i_symfrom == &s_float
113 || x->i_symfrom == &s_symbol || x->i_symfrom == &s_pointer)
114 typedmess(x->i_dest, x->i_symto, argc, argv);
115 else if (!x->i_symfrom) pd_list(x->i_dest, s, argc, argv);
116 else inlet_wrong(x, &s_list);
119 static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
121 if (x->i_symfrom == s)
122 typedmess(x->i_dest, x->i_symto, argc, argv);
123 else if (!x->i_symfrom)
124 typedmess(x->i_dest, s, argc, argv);
125 else inlet_wrong(x, s);
128 void inlet_free(t_inlet *x)
130 t_object *y = x->i_owner;
131 t_inlet *x2;
132 if (y->ob_inlet == x) y->ob_inlet = x->i_next;
133 else for (x2 = y->ob_inlet; x2; x2 = x2->i_next)
134 if (x2->i_next == x)
136 x2->i_next = x->i_next;
137 break;
139 t_freebytes(x, sizeof(*x));
142 /* ----- pointerinlets, floatinlets, syminlets: optimized inlets ------- */
144 static void pointerinlet_pointer(t_inlet *x, t_gpointer *gp)
146 gpointer_unset(x->i_pointerslot);
147 *(x->i_pointerslot) = *gp;
148 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
151 t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp)
153 t_inlet *x = (t_inlet *)pd_new(pointerinlet_class), *y, *y2;
154 x->i_owner = owner;
155 x->i_dest = 0;
156 x->i_symfrom = &s_pointer;
157 x->i_pointerslot = gp;
158 x->i_next = 0;
159 if((y = owner->ob_inlet))
161 while((y2 = y->i_next)) y = y2;
162 y->i_next = x;
164 else owner->ob_inlet = x;
165 return (x);
168 static void floatinlet_float(t_inlet *x, t_float f)
170 *(x->i_floatslot) = f;
173 t_inlet *floatinlet_new(t_object *owner, t_float *fp)
175 t_inlet *x = (t_inlet *)pd_new(floatinlet_class), *y, *y2;
176 x->i_owner = owner;
177 x->i_dest = 0;
178 x->i_symfrom = &s_float;
179 x->i_floatslot = fp;
180 x->i_next = 0;
181 if((y = owner->ob_inlet))
183 while((y2 = y->i_next)) y = y2;
184 y->i_next = x;
186 else owner->ob_inlet = x;
187 return (x);
190 static void symbolinlet_symbol(t_inlet *x, t_symbol *s)
192 *(x->i_symslot) = s;
195 t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp)
197 t_inlet *x = (t_inlet *)pd_new(symbolinlet_class), *y, *y2;
198 x->i_owner = owner;
199 x->i_dest = 0;
200 x->i_symfrom = &s_symbol;
201 x->i_symslot = sp;
202 x->i_next = 0;
203 if((y = owner->ob_inlet))
205 while((y2 = y->i_next)) y = y2;
206 y->i_next = x;
208 else owner->ob_inlet = x;
209 return (x);
212 /* ---------------------- routine to handle lists ---------------------- */
214 /* objects interpret lists by feeding them to the individual inlets.
215 Before you call this check that the object doesn't have a more
216 specific way to handle lists. */
217 void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv)
219 t_atom *ap;
220 int count;
221 t_inlet *ip = ((t_object *)x)->ob_inlet;
223 #ifdef ROCKBOX
224 (void) s;
225 #endif
227 if (!argc) return;
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);
239 void obj_init(void)
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);
254 floatinlet_class = class_new(gensym("inlet"), 0, 0,
255 sizeof(t_inlet), CLASS_PD, 0);
256 class_addfloat(floatinlet_class, (t_method)floatinlet_float);
258 symbolinlet_class = class_new(gensym("inlet"), 0, 0,
259 sizeof(t_inlet), CLASS_PD, 0);
260 class_addsymbol(symbolinlet_class, symbolinlet_symbol);
264 /* --------------------------- outlets ------------------------------ */
266 static char *stacklimit, *topstack;
267 #define STACKSIZE 1000000
268 static int outlet_eventno;
270 /* set a stack limit (on each incoming event that can set off messages)
271 for the outlet functions to check to prevent stack overflow from message
272 recursion */
273 void outlet_setstacklim(void)
275 char c;
276 topstack = &c;
277 stacklimit = (&c) - STACKSIZE;
278 outlet_eventno++;
281 /* get a number unique to the (clock, MIDI, GUI, etc.) event we're on */
282 int sched_geteventno( void)
284 return (outlet_eventno);
287 struct _outconnect
289 struct _outconnect *oc_next;
290 t_pd *oc_to;
293 struct _outlet
295 t_object *o_owner;
296 struct _outlet *o_next;
297 t_outconnect *o_connections;
298 t_symbol *o_sym;
301 t_outlet *outlet_new(t_object *owner, t_symbol *s)
303 t_outlet *x = (t_outlet *)getbytes(sizeof(*x)), *y, *y2;
304 x->o_owner = owner;
305 x->o_next = 0;
306 if((y = owner->ob_outlet))
308 while((y2 = y->o_next)) y = y2;
309 y->o_next = x;
311 else owner->ob_outlet = x;
312 x->o_connections = 0;
313 x->o_sym = s;
314 return (x);
317 static void outlet_stackerror(t_outlet *x)
319 pd_error(x->o_owner, "stack overflow");
320 stacklimit = topstack;
323 void outlet_bang(t_outlet *x)
325 t_outconnect *oc;
326 char c;
327 if (&c < stacklimit)
328 outlet_stackerror(x);
329 else for (oc = x->o_connections; oc; oc = oc->oc_next)
330 pd_bang(oc->oc_to);
333 void outlet_pointer(t_outlet *x, t_gpointer *gp)
335 t_outconnect *oc;
336 t_gpointer gpointer;
337 char c;
338 if (&c < stacklimit)
339 outlet_stackerror(x);
340 else
342 #if 0
343 gpointer_copy(gp, &gpointer);
344 for (oc = x->o_connections; oc; oc = oc->oc_next)
345 pd_pointer(oc->oc_to, &gpointer);
346 gpointer_unset(&gpointer);
347 #else
348 gpointer = *gp;
349 for (oc = x->o_connections; oc; oc = oc->oc_next)
350 pd_pointer(oc->oc_to, &gpointer);
351 #endif
355 void outlet_float(t_outlet *x, t_float f)
357 t_outconnect *oc;
358 char c;
359 if (&c < stacklimit)
360 outlet_stackerror(x);
361 else for (oc = x->o_connections; oc; oc = oc->oc_next)
362 pd_float(oc->oc_to, f);
365 void outlet_symbol(t_outlet *x, t_symbol *s)
367 t_outconnect *oc;
368 char c;
369 if (&c < stacklimit)
370 outlet_stackerror(x);
371 else for (oc = x->o_connections; oc; oc = oc->oc_next)
372 pd_symbol(oc->oc_to, s);
375 void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
377 t_outconnect *oc;
378 char c;
379 if (&c < stacklimit)
380 outlet_stackerror(x);
381 else for (oc = x->o_connections; oc; oc = oc->oc_next)
382 pd_list(oc->oc_to, s, argc, argv);
385 void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
387 t_outconnect *oc;
388 char c;
389 if (&c < stacklimit)
390 outlet_stackerror(x);
391 else for (oc = x->o_connections; oc; oc = oc->oc_next)
392 typedmess(oc->oc_to, s, argc, argv);
395 /* get the outlet's declared symbol */
396 t_symbol *outlet_getsymbol(t_outlet *x)
398 return (x->o_sym);
401 void outlet_free(t_outlet *x)
403 t_object *y = x->o_owner;
404 t_outlet *x2;
405 if (y->ob_outlet == x) y->ob_outlet = x->o_next;
406 else for (x2 = y->ob_outlet; x2; x2 = x2->o_next)
407 if (x2->o_next == x)
409 x2->o_next = x->o_next;
410 break;
412 t_freebytes(x, sizeof(*x));
415 t_outconnect *obj_connect(t_object *source, int outno,
416 t_object *sink, int inno)
418 t_inlet *i;
419 t_outlet *o;
420 t_pd *to;
421 t_outconnect *oc, *oc2;
423 for (o = source->ob_outlet; o && outno; o = o->o_next, outno--) ;
424 if (!o) return (0);
426 if (sink->ob_pd->c_firstin)
428 if (!inno)
430 to = &sink->ob_pd;
431 goto doit;
433 else inno--;
435 for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
436 if (!i) return (0);
437 to = &i->i_pd;
438 doit:
439 oc = (t_outconnect *)t_getbytes(sizeof(*oc));
440 oc->oc_next = 0;
441 oc->oc_to = to;
442 /* append it to the end of the list */
443 /* LATER we might cache the last "oc" to make this faster. */
444 if ((oc2 = o->o_connections))
446 while (oc2->oc_next) oc2 = oc2->oc_next;
447 oc2->oc_next = oc;
449 else o->o_connections = oc;
450 if (o->o_sym == &s_signal) canvas_update_dsp();
452 return (oc);
455 void obj_disconnect(t_object *source, int outno, t_object *sink, int inno)
457 t_inlet *i;
458 t_outlet *o;
459 t_pd *to;
460 t_outconnect *oc, *oc2;
462 for (o = source->ob_outlet; o && outno; o = o->o_next, outno--)
463 if (!o) return;
464 if (sink->ob_pd->c_firstin)
466 if (!inno)
468 to = &sink->ob_pd;
469 goto doit;
471 else inno--;
473 for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
474 if (!i) return;
475 to = &i->i_pd;
476 doit:
477 if (!(oc = o->o_connections)) return;
478 if (oc->oc_to == to)
480 o->o_connections = oc->oc_next;
481 freebytes(oc, sizeof(*oc));
482 goto done;
484 while((oc2 = oc->oc_next))
486 if (oc2->oc_to == to)
488 oc->oc_next = oc2->oc_next;
489 freebytes(oc2, sizeof(*oc2));
490 goto done;
492 oc = oc2;
494 done:
495 if (o->o_sym == &s_signal) canvas_update_dsp();
498 /* ------ traversal routines for code that can't see our structures ------ */
500 int obj_noutlets(t_object *x)
502 int n;
503 t_outlet *o;
504 for (o = x->ob_outlet, n = 0; o; o = o->o_next) n++;
505 return (n);
508 int obj_ninlets(t_object *x)
510 int n;
511 t_inlet *i;
512 for (i = x->ob_inlet, n = 0; i; i = i->i_next) n++;
513 if (x->ob_pd->c_firstin) n++;
514 return (n);
517 t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout)
519 t_outlet *o = x->ob_outlet;
520 while (nout-- && o) o = o->o_next;
521 *op = o;
522 if (o) return (o->o_connections);
523 else return (0);
526 t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect,
527 t_object **destp, t_inlet **inletp, int *whichp)
529 t_pd *y;
530 y = lastconnect->oc_to;
531 if (ISINLET(y))
533 int n;
534 t_inlet *i = (t_inlet *)y, *i2;
535 t_object *dest = i->i_owner;
536 for (n = dest->ob_pd->c_firstin, i2 = dest->ob_inlet;
537 i2 && i2 != i; i2 = i2->i_next) n++;
538 *whichp = n;
539 *destp = dest;
540 *inletp = i;
542 else
544 *whichp = 0;
545 *inletp = 0;
546 *destp = ((t_object *)y);
548 return (lastconnect->oc_next);
551 /* this one checks that a pd is indeed a patchable object, and returns
552 it, correctly typed, or zero if the check failed. */
553 t_object *pd_checkobject(t_pd *x)
555 if ((*x)->c_patchable) return ((t_object *)x);
556 else return (0);
559 /* move an inlet or outlet to the head of the list */
560 void obj_moveinletfirst(t_object *x, t_inlet *i)
562 t_inlet *i2;
563 if (x->ob_inlet == i) return;
564 else for (i2 = x->ob_inlet; i2; i2 = i2->i_next)
565 if (i2->i_next == i)
567 i2->i_next = i->i_next;
568 i->i_next = x->ob_inlet;
569 x->ob_inlet = i;
570 return;
574 void obj_moveoutletfirst(t_object *x, t_outlet *o)
576 t_outlet *o2;
577 if (x->ob_outlet == o) return;
578 else for (o2 = x->ob_outlet; o2; o2 = o2->o_next)
579 if (o2->o_next == o)
581 o2->o_next = o->o_next;
582 o->o_next = x->ob_outlet;
583 x->ob_outlet = o;
584 return;
588 /* routines for DSP sorting, which are used in d_ugen.c and g_canvas.c */
589 /* LATER try to consolidate all the slightly different routines. */
591 int obj_nsiginlets(t_object *x)
593 int n;
594 t_inlet *i;
595 for (i = x->ob_inlet, n = 0; i; i = i->i_next)
596 if (i->i_symfrom == &s_signal) n++;
597 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin) n++;
598 return (n);
601 /* get the index, among signal inlets, of the mth inlet overall */
602 int obj_siginletindex(t_object *x, int m)
604 int n = 0;
605 t_inlet *i;
606 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
608 if (!m--) return (0);
609 n++;
611 for (i = x->ob_inlet; i; i = i->i_next, m--)
612 if (i->i_symfrom == &s_signal)
614 if (m == 0) return (n);
615 n++;
617 return (-1);
620 int obj_issignalinlet(t_object *x, int m)
622 t_inlet *i;
623 if (x->ob_pd->c_firstin)
625 if (!m)
626 return (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin);
627 else m--;
629 for (i = x->ob_inlet; i && m; i = i->i_next, m--)
631 return (i && (i->i_symfrom == &s_signal));
634 int obj_nsigoutlets(t_object *x)
636 int n;
637 t_outlet *o;
638 for (o = x->ob_outlet, n = 0; o; o = o->o_next)
639 if (o->o_sym == &s_signal) n++;
640 return (n);
643 int obj_sigoutletindex(t_object *x, int m)
645 int n;
646 t_outlet *o2;
647 for (o2 = x->ob_outlet, n = 0; o2; o2 = o2->o_next, m--)
648 if (o2->o_sym == &s_signal)
650 if (m == 0) return (n);
651 n++;
653 return (-1);
656 int obj_issignaloutlet(t_object *x, int m)
658 int n;
659 t_outlet *o2;
660 for (o2 = x->ob_outlet, n = 0; o2 && m--; o2 = o2->o_next);
661 return (o2 && (o2->o_sym == &s_signal));
664 t_sample *obj_findsignalscalar(t_object *x, int m)
666 int n = 0;
667 t_inlet *i;
668 if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
670 if (!m--)
671 return (x->ob_pd->c_floatsignalin > 0 ?
672 (t_sample *)(((char *)x) + x->ob_pd->c_floatsignalin) : 0);
673 n++;
675 for (i = x->ob_inlet; i; i = i->i_next, m--)
676 if (i->i_symfrom == &s_signal)
678 if (m == 0)
679 return (&i->i_un.iu_floatsignalvalue);
680 n++;
682 return (0);
685 /* and these are only used in g_io.c... */
687 int inlet_getsignalindex(t_inlet *x)
689 int n = 0;
690 t_inlet *i;
691 for (i = x->i_owner->ob_inlet, n = 0; i && i != x; i = i->i_next)
692 if (i->i_symfrom == &s_signal) n++;
693 return (n);
696 int outlet_getsignalindex(t_outlet *x)
698 int n = 0;
699 t_outlet *o;
700 for (o = x->o_owner->ob_outlet, n = 0; o && o != x; o = o->o_next)
701 if (o->o_sym == &s_signal) n++;
702 return (n);