diff options
author | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-22 21:58:48 +0000 |
---|---|---|
committer | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-22 21:58:48 +0000 |
commit | 513389b4c1bc8afe4b2dc9947c534bfeb105e3da (patch) | |
tree | 10e673b35651ac567fed2eda0c679c7ade64cbc6 /apps/plugins/pdbox/PDa/src/m_obj.c | |
parent | 95fa7f6a2ef466444fbe3fe87efc6d5db6b77b36 (diff) | |
download | rockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.tar.gz rockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.zip |
Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin project of Wincent Balin. Stripped some non-sourcefiles and added a rockbox readme that needs a bit more info from Wincent. Is added to CATEGORIES and viewers, but not yet to SUBDIRS (ie doesn't build yet)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21044 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/m_obj.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/m_obj.c | 1394 |
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 | ||
6 | can interconnect via inlets and outlets; also, the (terse) generic | ||
7 | behavior for "gobjs" appears at the end of this file. */ | ||
8 | |||
9 | #include "m_pd.h" | ||
10 | #include "m_imp.h" | ||
11 | |||
12 | union 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 | |||
21 | struct _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 | |||
36 | static 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 | |||
46 | t_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 | |||
65 | static 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: */ | ||
72 | static 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 | |||
80 | static 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 | |||
88 | static 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 | |||
99 | static 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 | |||
107 | static 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 | |||
117 | static 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 | |||
126 | void 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 | |||
142 | static 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 | |||
149 | t_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 | |||
166 | static void floatinlet_float(t_inlet *x, t_float f) | ||
167 | { | ||
168 | *(x->i_floatslot) = f; | ||
169 | } | ||
170 | |||
171 | t_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 | |||
188 | static void symbolinlet_symbol(t_inlet *x, t_symbol *s) | ||
189 | { | ||
190 | *(x->i_symslot) = s; | ||
191 | } | ||
192 | |||
193 | t_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. */ | ||
215 | void 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 | |||
232 | void 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 | |||
259 | static char *stacklimit, *topstack; | ||
260 | #define STACKSIZE 1000000 | ||
261 | static 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 */ | ||
266 | void 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 */ | ||
275 | int sched_geteventno( void) | ||
276 | { | ||
277 | return (outlet_eventno); | ||
278 | } | ||
279 | |||
280 | struct _outconnect | ||
281 | { | ||
282 | struct _outconnect *oc_next; | ||
283 | t_pd *oc_to; | ||
284 | }; | ||
285 | |||
286 | struct _outlet | ||
287 | { | ||
288 | t_object *o_owner; | ||
289 | struct _outlet *o_next; | ||
290 | t_outconnect *o_connections; | ||
291 | t_symbol *o_sym; | ||
292 | }; | ||
293 | |||
294 | t_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 | |||
310 | static void outlet_stackerror(t_outlet *x) | ||
311 | { | ||
312 | pd_error(x->o_owner, "stack overflow"); | ||
313 | stacklimit = topstack; | ||
314 | } | ||
315 | |||
316 | void 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 | |||
326 | void 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 | |||
348 | void 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 | |||
358 | void 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 | |||
368 | void 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 | |||
378 | void 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 */ | ||
389 | t_symbol *outlet_getsymbol(t_outlet *x) | ||
390 | { | ||
391 | return (x->o_sym); | ||
392 | } | ||
393 | |||
394 | void 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 | |||
408 | t_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; | ||
431 | doit: | ||
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 | |||
448 | void 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; | ||
469 | doit: | ||
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 | } | ||
487 | done: | ||
488 | if (o->o_sym == &s_signal) canvas_update_dsp(); | ||
489 | } | ||
490 | |||
491 | /* ------ traversal routines for code that can't see our structures ------ */ | ||
492 | |||
493 | int 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 | |||
501 | int 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 | |||
510 | t_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 | |||
519 | t_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. */ | ||
546 | t_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 */ | ||
553 | void 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 | |||
567 | void 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 | |||
584 | int 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 */ | ||
595 | int 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 | |||
613 | int 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 | |||
627 | int 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 | |||
636 | int 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 | |||
649 | int 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 | |||
657 | t_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 | |||
680 | int 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 | |||
689 | int 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 | ||
703 | can interconnect via inlets and outlets; also, the (terse) generic | ||
704 | behavior for "gobjs" appears at the end of this file. */ | ||
705 | |||
706 | #include "m_pd.h" | ||
707 | #include "m_imp.h" | ||
708 | |||
709 | union 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 | |||
718 | struct _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 | |||
733 | static 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 | |||
743 | t_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 | |||
762 | static 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: */ | ||
769 | static 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 | |||
777 | static 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 | |||
785 | static 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 | |||
796 | static 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 | |||
804 | static 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 | |||
814 | static 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 | |||
823 | void 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 | |||
839 | static 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 | |||
846 | t_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 | |||
863 | static void floatinlet_float(t_inlet *x, t_float f) | ||
864 | { | ||
865 | *(x->i_floatslot) = f; | ||
866 | } | ||
867 | |||
868 | t_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 | |||
885 | static void symbolinlet_symbol(t_inlet *x, t_symbol *s) | ||
886 | { | ||
887 | *(x->i_symslot) = s; | ||
888 | } | ||
889 | |||
890 | t_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. */ | ||
912 | void 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 | |||
929 | void 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 | |||
956 | static char *stacklimit, *topstack; | ||
957 | #define STACKSIZE 1000000 | ||
958 | static 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 */ | ||
963 | void 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 */ | ||
972 | int sched_geteventno( void) | ||
973 | { | ||
974 | return (outlet_eventno); | ||
975 | } | ||
976 | |||
977 | struct _outconnect | ||
978 | { | ||
979 | struct _outconnect *oc_next; | ||
980 | t_pd *oc_to; | ||
981 | }; | ||
982 | |||
983 | struct _outlet | ||
984 | { | ||
985 | t_object *o_owner; | ||
986 | struct _outlet *o_next; | ||
987 | t_outconnect *o_connections; | ||
988 | t_symbol *o_sym; | ||
989 | }; | ||
990 | |||
991 | t_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 | |||
1007 | static void outlet_stackerror(t_outlet *x) | ||
1008 | { | ||
1009 | pd_error(x->o_owner, "stack overflow"); | ||
1010 | stacklimit = topstack; | ||
1011 | } | ||
1012 | |||
1013 | void 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 | |||
1023 | void 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 | |||
1045 | void 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 | |||
1055 | void 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 | |||
1065 | void 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 | |||
1075 | void 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 */ | ||
1086 | t_symbol *outlet_getsymbol(t_outlet *x) | ||
1087 | { | ||
1088 | return (x->o_sym); | ||
1089 | } | ||
1090 | |||
1091 | void 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 | |||
1105 | t_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; | ||
1128 | doit: | ||
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 | |||
1145 | void 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; | ||
1166 | doit: | ||
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 | } | ||
1184 | done: | ||
1185 | if (o->o_sym == &s_signal) canvas_update_dsp(); | ||
1186 | } | ||
1187 | |||
1188 | /* ------ traversal routines for code that can't see our structures ------ */ | ||
1189 | |||
1190 | int 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 | |||
1198 | int 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 | |||
1207 | t_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 | |||
1216 | t_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. */ | ||
1243 | t_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 */ | ||
1250 | void 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 | |||
1264 | void 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 | |||
1281 | int 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 */ | ||
1292 | int 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 | |||
1310 | int 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 | |||
1324 | int 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 | |||
1333 | int 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 | |||
1346 | int 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 | |||
1354 | t_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 | |||
1377 | int 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 | |||
1386 | int 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 | |||