| Block by block processing | 
|---|
        The loop starts with FOREACH-FRAME and all the nested loops
        (also within VUGs but not within UGENs) are merged in a single loop (the
        first). The indexes of the loop are CURRENT-FRAME and
        CURRENT-SAMPLE and the sample-counter is updated when we use
        NOW inside a FOREACH-FRAME loop.
      
Some simple examples:
(in-package :scratch) (dsp! sin-test (freq amp) (with-samples ((k (* +twopi+ freq *sample-duration*))) (foreach-frame (out (* amp (sin (* k (now)))))))) SCRATCH> (block-size) 1 SCRATCH> (set-rt-block-size 64) 64 SCRATCH> (block-size) 64 SCRATCH> (rt-start) SCRATCH> (sin-test 440 .3) SCRATCH> (free 0) (define-vug filter-in ((ch fixnum) fcut bp amp) (foreach-frame (* amp (butter-bp (audio-in ch) fcut bp)))) (dsp! in-out-test () (foreach-frame ;; There is only one loop because the nested FOREACH-FRAME loops ;; are merged with the first. (out (filter-in 0 2500 100 20) (filter-in 1 2500 100 20)))) SCRATCH> (in-out-test) SCRATCH> (free 0) (defvar *sintab* (make-buffer 8192 :fill-function (gen:partials '(1)))) (dsp! sintonia (freq amp pos) (with-samples ((x (osc *sintab* freq amp 0 :linear)) (alpha (* +half-pi+ pos)) (left (cos alpha)) (right (sin alpha))) (foreach-frame (out (* left x) (* right x))))) (defun new-frequencies (max) (rt-eval () (dograph (n) (set-control n :freq (+ 100 (random max)))))) SCRATCH> (loop repeat 100 do (sintonia (+ 100 (random 3000)) .01 (random 1.0))) SCRATCH> (new-frequencies 5000) SCRATCH> (free 0)
        A UGEN is a compiled VUG and it's impossible to merge
        FOREACH-FRAME with another loop compiled within a UGEN.
        A efficient technique is to compute an array of samples within the UGEN.
        For example:
      
(define-ugen envelope* frame ((env envelope) gate time-scale (done-action function)) (with ((frm (make-frame (block-size)))) (foreach-frame (setf (frame-ref frm current-frame) (envelope env gate time-scale done-action))) frm)) (dsp! bbb-ugen-test ((env envelope) freq amp gate) (with ((frm (envelope* env gate 1 #'free))) (declare (type frame frm)) ;; Set the envelope before the next loop. (maybe-expand frm) (foreach-frame (stereo (* (frame-ref frm current-frame) (gbuzz freq amp 10 1 .5)))))) (defvar *env-test* (make-adsr 1.2 .09 .9 .5)) SCRATCH> (bbb-ugen-test *env-test* 440 .3 1 :id #xee) SCRATCH> (set-control #xee :gate 0) SCRATCH> (free #xee) SCRATCH> (set-rt-block-size 1)
        The index of the array is CURRENT-FRAME because the output
        of ENVELOPE is mono. With a multi-channel output, the index is
      
(+ CURRENT-SAMPLE <channel>)
        where <channel> is the number of the channel
        starting from zero.
      
        Note: a FRAME is an array of samples, so SMP-REF and
        FRAME-REF are the same.
      
| Getting Started with Incudine | Home |