;;; this is a translation to Snd (from CLM's prc-toolkit95.lisp) ;;; of Perry Cook's Physical Modelling Toolkit. (provide 'snd-prc95.scm) (if (provided? 'snd) (require snd-ws.scm) (require sndlib-ws.scm)) (define* (make-reed (offset 0.6) (slope -0.8)) (float-vector offset slope)) (define (reedtable r samp) (min 1.0 (+ (r 0) (* (r 1) samp)))) (define* (make-bowtable (offset 0.0) (slope 1.0)) (float-vector offset slope)) (define (bowtable b samp) (max 0.0 (- 1.0 (abs (* (b 1) (+ samp (b 0))))))) (define (jettable samp) (max -1.0 (min 1.0 (* samp (- (* samp samp) 1.0))))) (define* (make-onezero (gain 0.5) (zerocoeff 1.0)) (make-one-zero gain (* gain zerocoeff))) (define* (make-onep (polecoeff 0.9)) (make-one-pole (- 1.0 polecoeff) (- polecoeff))) (define (set-pole p val) (set! (mus-ycoeff p 1) (- val)) (set! (mus-xcoeff p 0) (- 1.0 val))) (define (set-gain p val) (set! (mus-xcoeff p 0) (* (mus-xcoeff p 0) val))) (define (lip-set-freq b freq) (set! (mus-frequency b) freq)) (define (lip b mouthsample boresample) (let ((temp (formant b (- mouthsample boresample)))) (set! temp (min 1.0 (* temp temp))) (+ (* temp mouthsample) (* (- 1.0 temp) boresample)))) (define (make-dc-block) (float-vector 0.0 0.0)) (define (dc-block b samp) (set! (b 1) (- (+ samp (* 0.99 (b 1))) (b 0))) (set! (b 0) samp) (b 1)) ;; we could also use a filter generator here: (make-filter 2 (float-vector 1 -1) (float-vector 0 -0.99)) ;;; this ia a 0-based versions of the clm delays (defgenerator dlya (outp 0) (input #f)) (define (make-delayl len lag) ;; Perry's original had linear interp bug, I think -- this form is more in tune (make-dlya :input (make-delay len :max-size (ceiling (+ len lag 1))) :outp (- lag len))) (define (delayl d samp) (delay-tick (d 'input) samp) (tap (d 'input) (d 'outp))) ;;; now some example instruments (definstrument (plucky beg dur freq amplitude maxa) ;; (with-sound () (plucky 0 .3 440 .2 1.0)) (let ((len (+ 1 (floor (/ *clm-srate* 100.0))))) ; 100 = lowest freq (let ((delayline (make-delayl len (- (/ *clm-srate* freq) 0.5))) (filt (make-onezero)) (start (seconds->samples beg)) (end (seconds->samples (+ beg dur))) (dout 0.0)) (do ((i 0 (+ i 1))) ((= i len)) (set! dout (delayl delayline (+ (* 0.99 dout) (mus-random maxa))))) (do ((i start (+ i 1))) ((= i end)) (set! dout (delayl delayline (one-zero filt dout))) (outa i (* amplitude dout)))))) ;;; freq is off in this one (in prc's original also) (definstrument (bowstr beg dur frq amplitude maxa) ;; (with-sound () (bowstr 0 .3 220 .2 1.0)) (let ((len (+ 1 (floor (/ *clm-srate* 100.0))))) ; 100 = lowest freq (let ((ratio 0.8317) (rate .001) (bowing #t) (temp (- (/ *clm-srate* frq) 4.0))) (let ((neckdelay (make-delayl len (* temp ratio))) (bridgedelay (make-delayl (floor (/ len 2)) (* temp (- 1.0 ratio)))) (bowtab (make-bowtable :slope 3.0)) (filt (make-onep)) (bowvelocity rate) (maxvelocity maxa) (attackrate rate) (st (seconds->samples beg)) (end (seconds->samples (+ beg dur))) (release (seconds->samples (* .8 dur))) (ctr 0) (bridgeout 0.0) (neckout 0.0)) (set-pole filt 0.6) (set-gain filt 0.3) (do ((i st (+ i 1)) (bridgerefl 0.0 0.0) (nutrefl 0.0 0.0) (veldiff 0.0 0.0) (stringvel 0.0 0.0) (bowtemp 0.0 0.0)) ((= i end)) (if bowing (if (not (= maxvelocity bowvelocity)) (set! bowvelocity ((if (< bowvelocity maxvelocity) + -) bowvelocity attackrate))) (if (> bowvelocity 0.0) (set! bowvelocity (- bowvelocity attackrate)))) (set! bowtemp (* 0.3 bowvelocity)) (let ((filt-output (one-pole filt bridgeout))) (set! bridgerefl (- filt-output)) (set! nutrefl (- neckout)) (set! stringvel (+ bridgerefl nutrefl)) (set! veldiff (- bowtemp stringvel)) (set! veldiff (* veldiff (bowtable bowtab veldiff))) (set! neckout (delayl neckdelay (+ bridgerefl veldiff))) (set! bridgeout (delayl bridgedelay (+ nutrefl veldiff))) (outa i (* amplitude 10.0 filt-output)) (if (= ctr release) (begin (set! bowing #f) (set! attackrate .0005))) (set! ctr (+ ctr 1)))))))) (definstrument (brass beg dur freq amplitude maxa) ;; does this work at all? (let ((len (+ 1 (floor (/ *clm-srate* 100.0))))) (let ((blowing #t) (rate .001) (breathpressure 0.0)) ; 0.1 ? (let ((delayline (make-delayl len (+ 1.0 (/ *clm-srate* freq)))) (lipfilter (make-formant freq)) (dcblocker (make-dc-block)) (maxpressure maxa) (attackrate rate) (st (seconds->samples beg)) (end (seconds->samples (+ beg dur))) (release (seconds->samples (* .8 dur))) (ctr 0) (dout 0.0)) (do ((i st (+ i 1))) ((= i end)) (if blowing (if (not (= maxpressure breathpressure)) (set! breathpressure ((if (< breathpressure maxpressure) + -) breathpressure attackrate))) (if (> breathpressure 0.0) (set! breathpressure (- breathpressure attackrate)))) (set! dout (delayl delayline (dc-block dcblocker (lip lipfilter (* 0.3 breathpressure) (* 0.9 dout))))) (outa i (* amplitude dout)) (if (= ctr release) (begin (set! blowing #f) (set! attackrate .0005))) (set! ctr (+ ctr 1))))))) (definstrument (clarinet beg dur freq amplitude maxa) ;; (with-sound () (clarinet 0 .3 440 .2 1.0)) (let ((len (+ 1 (floor (/ *clm-srate* 100.0))))) (let ((blowing #t) (breathpressure 0.0) ; 0.1 ? (rate .001)) (let ((delayline (make-delayl len (- (* 0.5 (/ *clm-srate* freq)) 1.0))) (rtable (make-reed :offset 0.7 :slope -0.3)) (filt (make-onezero)) (maxpressure maxa) (attackrate rate) (st (seconds->samples beg)) (end (seconds->samples (+ beg dur))) (ctr 0) (release (seconds->samples (* .8 dur))) (dlyout 0.0)) (do ((i st (+ i 1))) ((= i end)) (if blowing (if (not (= maxpressure breathpressure)) (set! breathpressure ((if (< breathpressure maxpressure) + -) breathpressure attackrate))) (if (> breathpressure 0.0) (set! breathpressure (- breathpressure attackrate)))) (let ((pressurediff (- (one-zero filt (* -0.95 dlyout)) breathpressure))) (set! dlyout (delayl delayline (+ breathpressure (* pressurediff (reedtable rtable pressurediff)))))) (outa i (* amplitude dlyout)) (if (= ctr release) (begin (set! blowing #f) (set! attackrate .0005))) (set! ctr (+ ctr 1))))))) (definstrument (flute beg dur freq amplitude maxa) ;; (with-sound () (flute 0 .3 440 .2 1.0)) (let ((len (+ 1 (floor (/ *clm-srate* 100.0))))) (let ((jetrefl 0.6) (endrefl 0.6) (sinphase 0.0) (blowing #t) (rate .0005) (breathpressure 0.0) ; 0.1 ? (ratio 0.8) (temp (- (/ *clm-srate* freq) 5.0))) (let ((jetdelay (make-delayl (floor (/ len 2)) (* temp (- 1.0 ratio)))) (boredelay (make-delayl len (* ratio temp))) (filt (make-onep)) (dcblocker (make-dc-block)) (maxpressure maxa) (attackrate rate) (st (seconds->samples beg)) (end (seconds->samples (+ beg dur))) (ctr 0) (release (seconds->samples (* .8 dur))) (boreout 0.0)) (set-pole filt 0.8) (set-gain filt -1.0) (do ((i st (+ i 1))) ((= i end)) (let ((randpressure (random (* 0.1 breathpressure)))) (set! sinphase (+ sinphase 0.0007)) ;5 hz vibrato? (if (> sinphase 6.28) (set! sinphase (- sinphase 6.28))) (set! randpressure (+ randpressure (* 0.05 breathpressure (sin sinphase)))) (if blowing (if (not (= maxpressure breathpressure)) (set! breathpressure ((if (< breathpressure maxpressure) + -) breathpressure attackrate))) (if (> breathpressure 0.0) (set! breathpressure (- breathpressure attackrate)))) (let ((pressurediff (let ((temp (dc-block dcblocker (one-pole filt boreout)))) (+ (jettable (delayl jetdelay (- (+ breathpressure randpressure) (* jetrefl temp)))) (* endrefl temp))))) (set! boreout (delayl boredelay pressurediff))) (outa i (* 0.3 amplitude boreout)) (if (= ctr release) (begin (set! blowing #f) (set! attackrate .0005))) (set! ctr (+ ctr 1)))))))) #| (with-sound () (plucky 0 .3 440 .2 1.0) (bowstr .5 .3 220 .2 1.0) (brass 1 .3 440 .2 1.0) (clarinet 1.5 .3 440 .2 1.0) (flute 2 .3 440 .2 1.0)) |#