A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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#ifdef ROCKBOX
25#include "plugin.h"
26#include "../../pdbox.h"
27#include "m_pd.h"
28#include "m_imp.h"
29#else /* ROCKBOX */
30#include "m_pd.h"
31#include "m_imp.h"
32#include <stdlib.h>
33#include <stdarg.h>
34#endif /* ROCKBOX */
35
36extern t_class *vinlet_class, *voutlet_class, *canvas_class;
37t_sample *obj_findsignalscalar(t_object *x, int m);
38static int ugen_loud;
39EXTERN_STRUCT _vinlet;
40EXTERN_STRUCT _voutlet;
41
42void vinlet_dspprolog(struct _vinlet *x, t_signal **parentsigs,
43 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
44 int switched);
45void voutlet_dspprolog(struct _voutlet *x, t_signal **parentsigs,
46 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
47 int switched);
48void voutlet_dspepilog(struct _voutlet *x, t_signal **parentsigs,
49 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
50 int switched);
51
52t_int *zero_perform(t_int *w) /* zero out a vector */
53{
54 t_float *out = (t_float *)(w[1]);
55 int n = (int)(w[2]);
56 while (n--) *out++ = 0;
57 return (w+3);
58}
59
60t_int *zero_perf8(t_int *w)
61{
62 t_float *out = (t_float *)(w[1]);
63 int n = (int)(w[2]);
64
65 for (; n; n -= 8, out += 8)
66 {
67 out[0] = 0;
68 out[1] = 0;
69 out[2] = 0;
70 out[3] = 0;
71 out[4] = 0;
72 out[5] = 0;
73 out[6] = 0;
74 out[7] = 0;
75 }
76 return (w+3);
77}
78
79void dsp_add_zero(t_sample *out, int n)
80{
81 if (n&7)
82 dsp_add(zero_perform, 2, out, n);
83 else
84 dsp_add(zero_perf8, 2, out, n);
85}
86
87/* ---------------------------- block~ ----------------------------- */
88
89/* The "block~ object maintains the containing canvas's DSP computation,
90calling it at a super- or sub-multiple of the containing canvas's
91calling frequency. The block~'s creation arguments specify block size
92and overlap. Block~ does no "dsp" computation in its own right, but it
93adds prolog and epilog code before and after the canvas's unit generators.
94
95A subcanvas need not have a block~ at all; if there's none, its
96ugens are simply put on the list without any prolog or epilog code.
97
98Block~ may be invoked as switch~, in which case it also acts to switch the
99subcanvas on and off. The overall order of scheduling for a subcanvas
100is thus,
101
102 inlet and outlet prologue code (1)
103 block prologue (2)
104 the objects in the subcanvas, including inlets and outlets
105 block epilogue (2)
106 outlet epilogue code (2)
107
108where (1) means, "if reblocked" and (2) means, "if reblocked or switched".
109
110If we're reblocked, the inlet prolog and outlet epilog code takes care of
111overlapping and buffering to deal with vector size changes. If we're switched
112but not reblocked, the inlet prolog is not needed, and the output epilog is
113ONLY run when the block is switched off; in this case the epilog code simply
114copies zeros to all signal outlets.
115*/
116
117static int dsp_phase;
118static t_class *block_class;
119
120typedef struct _block
121{
122 t_object x_obj;
123 int x_vecsize;
124 int x_overlap;
125 int x_phase; /* from 0 to period-1; when zero we run the block */
126 int x_period; /* submultiple of containing canvas */
127 int x_frequency; /* supermultiple of comtaining canvas */
128 int x_count;
129 int x_blocklength; /* length of dspchain for this block */
130 int x_epiloglength; /* length of epilog */
131 char x_switched; /* true if we're acting as a a switch */
132 char x_switchon; /* true if we're switched on */
133 char x_reblock; /* true if inlets and outlets are reblocking */
134 int x_upsample; /* IOhannes: upsampling-factor */
135 int x_downsample; /* IOhannes: downsampling-factor */
136
137} t_block;
138
139static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
140 t_floatarg fupsample);
141
142static void *block_new(t_floatarg fvecsize, t_floatarg foverlap,
143 t_floatarg fupsample) /* IOhannes */
144{
145 t_block *x = (t_block *)pd_new(block_class);
146 x->x_phase = 0;
147 x->x_period = 1;
148 x->x_frequency = 1;
149 x->x_switched = 0;
150 x->x_switchon = 1;
151 block_set(x, fvecsize, foverlap, fupsample);
152 return (x);
153}
154
155static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
156 t_floatarg fupsample)
157{
158 int upsample, downsample; /* IOhannes */
159 int vecsize = fvecsize;
160 int overlap = foverlap;
161 int dspstate = canvas_suspend_dsp();
162 if (overlap < 1)
163 overlap = 1;
164 if (vecsize < 0)
165 vecsize = 0; /* this means we'll get it from parent later. */
166
167 /* IOhannes { */
168 if (fupsample <= 0) upsample = downsample = 1;
169 else if (fupsample >= 1) {
170 upsample = fupsample;
171 downsample = 1;
172 } else {
173 downsample = 1.0 / fupsample;
174 upsample = 1;
175 }
176 /* } IOhannes */
177
178 if (vecsize && (vecsize != (1 << ilog2(vecsize))))
179 {
180 pd_error(x, "block~: vector size not a power of 2");
181 vecsize = 64;
182 }
183 if (overlap != (1 << ilog2(overlap)))
184 {
185 pd_error(x, "block~: overlap not a power of 2");
186 overlap = 1;
187 }
188 /* IOhannes { */
189 if (downsample != (1 << ilog2(downsample)))
190 {
191 pd_error(x, "block~: downsampling not a power of 2");
192 downsample = 1;
193 }
194 if (upsample != (1 << ilog2(upsample)))
195 {
196 pd_error(x, "block~: upsampling not a power of 2");
197 upsample = 1;
198 }
199 /* } IOhannes */
200
201
202 x->x_vecsize = vecsize;
203 x->x_overlap = overlap;
204 /* IOhannes { */
205 x->x_upsample = upsample;
206 x->x_downsample = downsample;
207 /* } IOhannes */
208 canvas_resume_dsp(dspstate);
209}
210
211static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap,
212 t_floatarg fupsample) /* IOhannes */
213{
214 t_block *x = (t_block *)(block_new(fvecsize, foverlap, fupsample)); /* IOhannes */
215 x->x_switched = 1;
216 x->x_switchon = 0;
217 return (x);
218}
219
220static void block_float(t_block *x, t_floatarg f)
221{
222 if (x->x_switched)
223 x->x_switchon = (f != 0);
224}
225#define PROLOGCALL 2
226#define EPILOGCALL 2
227
228static t_int *block_prolog(t_int *w)
229{
230 t_block *x = (t_block *)w[1];
231 int phase = x->x_phase;
232 /* if we're switched off, jump past the epilog code */
233 if (!x->x_switchon)
234 return (w + x->x_blocklength);
235 if (phase)
236 {
237 phase++;
238 if (phase == x->x_period) phase = 0;
239 x->x_phase = phase;
240 return (w + x->x_blocklength); /* skip block; jump past epilog */
241 }
242 else
243 {
244 x->x_count = x->x_frequency;
245 x->x_phase = (x->x_period > 1 ? 1 : 0);
246 return (w + PROLOGCALL); /* beginning of block is next ugen */
247 }
248}
249
250static t_int *block_epilog(t_int *w)
251{
252 t_block *x = (t_block *)w[1];
253 int count = x->x_count - 1;
254 if (!x->x_reblock)
255 return (w + x->x_epiloglength + EPILOGCALL);
256 if (count)
257 {
258 x->x_count = count;
259 return (w - (x->x_blocklength -
260 (PROLOGCALL + EPILOGCALL))); /* go to ugen after prolog */
261 }
262 else return (w + EPILOGCALL);
263}
264
265static void block_dsp(t_block *x, t_signal **sp)
266{
267#ifdef ROCKBOX
268 (void) x;
269 (void) sp;
270#endif
271 /* do nothing here */
272}
273
274/* ------------------ DSP call list ----------------------- */
275
276static t_int *dsp_chain;
277static int dsp_chainsize;
278
279void dsp_add(t_perfroutine f, int n, ...)
280{
281 int newsize = dsp_chainsize + n+1, i;
282 va_list ap;
283
284 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
285 newsize * sizeof (t_int));
286 dsp_chain[dsp_chainsize-1] = (t_int)f;
287 va_start(ap, n);
288 for (i = 0; i < n; i++)
289 dsp_chain[dsp_chainsize + i] = va_arg(ap, t_int);
290 va_end(ap);
291 dsp_chain[newsize-1] = 0;
292 dsp_chainsize = newsize;
293}
294
295 /* at Guenter's suggestion, here's a vectorized version */
296void dsp_addv(t_perfroutine f, int n, t_int *vec)
297{
298 int newsize = dsp_chainsize + n+1, i;
299
300 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
301 newsize * sizeof (t_int));
302 dsp_chain[dsp_chainsize-1] = (t_int)f;
303 for (i = 0; i < n; i++)
304 dsp_chain[dsp_chainsize + i] = vec[i];
305 dsp_chain[newsize-1] = 0;
306 dsp_chainsize = newsize;
307}
308
309void dsp_tick(void)
310{
311 if (dsp_chain)
312 {
313 t_int *ip;
314 for (ip = dsp_chain; *ip; ) ip = (*(t_perfroutine)(*ip))(ip);
315 dsp_phase++;
316 }
317}
318
319/* ---------------- signals ---------------------------- */
320
321int ilog2(int n)
322{
323 int r = -1;
324 if (n <= 0) return(0);
325 while (n)
326 {
327 r++;
328 n >>= 1;
329 }
330 return (r);
331}
332
333 /* list of signals which can be reused, sorted by buffer size */
334static t_signal *signal_freelist[MAXLOGSIG+1];
335 /* list of reusable "borrowed" signals (which don't own sample buffers) */
336static t_signal *signal_freeborrowed;
337 /* list of all signals allocated (not including "borrowed" ones) */
338static t_signal *signal_usedlist;
339
340 /* call this when DSP is stopped to free all the signals */
341void signal_cleanup(void)
342{
343#ifdef ROCKBOX
344 t_signal *sig;
345#else
346 t_signal **svec, *sig, *sig2;
347#endif
348 int i;
349 while((sig = signal_usedlist))
350 {
351 signal_usedlist = sig->s_nextused;
352 if (!sig->s_isborrowed)
353 t_freebytes(sig->s_vec, sig->s_n * sizeof (*sig->s_vec));
354 t_freebytes(sig, sizeof *sig);
355 }
356 for (i = 0; i <= MAXLOGSIG; i++)
357 signal_freelist[i] = 0;
358 signal_freeborrowed = 0;
359}
360
361 /* mark the signal "reusable." */
362void signal_makereusable(t_signal *sig)
363{
364 int logn = ilog2(sig->s_n);
365#if 1
366 t_signal *s5;
367 for (s5 = signal_freeborrowed; s5; s5 = s5->s_nextfree)
368 {
369 if (s5 == sig)
370 {
371 bug("signal_free 3");
372 return;
373 }
374 }
375 for (s5 = signal_freelist[logn]; s5; s5 = s5->s_nextfree)
376 {
377 if (s5 == sig)
378 {
379 bug("signal_free 4");
380 return;
381 }
382 }
383#endif
384 if (ugen_loud) post("free %x: %d", sig, sig->s_isborrowed);
385 if (sig->s_isborrowed)
386 {
387 /* if the signal is borrowed, decrement the borrowed-from signal's
388 reference count, possibly marking it reusable too */
389 t_signal *s2 = sig->s_borrowedfrom;
390 if ((s2 == sig) || !s2)
391 bug("signal_free");
392 s2->s_refcount--;
393 if (!s2->s_refcount)
394 signal_makereusable(s2);
395 sig->s_nextfree = signal_freeborrowed;
396 signal_freeborrowed = sig;
397 }
398 else
399 {
400 /* if it's a real signal (not borrowed), put it on the free list
401 so we can reuse it. */
402 if (signal_freelist[logn] == sig) bug("signal_free 2");
403 sig->s_nextfree = signal_freelist[logn];
404 signal_freelist[logn] = sig;
405 }
406}
407
408 /* reclaim or make an audio signal. If n is zero, return a "borrowed"
409 signal whose buffer and size will be obtained later via
410 signal_setborrowed(). */
411
412t_signal *signal_new(int n, float sr)
413{
414#ifdef ROCKBOX
415 int logn;
416#else
417 int logn, n2;
418#endif
419 t_signal *ret, **whichlist;
420#ifndef ROCKBOX
421 t_sample *fp;
422#endif
423 logn = ilog2(n);
424 if (n)
425 {
426 if (n != (1 << logn))
427 bug("signal buffer not a power of 2");
428 if (logn > MAXLOGSIG)
429 bug("signal buffer too large");
430 whichlist = signal_freelist + logn;
431 }
432 else
433 whichlist = &signal_freeborrowed;
434
435 /* first try to reclaim one from the free list */
436 if((ret = *whichlist))
437 *whichlist = ret->s_nextfree;
438 else
439 {
440 /* LATER figure out what to do for out-of-space here! */
441 ret = (t_signal *)t_getbytes(sizeof *ret);
442 if (n)
443 {
444 ret->s_vec = (t_sample *)getbytes(n * sizeof (*ret->s_vec));
445 ret->s_isborrowed = 0;
446 }
447 else
448 {
449 ret->s_vec = 0;
450 ret->s_isborrowed = 1;
451 }
452 ret->s_nextused = signal_usedlist;
453 signal_usedlist = ret;
454 }
455 ret->s_n = n;
456 ret->s_sr = sr;
457 ret->s_refcount = 0;
458 ret->s_borrowedfrom = 0;
459 if (ugen_loud) post("new %x: %d", ret, ret->s_isborrowed);
460 return (ret);
461}
462
463static t_signal *signal_newlike(const t_signal *sig)
464{
465 return (signal_new(sig->s_n, sig->s_sr));
466}
467
468void signal_setborrowed(t_signal *sig, t_signal *sig2)
469{
470 if (!sig->s_isborrowed || sig->s_borrowedfrom)
471 bug("signal_setborrowed");
472 if (sig == sig2)
473 bug("signal_setborrowed 2");
474 sig->s_borrowedfrom = sig2;
475 sig->s_vec = sig2->s_vec;
476 sig->s_n = sig2->s_n;
477}
478
479int signal_compatible(t_signal *s1, t_signal *s2)
480{
481 return (s1->s_n == s2->s_n && s1->s_sr == s2->s_sr);
482}
483
484/* ------------------ ugen ("unit generator") sorting ----------------- */
485
486typedef struct _ugenbox
487{
488 struct _siginlet *u_in;
489 int u_nin;
490 struct _sigoutlet *u_out;
491 int u_nout;
492 int u_phase;
493 struct _ugenbox *u_next;
494 t_object *u_obj;
495 int u_done;
496} t_ugenbox;
497
498typedef struct _siginlet
499{
500 int i_nconnect;
501 int i_ngot;
502 t_signal *i_signal;
503} t_siginlet;
504
505typedef struct _sigoutconnect
506{
507 t_ugenbox *oc_who;
508 int oc_inno;
509 struct _sigoutconnect *oc_next;
510} t_sigoutconnect;
511
512typedef struct _sigoutlet
513{
514 int o_nconnect;
515 int o_nsent;
516 t_signal *o_signal;
517 t_sigoutconnect *o_connections;
518} t_sigoutlet;
519
520
521struct _dspcontext
522{
523 struct _ugenbox *dc_ugenlist;
524 struct _dspcontext *dc_parentcontext;
525 int dc_ninlets;
526 int dc_noutlets;
527 t_signal **dc_iosigs;
528 float dc_srate;
529 int dc_vecsize;
530 char dc_toplevel; /* true if "iosigs" is invalid. */
531 char dc_reblock; /* true if we have to reblock inlets/outlets */
532 char dc_switched; /* true if we're switched */
533
534};
535
536#define t_dspcontext struct _dspcontext
537
538static int ugen_sortno = 0;
539static t_dspcontext *ugen_currentcontext;
540
541void ugen_stop(void)
542{
543#ifndef ROCKBOX
544 t_signal *s;
545 int i;
546#endif
547 if (dsp_chain)
548 {
549 freebytes(dsp_chain, dsp_chainsize * sizeof (t_int));
550 dsp_chain = 0;
551 }
552 signal_cleanup();
553
554}
555
556void ugen_start(void)
557{
558 ugen_stop();
559 ugen_sortno++;
560 dsp_chain = (t_int *)getbytes(sizeof(*dsp_chain));
561 dsp_chain[0] = 0;
562 dsp_chainsize = 1;
563 if (ugen_currentcontext) bug("ugen_start");
564}
565
566int ugen_getsortno(void)
567{
568 return (ugen_sortno);
569}
570
571#if 0
572void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
573{
574 int i, count;
575 t_signal *sig;
576 for (count = 0, sig = signal_usedlist; sig;
577 count++, sig = sig->s_nextused)
578 ;
579 post("used signals %d", count);
580 for (i = 0; i < MAXLOGSIG; i++)
581 {
582 for (count = 0, sig = signal_freelist[i]; sig;
583 count++, sig = sig->s_nextfree)
584 ;
585 if (count)
586 post("size %d: free %d", (1 << i), count);
587 }
588 for (count = 0, sig = signal_freeborrowed; sig;
589 count++, sig = sig->s_nextfree)
590 ;
591 post("free borrowed %d", count);
592
593 ugen_loud = argc;
594}
595#endif
596
597 /* start building the graph for a canvas */
598t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
599 int ninlets, int noutlets)
600{
601 t_dspcontext *dc = (t_dspcontext *)getbytes(sizeof(*dc));
602#ifndef ROCKBOX
603 float parent_srate, srate;
604 int parent_vecsize, vecsize;
605#endif
606
607 if (ugen_loud) post("ugen_start_graph...");
608
609 dc->dc_ugenlist = 0;
610 dc->dc_toplevel = toplevel;
611 dc->dc_iosigs = sp;
612 dc->dc_ninlets = ninlets;
613 dc->dc_noutlets = noutlets;
614 dc->dc_parentcontext = ugen_currentcontext;
615 ugen_currentcontext = dc;
616 return (dc);
617}
618
619 /* first the canvas calls this to create all the boxes... */
620void ugen_add(t_dspcontext *dc, t_object *obj)
621{
622 t_ugenbox *x = (t_ugenbox *)getbytes(sizeof *x);
623 int i;
624 t_sigoutlet *uout;
625 t_siginlet *uin;
626
627 x->u_next = dc->dc_ugenlist;
628 dc->dc_ugenlist = x;
629 x->u_obj = obj;
630 x->u_nin = obj_nsiginlets(obj);
631 x->u_in = getbytes(x->u_nin * sizeof (*x->u_in));
632 for (uin = x->u_in, i = x->u_nin; i--; uin++)
633 uin->i_nconnect = 0;
634 x->u_nout = obj_nsigoutlets(obj);
635 x->u_out = getbytes(x->u_nout * sizeof (*x->u_out));
636 for (uout = x->u_out, i = x->u_nout; i--; uout++)
637 uout->o_connections = 0, uout->o_nconnect = 0;
638}
639
640 /* and then this to make all the connections. */
641void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2,
642 int inno)
643{
644 t_ugenbox *u1, *u2;
645 t_sigoutlet *uout;
646 t_siginlet *uin;
647 t_sigoutconnect *oc;
648 int sigoutno = obj_sigoutletindex(x1, outno);
649 int siginno = obj_siginletindex(x2, inno);
650 if (ugen_loud)
651 post("%s -> %s: %d->%d",
652 class_getname(x1->ob_pd),
653 class_getname(x2->ob_pd), outno, inno);
654 for (u1 = dc->dc_ugenlist; u1 && u1->u_obj != x1; u1 = u1->u_next);
655 for (u2 = dc->dc_ugenlist; u2 && u2->u_obj != x2; u2 = u2->u_next);
656 if (!u1 || !u2 || siginno < 0)
657 {
658 pd_error((u1 ? u1->u_obj : NULL),
659 "signal outlet connect to nonsignal inlet (ignored)");
660 return;
661 }
662 if (sigoutno < 0 || sigoutno >= u1->u_nout || siginno >= u2->u_nin)
663 {
664 bug("ugen_connect %s %s %d %d (%d %d)",
665 class_getname(x1->ob_pd),
666 class_getname(x2->ob_pd), sigoutno, siginno, u1->u_nout,
667 u2->u_nin);
668 }
669 uout = u1->u_out + sigoutno;
670 uin = u2->u_in + siginno;
671
672 /* add a new connection to the outlet's list */
673 oc = (t_sigoutconnect *)getbytes(sizeof *oc);
674 oc->oc_next = uout->o_connections;
675 uout->o_connections = oc;
676 oc->oc_who = u2;
677 oc->oc_inno = siginno;
678 /* update inlet and outlet counts */
679 uout->o_nconnect++;
680 uin->i_nconnect++;
681}
682
683 /* get the index of a ugenbox or -1 if it's not on the list */
684static int ugen_index(t_dspcontext *dc, t_ugenbox *x)
685{
686 int ret;
687 t_ugenbox *u;
688 for (u = dc->dc_ugenlist, ret = 0; u; u = u->u_next, ret++)
689 if (u == x) return (ret);
690 return (-1);
691}
692
693 /* put a ugenbox on the chain, recursively putting any others on that
694 this one might uncover. */
695static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
696{
697 t_sigoutlet *uout;
698 t_siginlet *uin;
699#ifdef ROCKBOX
700 t_sigoutconnect *oc;
701#else
702 t_sigoutconnect *oc, *oc2;
703#endif
704 t_class *class = pd_class(&u->u_obj->ob_pd);
705 int i, n;
706 /* suppress creating new signals for the outputs of signal
707 inlets and subpatchs; except in the case we're an inlet and "blocking"
708 is set. We don't yet know if a subcanvas will be "blocking" so there
709 we delay new signal creation, which will be handled by calling
710 signal_setborrowed in the ugen_done_graph routine below. */
711 int nonewsigs = (class == canvas_class ||
712 ((class == vinlet_class) && !(dc->dc_reblock)));
713 /* when we encounter a subcanvas or a signal outlet, suppress freeing
714 the input signals as they may be "borrowed" for the super or sub
715 patch; same exception as above, but also if we're "switched" we
716 have to do a copy rather than a borrow. */
717 int nofreesigs = (class == canvas_class ||
718 ((class == voutlet_class) && !(dc->dc_reblock || dc->dc_switched)));
719 t_signal **insig, **outsig, **sig, *s1, *s2, *s3;
720 t_ugenbox *u2;
721
722 if (ugen_loud) post("doit %s %d %d", class_getname(class), nofreesigs,
723 nonewsigs);
724 for (i = 0, uin = u->u_in; i < u->u_nin; i++, uin++)
725 {
726 if (!uin->i_nconnect)
727 {
728 t_sample *scalar;
729 s3 = signal_new(dc->dc_vecsize, dc->dc_srate);
730 /* post("%s: unconnected signal inlet set to zero",
731 class_getname(u->u_obj->ob_pd)); */
732 if((scalar = obj_findsignalscalar(u->u_obj, i)))
733 dsp_add_scalarcopy(scalar, s3->s_vec, s3->s_n);
734 else
735 dsp_add_zero(s3->s_vec, s3->s_n);
736 uin->i_signal = s3;
737 s3->s_refcount = 1;
738 }
739 }
740 insig = (t_signal **)getbytes((u->u_nin + u->u_nout) * sizeof(t_signal *));
741 outsig = insig + u->u_nin;
742 for (sig = insig, uin = u->u_in, i = u->u_nin; i--; sig++, uin++)
743 {
744 int newrefcount;
745 *sig = uin->i_signal;
746 newrefcount = --(*sig)->s_refcount;
747 /* if the reference count went to zero, we free the signal now,
748 unless it's a subcanvas or outlet; these might keep the
749 signal around to send to objects connected to them. In this
750 case we increment the reference count; the corresponding decrement
751 is in sig_makereusable(). */
752 if (nofreesigs)
753 (*sig)->s_refcount++;
754 else if (!newrefcount)
755 signal_makereusable(*sig);
756 }
757 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
758 {
759 /* similarly, for outlets of subcanvases we delay creating
760 them; instead we create "borrowed" ones so that the refcount
761 is known. The subcanvas replaces the fake signal with one showing
762 where the output data actually is, to avoid having to copy it.
763 For any other object, we just allocate a new output vector;
764 since we've already freed the inputs the objects might get called
765 "in place." */
766 if (nonewsigs)
767 {
768 *sig = uout->o_signal =
769 signal_new(0, dc->dc_srate);
770 }
771 else
772 *sig = uout->o_signal = signal_new(dc->dc_vecsize, dc->dc_srate);
773 (*sig)->s_refcount = uout->o_nconnect;
774 }
775 /* now call the DSP scheduling routine for the ugen. This
776 routine must fill in "borrowed" signal outputs in case it's either
777 a subcanvas or a signal inlet. */
778 mess1(&u->u_obj->ob_pd, gensym("dsp"), insig);
779
780 /* if any output signals aren't connected to anyone, free them
781 now; otherwise they'll either get freed when the reference count
782 goes back to zero, or even later as explained above. */
783
784 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
785 {
786 if (!(*sig)->s_refcount)
787 signal_makereusable(*sig);
788 }
789 if (ugen_loud)
790 {
791 if (u->u_nin + u->u_nout == 0) post("put %s %d",
792 class_getname(u->u_obj->ob_pd), ugen_index(dc, u));
793 else if (u->u_nin + u->u_nout == 1) post("put %s %d (%x)",
794 class_getname(u->u_obj->ob_pd), ugen_index(dc, u), sig[0]);
795 else if (u->u_nin + u->u_nout == 2) post("put %s %d (%x %x)",
796 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
797 sig[0], sig[1]);
798 else post("put %s %d (%x %x %x ...)",
799 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
800 sig[0], sig[1], sig[2]);
801 }
802
803 /* pass it on and trip anyone whose last inlet was filled */
804 for (uout = u->u_out, i = u->u_nout; i--; uout++)
805 {
806 s1 = uout->o_signal;
807 for (oc = uout->o_connections; oc; oc = oc->oc_next)
808 {
809 u2 = oc->oc_who;
810 uin = &u2->u_in[oc->oc_inno];
811 /* if there's already someone here, sum the two */
812 if((s2 = uin->i_signal))
813 {
814 s1->s_refcount--;
815 s2->s_refcount--;
816 if (!signal_compatible(s1, s2))
817 {
818 pd_error(u->u_obj, "%s: incompatible signal inputs",
819 class_getname(u->u_obj->ob_pd));
820 return;
821 }
822 s3 = signal_newlike(s1);
823 dsp_add_plus(s1->s_vec, s2->s_vec, s3->s_vec, s1->s_n);
824 uin->i_signal = s3;
825 s3->s_refcount = 1;
826 if (!s1->s_refcount) signal_makereusable(s1);
827 if (!s2->s_refcount) signal_makereusable(s2);
828 }
829 else uin->i_signal = s1;
830 uin->i_ngot++;
831 /* if we didn't fill this inlet don't bother yet */
832 if (uin->i_ngot < uin->i_nconnect)
833 goto notyet;
834 /* if there's more than one, check them all */
835 if (u2->u_nin > 1)
836 {
837 for (uin = u2->u_in, n = u2->u_nin; n--; uin++)
838 if (uin->i_ngot < uin->i_nconnect) goto notyet;
839 }
840 /* so now we can schedule the ugen. */
841 ugen_doit(dc, u2);
842 notyet: ;
843 }
844 }
845 t_freebytes(insig,(u->u_nin + u->u_nout) * sizeof(t_signal *));
846 u->u_done = 1;
847}
848
849 /* once the DSP graph is built, we call this routine to sort it.
850 This routine also deletes the graph; later we might want to leave the
851 graph around, in case the user is editing the DSP network, to save having
852 to recreate it all the time. But not today. */
853
854void ugen_done_graph(t_dspcontext *dc)
855{
856#ifdef ROCKBOX
857 t_ugenbox *u;
858#else
859 t_ugenbox *u, *u2;
860#endif
861 t_sigoutlet *uout;
862 t_siginlet *uin;
863 t_sigoutconnect *oc, *oc2;
864 int i, n;
865 t_block *blk;
866 t_dspcontext *parent_context = dc->dc_parentcontext;
867 float parent_srate;
868 int parent_vecsize;
869 int period, frequency, /* phase, */ vecsize;
870 float srate;
871 int chainblockbegin; /* DSP chain onset before block prolog code */
872 int chainblockend; /* and after block epilog code */
873 int chainafterall; /* and after signal outlet epilog */
874 int reblock = 0, switched;
875 int downsample = 1, upsample = 1; /* IOhannes */
876 /* debugging printout */
877
878 if (ugen_loud)
879 {
880 post("ugen_done_graph...");
881 for (u = dc->dc_ugenlist; u; u = u->u_next)
882 {
883 post("ugen: %s", class_getname(u->u_obj->ob_pd));
884 for (uout = u->u_out, i = 0; i < u->u_nout; uout++, i++)
885 for (oc = uout->o_connections; oc; oc = oc->oc_next)
886 {
887 post("... out %d to %s, index %d, inlet %d", i,
888 class_getname(oc->oc_who->u_obj->ob_pd),
889 ugen_index(dc, oc->oc_who), oc->oc_inno);
890 }
891 }
892 }
893
894 /* search for an object of class "block~" */
895 for (u = dc->dc_ugenlist, blk = 0; u; u = u->u_next)
896 {
897 t_pd *zz = &u->u_obj->ob_pd;
898 if (pd_class(zz) == block_class)
899 {
900 if (blk)
901 pd_error(blk, "conflicting block~ objects in same page");
902 else blk = (t_block *)zz;
903 }
904 }
905
906 /* figure out block size, calling frequency, sample rate */
907 if (parent_context)
908 {
909 parent_srate = parent_context->dc_srate;
910 parent_vecsize = parent_context->dc_vecsize;
911 }
912 else
913 {
914 parent_srate = sys_getsr();
915 parent_vecsize = sys_getblksize();
916 }
917 if (blk)
918 {
919 int realoverlap;
920 vecsize = blk->x_vecsize;
921 if (vecsize == 0)
922 vecsize = parent_vecsize;
923 realoverlap = blk->x_overlap;
924 if (realoverlap > vecsize) realoverlap = vecsize;
925 /* IOhannes { */
926 downsample = blk->x_downsample;
927 upsample = blk->x_upsample;
928 if (downsample > parent_vecsize) downsample=parent_vecsize;
929 period = (vecsize * downsample)/
930 (parent_vecsize * realoverlap * upsample);
931 frequency = (parent_vecsize * realoverlap * upsample)/
932 (vecsize * downsample);
933 /* } IOhannes*/
934 /* phase = blk->x_phase; */
935 srate = parent_srate * realoverlap * upsample / downsample;
936 /* IOhannes */
937 if (period < 1) period = 1;
938 if (frequency < 1) frequency = 1;
939 blk->x_frequency = frequency;
940 blk->x_period = period;
941 blk->x_phase = dsp_phase & (period - 1);
942 if (! parent_context || (realoverlap != 1) ||
943 (vecsize != parent_vecsize) ||
944 (downsample != 1) || (upsample != 1)) /* IOhannes */
945 reblock = 1;
946 switched = blk->x_switched;
947 }
948 else
949 {
950 srate = parent_srate;
951 vecsize = parent_vecsize;
952 downsample = upsample = 1;/* IOhannes */
953 period = frequency = 1;
954 /* phase = 0; */
955 if (!parent_context) reblock = 1;
956 switched = 0;
957 }
958 dc->dc_reblock = reblock;
959 dc->dc_switched = switched;
960 dc->dc_srate = srate;
961 dc->dc_vecsize = vecsize;
962
963 /* if we're reblocking or switched, we now have to create output
964 signals to fill in for the "borrowed" ones we have now. This
965 is also possibly true even if we're not blocked/switched, in
966 the case that there was a signal loop. But we don't know this
967 yet. */
968
969 if (dc->dc_iosigs && (switched || reblock))
970 {
971 t_signal **sigp;
972 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
973 i++, sigp++)
974 {
975 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
976 {
977 signal_setborrowed(*sigp,
978 signal_new(parent_vecsize, parent_srate));
979 (*sigp)->s_refcount++;
980
981 if (ugen_loud) post("set %x->%x", *sigp,
982 (*sigp)->s_borrowedfrom);
983 }
984 }
985 }
986
987 if (ugen_loud)
988 post("reblock %d, switched %d", reblock, switched);
989
990 /* schedule prologs for inlets and outlets. If the "reblock" flag
991 is set, an inlet will put code on the DSP chain to copy its input
992 into an internal buffer here, before any unit generators' DSP code
993 gets scheduled. If we don't "reblock", inlets will need to get
994 pointers to their corresponding inlets/outlets on the box we're inside,
995 if any. Outlets will also need pointers, unless we're switched, in
996 which case outlet epilog code will kick in. */
997
998 for (u = dc->dc_ugenlist; u; u = u->u_next)
999 {
1000 t_pd *zz = &u->u_obj->ob_pd;
1001#ifdef ROCKBOX
1002 t_signal **outsigs = dc->dc_iosigs;
1003#else
1004 t_signal **insigs = dc->dc_iosigs, **outsigs = dc->dc_iosigs;
1005#endif
1006 if (outsigs) outsigs += dc->dc_ninlets;
1007
1008 if (pd_class(zz) == vinlet_class)
1009 vinlet_dspprolog((struct _vinlet *)zz,
1010 dc->dc_iosigs, vecsize, dsp_phase, period, frequency,
1011 downsample, upsample, /* IOhannes */
1012 reblock, switched);
1013 else if (pd_class(zz) == voutlet_class)
1014 voutlet_dspprolog((struct _voutlet *)zz,
1015 outsigs, vecsize, dsp_phase, period, frequency,
1016 downsample, upsample, /* IOhannes */
1017 reblock, switched);
1018 }
1019 chainblockbegin = dsp_chainsize;
1020
1021 if (blk && (reblock || switched)) /* add the block DSP prolog */
1022 dsp_add(block_prolog, 1, blk);
1023
1024 /* Initialize for sorting */
1025 for (u = dc->dc_ugenlist; u; u = u->u_next)
1026 {
1027 u->u_done = 0;
1028 for (uout = u->u_out, i = u->u_nout; i--; uout++)
1029 uout->o_nsent = 0;
1030 for (uin = u->u_in, i = u->u_nin; i--; uin++)
1031 uin->i_ngot = 0, uin->i_signal = 0;
1032 }
1033
1034 /* Do the sort */
1035
1036 for (u = dc->dc_ugenlist; u; u = u->u_next)
1037 {
1038 /* check that we have no connected signal inlets */
1039 if (u->u_done) continue;
1040 for (uin = u->u_in, i = u->u_nin; i--; uin++)
1041 if (uin->i_nconnect) goto next;
1042
1043 ugen_doit(dc, u);
1044 next: ;
1045 }
1046
1047 /* check for a DSP loop, which is evidenced here by the presence
1048 of ugens not yet scheduled. */
1049
1050 for (u = dc->dc_ugenlist; u; u = u->u_next)
1051 if (!u->u_done)
1052 {
1053 t_signal **sigp;
1054 pd_error(u->u_obj,
1055 "DSP loop detected (some tilde objects not scheduled)");
1056 /* this might imply that we have unfilled "borrowed" outputs
1057 which we'd better fill in now. */
1058 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
1059 i++, sigp++)
1060 {
1061 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
1062 {
1063 t_signal *s3 = signal_new(parent_vecsize, parent_srate);
1064 signal_setborrowed(*sigp, s3);
1065 (*sigp)->s_refcount++;
1066 dsp_add_zero(s3->s_vec, s3->s_n);
1067 if (ugen_loud)
1068 post("oops, belatedly set %x->%x", *sigp,
1069 (*sigp)->s_borrowedfrom);
1070 }
1071 }
1072 break; /* don't need to keep looking. */
1073 }
1074
1075 if (blk && (reblock || switched)) /* add block DSP epilog */
1076 dsp_add(block_epilog, 1, blk);
1077 chainblockend = dsp_chainsize;
1078
1079 /* add epilogs for outlets. */
1080
1081 for (u = dc->dc_ugenlist; u; u = u->u_next)
1082 {
1083 t_pd *zz = &u->u_obj->ob_pd;
1084 if (pd_class(zz) == voutlet_class)
1085 {
1086 t_signal **iosigs = dc->dc_iosigs;
1087 if (iosigs) iosigs += dc->dc_ninlets;
1088 voutlet_dspepilog((struct _voutlet *)zz,
1089 iosigs, vecsize, dsp_phase, period, frequency,
1090 downsample, upsample, /* IOhannes */
1091 reblock, switched);
1092 }
1093 }
1094
1095 chainafterall = dsp_chainsize;
1096 if (blk)
1097 {
1098 blk->x_blocklength = chainblockend - chainblockbegin;
1099 blk->x_epiloglength = chainafterall - chainblockend;
1100 blk->x_reblock = reblock;
1101 }
1102
1103 if (ugen_loud)
1104 {
1105 t_int *ip;
1106 if (!dc->dc_parentcontext)
1107 for (i = dsp_chainsize, ip = dsp_chain; i--; ip++)
1108 post("chain %x", *ip);
1109 post("... ugen_done_graph done.");
1110 }
1111 /* now delete everything. */
1112 while (dc->dc_ugenlist)
1113 {
1114 for (uout = dc->dc_ugenlist->u_out, n = dc->dc_ugenlist->u_nout;
1115 n--; uout++)
1116 {
1117 oc = uout->o_connections;
1118 while (oc)
1119 {
1120 oc2 = oc->oc_next;
1121 freebytes(oc, sizeof *oc);
1122 oc = oc2;
1123 }
1124 }
1125 freebytes(dc->dc_ugenlist->u_out, dc->dc_ugenlist->u_nout *
1126 sizeof (*dc->dc_ugenlist->u_out));
1127 freebytes(dc->dc_ugenlist->u_in, dc->dc_ugenlist->u_nin *
1128 sizeof(*dc->dc_ugenlist->u_in));
1129 u = dc->dc_ugenlist;
1130 dc->dc_ugenlist = u->u_next;
1131 freebytes(u, sizeof *u);
1132 }
1133 if (ugen_currentcontext == dc)
1134 ugen_currentcontext = dc->dc_parentcontext;
1135 else bug("ugen_currentcontext");
1136 freebytes(dc, sizeof(*dc));
1137
1138}
1139
1140t_signal *ugen_getiosig(int index, int inout)
1141{
1142 if (!ugen_currentcontext) bug("ugen_getiosig");
1143 if (ugen_currentcontext->dc_toplevel) return (0);
1144 if (inout) index += ugen_currentcontext->dc_ninlets;
1145 return (ugen_currentcontext->dc_iosigs[index]);
1146}
1147
1148
1149/* -------------------- setup routine -------------------------- */
1150
1151void d_ugen_setup(void) /* really just block_setup */
1152{
1153 block_class = class_new(gensym("block~"), (t_newmethod)block_new, 0,
1154 sizeof(t_block), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
1155 class_addcreator((t_newmethod)switch_new, gensym("switch~"),
1156 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
1157 class_addmethod(block_class, (t_method)block_set, gensym("set"),
1158 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
1159 class_addmethod(block_class, (t_method)block_dsp, gensym("dsp"), 0);
1160 class_addfloat(block_class, block_float);
1161}