From 8dbec761cf858ea65900c8a094599857208d8c3a Mon Sep 17 00:00:00 2001 From: "N.N." Date: Tue, 5 Jan 2010 22:49:36 +0000 Subject: svn path=/trunk/; revision=12907 --- desiredata/src/d_ugen.c | 972 ------------------------------------------------ 1 file changed, 972 deletions(-) delete mode 100644 desiredata/src/d_ugen.c (limited to 'desiredata/src/d_ugen.c') diff --git a/desiredata/src/d_ugen.c b/desiredata/src/d_ugen.c deleted file mode 100644 index cccedbe7..00000000 --- a/desiredata/src/d_ugen.c +++ /dev/null @@ -1,972 +0,0 @@ -/* Copyright (c) 1997-1999 Miller Puckette. -* For information on usage and redistribution, and for a DISCLAIMER OF ALL -* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - -/* These routines build a copy of the DSP portion of a graph, which is - then sorted into a linear list of DSP operations which are added to - the DSP duty cycle called by the scheduler. Once that's been done, - we delete the copy. The DSP objects are represented by "ugenbox" - structures which are parallel to the DSP objects in the graph and - have vectors of siginlets and sigoutlets which record their - interconnections. -*/ - -/* hacked to run subpatches with different power-of-2 samplerates - mfg.gfd.uil IOhannes */ - -#define PD_PLUSPLUS_FACE -#include "desire.h" -#include -#include - -/* T.Grill - include SIMD functionality */ -#include "m_simd.h" - -extern t_class *vinlet_class, *voutlet_class, *canvas_class; -t_sample *obj_findsignalscalar(t_object *x, int m); -static int ugen_loud; -static t_int *dsp_chain; -static int dsp_chainsize; -struct t_vinlet; -struct t_voutlet; - -void vinlet_dspprolog(t_vinlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period, int frequency, - int downsample, int upsample, int reblock, int switched); -void voutlet_dspprolog(t_voutlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period, int frequency, - int downsample, int upsample, int reblock, int switched); -void voutlet_dspepilog(t_voutlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period, int frequency, - int downsample, int upsample, int reblock, int switched); - -/* zero out a vector */ -t_int *zero_perform(t_int *w) { - t_float *out = (t_float *)w[1]; - int n = int(w[2]); - while (n--) *out++ = 0; - return w+3; -} - -t_int *zero_perf8(t_int *w) { - t_float *out = (t_float *)w[1]; - int n = int(w[2]); - for (; n; n -= 8, out += 8) { - out[0] = 0; out[1] = 0; - out[2] = 0; out[3] = 0; - out[4] = 0; out[5] = 0; - out[6] = 0; out[7] = 0; - } - return w+3; -} - -void dsp_add_zero(t_sample *out, int n) { - if (n&7) dsp_add(zero_perform, 2, out, n); - else if(SIMD_CHECK1(n,out)) dsp_add(zero_perf_simd, 2, out, n); - else dsp_add(zero_perf8, 2, out, n); -} - -/* ---------------------------- block~ ----------------------------- */ -/* The "block~ object maintains the containing canvas's DSP computation, -calling it at a super- or sub-multiple of the containing canvas's -calling frequency. The block~'s creation arguments specify block size -and overlap. Block~ does no "dsp" computation in its own right, but it -adds prolog and epilog code before and after the canvas's unit generators. - -A subcanvas need not have a block~ at all; if there's none, its -ugens are simply put on the list without any prolog or epilog code. - -Block~ may be invoked as switch~, in which case it also acts to switch the -subcanvas on and off. The overall order of scheduling for a subcanvas -is thus, - - inlet and outlet prologue code (1) - block prologue (2) - the objects in the subcanvas, including inlets and outlets - block epilogue (2) - outlet epilogue code (2) - -where (1) means, "if reblocked" and (2) means, "if reblocked or switched". - -If we're reblocked, the inlet prolog and outlet epilog code takes care of -overlapping and buffering to deal with vector size changes. If we're switched -but not reblocked, the inlet prolog is not needed, and the output epilog is -ONLY run when the block is switched off; in this case the epilog code simply -copies zeros to all signal outlets. -*/ - -static int dsp_phase; -static t_class *block_class; - -struct t_block : t_object { - int vecsize; /* size of audio signals in this block */ - int calcsize; /* number of samples actually to compute */ - int overlap; - int phase; /* from 0 to period-1; when zero we run the block */ - int period; /* submultiple of containing canvas */ - int frequency; /* supermultiple of comtaining canvas */ - int count; /* number of times parent block has called us */ - int chainonset; /* beginning of code in DSP chain */ - int blocklength; /* length of dspchain for this block */ - int epiloglength; /* length of epilog */ - char switched; /* true if we're acting as a a switch */ - char switchon; /* true if we're switched on */ - char reblock; /* true if inlets and outlets are reblocking */ - int upsample; /* IOhannes: upsampling-factor */ - int downsample; /* IOhannes: downsampling-factor */ - int x_return; /* stop right after this block (for one-shots) */ -}; - -static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap, t_floatarg fupsample); - -static void *block_new(t_floatarg fcalcsize, t_floatarg foverlap, t_floatarg fupsample) /* IOhannes */ { - t_block *x = (t_block *)pd_new(block_class); - x->phase = 0; - x->period = 1; - x->frequency = 1; - x->switched = 0; - x->switchon = 1; - block_set(x, fcalcsize, foverlap, fupsample); - return x; -} - -static void block_set(t_block *x, t_floatarg fcalcsize, t_floatarg foverlap, t_floatarg fupsample) { - int upsample, downsample; /* IOhannes */ - int calcsize = (int)fcalcsize; - int overlap = (int)foverlap; - int dspstate = canvas_suspend_dsp(); - if (overlap < 1) overlap = 1; - if (calcsize < 0) calcsize = 0; /* this means we'll get it from parent later. */ - /* IOhannes { */ - if (fupsample <= 0) upsample = downsample = 1; - else if (fupsample >= 1) { - upsample = (int)fupsample; - downsample = 1; - } else { - downsample = int(1.0 / fupsample); - upsample = 1; - } - /* } IOhannes */ - /* vecsize is smallest power of 2 large enough to hold calcsize */ - int vecsize = 0; - if (calcsize) { - vecsize = (1 << ilog2(calcsize)); - if (vecsize != calcsize) vecsize *= 2; - } - if (vecsize && vecsize != (1 << ilog2(vecsize))) {error("block~: vector size not a power of 2"); vecsize = 64;} - if ( overlap != (1 << ilog2(overlap))) {error("block~: overlap not a power of 2"); overlap = 1;} - /* IOhannes { */ - if (downsample != (1 << ilog2(downsample))) {error("block~: downsampling not a power of 2"); downsample = 1;} - if ( upsample != (1 << ilog2( upsample))) {error("block~: upsampling not a power of 2"); upsample = 1;} - /* } IOhannes */ - x->calcsize = calcsize; - x->vecsize = vecsize; - x->overlap = overlap; - /* IOhannes { */ - x->upsample = upsample; - x->downsample = downsample; - /* } IOhannes */ - canvas_resume_dsp(dspstate); -} - -static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap, t_floatarg fupsample) /* IOhannes */ { - t_block *x = (t_block *)(block_new(fvecsize, foverlap, fupsample)); /* IOhannes */ - x->switched = 1; - x->switchon = 0; - return x; -} - -static void block_float(t_block *x, t_floatarg f) { - if (x->switched) x->switchon = f!=0; -} - -static void block_bang(t_block *x) { - if (x->switched && !x->switchon) { - x->x_return = 1; - for (t_int *ip = dsp_chain + x->chainonset; ip; ) ip = t_perfroutine(*ip)(ip); - x->x_return = 0; - } else error("bang to block~ or on-state switch~ has no effect"); -} - -#define PROLOGCALL 2 -#define EPILOGCALL 2 - -static t_int *block_prolog(t_int *w) { - t_block *x = (t_block *)w[1]; - int phase = x->phase; - /* if we're switched off, jump past the epilog code */ - if (!x->switchon) return w+x->blocklength; - if (phase) { - phase++; - if (phase == x->period) phase = 0; - x->phase = phase; - return w+x->blocklength; /* skip block; jump past epilog */ - } else { - x->count = x->frequency; - x->phase = (x->period > 1 ? 1 : 0); - return w+PROLOGCALL; /* beginning of block is next ugen */ - } -} - -static t_int *block_epilog(t_int *w) { - t_block *x = (t_block *)w[1]; - int count = x->count - 1; - if (x->x_return) return 0; - if (!x->reblock) return w+x->epiloglength+EPILOGCALL; - if (count) { - x->count = count; - return w - (x->blocklength - (PROLOGCALL + EPILOGCALL)); /* go to ugen after prolog */ - } else return w+EPILOGCALL; -} - -static void block_dsp(t_block *x, t_signal **sp) {/* do nothing here */} - -void block_tilde_setup() { - block_class = class_new2("block~", (t_newmethod)block_new, 0, sizeof(t_block), 0,"FFF"); - class_addcreator2("switch~",(t_newmethod)switch_new,"FFF"); - class_addmethod2(block_class, (t_method)block_set,"set","FFF"); - class_addmethod2(block_class, (t_method)block_dsp,"dsp",""); - class_addfloat(block_class, block_float); - class_addbang(block_class, block_bang); -} - -/* ------------------ DSP call list ----------------------- */ - -static t_int dsp_done(t_int *w) {return 0;} - -void dsp_add(t_perfroutine f, int n, ...) { - va_list ap; - va_start(ap, n); - int newsize = dsp_chainsize + n+1; - dsp_chain = (t_int *)resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int), newsize * sizeof (t_int)); - dsp_chain[dsp_chainsize-1] = (t_int)f; - for (int i=0; i>= 1; - } - return r; -} - -/* list of signals which can be reused, sorted by buffer size */ -static t_signal *signal_freelist[MAXLOGSIG+1]; -/* list of reusable "borrowed" signals (which don't own sample buffers) */ -static t_signal *signal_freeborrowed; -/* list of all signals allocated (not including "borrowed" ones) */ -static t_signal *signal_usedlist; - -/* call this when DSP is stopped to free all the signals */ -void signal_cleanup() { - t_signal *sig; - while ((sig = signal_usedlist)) { - signal_usedlist = sig->nextused; - if (!sig->isborrowed) { -#ifndef VECTORALIGNMENT - free(sig->v); -#else - freealignedbytes(sig->v, sig->vecsize * sizeof (*sig->v)); -#endif - } - free(sig); - } - for (int i=0; i<=MAXLOGSIG; i++) signal_freelist[i] = 0; - signal_freeborrowed = 0; -} - -/* mark the signal "reusable." */ -extern "C" void signal_makereusable(t_signal *sig) { - int logn = ilog2(sig->vecsize); -#if 1 - for (t_signal *s5 = signal_freeborrowed; s5; s5 = s5->nextfree) {if (s5 == sig) {bug("signal_free 3"); return;}} - for (t_signal *s5 = signal_freelist[logn]; s5; s5 = s5->nextfree) {if (s5 == sig) {bug("signal_free 4"); return;}} -#endif - if (ugen_loud) post("free %lx: %d", long(sig), sig->isborrowed); - if (sig->isborrowed) { - /* if the signal is borrowed, decrement the borrowed-from signal's reference count, possibly marking it reusable too */ - t_signal *s2 = sig->borrowedfrom; - if ((s2 == sig) || !s2) bug("signal_free"); - s2->refcount--; - if (!s2->refcount) signal_makereusable(s2); - sig->nextfree = signal_freeborrowed; - signal_freeborrowed = sig; - } else { - /* if it's a real signal (not borrowed), put it on the free list so we can reuse it. */ - if (signal_freelist[logn] == sig) bug("signal_free 2"); - sig->nextfree = signal_freelist[logn]; - signal_freelist[logn] = sig; - } -} - -/* reclaim or make an audio signal. If n is zero, return a "borrowed" - signal whose buffer and size will be obtained later via signal_setborrowed(). */ -t_signal *signal_new(int n, float sr) { - int vecsize = 0; - t_signal *ret, **whichlist; - int logn = ilog2(n); - if (n) { - if ((vecsize = (1< MAXLOGSIG) bug("signal buffer too large"); - whichlist = signal_freelist + logn; - } else whichlist = &signal_freeborrowed; - /* first try to reclaim one from the free list */ - ret = *whichlist; - if (ret) *whichlist = ret->nextfree; - else { - /* LATER figure out what to do for out-of-space here! */ - ret = (t_signal *)t_getbytes(sizeof *ret); - if (n) { -#ifndef VECTORALIGNMENT - ret->v = (t_sample *)getbytes(vecsize * sizeof (*ret->v)); -#else - /* T.Grill - make signal vectors aligned! */ - ret->v = (t_sample *)getalignedbytes(vecsize * sizeof (*ret->v)); -#endif - ret->isborrowed = 0; - } else { - ret->v = 0; - ret->isborrowed = 1; - } - ret->nextused = signal_usedlist; - signal_usedlist = ret; - } - ret->n = n; - ret->vecsize = vecsize; - ret->sr = sr; - ret->refcount = 0; - ret->borrowedfrom = 0; - if (ugen_loud) post("new %lx: %d", long(ret), ret->isborrowed); - return ret; -} - -static t_signal *signal_newlike(const t_signal *sig) {return signal_new(sig->n, sig->sr);} - -extern "C" void signal_setborrowed(t_signal *sig, t_signal *sig2) { - if (!sig->isborrowed || sig->borrowedfrom) bug("signal_setborrowed"); - if (sig == sig2) bug("signal_setborrowed 2"); - sig->borrowedfrom = sig2; - sig->v = sig2->v; - sig->n = sig2->n; - sig->vecsize = sig2->vecsize; -} - -int signal_compatible(t_signal *s1, t_signal *s2) {return s1->n == s2->n && s1->sr == s2->sr;} - -/* ------------------ ugen ("unit generator") sorting ----------------- */ - -struct t_ugenbox { - struct t_siginlet *in; int nin; - struct t_sigoutlet *out; int nout; - int u_phase; - t_ugenbox *next; - t_object *obj; - int done; -}; - -struct t_siginlet { - int nconnect; - int ngot; - t_signal *signal; -}; - -struct t_sigoutconnect { - t_ugenbox *who; - int inno; - t_sigoutconnect *next; -}; - -struct t_sigoutlet { - int nconnect; - int nsent; - t_signal *signal; - t_sigoutconnect *connections; -}; - -struct t_dspcontext { - t_ugenbox *ugenlist; - t_dspcontext *parentcontext; - int ninlets; - int noutlets; - t_signal **iosigs; - float srate; - int vecsize; /* vector size, power of two */ - int calcsize; /* number of elements to calculate */ - char toplevel; /* true if "iosigs" is invalid. */ - char reblock; /* true if we have to reblock inlets/outlets */ - char switched; /* true if we're switched */ -}; - -static int ugen_sortno = 0; -static t_dspcontext *ugen_currentcontext; - -void ugen_stop() { - if (dsp_chain) { - free(dsp_chain); - dsp_chain = 0; - } - signal_cleanup(); -} - -void ugen_start() { - ugen_stop(); - ugen_sortno++; - dsp_chain = (t_int *)getbytes(sizeof(*dsp_chain)); - dsp_chain[0] = (t_int)dsp_done; - dsp_chainsize = 1; - if (ugen_currentcontext) bug("ugen_start"); -} - -int ugen_getsortno() {return ugen_sortno;} - -#if 0 -void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) { - int i, count; - t_signal *sig; - for (count = 0, sig = signal_usedlist; sig; count++, sig = sig->nextused) {} - post("used signals %d", count); - for (i = 0; i < MAXLOGSIG; i++) { - for (count = 0, sig = signal_freelist[i]; sig; count++, sig = sig->nextfree) {} - if (count) post("size %d: free %d", (1 << i), count); - } - for (count = 0, sig = signal_freeborrowed; sig; count++, sig = sig->nextfree) {} - post("free borrowed %d", count); - ugen_loud = argc; -} -#endif - -/* start building the graph for a canvas */ -extern "C" t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp, int ninlets, int noutlets) { - t_dspcontext *dc = (t_dspcontext *)getbytes(sizeof(*dc)); - if (ugen_loud) post("ugen_start_graph..."); - dc->ugenlist = 0; - dc->toplevel = toplevel; - dc->iosigs = sp; - dc->ninlets = ninlets; - dc->noutlets = noutlets; - dc->parentcontext = ugen_currentcontext; - ugen_currentcontext = dc; - return dc; -} - -/* first the canvas calls this to create all the boxes... */ -extern "C" void ugen_add(t_dspcontext *dc, t_object *obj) { - t_ugenbox *x = (t_ugenbox *)getbytes(sizeof *x); - int i; - t_sigoutlet *uout; - t_siginlet *uin; - x->next = dc->ugenlist; - dc->ugenlist = x; - x->obj = obj; - x->nin = obj_nsiginlets(obj); - x->in = (t_siginlet *)getbytes(x->nin * sizeof (*x->in)); - for (uin = x->in, i = x->nin; i--; uin++) uin->nconnect = 0; - x->nout = obj_nsigoutlets(obj); - x->out = (t_sigoutlet *)getbytes(x->nout * sizeof (*x->out)); - for (uout = x->out, i = x->nout; i--; uout++) uout->connections = 0, uout->nconnect = 0; -} - -/* and then this to make all the connections. */ -extern "C" void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2, int inno) { - t_ugenbox *u1, *u2; - int sigoutno = obj_sigoutletindex(x1, outno); - int siginno = obj_siginletindex(x2, inno); - if (ugen_loud) post("%s -> %s: %d->%d", class_getname(x1->ob_pd), class_getname(x2->ob_pd), outno, inno); - for (u1 = dc->ugenlist; u1 && u1->obj != x1; u1 = u1->next) {} - for (u2 = dc->ugenlist; u2 && u2->obj != x2; u2 = u2->next) {} - if (!u1 || !u2 || siginno < 0) { - pd_error(u1->obj, "signal outlet connect to nonsignal inlet (ignored)"); - return; - } - if (sigoutno < 0 || sigoutno >= u1->nout || siginno >= u2->nin) { - bug("ugen_connect %s %s %d %d (%d %d)", - class_getname(x1->ob_pd), class_getname(x2->ob_pd), sigoutno, siginno, u1->nout, u2->nin); - } - t_sigoutlet *uout = u1->out + sigoutno; - t_siginlet * uin = u2->in + siginno; - /* add a new connection to the outlet's list */ - t_sigoutconnect *oc = (t_sigoutconnect *)getbytes(sizeof *oc); - oc->next = uout->connections; - uout->connections = oc; - oc->who = u2; - oc->inno = siginno; - /* update inlet and outlet counts */ - uout->nconnect++; - uin->nconnect++; -} - -/* get the index of a ugenbox or -1 if it's not on the list */ -static int ugen_index(t_dspcontext *dc, t_ugenbox *x) { - int ret=0; - for (t_ugenbox *u = dc->ugenlist; u; u = u->next, ret++) if (u == x) return ret; - return -1; -} - -/* put a ugenbox on the chain, recursively putting any others on that this one might uncover. */ -static void ugen_doit(t_dspcontext *dc, t_ugenbox *u) { - t_sigoutlet *uout; - t_siginlet *uin; - t_sigoutconnect *oc; - t_class *klass = pd_class(u->obj); - int i, n; - /* suppress creating new signals for the outputs of signal-inlets and subpatches, except in the case we're an inlet - and "blocking" is set. We don't yet know if a subcanvas will be "blocking" so there we delay new signal creation, - which will be handled by calling signal_setborrowed in the ugen_done_graph routine below. When we encounter a - subcanvas or a signal outlet, suppress freeing the input signals as they may be "borrowed" for the parent or subpatch; - same exception as above, but also if we're "switched" we have to do a copy rather than a borrow. */ - int nonewsigs = klass==canvas_class || (klass==vinlet_class && ! dc->reblock ); - int nofreesigs = klass==canvas_class || (klass==voutlet_class && !(dc->reblock || dc->switched)); - t_signal **insig, **outsig, **sig, *s1, *s2, *s3; - t_ugenbox *u2; - if (ugen_loud) post("doit %s %d %d", class_getname(klass), nofreesigs, nonewsigs); - for (i = 0, uin = u->in; i < u->nin; i++, uin++) { - if (!uin->nconnect) { - t_sample *scalar; - s3 = signal_new(dc->vecsize, dc->srate); - /* post("%s: unconnected signal inlet set to zero", class_getname(u->obj->ob_pd)); */ - if ((scalar = obj_findsignalscalar(u->obj, i))) dsp_add_scalarcopy(scalar, s3->v, s3->n); - else dsp_add_zero(s3->v, s3->n); - uin->signal = s3; - s3->refcount = 1; - } - } - insig = (t_signal **)getbytes((u->nin + u->nout) * sizeof(t_signal *)); - outsig = insig + u->nin; - for (sig = insig, uin = u->in, i = u->nin; i--; sig++, uin++) { - int newrefcount; - *sig = uin->signal; - newrefcount = --(*sig)->refcount; - /* if the reference count went to zero, we free the signal now, - unless it's a subcanvas or outlet; these might keep the - signal around to send to objects connected to them. In this - case we increment the reference count; the corresponding decrement - is in sig_makereusable(). */ - if (nofreesigs) (*sig)->refcount++; - else if (!newrefcount) signal_makereusable(*sig); - } - for (sig = outsig, uout = u->out, i = u->nout; i--; sig++, uout++) { - /* similarly, for outlets of subcanvases we delay creating - them; instead we create "borrowed" ones so that the refcount - is known. The subcanvas replaces the fake signal with one showing - where the output data actually is, to avoid having to copy it. - For any other object, we just allocate a new output vector; - since we've already freed the inputs the objects might get called "in place." */ - *sig = uout->signal = nonewsigs ? - signal_new(0, dc->srate) : - signal_new(dc->vecsize, dc->srate); - (*sig)->refcount = uout->nconnect; - } - /* now call the DSP scheduling routine for the ugen. This routine must fill in "borrowed" - signal outputs in case it's either a subcanvas or a signal inlet. */ - mess1(u->obj, gensym("dsp"), insig); - /* if any output signals aren't connected to anyone, free them now; otherwise they'll either - get freed when the reference count goes back to zero, or even later as explained above. */ - for (sig = outsig, uout = u->out, i = u->nout; i--; sig++, uout++) { - if (!(*sig)->refcount) signal_makereusable(*sig); - } - if (ugen_loud) { - if (u->nin+u->nout==0) post("put %s %d", class_getname(u->obj->ob_pd),ugen_index(dc,u)); - else if (u->nin+u->nout==1) post("put %s %d (%lx)", class_getname(u->obj->ob_pd),ugen_index(dc,u),long(sig[0])); - else if (u->nin+u->nout==2) post("put %s %d (%lx %lx)",class_getname(u->obj->ob_pd),ugen_index(dc,u),long(sig[0]),long(sig[1])); - else post("put %s %d (%lx %lx %lx ...)",class_getname(u->obj->ob_pd),ugen_index(dc,u),long(sig[0]),long(sig[1]),long(sig[2])); - } - /* pass it on and trip anyone whose last inlet was filled */ - for (uout = u->out, i = u->nout; i--; uout++) { - s1 = uout->signal; - for (oc = uout->connections; oc; oc = oc->next) { - u2 = oc->who; - uin = &u2->in[oc->inno]; - /* if there's already someone here, sum the two */ - s2 = uin->signal; - if (s2) { - s1->refcount--; - s2->refcount--; - if (!signal_compatible(s1, s2)) {pd_error(u->obj, "%s: incompatible signal inputs", class_getname(u->obj->ob_pd)); return;} - s3 = signal_newlike(s1); - dsp_add_plus(s1->v, s2->v, s3->v, s1->n); - uin->signal = s3; - s3->refcount = 1; - if (!s1->refcount) signal_makereusable(s1); - if (!s2->refcount) signal_makereusable(s2); - } else uin->signal = s1; - uin->ngot++; - if (uin->ngot < uin->nconnect) goto notyet; - if (u2->nin > 1) for (uin = u2->in, n = u2->nin; n--; uin++) if (uin->ngot < uin->nconnect) goto notyet; - ugen_doit(dc, u2); - notyet: ; - } - } - free(insig); - u->done = 1; -} - -/* once the DSP graph is built, we call this routine to sort it. This routine also deletes the graph; later we might - want to leave the graph around, in case the user is editing the DSP network, to save having to recreate it all the - time. But not today. */ -extern "C" void ugen_done_graph(t_dspcontext *dc) { - t_sigoutlet *uout; - t_siginlet *uin; - int i, n; - t_block *blk; - int period, frequency, phase, vecsize, calcsize; - float srate; - int reblock = 0, switched; - int downsample = 1, upsample = 1; /* IOhannes */ - /* debugging printout */ - if (ugen_loud) { - post("ugen_done_graph..."); - for (t_ugenbox *u = dc->ugenlist; u; u = u->next) { - post("ugen: %s", class_getname(u->obj->ob_pd)); - for (uout = u->out, i = 0; i < u->nout; uout++, i++) - for (t_sigoutconnect *oc = uout->connections; oc; oc = oc->next) { - post("... out %d to %s, index %d, inlet %d", i, class_getname(oc->who->obj->ob_pd), ugen_index(dc, oc->who), oc->inno); - } - } - } - /* search for an object of class "block~" */ - blk = 0; - for (t_ugenbox *u = dc->ugenlist; u; u = u->next) { - t_pd *zz = u->obj; - if (pd_class(zz) == block_class) { - if (blk) pd_error(blk, "conflicting block~ objects in same page"); - else blk = (t_block *)zz; - } - } - t_dspcontext *parent_context = dc->parentcontext; - float parent_srate = parent_context ? parent_context->srate : sys_getsr(); - int parent_vecsize = parent_context ? parent_context->vecsize : sys_getblksize(); - if (blk) { - int realoverlap; - vecsize = blk->vecsize; if (!vecsize) vecsize = parent_vecsize; - calcsize = blk->calcsize;if (!calcsize) calcsize = vecsize; - realoverlap = blk->overlap; if (realoverlap > vecsize) realoverlap = vecsize; - /* IOhannes { */ - downsample = blk->downsample; - upsample = blk->upsample; - if (downsample > parent_vecsize) downsample=parent_vecsize; - period = (vecsize * downsample) / (parent_vecsize * realoverlap * upsample); - frequency = (parent_vecsize * realoverlap * upsample) / (vecsize * downsample); - /* } IOhannes*/ - phase = blk->phase; - srate = parent_srate * realoverlap * upsample / downsample; - /* IOhannes */ - if (period < 1) period = 1; - if (frequency < 1) frequency = 1; - blk->frequency = frequency; - blk->period = period; - blk->phase = dsp_phase & (period - 1); - if (!parent_context || realoverlap!=1 || vecsize!=parent_vecsize || downsample!=1 || upsample!=1) /* IOhannes */ - reblock = 1; - switched = blk->switched; - } else { - srate = parent_srate; - vecsize = parent_vecsize; - calcsize = parent_context ? parent_context->calcsize : vecsize; - downsample = upsample = 1;/* IOhannes */ - period = frequency = 1; - phase = 0; - if (!parent_context) reblock = 1; - switched = 0; - } - dc->reblock = reblock; - dc->switched = switched; - dc->srate = srate; - dc->vecsize = vecsize; - dc->calcsize = calcsize; - /* if we're reblocking or switched, we now have to create output signals to fill in for the "borrowed" ones we - have now. This is also possibly true even if we're not blocked/switched, in the case that there was a - signal loop. But we don't know this yet. */ - if (dc->iosigs && (switched || reblock)) { - t_signal **sigp; - for (i = 0, sigp = dc->iosigs + dc->ninlets; i < dc->noutlets; i++, sigp++) { - if ((*sigp)->isborrowed && !(*sigp)->borrowedfrom) { - signal_setborrowed(*sigp, signal_new(parent_vecsize, parent_srate)); - (*sigp)->refcount++; - if (ugen_loud) post("set %lx->%lx", long(*sigp), long((*sigp)->borrowedfrom)); - } - } - } - if (ugen_loud) post("reblock %d, switched %d", reblock, switched); - /* schedule prologs for inlets and outlets. If the "reblock" flag is set, an inlet will put code on the DSP chain - to copy its input into an internal buffer here, before any unit generators' DSP code gets scheduled. If we don't - "reblock", inlets will need to get pointers to their corresponding inlets/outlets on the box we're inside, - if any. Outlets will also need pointers, unless we're switched, in which case outlet epilog code will kick in. */ - for (t_ugenbox *u = dc->ugenlist; u; u = u->next) { - t_pd *zz = u->obj; - t_signal **outsigs = dc->iosigs; - if (outsigs) outsigs += dc->ninlets; - if (pd_class(zz) == vinlet_class) - vinlet_dspprolog((t_vinlet *)zz, dc->iosigs, vecsize, calcsize, dsp_phase, period, frequency, - downsample, upsample, reblock, switched); - else if (pd_class(zz) == voutlet_class) - voutlet_dspprolog((t_voutlet *)zz, outsigs, vecsize, calcsize, dsp_phase, period, frequency, - downsample, upsample, reblock, switched); - } - int chainblockbegin = dsp_chainsize; /* DSP chain onset before block prolog code */ - if (blk && (reblock || switched)) { /* add the block DSP prolog */ - dsp_add(block_prolog, 1, blk); - blk->chainonset = dsp_chainsize - 1; - } - /* Initialize for sorting */ - for (t_ugenbox *u = dc->ugenlist; u; u = u->next) { - u->done = 0; - for (uout = u->out, i = u->nout; i--; uout++) uout->nsent = 0; - for (uin = u->in, i = u->nin; i--; uin++) uin->ngot = 0, uin->signal = 0; - } - /* Do the sort */ - for (t_ugenbox *u = dc->ugenlist; u; u = u->next) { - /* check that we have no connected signal inlets */ - if (u->done) continue; - for (uin = u->in, i = u->nin; i--; uin++) - if (uin->nconnect) goto next; - ugen_doit(dc, u); - next: ; - } - /* check for a DSP loop, which is evidenced here by the presence of ugens not yet scheduled. */ - for (t_ugenbox *u = dc->ugenlist; u; u = u->next) if (!u->done) { - t_signal **sigp; - pd_error(u->obj, "DSP loop detected (some tilde objects not scheduled)"); - /* this might imply that we have unfilled "borrowed" outputs which we'd better fill in now. */ - for (i = 0, sigp = dc->iosigs + dc->ninlets; i < dc->noutlets; i++, sigp++) { - if ((*sigp)->isborrowed && !(*sigp)->borrowedfrom) { - t_signal *s3 = signal_new(parent_vecsize, parent_srate); - signal_setborrowed(*sigp, s3); - (*sigp)->refcount++; - dsp_add_zero(s3->v, s3->n); - if (ugen_loud) post("oops, belatedly set %lx->%lx", long(*sigp), long((*sigp)->borrowedfrom)); - } - } - break; /* don't need to keep looking. */ - } - /* add block DSP epilog */ - if (blk && (reblock || switched)) dsp_add(block_epilog, 1, blk); - int chainblockend = dsp_chainsize; /* and after block epilog code */ - /* add epilogs for outlets. */ - for (t_ugenbox *u = dc->ugenlist; u; u = u->next) { - t_pd *zz = u->obj; - if (pd_class(zz) == voutlet_class) { - t_signal **iosigs = dc->iosigs; - if (iosigs) iosigs += dc->ninlets; - voutlet_dspepilog((t_voutlet *)zz, iosigs, vecsize, calcsize, dsp_phase, period, frequency, - downsample, upsample, reblock, switched); - } - } - int chainafterall = dsp_chainsize; /* and after signal outlet epilog */ - if (blk) { - blk->blocklength = chainblockend - chainblockbegin; - blk->epiloglength = chainafterall - chainblockend; - blk->reblock = reblock; - } - if (ugen_loud) { - t_int *ip; - if (!dc->parentcontext) for (i=dsp_chainsize, ip=dsp_chain; i--; ip++) post("chain %lx", *ip); - post("... ugen_done_graph done."); - } - /* now delete everything. */ - while (dc->ugenlist) { - for (uout = dc->ugenlist->out, n = dc->ugenlist->nout; n--; uout++) { - t_sigoutconnect *oc = uout->connections, *oc2; - while (oc) { - oc2 = oc->next; - free(oc); - oc = oc2; - } - } - free(dc->ugenlist->out); - free(dc->ugenlist->in); - t_ugenbox *u = dc->ugenlist; - dc->ugenlist = u->next; - free(u); - } - if (ugen_currentcontext == dc) ugen_currentcontext = dc->parentcontext; else bug("ugen_currentcontext"); - free(dc); -} - -t_signal *ugen_getiosig(int index, int inout) { - if (!ugen_currentcontext) bug("ugen_getiosig"); - if (ugen_currentcontext->toplevel) return 0; - if (inout) index += ugen_currentcontext->ninlets; - return ugen_currentcontext->iosigs[index]; -} - -/* resampling code originally by Johannes Zmölnig in 2001 */ -/* also "block-resampling" added by Johannes in 2004.09 */ -/* --------------------- up/down-sampling --------------------- */ -/* LATER: add some downsampling-filters for HOLD and LINEAR */ - -/* up: upsampling factor */ -/* down: downsampling factor */ -/* parent: original vectorsize */ -t_int *downsampling_perform_0(t_int *w) { - PERFORM4ARGS(t_float *,in, t_float *,out, int,down, int,parent); - int n=parent/down; - while(n--) {*out++=*in; in+=down;} - return w+5; -} -/* the downsampled vector is exactly the first part of the parent vector; the rest of the parent is just skipped - * cool for FFT-data, where you only want to process the significant (1st) part of the vector */ -t_int *downsampling_perform_block(t_int *w) { - PERFORM4ARGS(t_float *,in, t_float *,out, int,down, int,parent); - int n=parent/down; - while(n--) *out++=*in++; - return w+5; -} -t_int *upsampling_perform_0(t_int *w) { - PERFORM4ARGS(t_float *,in, t_float *,out, int,up, int,parent); - int n=parent*up; - t_float *dummy = out; - while(n--) *out++=0; - n = parent; - out = dummy; - while(n--) {*out=*in++; out+=up;} - return w+5; -} -t_int *upsampling_perform_hold(t_int *w) { - PERFORM4ARGS(t_float *,in, t_float *,out, int,up, int,parent); - int i=up; - t_float *dum_out = out; - t_float *dum_in = in; - while (i--) { - int n = parent; - out = dum_out+i; - in = dum_in; - while(n--) {*out=*in++; out+=up;} - } - return w+5; -} -t_int *upsampling_perform_linear(t_int *w) { - PERFORM5ARGS(t_resample *,x, t_float *,in, t_float *,out, int,up, int,parent); - const int length = parent*up; - t_float a=*x->buffer, b=*in; - const t_float up_inv = (t_float)1.0/up; - t_float findex = 0.f; - for (int n=0; nbuffer = a; - return w+6; -} -/* 1st part of the upsampled signal-vector will be the original one; 2nd part of the upsampled signal-vector is just 0 - * cool for FFT-data, where you only want to process the significant (1st) part of the vector */ -t_int *upsampling_perform_block(t_int *w) { - PERFORM4ARGS(t_float *,in, t_float *,out, int,up, int,parent); - int i=parent; - int n=parent*(up-1); - while (i--) *out++=*in++; - while (n--) *out++=0.f; - return w+5; -} - -/* ----------------------- public -------------------------------- */ -/* utils */ - -void resample_init(t_resample *x) { - x->method=0; - x->downsample=x->upsample=1; - x->n = x->coefsize = x->bufsize = 0; - x->v = x->coeffs = x->buffer = 0; -} -void resample_free(t_resample *x) { - if (x->n) free(x->v); - if (x->coefsize) free(x->coeffs); - if (x->bufsize) free(x->buffer); - x->n = x->coefsize = x->bufsize = 0; - x->v = x->coeffs = x->buffer = 0; -} -void resample_dsp(t_resample *x, t_sample* in, int insize, t_sample* out, int outsize, int method) { - if (insize == outsize) {bug("nothing to be done"); return;} - if (insize > outsize) { /* downsampling */ - if (insize % outsize) {error("bad downsampling factor"); return;} - switch (method) { - case RESAMPLE_BLOCK: dsp_add(downsampling_perform_block, 4, in, out, insize/outsize, insize); break; - default: dsp_add(downsampling_perform_0, 4, in, out, insize/outsize, insize); - } - } else { /* upsampling */ - if (outsize % insize) {error("bad upsampling factor"); return;} - switch (method) { - case RESAMPLE_HOLD: dsp_add(upsampling_perform_hold, 4, in, out, outsize/insize, insize); break; - case RESAMPLE_LINEAR: - if (x->bufsize != 1) { - free(x->buffer); - x->bufsize = 1; - x->buffer = (t_float *)t_getbytes(x->bufsize*sizeof(*x->buffer)); - } - dsp_add(upsampling_perform_linear, 5, x, in, out, outsize/insize, insize); - break; - case RESAMPLE_BLOCK: dsp_add(upsampling_perform_block, 4, in, out, outsize/insize, insize); break; - default: dsp_add(upsampling_perform_0, 4, in, out, outsize/insize, insize); - } - } -} -void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method) { - if (insize==outsize) { free(x->v); x->n = 0; x->v = in; return;} - if (x->n != outsize) { free(x->v); x->v = (t_float *)t_getbytes(outsize * sizeof(*x->v)); x->n = outsize;} - resample_dsp(x, in, insize, x->v, x->n, method); -} -void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method) { - if (insize==outsize) {if (x->n) free(x->v); x->n = 0; x->v = out; return;} - if (x->n != insize) { free(x->v); x->v = (t_float *)t_getbytes(insize * sizeof(*x->v)); x->n = insize;} - resample_dsp(x, x->v, x->n, out, outsize, method); -} - -/* ------------------------ samplerate~ -------------------------- */ - -static t_class *samplerate_tilde_class; -struct t_samplerate : t_object { - t_canvas *canvas; -}; -extern "C" void *canvas_getblock(t_class *blockclass, t_canvas **canvasp); -static void samplerate_tilde_bang(t_samplerate *x) { - float srate = sys_getsr(); - t_canvas *canvas = x->canvas; - while (canvas) { - t_block *b = (t_block *)canvas_getblock(block_class, &canvas); - if (b) srate *= float(b->upsample) / float(b->downsample); - } - x->ob_outlet->send(srate); -} -static void *samplerate_tilde_new(t_symbol *s) { - t_samplerate *x = (t_samplerate *)pd_new(samplerate_tilde_class); - outlet_new(x,&s_float); - x->canvas = canvas_getcurrent(); - return x; -} -static void samplerate_tilde_setup() { - samplerate_tilde_class = class_new2("samplerate~",samplerate_tilde_new,0,sizeof(t_samplerate),0,""); - class_addbang(samplerate_tilde_class, samplerate_tilde_bang); -} - -/* -------------------- setup routine -------------------------- */ - -void d_ugen_setup () { - block_tilde_setup(); - samplerate_tilde_setup(); -} -- cgit v1.2.1