First steps with "real" UGens | ||
---|---|---|
Part 1 | Part 2 |
The arrangement of multiple Virtual UGens is not a true combination but a fusion, because the original evanescent VUGs are melted away.
However, sometimes the threaded code of the classic UGen is useful, in particular to get a faster compilation of DSP, a reduced use of the memory and a minor stress for the gc.
We can reuse a compiled Virtual UGen. The syntax of
COMPILE-VUG
is:
(compile-vug name-or-vug return-type &optional force-p)
for example:
(in-package :scratch) SCRATCH> (set-rt-block-size 1) SCRATCH> (rt-start) SCRATCH> (compile-vug 'envelope 'sample) SCRATCH> (vug 'envelope) #<VUG ENVELOPE> SCRATCH> (ugen 'envelope) #<UGEN ENVELOPE>
Now, when we use ENVELOPE
inside the definition of a DSP
(or UGEN because we can also use nested UGENs), for example
(dsp! ugen-test (freq amp atk rel) (stereo (* (envelope (make-perc atk rel) 1 1 #'free) (osc *sine-table* freq amp)))) SCRATCH> (ugen-test 440 .3 .01 .5)
the generated code uses the UGEN called ENVELOPE
and not the
VUG with the same name.
COMPILE-VUG
works with VUGs but not with VUG-MACROs,
because a VUG-MACRO is like many VUGs in one. Have no fear, it isn't a
problem, we can define a UGEN with the macro DEFINE-UGEN
.
The syntax is
(define-ugen name return-type lambda-list &body body)
It is similar to DEFINE-VUG
but with a new argument
RETURN-TYPE
. For example:
(define-ugen oscili sample (amp cps (buf buffer)) "A simple oscillator with linear interpolation." (osc buf cps amp 0 :linear)) (dsp! ugen-test2 (freq amp atk rel) (stereo (* (envelope (make-perc atk rel) 1 1 #'free) (oscili amp freq *sine-table*)))) SCRATCH> (ugen-test2 440 .3 .01 .5)
where UGEN-TEST2
is defined with the two UGENs
ENVELOPE
and OSCILI
. The following example
shows the use of nested UGENs:
(define-ugen perc-sine sample (freq amp atk rel) (* (envelope (make-perc atk rel) 1 1 #'free) (oscili amp freq *sine-table*))) (dsp! ugen-test3 (freq amp atk rel) (stereo (perc-sine freq amp atk rel))) SCRATCH> (ugen-test3 440 .3 .01 .5)
Ok, habemus UGens, but where are the VUGs ENVELOPE
and
OSCILI
?
After the creation of a UGEN, a VUG comes into play when the related
UGEN is inlined. For example, we can define a UGEN called
PERC-SINE*
with the VUGs ENVELOPE
and
OSCILI
:
(define-ugen perc-sine* sample (freq amp atk rel) (declare (inline envelope oscili)) (* (envelope (make-perc atk rel) 1 1 #'free) (oscili amp freq *sine-table*))) (dsp! ugen-test4 (freq amp atk rel) (stereo (perc-sine* freq amp atk rel))) SCRATCH> (ugen-test4 440 .3 .01 .5)
It is necessary to think before to use a UGEN instead of a VUG. For
example, the UGEN PAN2
(compile-vug 'pan2 'sample) (dsp! pan2-ugen-bug (freq amp pos) (foreach-channel (cout (pan2 (oscili amp freq *sine-table*) pos)))) ;; Ops, the frequency is 880 instead of 440 !? SCRATCH> (pan2-ugen-bug 440 .3 .5) SCRATCH> (free 0)
doesn't work with the current implementation of PAN2
(branching based on CURRENT-CHANNEL
) because a UGEN is a
rigid object and it is not ductile like a VUG. It works only when it is
a VUG, because in this case the input (VUG or UGEN) is merged inside the
VUG. When PAN2
is a UGEN, the input is computed for any
channel before to require the output of PAN2
. It appears
complicated but it's genuinely logic. So, some possible alternatives to
fix the prior example are:
(dsp! pan-test1 (freq amp pos) (declare (inline pan2)) (foreach-channel (cout (pan2 (oscili amp freq *sine-table*) pos)))) SCRATCH> (pan-test1 440 .3 .5) SCRATCH> (free 0) (define-ugen my-pan2 frame (in pos) "Stereo equal power panpot." (with-samples ((alpha (* +half-pi+ pos))) (samples (* in (cos alpha)) (* in (sin alpha))))) (dsp! pan-test2 (freq amp pos) (multiple-sample-bind (l r) (my-pan2 (oscili amp freq *sine-table*) pos) (out l r))) SCRATCH> (pan-test2 440 .3 .5) SCRATCH> (free 0)
Finally, we can see all the defined UGENs with
ALL-UGEN-NAMES
:
SCRATCH> (all-ugen-names)
(ENVELOPE MY-PAN2 OSCILI PAN2 PERC-SINE PERC-SINE*)
After the cancellation of a UGEN by using DESTROY-UGEN
, the
related VUG is still alive:
SCRATCH> (destroy-ugen 'envelope) SCRATCH> (ugen 'envelope) NIL SCRATCH> (vug 'envelope) #<VUG ENVELOPE> SCRATCH> (compiled-vug-p 'envelope) NIL
Getting Started with Incudine | Home | Part 2 |