Getting Started with Incudine | ||
---|---|---|
Part 3 | Part 4 |
DSP-DEBUG
is an utility to inspect the code generated by the
DSP!
macro. The syntax is the same of DSP!
but
DSP-DEBUG
returns a function to call with the DSP arguments.
The result of the evaluation of that function is the code generated by
DSP!
. Here is an example:
SCRATCH> (dsp-debug foo (freq amp pos) (foreach-channel (cout (pan2 (osc *sine-table* freq amp 0 :linear) pos)))) #<FUNCTION (LAMBDA (FREQ AMP POS &OPTIONAL ...)) {10085C184B}> SCRATCH> (funcall * 440 .3 .5) (LAMBDA (INCUDINE.VUG::%DSP-NODE%) (DECLARE (OPTIMIZE SPEED (SAFETY 0)) (TYPE NODE INCUDINE.VUG::%DSP-NODE%)) (INCUDINE.VUG::WITH-DSP-PREAMBLE (#:DSP538 'FOO #:CONTROL-TABLE539 #:TO-FREE540 #:FREE-HOOK541) (INCUDINE.VUG::WITH-FOREIGN-ARRAYS ((#:SMPVEC544 #:SMPVECW543 'SAMPLE 9) (#:F32VEC546 #:F32VECW545 :FLOAT 0) (#:F64VEC548 #:F64VECW547 :DOUBLE 0) (#:I32VEC550 #:I32VECW549 :INT32 0) (#:I64VEC552 #:I64VECW551 :INT64 0) (#:PTRVEC554 #:PTRVECW553 :POINTER 1)) (INCUDINE.VUG::WITH-SAMPLE-VARIABLES ((#:FREQ518 #:AMP519 #:POS520 #:FRAC85529 #:LODIV87530 #:IN533 #:ALPHA535 #:LEFT536 #:RIGHT537) #:SMPVEC544 'SAMPLE) (INCUDINE.VUG::WITH-FOREIGN-VARIABLES ((NIL #:F32VEC546 :FLOAT) (NIL #:F64VEC548 :DOUBLE) (NIL #:I32VEC550 :INT32) (NIL #:I64VEC552 :INT64) ((#:DATA80528) #:PTRVEC554 :POINTER)) (INCUDINE.VUG::WITH-INIT-FRAMES (SETF #:FREQ518 440.0d0) (SETF #:AMP519 0.3d0) (SETF #:POS520 0.5d0) (LET* ((#:BUF521 *SINE-TABLE*) (#:FREQ-INC77525 (SAMPLE->FIXNUM (* #:FREQ518 *CPS2INC*))) (#:PHS78526 0) (#:MINUS-LOBITS79527 (- (BUFFER-LOBITS #:BUF521)))) (DECLARE (TYPE BUFFER #:BUF521)) (DECLARE (TYPE FIXNUM #:FREQ-INC77525)) (DECLARE (TYPE FIXNUM #:PHS78526)) (DECLARE (TYPE (INTEGER -24 0) #:MINUS-LOBITS79527)) (SETF #:DATA80528 (BUFFER-DATA #:BUF521)) (SETF #:LODIV87530 (BUFFER-LODIV #:BUF521)) (LET* ((#:LOMASK88531 (BUFFER-LOMASK #:BUF521)) (#:MASK86532 (BUFFER-MASK #:BUF521))) (DECLARE (TYPE NON-NEGATIVE-FIXNUM #:LOMASK88531)) (DECLARE (TYPE NON-NEGATIVE-FIXNUM #:MASK86532)) (SETF #:ALPHA535 (* +HALF-PI+ #:POS520)) (SETF #:LEFT536 (COS #:ALPHA535)) (SETF #:RIGHT537 (SIN #:ALPHA535)) (LABELS () (PROGN (SETF (GETHASH "FREQ" #:CONTROL-TABLE539) (CONS (LAMBDA (#:VALUE555) (DECLARE (SB-EXT:MUFFLE-CONDITIONS SB-EXT:COMPILER-NOTE)) (SETF #:FREQ518 (INCUDINE.UTIL::FORCE-SAMPLE-FORMAT #:VALUE555)) (SETF #:FREQ-INC77525 (SAMPLE->FIXNUM (* #:FREQ518 *CPS2INC*))) (VALUES)) (LAMBDA () (DECLARE (SB-EXT:MUFFLE-CONDITIONS SB-EXT:COMPILER-NOTE)) #:FREQ518))) (SETF (GETHASH "AMP" #:CONTROL-TABLE539) (CONS (LAMBDA (#:VALUE556) (DECLARE (SB-EXT:MUFFLE-CONDITIONS SB-EXT:COMPILER-NOTE)) (SETF #:AMP519 (INCUDINE.UTIL::FORCE-SAMPLE-FORMAT #:VALUE556)) (VALUES)) (LAMBDA () (DECLARE (SB-EXT:MUFFLE-CONDITIONS SB-EXT:COMPILER-NOTE)) #:AMP519))) (SETF (GETHASH "POS" #:CONTROL-TABLE539) (CONS (LAMBDA (#:VALUE557) (DECLARE (SB-EXT:MUFFLE-CONDITIONS SB-EXT:COMPILER-NOTE)) (SETF #:POS520 (INCUDINE.UTIL::FORCE-SAMPLE-FORMAT #:VALUE557)) (SETF #:ALPHA535 (* +HALF-PI+ #:POS520)) (SETF #:LEFT536 (COS #:ALPHA535)) (SETF #:RIGHT537 (SIN #:ALPHA535)) (VALUES)) (LAMBDA () (DECLARE (SB-EXT:MUFFLE-CONDITIONS SB-EXT:COMPILER-NOTE)) #:POS520))) (SETF (GETHASH (LIST :POINTER "FREQ") #:CONTROL-TABLE539) (REDUCE-WARNINGS (CONS (GET-POINTER #:FREQ518) (LAMBDA () (DECLARE (SB-EXT:MUFFLE-CONDITIONS SB-EXT:COMPILER-NOTE)) (SETF #:FREQ-INC77525 (SAMPLE->FIXNUM (* #:FREQ518 *CPS2INC*))))))) (SETF (GETHASH (LIST :POINTER "AMP") #:CONTROL-TABLE539) (REDUCE-WARNINGS (CONS (GET-POINTER #:AMP519) (LAMBDA ())))) (SETF (GETHASH (LIST :POINTER "POS") #:CONTROL-TABLE539) (REDUCE-WARNINGS (CONS (GET-POINTER #:POS520) (LAMBDA () (DECLARE (SB-EXT:MUFFLE-CONDITIONS SB-EXT:COMPILER-NOTE)) (SETF #:ALPHA535 (* +HALF-PI+ #:POS520)) (SETF #:LEFT536 (COS #:ALPHA535)) (SETF #:RIGHT537 (SIN #:ALPHA535)))))) (SETF (GETHASH "%CONTROL-LIST%" #:CONTROL-TABLE539) (CONS NIL (LAMBDA () (DECLARE (SB-EXT:MUFFLE-CONDITIONS SB-EXT:COMPILER-NOTE)) (LIST #:FREQ518 #:AMP519 #:POS520)))) (SETF (GETHASH "%CONTROL-NAMES%" #:CONTROL-TABLE539) (CONS NIL (LAMBDA () '(FREQ AMP POS))))) NIL (PROGN (SETF (INCUDINE.VUG::DSP-NAME #:DSP538) 'FOO) (SETF (INCUDINE::NODE-CONTROLS INCUDINE.VUG::%DSP-NODE%) #:CONTROL-TABLE539) (INCUDINE.VUG::UPDATE-FREE-HOOK INCUDINE.VUG::%DSP-NODE% #:FREE-HOOK541) (PROGN (SETF #:PHS78526 (LOGAND (THE FIXNUM (+ #:PHS78526 (SAMPLE->FIXNUM (* 0.0d0 +RAD2INC+)))) +PHASE-MASK+))) (SETF #:TO-FREE540 INCUDINE::*TO-FREE*) (INCUDINE.VUG::SET-DSP-OBJECT #:DSP538 :INIT-FUNCTION (LAMBDA (#:NODE542 FREQ AMP POS) (DECLARE (SB-EXT:MUFFLE-CONDITIONS SB-EXT:COMPILER-NOTE)) (INCUDINE.VUG::RESET-FOREIGN-ARRAYS #:SMPVEC544 9 8 #:F32VEC546 0 4 #:F64VEC548 0 8 #:I32VEC550 0 4 #:I64VEC552 0 8 #:PTRVEC554 1 8) (SETF (INCUDINE::NODE-CONTROLS #:NODE542) (INCUDINE.VUG::DSP-CONTROLS #:DSP538)) (SETF INCUDINE.VUG::%DSP-NODE% #:NODE542) (SETF INCUDINE.VUG::*DSP-NODE* #:NODE542) (INCUDINE.VUG::WITH-INIT-FRAMES (INCUDINE.VUG::FREE-INCUDINE-OBJECTS #:TO-FREE540) (LET ((INCUDINE::*TO-FREE* NIL)) (PROGN (SETF #:FREQ518 (COERCE FREQ 'SAMPLE)) (SETF #:AMP519 (COERCE AMP 'SAMPLE)) (SETF #:POS520 (COERCE POS 'SAMPLE)) (SETF #:BUF521 *SINE-TABLE*) (SETF #:FREQ-INC77525 (SAMPLE->FIXNUM (* #:FREQ518 *CPS2INC*))) (SETF #:PHS78526 0) (SETF #:MINUS-LOBITS79527 (- (BUFFER-LOBITS #:BUF521))) (SETF #:DATA80528 (BUFFER-DATA #:BUF521)) (SETF #:LODIV87530 (BUFFER-LODIV #:BUF521)) (SETF #:LOMASK88531 (BUFFER-LOMASK #:BUF521)) (SETF #:MASK86532 (BUFFER-MASK #:BUF521)) (SETF #:ALPHA535 (* +HALF-PI+ #:POS520)) (SETF #:LEFT536 (COS #:ALPHA535)) (SETF #:RIGHT537 (SIN #:ALPHA535))) (INCUDINE.VUG::UPDATE-FREE-HOOK #:NODE542 #:FREE-HOOK541) (PROGN (SETF #:PHS78526 (LOGAND (THE FIXNUM (+ #:PHS78526 (SAMPLE->FIXNUM (* 0.0d0 +RAD2INC+)))) +PHASE-MASK+))) (SETF #:TO-FREE540 INCUDINE::*TO-FREE*))) #:NODE542) :FREE-FUNCTION (LAMBDA () (FREE #:SMPVECW543) (FREE #:PTRVECW553)) :PERF-FUNCTION (LAMBDA () (INCUDINE.VUG::WITH-INIT-FRAMES (BLOCK NIL (LET ((#:I69 0)) (DECLARE (TYPE CHANNEL-NUMBER #:I69)) (TAGBODY (GO #:G71) #:G70 (TAGBODY (LET ((CURRENT-CHANNEL #:I69)) (DECLARE (TYPE CHANNEL-NUMBER CURRENT-CHANNEL) (IGNORABLE CURRENT-CHANNEL)) (PROGN (INCF (AUDIO-OUT CURRENT-CHANNEL) (SAMPLE (IF (= CURRENT-CHANNEL 0) (* #:LEFT536 (SETF #:IN533 (PROGN NIL (LET ((#:INDEX81 (THE FIXNUM (ASH #:PHS78526 #:MINUS-LOBITS79527)))) (LET ((#:G83 (* #:AMP519 (PROGN (SETF #:FRAC85529 (* #:LODIV87530 (LOGAND #:PHS78526 #:LOMASK88531))) (LINEAR-INTERP #:FRAC85529 (SMP-REF #:DATA80528 #:INDEX81) (SMP-REF #:DATA80528 (LOGAND (THE FIXNUM (1+ #:INDEX81)) #:MASK86532))))))) (SETF #:PHS78526 (LOGAND (THE FIXNUM (+ #:PHS78526 #:FREQ-INC77525)) +PHASE-MASK+)) #:G83))))) (IF (= CURRENT-CHANNEL 1) (* #:RIGHT537 #:IN533) (THE T +SAMPLE-ZERO+))))) (VALUES)))) (PSETQ #:I69 (1+ #:I69)) #:G71 (IF (>= #:I69 *NUMBER-OF-OUTPUT-BUS-CHANNELS*) NIL (GO #:G70)) (RETURN-FROM NIL NIL)))) (VALUES)))) (INCUDINE.UTIL::FINALIZE (INCUDINE.VUG::DSP-INIT-FUNCTION #:DSP538) (LAMBDA () (FUNCALL (INCUDINE.VUG::DSP-FREE-FUNCTION #:DSP538)) (INCUDINE.VUG::%%FREE-DSP-INSTANCE #:DSP538))) (VALUES (INCUDINE.VUG::DSP-INIT-FUNCTION #:DSP538) (INCUDINE.VUG::DSP-PERF-FUNCTION #:DSP538))))))))))))
The generated code is divided in the following parts:
- Initialization
- Creation of the hash-table for the control parameters.
- Function definition to re-initialize a DSP instance.
- Function definition to free the memory when the game is over.
- Function definition to perform on each tick.
The FREE-DSP-INSTANCES
function frees the cached DSP instances.
SCRATCH> (free-dsp-instances) SCRATCH> (get-foreign-sample-free-size) 67102464 SCRATCH> (get-rt-memory-free-size) 67102464
GET-FOREIGN-SAMPLE-FREE-SIZE
returns the number of
bytes that can be allocated from the foreign memory pool used to
allocate arrays of samples in DSP and UGEN instances from the
real-time thread. We can set the related memory pool size by
changing the value of the configuration variable
*FOREIGN-SAMPLE-POOL-SIZE*
in ${HOME}/.incudinerc
(the default is 64MB).
GET-RT-MEMORY-FREE-SIZE
returns the free available memory
allocable in realtime, without considering the allocations of SAMPLE
type counted by GET-FOREIGN-SAMPLE-FREE-SIZE
. We can set
the size of the related memory pool by changing the value of
*FOREIGN-RT-MEMORY-POOL-SIZE*
in ${HOME}/.incudinerc
(the default is 64MB).
The function DESTROY-DSP
removes a DSP definition and
all the associated memory.
The function ALL-DSP-NAMES
returns all the defined DSPs.
We can use the combination of DESTROY-DSP
and ALL-DSP-NAMES
to remove all the defined DSP:
SCRATCH> (mapc #'destroy-dsp (all-dsp-names)) SCRATCH> (all-dsp-names) NIL
Incudine has some facilities for diagnostics. There are four levels for the logger:
- error
- warn
- info
- debug
Every level in the list enables the previous levels. It means that if
LOGGER-LEVEL
is :DEBUG
, all the levels are
enabled. If LOGGER-LEVEL
is :ERROR
, only the
error messages are enabled. The default is :WARN
.
*LOGGER-STREAM*
and *LOGGER-FORCE-OUTPUT-P*
default to *STANDARD-OUTPUT*
and T
, respectively.
Some examples:
SCRATCH> (logger-level) :WARN SCRATCH> (msg error "wrong direction") ERROR: wrong direction NIL SCRATCH> (msg warn "the DSP can explode") WARN: the DSP can explode NIL SCRATCH> (msg info "new group ~A" (1+ (random 100))) NIL SCRATCH> (setf (logger-level) :info) :INFO SCRATCH> (msg info "new group ~A" (1+ (random 100))) new group 42 NIL SCRATCH> (msg debug "the value of FREQ is ~,2F" (random 1000.0)) NIL SCRATCH> (setf (logger-level) :debug) :DEBUG SCRATCH> (msg debug "the value of FREQ is ~,2F" (random 1000.0)) DEBUG: the value of FREQ is 826.75 NIL SCRATCH> (msg info "free all nodes") free all nodes NIL SCRATCH> (setf (logger-level) :error) :ERROR SCRATCH> (msg warn "a wolf!") NIL SCRATCH> (setf (logger-level) :warn) :WARN SCRATCH> (msg warn "a wolf!") WARN: a wolf! NIL SCRATCH> (msg error "unknown device") ERROR: unknown device NIL
The LOGGER-TIME
function returns the time unit used for the
log messages. Should be one of :SEC
, :SAMP
or
NIL
(default). LOGGER-TIME
is setfable.
SCRATCH> (logger-time) NIL SCRATCH> (setf (logger-time) :sec) :SEC SCRATCH> (msg warn "too late") 13878.763 WARN: too late NIL SCRATCH> (setf (logger-time) :samp) :SAMP SCRATCH> (msg warn "too late") 667113472.0 WARN: too late NIL SCRATCH> (setf (logger-time-function) (lambda () (let ((seconds-p (eq (logger-time) :sec))) (format *logger-stream* "[~:[~,1F~;~,3F~]] " seconds-p (* (now) (if seconds-p *sample-duration* 1)))))) SCRATCH> (msg warn "LOGGER-TIME-FUNCTION redefined") [675466240.0] WARN: LOGGER-TIME-FUNCTION redefined NIL SCRATCH> (setf (logger-time-function) nil) #<FUNCTION INCUDINE.UTIL::DEFAULT-LOGGER-TIME-FUNCTION> SCRATCH> (setf (logger-time) nil) NIL
We have to use NRT-MSG
instead of MSG
to write messages from rt-thread
, the thread of the audio cycle.
For example:
SCRATCH> (rt-eval () (msg warn "Don't use MSG from rt-thread!")) ; wrong WARN: Don't use MSG from rt-thread! NIL SCRATCH> (setf (logger-level) :info) :INFO SCRATCH> (rt-eval () (nrt-msg info "NRT-MSG is ok from rt-thread")) NRT-MSG is ok from rt-thread NIL SCRATCH> (setf (logger-level) :warn) :WARN SCRATCH> (msg warn "~A" (map 'string #'code-char '(84 72 69 32 69 78 68))) WARN: THE END
Part 3 | Home |