A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1161 lines 34 kB view raw
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}