summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/d_ugen.c
diff options
context:
space:
mode:
authorPeter D'Hoye <peter.dhoye@gmail.com>2009-05-22 21:58:48 +0000
committerPeter D'Hoye <peter.dhoye@gmail.com>2009-05-22 21:58:48 +0000
commit513389b4c1bc8afe4b2dc9947c534bfeb105e3da (patch)
tree10e673b35651ac567fed2eda0c679c7ade64cbc6 /apps/plugins/pdbox/PDa/src/d_ugen.c
parent95fa7f6a2ef466444fbe3fe87efc6d5db6b77b36 (diff)
downloadrockbox-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/d_ugen.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/d_ugen.c2252
1 files changed, 2252 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/d_ugen.c b/apps/plugins/pdbox/PDa/src/d_ugen.c
new file mode 100644
index 0000000000..9820f190cc
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_ugen.c
@@ -0,0 +1,2252 @@
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/* These routines build a copy of the DSP portion of a graph, which is
6 then sorted into a linear list of DSP operations which are added to
7 the DSP duty cycle called by the scheduler. Once that's been done,
8 we delete the copy. The DSP objects are represented by "ugenbox"
9 structures which are parallel to the DSP objects in the graph and
10 have vectors of siginlets and sigoutlets which record their
11 interconnections.
12*/
13
14/* hacked to run subpatches with different samplerates
15 * only samplerates that are a power_of_2-multiple of the
16 *
17 * mfg.gfd.uil
18 * IOhannes
19 *
20 * edited lines are marked with "IOhannes"
21 *
22 */
23
24
25#include "m_pd.h"
26#include "m_imp.h"
27#include <stdlib.h>
28#include <stdarg.h>
29
30extern t_class *vinlet_class, *voutlet_class, *canvas_class;
31t_sample *obj_findsignalscalar(t_object *x, int m);
32static int ugen_loud;
33EXTERN_STRUCT _vinlet;
34EXTERN_STRUCT _voutlet;
35
36void vinlet_dspprolog(struct _vinlet *x, t_signal **parentsigs,
37 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
38 int switched);
39void voutlet_dspprolog(struct _voutlet *x, t_signal **parentsigs,
40 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
41 int switched);
42void voutlet_dspepilog(struct _voutlet *x, t_signal **parentsigs,
43 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
44 int switched);
45
46t_int *zero_perform(t_int *w) /* zero out a vector */
47{
48 t_float *out = (t_float *)(w[1]);
49 int n = (int)(w[2]);
50 while (n--) *out++ = 0;
51 return (w+3);
52}
53
54t_int *zero_perf8(t_int *w)
55{
56 t_float *out = (t_float *)(w[1]);
57 int n = (int)(w[2]);
58
59 for (; n; n -= 8, out += 8)
60 {
61 out[0] = 0;
62 out[1] = 0;
63 out[2] = 0;
64 out[3] = 0;
65 out[4] = 0;
66 out[5] = 0;
67 out[6] = 0;
68 out[7] = 0;
69 }
70 return (w+3);
71}
72
73void dsp_add_zero(t_sample *out, int n)
74{
75 if (n&7)
76 dsp_add(zero_perform, 2, out, n);
77 else
78 dsp_add(zero_perf8, 2, out, n);
79}
80
81/* ---------------------------- block~ ----------------------------- */
82
83/* The "block~ object maintains the containing canvas's DSP computation,
84calling it at a super- or sub-multiple of the containing canvas's
85calling frequency. The block~'s creation arguments specify block size
86and overlap. Block~ does no "dsp" computation in its own right, but it
87adds prolog and epilog code before and after the canvas's unit generators.
88
89A subcanvas need not have a block~ at all; if there's none, its
90ugens are simply put on the list without any prolog or epilog code.
91
92Block~ may be invoked as switch~, in which case it also acts to switch the
93subcanvas on and off. The overall order of scheduling for a subcanvas
94is thus,
95
96 inlet and outlet prologue code (1)
97 block prologue (2)
98 the objects in the subcanvas, including inlets and outlets
99 block epilogue (2)
100 outlet epilogue code (2)
101
102where (1) means, "if reblocked" and (2) means, "if reblocked or switched".
103
104If we're reblocked, the inlet prolog and outlet epilog code takes care of
105overlapping and buffering to deal with vector size changes. If we're switched
106but not reblocked, the inlet prolog is not needed, and the output epilog is
107ONLY run when the block is switched off; in this case the epilog code simply
108copies zeros to all signal outlets.
109*/
110
111static int dsp_phase;
112static t_class *block_class;
113
114typedef struct _block
115{
116 t_object x_obj;
117 int x_vecsize;
118 int x_overlap;
119 int x_phase; /* from 0 to period-1; when zero we run the block */
120 int x_period; /* submultiple of containing canvas */
121 int x_frequency; /* supermultiple of comtaining canvas */
122 int x_count;
123 int x_blocklength; /* length of dspchain for this block */
124 int x_epiloglength; /* length of epilog */
125 char x_switched; /* true if we're acting as a a switch */
126 char x_switchon; /* true if we're switched on */
127 char x_reblock; /* true if inlets and outlets are reblocking */
128 int x_upsample; /* IOhannes: upsampling-factor */
129 int x_downsample; /* IOhannes: downsampling-factor */
130
131} t_block;
132
133static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
134 t_floatarg fupsample);
135
136static void *block_new(t_floatarg fvecsize, t_floatarg foverlap,
137 t_floatarg fupsample) /* IOhannes */
138{
139 t_block *x = (t_block *)pd_new(block_class);
140 x->x_phase = 0;
141 x->x_period = 1;
142 x->x_frequency = 1;
143 x->x_switched = 0;
144 x->x_switchon = 1;
145 block_set(x, fvecsize, foverlap, fupsample);
146 return (x);
147}
148
149static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
150 t_floatarg fupsample)
151{
152 int upsample, downsample; /* IOhannes */
153 int vecsize = fvecsize;
154 int overlap = foverlap;
155 int dspstate = canvas_suspend_dsp();
156 if (overlap < 1)
157 overlap = 1;
158 if (vecsize < 0)
159 vecsize = 0; /* this means we'll get it from parent later. */
160
161 /* IOhannes { */
162 if (fupsample <= 0) upsample = downsample = 1;
163 else if (fupsample >= 1) {
164 upsample = fupsample;
165 downsample = 1;
166 } else {
167 downsample = 1.0 / fupsample;
168 upsample = 1;
169 }
170 /* } IOhannes */
171
172 if (vecsize && (vecsize != (1 << ilog2(vecsize))))
173 {
174 pd_error(x, "block~: vector size not a power of 2");
175 vecsize = 64;
176 }
177 if (overlap != (1 << ilog2(overlap)))
178 {
179 pd_error(x, "block~: overlap not a power of 2");
180 overlap = 1;
181 }
182 /* IOhannes { */
183 if (downsample != (1 << ilog2(downsample)))
184 {
185 pd_error(x, "block~: downsampling not a power of 2");
186 downsample = 1;
187 }
188 if (upsample != (1 << ilog2(upsample)))
189 {
190 pd_error(x, "block~: upsampling not a power of 2");
191 upsample = 1;
192 }
193 /* } IOhannes */
194
195
196 x->x_vecsize = vecsize;
197 x->x_overlap = overlap;
198 /* IOhannes { */
199 x->x_upsample = upsample;
200 x->x_downsample = downsample;
201 /* } IOhannes */
202 canvas_resume_dsp(dspstate);
203}
204
205static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap,
206 t_floatarg fupsample) /* IOhannes */
207{
208 t_block *x = (t_block *)(block_new(fvecsize, foverlap, fupsample)); /* IOhannes */
209 x->x_switched = 1;
210 x->x_switchon = 0;
211 return (x);
212}
213
214static void block_float(t_block *x, t_floatarg f)
215{
216 if (x->x_switched)
217 x->x_switchon = (f != 0);
218}
219#define PROLOGCALL 2
220#define EPILOGCALL 2
221
222static t_int *block_prolog(t_int *w)
223{
224 t_block *x = (t_block *)w[1];
225 int phase = x->x_phase;
226 /* if we're switched off, jump past the epilog code */
227 if (!x->x_switchon)
228 return (w + x->x_blocklength);
229 if (phase)
230 {
231 phase++;
232 if (phase == x->x_period) phase = 0;
233 x->x_phase = phase;
234 return (w + x->x_blocklength); /* skip block; jump past epilog */
235 }
236 else
237 {
238 x->x_count = x->x_frequency;
239 x->x_phase = (x->x_period > 1 ? 1 : 0);
240 return (w + PROLOGCALL); /* beginning of block is next ugen */
241 }
242}
243
244static t_int *block_epilog(t_int *w)
245{
246 t_block *x = (t_block *)w[1];
247 int count = x->x_count - 1;
248 if (!x->x_reblock)
249 return (w + x->x_epiloglength + EPILOGCALL);
250 if (count)
251 {
252 x->x_count = count;
253 return (w - (x->x_blocklength -
254 (PROLOGCALL + EPILOGCALL))); /* go to ugen after prolog */
255 }
256 else return (w + EPILOGCALL);
257}
258
259static void block_dsp(t_block *x, t_signal **sp)
260{
261 /* do nothing here */
262}
263
264/* ------------------ DSP call list ----------------------- */
265
266static t_int *dsp_chain;
267static int dsp_chainsize;
268
269void dsp_add(t_perfroutine f, int n, ...)
270{
271 int newsize = dsp_chainsize + n+1, i;
272 va_list ap;
273
274 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
275 newsize * sizeof (t_int));
276 dsp_chain[dsp_chainsize-1] = (t_int)f;
277 va_start(ap, n);
278 for (i = 0; i < n; i++)
279 dsp_chain[dsp_chainsize + i] = va_arg(ap, t_int);
280 va_end(ap);
281 dsp_chain[newsize-1] = 0;
282 dsp_chainsize = newsize;
283}
284
285 /* at Guenter's suggestion, here's a vectorized version */
286void dsp_addv(t_perfroutine f, int n, t_int *vec)
287{
288 int newsize = dsp_chainsize + n+1, i;
289
290 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
291 newsize * sizeof (t_int));
292 dsp_chain[dsp_chainsize-1] = (t_int)f;
293 for (i = 0; i < n; i++)
294 dsp_chain[dsp_chainsize + i] = vec[i];
295 dsp_chain[newsize-1] = 0;
296 dsp_chainsize = newsize;
297}
298
299void dsp_tick(void)
300{
301 if (dsp_chain)
302 {
303 t_int *ip;
304 for (ip = dsp_chain; *ip; ) ip = (*(t_perfroutine)(*ip))(ip);
305 dsp_phase++;
306 }
307}
308
309/* ---------------- signals ---------------------------- */
310
311int ilog2(int n)
312{
313 int r = -1;
314 if (n <= 0) return(0);
315 while (n)
316 {
317 r++;
318 n >>= 1;
319 }
320 return (r);
321}
322
323 /* list of signals which can be reused, sorted by buffer size */
324static t_signal *signal_freelist[MAXLOGSIG+1];
325 /* list of reusable "borrowed" signals (which don't own sample buffers) */
326static t_signal *signal_freeborrowed;
327 /* list of all signals allocated (not including "borrowed" ones) */
328static t_signal *signal_usedlist;
329
330 /* call this when DSP is stopped to free all the signals */
331void signal_cleanup(void)
332{
333 t_signal **svec, *sig, *sig2;
334 int i;
335 while (sig = signal_usedlist)
336 {
337 signal_usedlist = sig->s_nextused;
338 if (!sig->s_isborrowed)
339 t_freebytes(sig->s_vec, sig->s_n * sizeof (*sig->s_vec));
340 t_freebytes(sig, sizeof *sig);
341 }
342 for (i = 0; i <= MAXLOGSIG; i++)
343 signal_freelist[i] = 0;
344 signal_freeborrowed = 0;
345}
346
347 /* mark the signal "reusable." */
348void signal_makereusable(t_signal *sig)
349{
350 int logn = ilog2(sig->s_n);
351#if 1
352 t_signal *s5;
353 for (s5 = signal_freeborrowed; s5; s5 = s5->s_nextfree)
354 {
355 if (s5 == sig)
356 {
357 bug("signal_free 3");
358 return;
359 }
360 }
361 for (s5 = signal_freelist[logn]; s5; s5 = s5->s_nextfree)
362 {
363 if (s5 == sig)
364 {
365 bug("signal_free 4");
366 return;
367 }
368 }
369#endif
370 if (ugen_loud) post("free %x: %d", sig, sig->s_isborrowed);
371 if (sig->s_isborrowed)
372 {
373 /* if the signal is borrowed, decrement the borrowed-from signal's
374 reference count, possibly marking it reusable too */
375 t_signal *s2 = sig->s_borrowedfrom;
376 if ((s2 == sig) || !s2)
377 bug("signal_free");
378 s2->s_refcount--;
379 if (!s2->s_refcount)
380 signal_makereusable(s2);
381 sig->s_nextfree = signal_freeborrowed;
382 signal_freeborrowed = sig;
383 }
384 else
385 {
386 /* if it's a real signal (not borrowed), put it on the free list
387 so we can reuse it. */
388 if (signal_freelist[logn] == sig) bug("signal_free 2");
389 sig->s_nextfree = signal_freelist[logn];
390 signal_freelist[logn] = sig;
391 }
392}
393
394 /* reclaim or make an audio signal. If n is zero, return a "borrowed"
395 signal whose buffer and size will be obtained later via
396 signal_setborrowed(). */
397
398t_signal *signal_new(int n, float sr)
399{
400 int logn, n2;
401 t_signal *ret, **whichlist;
402 t_sample *fp;
403 logn = ilog2(n);
404 if (n)
405 {
406 if (n != (1 << logn))
407 bug("signal buffer not a power of 2");
408 if (logn > MAXLOGSIG)
409 bug("signal buffer too large");
410 whichlist = signal_freelist + logn;
411 }
412 else
413 whichlist = &signal_freeborrowed;
414
415 /* first try to reclaim one from the free list */
416 if (ret = *whichlist)
417 *whichlist = ret->s_nextfree;
418 else
419 {
420 /* LATER figure out what to do for out-of-space here! */
421 ret = (t_signal *)t_getbytes(sizeof *ret);
422 if (n)
423 {
424 ret->s_vec = (t_sample *)getbytes(n * sizeof (*ret->s_vec));
425 ret->s_isborrowed = 0;
426 }
427 else
428 {
429 ret->s_vec = 0;
430 ret->s_isborrowed = 1;
431 }
432 ret->s_nextused = signal_usedlist;
433 signal_usedlist = ret;
434 }
435 ret->s_n = n;
436 ret->s_sr = sr;
437 ret->s_refcount = 0;
438 ret->s_borrowedfrom = 0;
439 if (ugen_loud) post("new %x: %d", ret, ret->s_isborrowed);
440 return (ret);
441}
442
443static t_signal *signal_newlike(const t_signal *sig)
444{
445 return (signal_new(sig->s_n, sig->s_sr));
446}
447
448void signal_setborrowed(t_signal *sig, t_signal *sig2)
449{
450 if (!sig->s_isborrowed || sig->s_borrowedfrom)
451 bug("signal_setborrowed");
452 if (sig == sig2)
453 bug("signal_setborrowed 2");
454 sig->s_borrowedfrom = sig2;
455 sig->s_vec = sig2->s_vec;
456 sig->s_n = sig2->s_n;
457}
458
459int signal_compatible(t_signal *s1, t_signal *s2)
460{
461 return (s1->s_n == s2->s_n && s1->s_sr == s2->s_sr);
462}
463
464/* ------------------ ugen ("unit generator") sorting ----------------- */
465
466typedef struct _ugenbox
467{
468 struct _siginlet *u_in;
469 int u_nin;
470 struct _sigoutlet *u_out;
471 int u_nout;
472 int u_phase;
473 struct _ugenbox *u_next;
474 t_object *u_obj;
475 int u_done;
476} t_ugenbox;
477
478typedef struct _siginlet
479{
480 int i_nconnect;
481 int i_ngot;
482 t_signal *i_signal;
483} t_siginlet;
484
485typedef struct _sigoutconnect
486{
487 t_ugenbox *oc_who;
488 int oc_inno;
489 struct _sigoutconnect *oc_next;
490} t_sigoutconnect;
491
492typedef struct _sigoutlet
493{
494 int o_nconnect;
495 int o_nsent;
496 t_signal *o_signal;
497 t_sigoutconnect *o_connections;
498} t_sigoutlet;
499
500
501struct _dspcontext
502{
503 struct _ugenbox *dc_ugenlist;
504 struct _dspcontext *dc_parentcontext;
505 int dc_ninlets;
506 int dc_noutlets;
507 t_signal **dc_iosigs;
508 float dc_srate;
509 int dc_vecsize;
510 char dc_toplevel; /* true if "iosigs" is invalid. */
511 char dc_reblock; /* true if we have to reblock inlets/outlets */
512 char dc_switched; /* true if we're switched */
513
514};
515
516#define t_dspcontext struct _dspcontext
517
518static int ugen_sortno = 0;
519static t_dspcontext *ugen_currentcontext;
520
521void ugen_stop(void)
522{
523 t_signal *s;
524 int i;
525 if (dsp_chain)
526 {
527 freebytes(dsp_chain, dsp_chainsize * sizeof (t_int));
528 dsp_chain = 0;
529 }
530 signal_cleanup();
531
532}
533
534void ugen_start(void)
535{
536 ugen_stop();
537 ugen_sortno++;
538 dsp_chain = (t_int *)getbytes(sizeof(*dsp_chain));
539 dsp_chain[0] = 0;
540 dsp_chainsize = 1;
541 if (ugen_currentcontext) bug("ugen_start");
542}
543
544int ugen_getsortno(void)
545{
546 return (ugen_sortno);
547}
548
549#if 0
550void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
551{
552 int i, count;
553 t_signal *sig;
554 for (count = 0, sig = signal_usedlist; sig;
555 count++, sig = sig->s_nextused)
556 ;
557 post("used signals %d", count);
558 for (i = 0; i < MAXLOGSIG; i++)
559 {
560 for (count = 0, sig = signal_freelist[i]; sig;
561 count++, sig = sig->s_nextfree)
562 ;
563 if (count)
564 post("size %d: free %d", (1 << i), count);
565 }
566 for (count = 0, sig = signal_freeborrowed; sig;
567 count++, sig = sig->s_nextfree)
568 ;
569 post("free borrowed %d", count);
570
571 ugen_loud = argc;
572}
573#endif
574
575 /* start building the graph for a canvas */
576t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
577 int ninlets, int noutlets)
578{
579 t_dspcontext *dc = (t_dspcontext *)getbytes(sizeof(*dc));
580 float parent_srate, srate;
581 int parent_vecsize, vecsize;
582
583 if (ugen_loud) post("ugen_start_graph...");
584
585 dc->dc_ugenlist = 0;
586 dc->dc_toplevel = toplevel;
587 dc->dc_iosigs = sp;
588 dc->dc_ninlets = ninlets;
589 dc->dc_noutlets = noutlets;
590 dc->dc_parentcontext = ugen_currentcontext;
591 ugen_currentcontext = dc;
592 return (dc);
593}
594
595 /* first the canvas calls this to create all the boxes... */
596void ugen_add(t_dspcontext *dc, t_object *obj)
597{
598 t_ugenbox *x = (t_ugenbox *)getbytes(sizeof *x);
599 int i;
600 t_sigoutlet *uout;
601 t_siginlet *uin;
602
603 x->u_next = dc->dc_ugenlist;
604 dc->dc_ugenlist = x;
605 x->u_obj = obj;
606 x->u_nin = obj_nsiginlets(obj);
607 x->u_in = getbytes(x->u_nin * sizeof (*x->u_in));
608 for (uin = x->u_in, i = x->u_nin; i--; uin++)
609 uin->i_nconnect = 0;
610 x->u_nout = obj_nsigoutlets(obj);
611 x->u_out = getbytes(x->u_nout * sizeof (*x->u_out));
612 for (uout = x->u_out, i = x->u_nout; i--; uout++)
613 uout->o_connections = 0, uout->o_nconnect = 0;
614}
615
616 /* and then this to make all the connections. */
617void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2,
618 int inno)
619{
620 t_ugenbox *u1, *u2;
621 t_sigoutlet *uout;
622 t_siginlet *uin;
623 t_sigoutconnect *oc;
624 int sigoutno = obj_sigoutletindex(x1, outno);
625 int siginno = obj_siginletindex(x2, inno);
626 if (ugen_loud)
627 post("%s -> %s: %d->%d",
628 class_getname(x1->ob_pd),
629 class_getname(x2->ob_pd), outno, inno);
630 for (u1 = dc->dc_ugenlist; u1 && u1->u_obj != x1; u1 = u1->u_next);
631 for (u2 = dc->dc_ugenlist; u2 && u2->u_obj != x2; u2 = u2->u_next);
632 if (!u1 || !u2 || siginno < 0)
633 {
634 pd_error(u1->u_obj,
635 "signal outlet connect to nonsignal inlet (ignored)");
636 return;
637 }
638 if (sigoutno < 0 || sigoutno >= u1->u_nout || siginno >= u2->u_nin)
639 {
640 bug("ugen_connect %s %s %d %d (%d %d)",
641 class_getname(x1->ob_pd),
642 class_getname(x2->ob_pd), sigoutno, siginno, u1->u_nout,
643 u2->u_nin);
644 }
645 uout = u1->u_out + sigoutno;
646 uin = u2->u_in + siginno;
647
648 /* add a new connection to the outlet's list */
649 oc = (t_sigoutconnect *)getbytes(sizeof *oc);
650 oc->oc_next = uout->o_connections;
651 uout->o_connections = oc;
652 oc->oc_who = u2;
653 oc->oc_inno = siginno;
654 /* update inlet and outlet counts */
655 uout->o_nconnect++;
656 uin->i_nconnect++;
657}
658
659 /* get the index of a ugenbox or -1 if it's not on the list */
660static int ugen_index(t_dspcontext *dc, t_ugenbox *x)
661{
662 int ret;
663 t_ugenbox *u;
664 for (u = dc->dc_ugenlist, ret = 0; u; u = u->u_next, ret++)
665 if (u == x) return (ret);
666 return (-1);
667}
668
669 /* put a ugenbox on the chain, recursively putting any others on that
670 this one might uncover. */
671static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
672{
673 t_sigoutlet *uout;
674 t_siginlet *uin;
675 t_sigoutconnect *oc, *oc2;
676 t_class *class = pd_class(&u->u_obj->ob_pd);
677 int i, n;
678 /* suppress creating new signals for the outputs of signal
679 inlets and subpatchs; except in the case we're an inlet and "blocking"
680 is set. We don't yet know if a subcanvas will be "blocking" so there
681 we delay new signal creation, which will be handled by calling
682 signal_setborrowed in the ugen_done_graph routine below. */
683 int nonewsigs = (class == canvas_class ||
684 (class == vinlet_class) && !(dc->dc_reblock));
685 /* when we encounter a subcanvas or a signal outlet, suppress freeing
686 the input signals as they may be "borrowed" for the super or sub
687 patch; same exception as above, but also if we're "switched" we
688 have to do a copy rather than a borrow. */
689 int nofreesigs = (class == canvas_class ||
690 (class == voutlet_class) && !(dc->dc_reblock || dc->dc_switched));
691 t_signal **insig, **outsig, **sig, *s1, *s2, *s3;
692 t_ugenbox *u2;
693
694 if (ugen_loud) post("doit %s %d %d", class_getname(class), nofreesigs,
695 nonewsigs);
696 for (i = 0, uin = u->u_in; i < u->u_nin; i++, uin++)
697 {
698 if (!uin->i_nconnect)
699 {
700 t_sample *scalar;
701 s3 = signal_new(dc->dc_vecsize, dc->dc_srate);
702 /* post("%s: unconnected signal inlet set to zero",
703 class_getname(u->u_obj->ob_pd)); */
704 if (scalar = obj_findsignalscalar(u->u_obj, i))
705 dsp_add_scalarcopy(scalar, s3->s_vec, s3->s_n);
706 else
707 dsp_add_zero(s3->s_vec, s3->s_n);
708 uin->i_signal = s3;
709 s3->s_refcount = 1;
710 }
711 }
712 insig = (t_signal **)getbytes((u->u_nin + u->u_nout) * sizeof(t_signal *));
713 outsig = insig + u->u_nin;
714 for (sig = insig, uin = u->u_in, i = u->u_nin; i--; sig++, uin++)
715 {
716 int newrefcount;
717 *sig = uin->i_signal;
718 newrefcount = --(*sig)->s_refcount;
719 /* if the reference count went to zero, we free the signal now,
720 unless it's a subcanvas or outlet; these might keep the
721 signal around to send to objects connected to them. In this
722 case we increment the reference count; the corresponding decrement
723 is in sig_makereusable(). */
724 if (nofreesigs)
725 (*sig)->s_refcount++;
726 else if (!newrefcount)
727 signal_makereusable(*sig);
728 }
729 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
730 {
731 /* similarly, for outlets of subcanvases we delay creating
732 them; instead we create "borrowed" ones so that the refcount
733 is known. The subcanvas replaces the fake signal with one showing
734 where the output data actually is, to avoid having to copy it.
735 For any other object, we just allocate a new output vector;
736 since we've already freed the inputs the objects might get called
737 "in place." */
738 if (nonewsigs)
739 {
740 *sig = uout->o_signal =
741 signal_new(0, dc->dc_srate);
742 }
743 else
744 *sig = uout->o_signal = signal_new(dc->dc_vecsize, dc->dc_srate);
745 (*sig)->s_refcount = uout->o_nconnect;
746 }
747 /* now call the DSP scheduling routine for the ugen. This
748 routine must fill in "borrowed" signal outputs in case it's either
749 a subcanvas or a signal inlet. */
750 mess1(&u->u_obj->ob_pd, gensym("dsp"), insig);
751
752 /* if any output signals aren't connected to anyone, free them
753 now; otherwise they'll either get freed when the reference count
754 goes back to zero, or even later as explained above. */
755
756 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
757 {
758 if (!(*sig)->s_refcount)
759 signal_makereusable(*sig);
760 }
761 if (ugen_loud)
762 {
763 if (u->u_nin + u->u_nout == 0) post("put %s %d",
764 class_getname(u->u_obj->ob_pd), ugen_index(dc, u));
765 else if (u->u_nin + u->u_nout == 1) post("put %s %d (%x)",
766 class_getname(u->u_obj->ob_pd), ugen_index(dc, u), sig[0]);
767 else if (u->u_nin + u->u_nout == 2) post("put %s %d (%x %x)",
768 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
769 sig[0], sig[1]);
770 else post("put %s %d (%x %x %x ...)",
771 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
772 sig[0], sig[1], sig[2]);
773 }
774
775 /* pass it on and trip anyone whose last inlet was filled */
776 for (uout = u->u_out, i = u->u_nout; i--; uout++)
777 {
778 s1 = uout->o_signal;
779 for (oc = uout->o_connections; oc; oc = oc->oc_next)
780 {
781 u2 = oc->oc_who;
782 uin = &u2->u_in[oc->oc_inno];
783 /* if there's already someone here, sum the two */
784 if (s2 = uin->i_signal)
785 {
786 s1->s_refcount--;
787 s2->s_refcount--;
788 if (!signal_compatible(s1, s2))
789 {
790 pd_error(u->u_obj, "%s: incompatible signal inputs",
791 class_getname(u->u_obj->ob_pd));
792 return;
793 }
794 s3 = signal_newlike(s1);
795 dsp_add_plus(s1->s_vec, s2->s_vec, s3->s_vec, s1->s_n);
796 uin->i_signal = s3;
797 s3->s_refcount = 1;
798 if (!s1->s_refcount) signal_makereusable(s1);
799 if (!s2->s_refcount) signal_makereusable(s2);
800 }
801 else uin->i_signal = s1;
802 uin->i_ngot++;
803 /* if we didn't fill this inlet don't bother yet */
804 if (uin->i_ngot < uin->i_nconnect)
805 goto notyet;
806 /* if there's more than one, check them all */
807 if (u2->u_nin > 1)
808 {
809 for (uin = u2->u_in, n = u2->u_nin; n--; uin++)
810 if (uin->i_ngot < uin->i_nconnect) goto notyet;
811 }
812 /* so now we can schedule the ugen. */
813 ugen_doit(dc, u2);
814 notyet: ;
815 }
816 }
817 t_freebytes(insig,(u->u_nin + u->u_nout) * sizeof(t_signal *));
818 u->u_done = 1;
819}
820
821 /* once the DSP graph is built, we call this routine to sort it.
822 This routine also deletes the graph; later we might want to leave the
823 graph around, in case the user is editing the DSP network, to save having
824 to recreate it all the time. But not today. */
825
826void ugen_done_graph(t_dspcontext *dc)
827{
828 t_ugenbox *u, *u2;
829 t_sigoutlet *uout;
830 t_siginlet *uin;
831 t_sigoutconnect *oc, *oc2;
832 int i, n;
833 t_block *blk;
834 t_dspcontext *parent_context = dc->dc_parentcontext;
835 float parent_srate;
836 int parent_vecsize;
837 int period, frequency, phase, vecsize;
838 float srate;
839 int chainblockbegin; /* DSP chain onset before block prolog code */
840 int chainblockend; /* and after block epilog code */
841 int chainafterall; /* and after signal outlet epilog */
842 int reblock = 0, switched;
843 int downsample = 1, upsample = 1; /* IOhannes */
844 /* debugging printout */
845
846 if (ugen_loud)
847 {
848 post("ugen_done_graph...");
849 for (u = dc->dc_ugenlist; u; u = u->u_next)
850 {
851 post("ugen: %s", class_getname(u->u_obj->ob_pd));
852 for (uout = u->u_out, i = 0; i < u->u_nout; uout++, i++)
853 for (oc = uout->o_connections; oc; oc = oc->oc_next)
854 {
855 post("... out %d to %s, index %d, inlet %d", i,
856 class_getname(oc->oc_who->u_obj->ob_pd),
857 ugen_index(dc, oc->oc_who), oc->oc_inno);
858 }
859 }
860 }
861
862 /* search for an object of class "block~" */
863 for (u = dc->dc_ugenlist, blk = 0; u; u = u->u_next)
864 {
865 t_pd *zz = &u->u_obj->ob_pd;
866 if (pd_class(zz) == block_class)
867 {
868 if (blk)
869 pd_error(blk, "conflicting block~ objects in same page");
870 else blk = (t_block *)zz;
871 }
872 }
873
874 /* figure out block size, calling frequency, sample rate */
875 if (parent_context)
876 {
877 parent_srate = parent_context->dc_srate;
878 parent_vecsize = parent_context->dc_vecsize;
879 }
880 else
881 {
882 parent_srate = sys_getsr();
883 parent_vecsize = sys_getblksize();
884 }
885 if (blk)
886 {
887 int realoverlap;
888 vecsize = blk->x_vecsize;
889 if (vecsize == 0)
890 vecsize = parent_vecsize;
891 realoverlap = blk->x_overlap;
892 if (realoverlap > vecsize) realoverlap = vecsize;
893 /* IOhannes { */
894 downsample = blk->x_downsample;
895 upsample = blk->x_upsample;
896 if (downsample > parent_vecsize) downsample=parent_vecsize;
897 period = (vecsize * downsample)/
898 (parent_vecsize * realoverlap * upsample);
899 frequency = (parent_vecsize * realoverlap * upsample)/
900 (vecsize * downsample);
901 /* } IOhannes*/
902 phase = blk->x_phase;
903 srate = parent_srate * realoverlap * upsample / downsample;
904 /* IOhannes */
905 if (period < 1) period = 1;
906 if (frequency < 1) frequency = 1;
907 blk->x_frequency = frequency;
908 blk->x_period = period;
909 blk->x_phase = dsp_phase & (period - 1);
910 if (! parent_context || (realoverlap != 1) ||
911 (vecsize != parent_vecsize) ||
912 (downsample != 1) || (upsample != 1)) /* IOhannes */
913 reblock = 1;
914 switched = blk->x_switched;
915 }
916 else
917 {
918 srate = parent_srate;
919 vecsize = parent_vecsize;
920 downsample = upsample = 1;/* IOhannes */
921 period = frequency = 1;
922 phase = 0;
923 if (!parent_context) reblock = 1;
924 switched = 0;
925 }
926 dc->dc_reblock = reblock;
927 dc->dc_switched = switched;
928 dc->dc_srate = srate;
929 dc->dc_vecsize = vecsize;
930
931 /* if we're reblocking or switched, we now have to create output
932 signals to fill in for the "borrowed" ones we have now. This
933 is also possibly true even if we're not blocked/switched, in
934 the case that there was a signal loop. But we don't know this
935 yet. */
936
937 if (dc->dc_iosigs && (switched || reblock))
938 {
939 t_signal **sigp;
940 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
941 i++, sigp++)
942 {
943 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
944 {
945 signal_setborrowed(*sigp,
946 signal_new(parent_vecsize, parent_srate));
947 (*sigp)->s_refcount++;
948
949 if (ugen_loud) post("set %x->%x", *sigp,
950 (*sigp)->s_borrowedfrom);
951 }
952 }
953 }
954
955 if (ugen_loud)
956 post("reblock %d, switched %d", reblock, switched);
957
958 /* schedule prologs for inlets and outlets. If the "reblock" flag
959 is set, an inlet will put code on the DSP chain to copy its input
960 into an internal buffer here, before any unit generators' DSP code
961 gets scheduled. If we don't "reblock", inlets will need to get
962 pointers to their corresponding inlets/outlets on the box we're inside,
963 if any. Outlets will also need pointers, unless we're switched, in
964 which case outlet epilog code will kick in. */
965
966 for (u = dc->dc_ugenlist; u; u = u->u_next)
967 {
968 t_pd *zz = &u->u_obj->ob_pd;
969 t_signal **insigs = dc->dc_iosigs, **outsigs = dc->dc_iosigs;
970 if (outsigs) outsigs += dc->dc_ninlets;
971
972 if (pd_class(zz) == vinlet_class)
973 vinlet_dspprolog((struct _vinlet *)zz,
974 dc->dc_iosigs, vecsize, dsp_phase, period, frequency,
975 downsample, upsample, /* IOhannes */
976 reblock, switched);
977 else if (pd_class(zz) == voutlet_class)
978 voutlet_dspprolog((struct _voutlet *)zz,
979 outsigs, vecsize, dsp_phase, period, frequency,
980 downsample, upsample, /* IOhannes */
981 reblock, switched);
982 }
983 chainblockbegin = dsp_chainsize;
984
985 if (blk && (reblock || switched)) /* add the block DSP prolog */
986 dsp_add(block_prolog, 1, blk);
987
988 /* Initialize for sorting */
989 for (u = dc->dc_ugenlist; u; u = u->u_next)
990 {
991 u->u_done = 0;
992 for (uout = u->u_out, i = u->u_nout; i--; uout++)
993 uout->o_nsent = 0;
994 for (uin = u->u_in, i = u->u_nin; i--; uin++)
995 uin->i_ngot = 0, uin->i_signal = 0;
996 }
997
998 /* Do the sort */
999
1000 for (u = dc->dc_ugenlist; u; u = u->u_next)
1001 {
1002 /* check that we have no connected signal inlets */
1003 if (u->u_done) continue;
1004 for (uin = u->u_in, i = u->u_nin; i--; uin++)
1005 if (uin->i_nconnect) goto next;
1006
1007 ugen_doit(dc, u);
1008 next: ;
1009 }
1010
1011 /* check for a DSP loop, which is evidenced here by the presence
1012 of ugens not yet scheduled. */
1013
1014 for (u = dc->dc_ugenlist; u; u = u->u_next)
1015 if (!u->u_done)
1016 {
1017 t_signal **sigp;
1018 pd_error(u->u_obj,
1019 "DSP loop detected (some tilde objects not scheduled)");
1020 /* this might imply that we have unfilled "borrowed" outputs
1021 which we'd better fill in now. */
1022 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
1023 i++, sigp++)
1024 {
1025 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
1026 {
1027 t_signal *s3 = signal_new(parent_vecsize, parent_srate);
1028 signal_setborrowed(*sigp, s3);
1029 (*sigp)->s_refcount++;
1030 dsp_add_zero(s3->s_vec, s3->s_n);
1031 if (ugen_loud)
1032 post("oops, belatedly set %x->%x", *sigp,
1033 (*sigp)->s_borrowedfrom);
1034 }
1035 }
1036 break; /* don't need to keep looking. */
1037 }
1038
1039 if (blk && (reblock || switched)) /* add block DSP epilog */
1040 dsp_add(block_epilog, 1, blk);
1041 chainblockend = dsp_chainsize;
1042
1043 /* add epilogs for outlets. */
1044
1045 for (u = dc->dc_ugenlist; u; u = u->u_next)
1046 {
1047 t_pd *zz = &u->u_obj->ob_pd;
1048 if (pd_class(zz) == voutlet_class)
1049 {
1050 t_signal **iosigs = dc->dc_iosigs;
1051 if (iosigs) iosigs += dc->dc_ninlets;
1052 voutlet_dspepilog((struct _voutlet *)zz,
1053 iosigs, vecsize, dsp_phase, period, frequency,
1054 downsample, upsample, /* IOhannes */
1055 reblock, switched);
1056 }
1057 }
1058
1059 chainafterall = dsp_chainsize;
1060 if (blk)
1061 {
1062 blk->x_blocklength = chainblockend - chainblockbegin;
1063 blk->x_epiloglength = chainafterall - chainblockend;
1064 blk->x_reblock = reblock;
1065 }
1066
1067 if (ugen_loud)
1068 {
1069 t_int *ip;
1070 if (!dc->dc_parentcontext)
1071 for (i = dsp_chainsize, ip = dsp_chain; i--; ip++)
1072 post("chain %x", *ip);
1073 post("... ugen_done_graph done.");
1074 }
1075 /* now delete everything. */
1076 while (dc->dc_ugenlist)
1077 {
1078 for (uout = dc->dc_ugenlist->u_out, n = dc->dc_ugenlist->u_nout;
1079 n--; uout++)
1080 {
1081 oc = uout->o_connections;
1082 while (oc)
1083 {
1084 oc2 = oc->oc_next;
1085 freebytes(oc, sizeof *oc);
1086 oc = oc2;
1087 }
1088 }
1089 freebytes(dc->dc_ugenlist->u_out, dc->dc_ugenlist->u_nout *
1090 sizeof (*dc->dc_ugenlist->u_out));
1091 freebytes(dc->dc_ugenlist->u_in, dc->dc_ugenlist->u_nin *
1092 sizeof(*dc->dc_ugenlist->u_in));
1093 u = dc->dc_ugenlist;
1094 dc->dc_ugenlist = u->u_next;
1095 freebytes(u, sizeof *u);
1096 }
1097 if (ugen_currentcontext == dc)
1098 ugen_currentcontext = dc->dc_parentcontext;
1099 else bug("ugen_currentcontext");
1100 freebytes(dc, sizeof(*dc));
1101
1102}
1103
1104t_signal *ugen_getiosig(int index, int inout)
1105{
1106 if (!ugen_currentcontext) bug("ugen_getiosig");
1107 if (ugen_currentcontext->dc_toplevel) return (0);
1108 if (inout) index += ugen_currentcontext->dc_ninlets;
1109 return (ugen_currentcontext->dc_iosigs[index]);
1110}
1111
1112
1113/* -------------------- setup routine -------------------------- */
1114
1115void d_ugen_setup(void) /* really just block_setup */
1116{
1117 block_class = class_new(gensym("block~"), (t_newmethod)block_new, 0,
1118 sizeof(t_block), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
1119 class_addcreator((t_newmethod)switch_new, gensym("switch~"),
1120 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
1121 class_addmethod(block_class, (t_method)block_set, gensym("set"),
1122 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
1123 class_addmethod(block_class, (t_method)block_dsp, gensym("dsp"), 0);
1124 class_addfloat(block_class, block_float);
1125}
1126
1127/* Copyright (c) 1997-1999 Miller Puckette.
1128* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1129* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1130
1131/* These routines build a copy of the DSP portion of a graph, which is
1132 then sorted into a linear list of DSP operations which are added to
1133 the DSP duty cycle called by the scheduler. Once that's been done,
1134 we delete the copy. The DSP objects are represented by "ugenbox"
1135 structures which are parallel to the DSP objects in the graph and
1136 have vectors of siginlets and sigoutlets which record their
1137 interconnections.
1138*/
1139
1140/* hacked to run subpatches with different samplerates
1141 * only samplerates that are a power_of_2-multiple of the
1142 *
1143 * mfg.gfd.uil
1144 * IOhannes
1145 *
1146 * edited lines are marked with "IOhannes"
1147 *
1148 */
1149
1150
1151#include "m_pd.h"
1152#include "m_imp.h"
1153#include <stdlib.h>
1154#include <stdarg.h>
1155
1156extern t_class *vinlet_class, *voutlet_class, *canvas_class;
1157t_sample *obj_findsignalscalar(t_object *x, int m);
1158static int ugen_loud;
1159EXTERN_STRUCT _vinlet;
1160EXTERN_STRUCT _voutlet;
1161
1162void vinlet_dspprolog(struct _vinlet *x, t_signal **parentsigs,
1163 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
1164 int switched);
1165void voutlet_dspprolog(struct _voutlet *x, t_signal **parentsigs,
1166 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
1167 int switched);
1168void voutlet_dspepilog(struct _voutlet *x, t_signal **parentsigs,
1169 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
1170 int switched);
1171
1172t_int *zero_perform(t_int *w) /* zero out a vector */
1173{
1174 t_float *out = (t_float *)(w[1]);
1175 int n = (int)(w[2]);
1176 while (n--) *out++ = 0;
1177 return (w+3);
1178}
1179
1180t_int *zero_perf8(t_int *w)
1181{
1182 t_float *out = (t_float *)(w[1]);
1183 int n = (int)(w[2]);
1184
1185 for (; n; n -= 8, out += 8)
1186 {
1187 out[0] = 0;
1188 out[1] = 0;
1189 out[2] = 0;
1190 out[3] = 0;
1191 out[4] = 0;
1192 out[5] = 0;
1193 out[6] = 0;
1194 out[7] = 0;
1195 }
1196 return (w+3);
1197}
1198
1199void dsp_add_zero(t_sample *out, int n)
1200{
1201 if (n&7)
1202 dsp_add(zero_perform, 2, out, n);
1203 else
1204 dsp_add(zero_perf8, 2, out, n);
1205}
1206
1207/* ---------------------------- block~ ----------------------------- */
1208
1209/* The "block~ object maintains the containing canvas's DSP computation,
1210calling it at a super- or sub-multiple of the containing canvas's
1211calling frequency. The block~'s creation arguments specify block size
1212and overlap. Block~ does no "dsp" computation in its own right, but it
1213adds prolog and epilog code before and after the canvas's unit generators.
1214
1215A subcanvas need not have a block~ at all; if there's none, its
1216ugens are simply put on the list without any prolog or epilog code.
1217
1218Block~ may be invoked as switch~, in which case it also acts to switch the
1219subcanvas on and off. The overall order of scheduling for a subcanvas
1220is thus,
1221
1222 inlet and outlet prologue code (1)
1223 block prologue (2)
1224 the objects in the subcanvas, including inlets and outlets
1225 block epilogue (2)
1226 outlet epilogue code (2)
1227
1228where (1) means, "if reblocked" and (2) means, "if reblocked or switched".
1229
1230If we're reblocked, the inlet prolog and outlet epilog code takes care of
1231overlapping and buffering to deal with vector size changes. If we're switched
1232but not reblocked, the inlet prolog is not needed, and the output epilog is
1233ONLY run when the block is switched off; in this case the epilog code simply
1234copies zeros to all signal outlets.
1235*/
1236
1237static int dsp_phase;
1238static t_class *block_class;
1239
1240typedef struct _block
1241{
1242 t_object x_obj;
1243 int x_vecsize;
1244 int x_overlap;
1245 int x_phase; /* from 0 to period-1; when zero we run the block */
1246 int x_period; /* submultiple of containing canvas */
1247 int x_frequency; /* supermultiple of comtaining canvas */
1248 int x_count;
1249 int x_blocklength; /* length of dspchain for this block */
1250 int x_epiloglength; /* length of epilog */
1251 char x_switched; /* true if we're acting as a a switch */
1252 char x_switchon; /* true if we're switched on */
1253 char x_reblock; /* true if inlets and outlets are reblocking */
1254 int x_upsample; /* IOhannes: upsampling-factor */
1255 int x_downsample; /* IOhannes: downsampling-factor */
1256
1257} t_block;
1258
1259static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
1260 t_floatarg fupsample);
1261
1262static void *block_new(t_floatarg fvecsize, t_floatarg foverlap,
1263 t_floatarg fupsample) /* IOhannes */
1264{
1265 t_block *x = (t_block *)pd_new(block_class);
1266 x->x_phase = 0;
1267 x->x_period = 1;
1268 x->x_frequency = 1;
1269 x->x_switched = 0;
1270 x->x_switchon = 1;
1271 block_set(x, fvecsize, foverlap, fupsample);
1272 return (x);
1273}
1274
1275static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
1276 t_floatarg fupsample)
1277{
1278 int upsample, downsample; /* IOhannes */
1279 int vecsize = fvecsize;
1280 int overlap = foverlap;
1281 int dspstate = canvas_suspend_dsp();
1282 if (overlap < 1)
1283 overlap = 1;
1284 if (vecsize < 0)
1285 vecsize = 0; /* this means we'll get it from parent later. */
1286
1287 /* IOhannes { */
1288 if (fupsample <= 0) upsample = downsample = 1;
1289 else if (fupsample >= 1) {
1290 upsample = fupsample;
1291 downsample = 1;
1292 } else {
1293 downsample = 1.0 / fupsample;
1294 upsample = 1;
1295 }
1296 /* } IOhannes */
1297
1298 if (vecsize && (vecsize != (1 << ilog2(vecsize))))
1299 {
1300 pd_error(x, "block~: vector size not a power of 2");
1301 vecsize = 64;
1302 }
1303 if (overlap != (1 << ilog2(overlap)))
1304 {
1305 pd_error(x, "block~: overlap not a power of 2");
1306 overlap = 1;
1307 }
1308 /* IOhannes { */
1309 if (downsample != (1 << ilog2(downsample)))
1310 {
1311 pd_error(x, "block~: downsampling not a power of 2");
1312 downsample = 1;
1313 }
1314 if (upsample != (1 << ilog2(upsample)))
1315 {
1316 pd_error(x, "block~: upsampling not a power of 2");
1317 upsample = 1;
1318 }
1319 /* } IOhannes */
1320
1321
1322 x->x_vecsize = vecsize;
1323 x->x_overlap = overlap;
1324 /* IOhannes { */
1325 x->x_upsample = upsample;
1326 x->x_downsample = downsample;
1327 /* } IOhannes */
1328 canvas_resume_dsp(dspstate);
1329}
1330
1331static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap,
1332 t_floatarg fupsample) /* IOhannes */
1333{
1334 t_block *x = (t_block *)(block_new(fvecsize, foverlap, fupsample)); /* IOhannes */
1335 x->x_switched = 1;
1336 x->x_switchon = 0;
1337 return (x);
1338}
1339
1340static void block_float(t_block *x, t_floatarg f)
1341{
1342 if (x->x_switched)
1343 x->x_switchon = (f != 0);
1344}
1345#define PROLOGCALL 2
1346#define EPILOGCALL 2
1347
1348static t_int *block_prolog(t_int *w)
1349{
1350 t_block *x = (t_block *)w[1];
1351 int phase = x->x_phase;
1352 /* if we're switched off, jump past the epilog code */
1353 if (!x->x_switchon)
1354 return (w + x->x_blocklength);
1355 if (phase)
1356 {
1357 phase++;
1358 if (phase == x->x_period) phase = 0;
1359 x->x_phase = phase;
1360 return (w + x->x_blocklength); /* skip block; jump past epilog */
1361 }
1362 else
1363 {
1364 x->x_count = x->x_frequency;
1365 x->x_phase = (x->x_period > 1 ? 1 : 0);
1366 return (w + PROLOGCALL); /* beginning of block is next ugen */
1367 }
1368}
1369
1370static t_int *block_epilog(t_int *w)
1371{
1372 t_block *x = (t_block *)w[1];
1373 int count = x->x_count - 1;
1374 if (!x->x_reblock)
1375 return (w + x->x_epiloglength + EPILOGCALL);
1376 if (count)
1377 {
1378 x->x_count = count;
1379 return (w - (x->x_blocklength -
1380 (PROLOGCALL + EPILOGCALL))); /* go to ugen after prolog */
1381 }
1382 else return (w + EPILOGCALL);
1383}
1384
1385static void block_dsp(t_block *x, t_signal **sp)
1386{
1387 /* do nothing here */
1388}
1389
1390/* ------------------ DSP call list ----------------------- */
1391
1392static t_int *dsp_chain;
1393static int dsp_chainsize;
1394
1395void dsp_add(t_perfroutine f, int n, ...)
1396{
1397 int newsize = dsp_chainsize + n+1, i;
1398 va_list ap;
1399
1400 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
1401 newsize * sizeof (t_int));
1402 dsp_chain[dsp_chainsize-1] = (t_int)f;
1403 va_start(ap, n);
1404 for (i = 0; i < n; i++)
1405 dsp_chain[dsp_chainsize + i] = va_arg(ap, t_int);
1406 va_end(ap);
1407 dsp_chain[newsize-1] = 0;
1408 dsp_chainsize = newsize;
1409}
1410
1411 /* at Guenter's suggestion, here's a vectorized version */
1412void dsp_addv(t_perfroutine f, int n, t_int *vec)
1413{
1414 int newsize = dsp_chainsize + n+1, i;
1415
1416 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
1417 newsize * sizeof (t_int));
1418 dsp_chain[dsp_chainsize-1] = (t_int)f;
1419 for (i = 0; i < n; i++)
1420 dsp_chain[dsp_chainsize + i] = vec[i];
1421 dsp_chain[newsize-1] = 0;
1422 dsp_chainsize = newsize;
1423}
1424
1425void dsp_tick(void)
1426{
1427 if (dsp_chain)
1428 {
1429 t_int *ip;
1430 for (ip = dsp_chain; *ip; ) ip = (*(t_perfroutine)(*ip))(ip);
1431 dsp_phase++;
1432 }
1433}
1434
1435/* ---------------- signals ---------------------------- */
1436
1437int ilog2(int n)
1438{
1439 int r = -1;
1440 if (n <= 0) return(0);
1441 while (n)
1442 {
1443 r++;
1444 n >>= 1;
1445 }
1446 return (r);
1447}
1448
1449 /* list of signals which can be reused, sorted by buffer size */
1450static t_signal *signal_freelist[MAXLOGSIG+1];
1451 /* list of reusable "borrowed" signals (which don't own sample buffers) */
1452static t_signal *signal_freeborrowed;
1453 /* list of all signals allocated (not including "borrowed" ones) */
1454static t_signal *signal_usedlist;
1455
1456 /* call this when DSP is stopped to free all the signals */
1457void signal_cleanup(void)
1458{
1459 t_signal **svec, *sig, *sig2;
1460 int i;
1461 while (sig = signal_usedlist)
1462 {
1463 signal_usedlist = sig->s_nextused;
1464 if (!sig->s_isborrowed)
1465 t_freebytes(sig->s_vec, sig->s_n * sizeof (*sig->s_vec));
1466 t_freebytes(sig, sizeof *sig);
1467 }
1468 for (i = 0; i <= MAXLOGSIG; i++)
1469 signal_freelist[i] = 0;
1470 signal_freeborrowed = 0;
1471}
1472
1473 /* mark the signal "reusable." */
1474void signal_makereusable(t_signal *sig)
1475{
1476 int logn = ilog2(sig->s_n);
1477#if 1
1478 t_signal *s5;
1479 for (s5 = signal_freeborrowed; s5; s5 = s5->s_nextfree)
1480 {
1481 if (s5 == sig)
1482 {
1483 bug("signal_free 3");
1484 return;
1485 }
1486 }
1487 for (s5 = signal_freelist[logn]; s5; s5 = s5->s_nextfree)
1488 {
1489 if (s5 == sig)
1490 {
1491 bug("signal_free 4");
1492 return;
1493 }
1494 }
1495#endif
1496 if (ugen_loud) post("free %x: %d", sig, sig->s_isborrowed);
1497 if (sig->s_isborrowed)
1498 {
1499 /* if the signal is borrowed, decrement the borrowed-from signal's
1500 reference count, possibly marking it reusable too */
1501 t_signal *s2 = sig->s_borrowedfrom;
1502 if ((s2 == sig) || !s2)
1503 bug("signal_free");
1504 s2->s_refcount--;
1505 if (!s2->s_refcount)
1506 signal_makereusable(s2);
1507 sig->s_nextfree = signal_freeborrowed;
1508 signal_freeborrowed = sig;
1509 }
1510 else
1511 {
1512 /* if it's a real signal (not borrowed), put it on the free list
1513 so we can reuse it. */
1514 if (signal_freelist[logn] == sig) bug("signal_free 2");
1515 sig->s_nextfree = signal_freelist[logn];
1516 signal_freelist[logn] = sig;
1517 }
1518}
1519
1520 /* reclaim or make an audio signal. If n is zero, return a "borrowed"
1521 signal whose buffer and size will be obtained later via
1522 signal_setborrowed(). */
1523
1524t_signal *signal_new(int n, float sr)
1525{
1526 int logn, n2;
1527 t_signal *ret, **whichlist;
1528 t_sample *fp;
1529 logn = ilog2(n);
1530 if (n)
1531 {
1532 if (n != (1 << logn))
1533 bug("signal buffer not a power of 2");
1534 if (logn > MAXLOGSIG)
1535 bug("signal buffer too large");
1536 whichlist = signal_freelist + logn;
1537 }
1538 else
1539 whichlist = &signal_freeborrowed;
1540
1541 /* first try to reclaim one from the free list */
1542 if (ret = *whichlist)
1543 *whichlist = ret->s_nextfree;
1544 else
1545 {
1546 /* LATER figure out what to do for out-of-space here! */
1547 ret = (t_signal *)t_getbytes(sizeof *ret);
1548 if (n)
1549 {
1550 ret->s_vec = (t_sample *)getbytes(n * sizeof (*ret->s_vec));
1551 ret->s_isborrowed = 0;
1552 }
1553 else
1554 {
1555 ret->s_vec = 0;
1556 ret->s_isborrowed = 1;
1557 }
1558 ret->s_nextused = signal_usedlist;
1559 signal_usedlist = ret;
1560 }
1561 ret->s_n = n;
1562 ret->s_sr = sr;
1563 ret->s_refcount = 0;
1564 ret->s_borrowedfrom = 0;
1565 if (ugen_loud) post("new %x: %d", ret, ret->s_isborrowed);
1566 return (ret);
1567}
1568
1569static t_signal *signal_newlike(const t_signal *sig)
1570{
1571 return (signal_new(sig->s_n, sig->s_sr));
1572}
1573
1574void signal_setborrowed(t_signal *sig, t_signal *sig2)
1575{
1576 if (!sig->s_isborrowed || sig->s_borrowedfrom)
1577 bug("signal_setborrowed");
1578 if (sig == sig2)
1579 bug("signal_setborrowed 2");
1580 sig->s_borrowedfrom = sig2;
1581 sig->s_vec = sig2->s_vec;
1582 sig->s_n = sig2->s_n;
1583}
1584
1585int signal_compatible(t_signal *s1, t_signal *s2)
1586{
1587 return (s1->s_n == s2->s_n && s1->s_sr == s2->s_sr);
1588}
1589
1590/* ------------------ ugen ("unit generator") sorting ----------------- */
1591
1592typedef struct _ugenbox
1593{
1594 struct _siginlet *u_in;
1595 int u_nin;
1596 struct _sigoutlet *u_out;
1597 int u_nout;
1598 int u_phase;
1599 struct _ugenbox *u_next;
1600 t_object *u_obj;
1601 int u_done;
1602} t_ugenbox;
1603
1604typedef struct _siginlet
1605{
1606 int i_nconnect;
1607 int i_ngot;
1608 t_signal *i_signal;
1609} t_siginlet;
1610
1611typedef struct _sigoutconnect
1612{
1613 t_ugenbox *oc_who;
1614 int oc_inno;
1615 struct _sigoutconnect *oc_next;
1616} t_sigoutconnect;
1617
1618typedef struct _sigoutlet
1619{
1620 int o_nconnect;
1621 int o_nsent;
1622 t_signal *o_signal;
1623 t_sigoutconnect *o_connections;
1624} t_sigoutlet;
1625
1626
1627struct _dspcontext
1628{
1629 struct _ugenbox *dc_ugenlist;
1630 struct _dspcontext *dc_parentcontext;
1631 int dc_ninlets;
1632 int dc_noutlets;
1633 t_signal **dc_iosigs;
1634 float dc_srate;
1635 int dc_vecsize;
1636 char dc_toplevel; /* true if "iosigs" is invalid. */
1637 char dc_reblock; /* true if we have to reblock inlets/outlets */
1638 char dc_switched; /* true if we're switched */
1639
1640};
1641
1642#define t_dspcontext struct _dspcontext
1643
1644static int ugen_sortno = 0;
1645static t_dspcontext *ugen_currentcontext;
1646
1647void ugen_stop(void)
1648{
1649 t_signal *s;
1650 int i;
1651 if (dsp_chain)
1652 {
1653 freebytes(dsp_chain, dsp_chainsize * sizeof (t_int));
1654 dsp_chain = 0;
1655 }
1656 signal_cleanup();
1657
1658}
1659
1660void ugen_start(void)
1661{
1662 ugen_stop();
1663 ugen_sortno++;
1664 dsp_chain = (t_int *)getbytes(sizeof(*dsp_chain));
1665 dsp_chain[0] = 0;
1666 dsp_chainsize = 1;
1667 if (ugen_currentcontext) bug("ugen_start");
1668}
1669
1670int ugen_getsortno(void)
1671{
1672 return (ugen_sortno);
1673}
1674
1675#if 0
1676void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
1677{
1678 int i, count;
1679 t_signal *sig;
1680 for (count = 0, sig = signal_usedlist; sig;
1681 count++, sig = sig->s_nextused)
1682 ;
1683 post("used signals %d", count);
1684 for (i = 0; i < MAXLOGSIG; i++)
1685 {
1686 for (count = 0, sig = signal_freelist[i]; sig;
1687 count++, sig = sig->s_nextfree)
1688 ;
1689 if (count)
1690 post("size %d: free %d", (1 << i), count);
1691 }
1692 for (count = 0, sig = signal_freeborrowed; sig;
1693 count++, sig = sig->s_nextfree)
1694 ;
1695 post("free borrowed %d", count);
1696
1697 ugen_loud = argc;
1698}
1699#endif
1700
1701 /* start building the graph for a canvas */
1702t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
1703 int ninlets, int noutlets)
1704{
1705 t_dspcontext *dc = (t_dspcontext *)getbytes(sizeof(*dc));
1706 float parent_srate, srate;
1707 int parent_vecsize, vecsize;
1708
1709 if (ugen_loud) post("ugen_start_graph...");
1710
1711 dc->dc_ugenlist = 0;
1712 dc->dc_toplevel = toplevel;
1713 dc->dc_iosigs = sp;
1714 dc->dc_ninlets = ninlets;
1715 dc->dc_noutlets = noutlets;
1716 dc->dc_parentcontext = ugen_currentcontext;
1717 ugen_currentcontext = dc;
1718 return (dc);
1719}
1720
1721 /* first the canvas calls this to create all the boxes... */
1722void ugen_add(t_dspcontext *dc, t_object *obj)
1723{
1724 t_ugenbox *x = (t_ugenbox *)getbytes(sizeof *x);
1725 int i;
1726 t_sigoutlet *uout;
1727 t_siginlet *uin;
1728
1729 x->u_next = dc->dc_ugenlist;
1730 dc->dc_ugenlist = x;
1731 x->u_obj = obj;
1732 x->u_nin = obj_nsiginlets(obj);
1733 x->u_in = getbytes(x->u_nin * sizeof (*x->u_in));
1734 for (uin = x->u_in, i = x->u_nin; i--; uin++)
1735 uin->i_nconnect = 0;
1736 x->u_nout = obj_nsigoutlets(obj);
1737 x->u_out = getbytes(x->u_nout * sizeof (*x->u_out));
1738 for (uout = x->u_out, i = x->u_nout; i--; uout++)
1739 uout->o_connections = 0, uout->o_nconnect = 0;
1740}
1741
1742 /* and then this to make all the connections. */
1743void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2,
1744 int inno)
1745{
1746 t_ugenbox *u1, *u2;
1747 t_sigoutlet *uout;
1748 t_siginlet *uin;
1749 t_sigoutconnect *oc;
1750 int sigoutno = obj_sigoutletindex(x1, outno);
1751 int siginno = obj_siginletindex(x2, inno);
1752 if (ugen_loud)
1753 post("%s -> %s: %d->%d",
1754 class_getname(x1->ob_pd),
1755 class_getname(x2->ob_pd), outno, inno);
1756 for (u1 = dc->dc_ugenlist; u1 && u1->u_obj != x1; u1 = u1->u_next);
1757 for (u2 = dc->dc_ugenlist; u2 && u2->u_obj != x2; u2 = u2->u_next);
1758 if (!u1 || !u2 || siginno < 0)
1759 {
1760 pd_error(u1->u_obj,
1761 "signal outlet connect to nonsignal inlet (ignored)");
1762 return;
1763 }
1764 if (sigoutno < 0 || sigoutno >= u1->u_nout || siginno >= u2->u_nin)
1765 {
1766 bug("ugen_connect %s %s %d %d (%d %d)",
1767 class_getname(x1->ob_pd),
1768 class_getname(x2->ob_pd), sigoutno, siginno, u1->u_nout,
1769 u2->u_nin);
1770 }
1771 uout = u1->u_out + sigoutno;
1772 uin = u2->u_in + siginno;
1773
1774 /* add a new connection to the outlet's list */
1775 oc = (t_sigoutconnect *)getbytes(sizeof *oc);
1776 oc->oc_next = uout->o_connections;
1777 uout->o_connections = oc;
1778 oc->oc_who = u2;
1779 oc->oc_inno = siginno;
1780 /* update inlet and outlet counts */
1781 uout->o_nconnect++;
1782 uin->i_nconnect++;
1783}
1784
1785 /* get the index of a ugenbox or -1 if it's not on the list */
1786static int ugen_index(t_dspcontext *dc, t_ugenbox *x)
1787{
1788 int ret;
1789 t_ugenbox *u;
1790 for (u = dc->dc_ugenlist, ret = 0; u; u = u->u_next, ret++)
1791 if (u == x) return (ret);
1792 return (-1);
1793}
1794
1795 /* put a ugenbox on the chain, recursively putting any others on that
1796 this one might uncover. */
1797static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
1798{
1799 t_sigoutlet *uout;
1800 t_siginlet *uin;
1801 t_sigoutconnect *oc, *oc2;
1802 t_class *class = pd_class(&u->u_obj->ob_pd);
1803 int i, n;
1804 /* suppress creating new signals for the outputs of signal
1805 inlets and subpatchs; except in the case we're an inlet and "blocking"
1806 is set. We don't yet know if a subcanvas will be "blocking" so there
1807 we delay new signal creation, which will be handled by calling
1808 signal_setborrowed in the ugen_done_graph routine below. */
1809 int nonewsigs = (class == canvas_class ||
1810 (class == vinlet_class) && !(dc->dc_reblock));
1811 /* when we encounter a subcanvas or a signal outlet, suppress freeing
1812 the input signals as they may be "borrowed" for the super or sub
1813 patch; same exception as above, but also if we're "switched" we
1814 have to do a copy rather than a borrow. */
1815 int nofreesigs = (class == canvas_class ||
1816 (class == voutlet_class) && !(dc->dc_reblock || dc->dc_switched));
1817 t_signal **insig, **outsig, **sig, *s1, *s2, *s3;
1818 t_ugenbox *u2;
1819
1820 if (ugen_loud) post("doit %s %d %d", class_getname(class), nofreesigs,
1821 nonewsigs);
1822 for (i = 0, uin = u->u_in; i < u->u_nin; i++, uin++)
1823 {
1824 if (!uin->i_nconnect)
1825 {
1826 t_sample *scalar;
1827 s3 = signal_new(dc->dc_vecsize, dc->dc_srate);
1828 /* post("%s: unconnected signal inlet set to zero",
1829 class_getname(u->u_obj->ob_pd)); */
1830 if (scalar = obj_findsignalscalar(u->u_obj, i))
1831 dsp_add_scalarcopy(scalar, s3->s_vec, s3->s_n);
1832 else
1833 dsp_add_zero(s3->s_vec, s3->s_n);
1834 uin->i_signal = s3;
1835 s3->s_refcount = 1;
1836 }
1837 }
1838 insig = (t_signal **)getbytes((u->u_nin + u->u_nout) * sizeof(t_signal *));
1839 outsig = insig + u->u_nin;
1840 for (sig = insig, uin = u->u_in, i = u->u_nin; i--; sig++, uin++)
1841 {
1842 int newrefcount;
1843 *sig = uin->i_signal;
1844 newrefcount = --(*sig)->s_refcount;
1845 /* if the reference count went to zero, we free the signal now,
1846 unless it's a subcanvas or outlet; these might keep the
1847 signal around to send to objects connected to them. In this
1848 case we increment the reference count; the corresponding decrement
1849 is in sig_makereusable(). */
1850 if (nofreesigs)
1851 (*sig)->s_refcount++;
1852 else if (!newrefcount)
1853 signal_makereusable(*sig);
1854 }
1855 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
1856 {
1857 /* similarly, for outlets of subcanvases we delay creating
1858 them; instead we create "borrowed" ones so that the refcount
1859 is known. The subcanvas replaces the fake signal with one showing
1860 where the output data actually is, to avoid having to copy it.
1861 For any other object, we just allocate a new output vector;
1862 since we've already freed the inputs the objects might get called
1863 "in place." */
1864 if (nonewsigs)
1865 {
1866 *sig = uout->o_signal =
1867 signal_new(0, dc->dc_srate);
1868 }
1869 else
1870 *sig = uout->o_signal = signal_new(dc->dc_vecsize, dc->dc_srate);
1871 (*sig)->s_refcount = uout->o_nconnect;
1872 }
1873 /* now call the DSP scheduling routine for the ugen. This
1874 routine must fill in "borrowed" signal outputs in case it's either
1875 a subcanvas or a signal inlet. */
1876 mess1(&u->u_obj->ob_pd, gensym("dsp"), insig);
1877
1878 /* if any output signals aren't connected to anyone, free them
1879 now; otherwise they'll either get freed when the reference count
1880 goes back to zero, or even later as explained above. */
1881
1882 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
1883 {
1884 if (!(*sig)->s_refcount)
1885 signal_makereusable(*sig);
1886 }
1887 if (ugen_loud)
1888 {
1889 if (u->u_nin + u->u_nout == 0) post("put %s %d",
1890 class_getname(u->u_obj->ob_pd), ugen_index(dc, u));
1891 else if (u->u_nin + u->u_nout == 1) post("put %s %d (%x)",
1892 class_getname(u->u_obj->ob_pd), ugen_index(dc, u), sig[0]);
1893 else if (u->u_nin + u->u_nout == 2) post("put %s %d (%x %x)",
1894 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
1895 sig[0], sig[1]);
1896 else post("put %s %d (%x %x %x ...)",
1897 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
1898 sig[0], sig[1], sig[2]);
1899 }
1900
1901 /* pass it on and trip anyone whose last inlet was filled */
1902 for (uout = u->u_out, i = u->u_nout; i--; uout++)
1903 {
1904 s1 = uout->o_signal;
1905 for (oc = uout->o_connections; oc; oc = oc->oc_next)
1906 {
1907 u2 = oc->oc_who;
1908 uin = &u2->u_in[oc->oc_inno];
1909 /* if there's already someone here, sum the two */
1910 if (s2 = uin->i_signal)
1911 {
1912 s1->s_refcount--;
1913 s2->s_refcount--;
1914 if (!signal_compatible(s1, s2))
1915 {
1916 pd_error(u->u_obj, "%s: incompatible signal inputs",
1917 class_getname(u->u_obj->ob_pd));
1918 return;
1919 }
1920 s3 = signal_newlike(s1);
1921 dsp_add_plus(s1->s_vec, s2->s_vec, s3->s_vec, s1->s_n);
1922 uin->i_signal = s3;
1923 s3->s_refcount = 1;
1924 if (!s1->s_refcount) signal_makereusable(s1);
1925 if (!s2->s_refcount) signal_makereusable(s2);
1926 }
1927 else uin->i_signal = s1;
1928 uin->i_ngot++;
1929 /* if we didn't fill this inlet don't bother yet */
1930 if (uin->i_ngot < uin->i_nconnect)
1931 goto notyet;
1932 /* if there's more than one, check them all */
1933 if (u2->u_nin > 1)
1934 {
1935 for (uin = u2->u_in, n = u2->u_nin; n--; uin++)
1936 if (uin->i_ngot < uin->i_nconnect) goto notyet;
1937 }
1938 /* so now we can schedule the ugen. */
1939 ugen_doit(dc, u2);
1940 notyet: ;
1941 }
1942 }
1943 t_freebytes(insig,(u->u_nin + u->u_nout) * sizeof(t_signal *));
1944 u->u_done = 1;
1945}
1946
1947 /* once the DSP graph is built, we call this routine to sort it.
1948 This routine also deletes the graph; later we might want to leave the
1949 graph around, in case the user is editing the DSP network, to save having
1950 to recreate it all the time. But not today. */
1951
1952void ugen_done_graph(t_dspcontext *dc)
1953{
1954 t_ugenbox *u, *u2;
1955 t_sigoutlet *uout;
1956 t_siginlet *uin;
1957 t_sigoutconnect *oc, *oc2;
1958 int i, n;
1959 t_block *blk;
1960 t_dspcontext *parent_context = dc->dc_parentcontext;
1961 float parent_srate;
1962 int parent_vecsize;
1963 int period, frequency, phase, vecsize;
1964 float srate;
1965 int chainblockbegin; /* DSP chain onset before block prolog code */
1966 int chainblockend; /* and after block epilog code */
1967 int chainafterall; /* and after signal outlet epilog */
1968 int reblock = 0, switched;
1969 int downsample = 1, upsample = 1; /* IOhannes */
1970 /* debugging printout */
1971
1972 if (ugen_loud)
1973 {
1974 post("ugen_done_graph...");
1975 for (u = dc->dc_ugenlist; u; u = u->u_next)
1976 {
1977 post("ugen: %s", class_getname(u->u_obj->ob_pd));
1978 for (uout = u->u_out, i = 0; i < u->u_nout; uout++, i++)
1979 for (oc = uout->o_connections; oc; oc = oc->oc_next)
1980 {
1981 post("... out %d to %s, index %d, inlet %d", i,
1982 class_getname(oc->oc_who->u_obj->ob_pd),
1983 ugen_index(dc, oc->oc_who), oc->oc_inno);
1984 }
1985 }
1986 }
1987
1988 /* search for an object of class "block~" */
1989 for (u = dc->dc_ugenlist, blk = 0; u; u = u->u_next)
1990 {
1991 t_pd *zz = &u->u_obj->ob_pd;
1992 if (pd_class(zz) == block_class)
1993 {
1994 if (blk)
1995 pd_error(blk, "conflicting block~ objects in same page");
1996 else blk = (t_block *)zz;
1997 }
1998 }
1999
2000 /* figure out block size, calling frequency, sample rate */
2001 if (parent_context)
2002 {
2003 parent_srate = parent_context->dc_srate;
2004 parent_vecsize = parent_context->dc_vecsize;
2005 }
2006 else
2007 {
2008 parent_srate = sys_getsr();
2009 parent_vecsize = sys_getblksize();
2010 }
2011 if (blk)
2012 {
2013 int realoverlap;
2014 vecsize = blk->x_vecsize;
2015 if (vecsize == 0)
2016 vecsize = parent_vecsize;
2017 realoverlap = blk->x_overlap;
2018 if (realoverlap > vecsize) realoverlap = vecsize;
2019 /* IOhannes { */
2020 downsample = blk->x_downsample;
2021 upsample = blk->x_upsample;
2022 if (downsample > parent_vecsize) downsample=parent_vecsize;
2023 period = (vecsize * downsample)/
2024 (parent_vecsize * realoverlap * upsample);
2025 frequency = (parent_vecsize * realoverlap * upsample)/
2026 (vecsize * downsample);
2027 /* } IOhannes*/
2028 phase = blk->x_phase;
2029 srate = parent_srate * realoverlap * upsample / downsample;
2030 /* IOhannes */
2031 if (period < 1) period = 1;
2032 if (frequency < 1) frequency = 1;
2033 blk->x_frequency = frequency;
2034 blk->x_period = period;
2035 blk->x_phase = dsp_phase & (period - 1);
2036 if (! parent_context || (realoverlap != 1) ||
2037 (vecsize != parent_vecsize) ||
2038 (downsample != 1) || (upsample != 1)) /* IOhannes */
2039 reblock = 1;
2040 switched = blk->x_switched;
2041 }
2042 else
2043 {
2044 srate = parent_srate;
2045 vecsize = parent_vecsize;
2046 downsample = upsample = 1;/* IOhannes */
2047 period = frequency = 1;
2048 phase = 0;
2049 if (!parent_context) reblock = 1;
2050 switched = 0;
2051 }
2052 dc->dc_reblock = reblock;
2053 dc->dc_switched = switched;
2054 dc->dc_srate = srate;
2055 dc->dc_vecsize = vecsize;
2056
2057 /* if we're reblocking or switched, we now have to create output
2058 signals to fill in for the "borrowed" ones we have now. This
2059 is also possibly true even if we're not blocked/switched, in
2060 the case that there was a signal loop. But we don't know this
2061 yet. */
2062
2063 if (dc->dc_iosigs && (switched || reblock))
2064 {
2065 t_signal **sigp;
2066 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
2067 i++, sigp++)
2068 {
2069 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
2070 {
2071 signal_setborrowed(*sigp,
2072 signal_new(parent_vecsize, parent_srate));
2073 (*sigp)->s_refcount++;
2074
2075 if (ugen_loud) post("set %x->%x", *sigp,
2076 (*sigp)->s_borrowedfrom);
2077 }
2078 }
2079 }
2080
2081 if (ugen_loud)
2082 post("reblock %d, switched %d", reblock, switched);
2083
2084 /* schedule prologs for inlets and outlets. If the "reblock" flag
2085 is set, an inlet will put code on the DSP chain to copy its input
2086 into an internal buffer here, before any unit generators' DSP code
2087 gets scheduled. If we don't "reblock", inlets will need to get
2088 pointers to their corresponding inlets/outlets on the box we're inside,
2089 if any. Outlets will also need pointers, unless we're switched, in
2090 which case outlet epilog code will kick in. */
2091
2092 for (u = dc->dc_ugenlist; u; u = u->u_next)
2093 {
2094 t_pd *zz = &u->u_obj->ob_pd;
2095 t_signal **insigs = dc->dc_iosigs, **outsigs = dc->dc_iosigs;
2096 if (outsigs) outsigs += dc->dc_ninlets;
2097
2098 if (pd_class(zz) == vinlet_class)
2099 vinlet_dspprolog((struct _vinlet *)zz,
2100 dc->dc_iosigs, vecsize, dsp_phase, period, frequency,
2101 downsample, upsample, /* IOhannes */
2102 reblock, switched);
2103 else if (pd_class(zz) == voutlet_class)
2104 voutlet_dspprolog((struct _voutlet *)zz,
2105 outsigs, vecsize, dsp_phase, period, frequency,
2106 downsample, upsample, /* IOhannes */
2107 reblock, switched);
2108 }
2109 chainblockbegin = dsp_chainsize;
2110
2111 if (blk && (reblock || switched)) /* add the block DSP prolog */
2112 dsp_add(block_prolog, 1, blk);
2113
2114 /* Initialize for sorting */
2115 for (u = dc->dc_ugenlist; u; u = u->u_next)
2116 {
2117 u->u_done = 0;
2118 for (uout = u->u_out, i = u->u_nout; i--; uout++)
2119 uout->o_nsent = 0;
2120 for (uin = u->u_in, i = u->u_nin; i--; uin++)
2121 uin->i_ngot = 0, uin->i_signal = 0;
2122 }
2123
2124 /* Do the sort */
2125
2126 for (u = dc->dc_ugenlist; u; u = u->u_next)
2127 {
2128 /* check that we have no connected signal inlets */
2129 if (u->u_done) continue;
2130 for (uin = u->u_in, i = u->u_nin; i--; uin++)
2131 if (uin->i_nconnect) goto next;
2132
2133 ugen_doit(dc, u);
2134 next: ;
2135 }
2136
2137 /* check for a DSP loop, which is evidenced here by the presence
2138 of ugens not yet scheduled. */
2139
2140 for (u = dc->dc_ugenlist; u; u = u->u_next)
2141 if (!u->u_done)
2142 {
2143 t_signal **sigp;
2144 pd_error(u->u_obj,
2145 "DSP loop detected (some tilde objects not scheduled)");
2146 /* this might imply that we have unfilled "borrowed" outputs
2147 which we'd better fill in now. */
2148 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
2149 i++, sigp++)
2150 {
2151 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
2152 {
2153 t_signal *s3 = signal_new(parent_vecsize, parent_srate);
2154 signal_setborrowed(*sigp, s3);
2155 (*sigp)->s_refcount++;
2156 dsp_add_zero(s3->s_vec, s3->s_n);
2157 if (ugen_loud)
2158 post("oops, belatedly set %x->%x", *sigp,
2159 (*sigp)->s_borrowedfrom);
2160 }
2161 }
2162 break; /* don't need to keep looking. */
2163 }
2164
2165 if (blk && (reblock || switched)) /* add block DSP epilog */
2166 dsp_add(block_epilog, 1, blk);
2167 chainblockend = dsp_chainsize;
2168
2169 /* add epilogs for outlets. */
2170
2171 for (u = dc->dc_ugenlist; u; u = u->u_next)
2172 {
2173 t_pd *zz = &u->u_obj->ob_pd;
2174 if (pd_class(zz) == voutlet_class)
2175 {
2176 t_signal **iosigs = dc->dc_iosigs;
2177 if (iosigs) iosigs += dc->dc_ninlets;
2178 voutlet_dspepilog((struct _voutlet *)zz,
2179 iosigs, vecsize, dsp_phase, period, frequency,
2180 downsample, upsample, /* IOhannes */
2181 reblock, switched);
2182 }
2183 }
2184
2185 chainafterall = dsp_chainsize;
2186 if (blk)
2187 {
2188 blk->x_blocklength = chainblockend - chainblockbegin;
2189 blk->x_epiloglength = chainafterall - chainblockend;
2190 blk->x_reblock = reblock;
2191 }
2192
2193 if (ugen_loud)
2194 {
2195 t_int *ip;
2196 if (!dc->dc_parentcontext)
2197 for (i = dsp_chainsize, ip = dsp_chain; i--; ip++)
2198 post("chain %x", *ip);
2199 post("... ugen_done_graph done.");
2200 }
2201 /* now delete everything. */
2202 while (dc->dc_ugenlist)
2203 {
2204 for (uout = dc->dc_ugenlist->u_out, n = dc->dc_ugenlist->u_nout;
2205 n--; uout++)
2206 {
2207 oc = uout->o_connections;
2208 while (oc)
2209 {
2210 oc2 = oc->oc_next;
2211 freebytes(oc, sizeof *oc);
2212 oc = oc2;
2213 }
2214 }
2215 freebytes(dc->dc_ugenlist->u_out, dc->dc_ugenlist->u_nout *
2216 sizeof (*dc->dc_ugenlist->u_out));
2217 freebytes(dc->dc_ugenlist->u_in, dc->dc_ugenlist->u_nin *
2218 sizeof(*dc->dc_ugenlist->u_in));
2219 u = dc->dc_ugenlist;
2220 dc->dc_ugenlist = u->u_next;
2221 freebytes(u, sizeof *u);
2222 }
2223 if (ugen_currentcontext == dc)
2224 ugen_currentcontext = dc->dc_parentcontext;
2225 else bug("ugen_currentcontext");
2226 freebytes(dc, sizeof(*dc));
2227
2228}
2229
2230t_signal *ugen_getiosig(int index, int inout)
2231{
2232 if (!ugen_currentcontext) bug("ugen_getiosig");
2233 if (ugen_currentcontext->dc_toplevel) return (0);
2234 if (inout) index += ugen_currentcontext->dc_ninlets;
2235 return (ugen_currentcontext->dc_iosigs[index]);
2236}
2237
2238
2239/* -------------------- setup routine -------------------------- */
2240
2241void d_ugen_setup(void) /* really just block_setup */
2242{
2243 block_class = class_new(gensym("block~"), (t_newmethod)block_new, 0,
2244 sizeof(t_block), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
2245 class_addcreator((t_newmethod)switch_new, gensym("switch~"),
2246 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
2247 class_addmethod(block_class, (t_method)block_set, gensym("set"),
2248 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
2249 class_addmethod(block_class, (t_method)block_dsp, gensym("dsp"), 0);
2250 class_addfloat(block_class, block_float);
2251}
2252