;;; cross fade instruments ;;; ;;; cross-fade sweeps up, down, or from mid-spectrum outwards, ;;; dissolve-fade chooses randomly -- like a graphical dissolve ;;; neither is exactly spectacular, but they work -- use similar sounds if possible (speech is problematic) ;;; ;;; translated from fade.ins (provide 'snd-fade.scm) (if (provided? 'snd) (require snd-ws.scm) (require sndlib-ws.scm)) (definstrument (cross-fade beg dur amp file1 file2 ramp-beg ramp-dur ramp-type bank-dur fs fwidth) ;; ramp-type 0=sweep up, 1=sweep down, 2=split from middle (if (> (+ (max bank-dur ramp-beg) ramp-dur bank-dur) dur) (begin (set! ramp-beg (* 0.25 dur)) (set! ramp-dur (* dur 0.49)) (set! bank-dur (* dur 0.24)))) (let ((fil1 (make-sampler 0 file1)) (fil2 (make-sampler 0 file2)) (start (seconds->samples beg)) (ramp-samps (seconds->samples ramp-dur)) (bank-samps (seconds->samples bank-dur)) (fs1 (make-vector fs))) (let ((bin (/ *clm-srate* (* 2 fs))) (radius (- 1.0 (/ fwidth (* 2 fs))))) (do ((k 0 (+ k 1))) ((= k fs)) (set! (fs1 k) (make-formant (* k bin) radius)))) (set! fs1 (make-formant-bank fs1)) (let ((end (+ start (seconds->samples dur))) (bank-incr (/ 1.0 bank-samps)) (ramp-incr (/ 1.0 ramp-samps)) (ramp-start (+ start (seconds->samples ramp-beg)))) (let ((bank1-start (- ramp-start bank-samps)) (ramp-end (+ ramp-start ramp-samps)) (bank2-start (+ ramp-start ramp-samps))) (do ((i start (+ i 1))) ((= i bank1-start)) ;; in first section -- just mix in file1 (outa i (* amp (read-sample fil1)))) (let ((bank2-end (+ bank2-start bank-samps)) (ramp 0.0) (outval 0.0) (inputs (make-float-vector fs)) (ifs (/ 1.0 fs)) (mid 0)) (do ((i bank1-start (+ i 1)) (bank1 0.0 (+ bank1 bank-incr))) ((= i ramp-start)) ;; in bank1 section -- fire up the resonators (let ((inval (read-sample fil1))) (set! outval (formant-bank fs1 inval)) (outa i (* amp (+ (* bank1 outval) (* (- 1.0 bank1) inval)))))) ;; in the ramp (case ramp-type ((0) (do ((i ramp-start (+ i 1))) ((= i ramp-end)) (let ((inval1 (read-sample fil1)) (inval2 (read-sample fil2))) ;; now the choice of spectral fade -- we should end with all bank1 0.0 and all bank2 1.0 (set! ramp (+ ramp ramp-incr)) ;; low freqs go first (if (>= ramp 0.5) (begin (set! mid (floor (* (- (* 2.0 ramp) 1.0) fs))) (fill! inputs inval2 0 mid) (float-vector-interpolate inputs mid fs 1.0 (- ifs) inval2 inval1) ;; (do ((k mid (+ k 1)) (ks 1.0 (- ks ifs))) ((>= k fs)) (float-vector-set! inputs k (+ (* ks inval2) (* (- 1.0 ks) inval1)))) ) (begin (set! mid (min fs (floor (* 2.0 ramp fs)))) (fill! inputs inval1 mid) (float-vector-interpolate inputs 0 mid (* 2.0 ramp) (- ifs) inval2 inval1) ;; (do ((k 0 (+ k 1)) (ks (* 2.0 ramp) (- ks ifs))) ((= k mid)) (float-vector-set! inputs k (+ (* ks inval2) (* (- 1.0 ks) inval1)))) )) (outa i (* amp (formant-bank fs1 inputs)))))) ((1) (do ((i ramp-start (+ i 1))) ((= i ramp-end)) (let ((inval1 (read-sample fil1)) (inval2 (read-sample fil2))) (set! ramp (+ ramp ramp-incr)) ;; high freqs go first (if (>= ramp 0.5) (let ((r2 (- (* 2.0 ramp) 1.0))) (set! mid (min fs (ceiling (* (- 1.0 r2) fs)))) (fill! inputs inval2 mid) (float-vector-interpolate inputs 0 mid r2 ifs inval2 inval1) ;; (do ((k 0 (+ k 1)) (ks r2 (+ ks ifs))) ((= k mid)) (float-vector-set! inputs k (+ (* ks inval2) (* (- 1.0 ks) inval1)))) ) (begin (set! mid (ceiling (* (- 1.0 (* 2.0 ramp)) fs))) (fill! inputs inval1 0 mid) (float-vector-interpolate inputs mid fs 0.0 ifs inval2 inval1) ;; (do ((k mid (+ k 1)) (ks 0.0 (+ ks ifs))) ((>= k fs)) (float-vector-set! inputs k (+ (* ks inval2) (* (- 1.0 ks) inval1)))) )) (outa i (* amp (formant-bank fs1 inputs)))))) (else (let ((half-fs (/ fs 2))) (do ((i ramp-start (+ i 1))) ((= i ramp-end)) (let ((inval1 (read-sample fil1)) (inval2 (read-sample fil2))) ;; now the choice of spectral fade -- we should end with all bank1 0.0 and all bank2 1.0 (set! ramp (+ ramp ramp-incr)) ;; sweep from midpoint out (fill! inputs inval1) (set! mid (min half-fs (floor (* fs ramp)))) (do ((k (- half-fs mid) (+ k 1)) (hk (+ half-fs mid -1) (- hk 1)) (ks (max 0.0 (- (* 2.0 ramp) 1.0)) (+ ks ifs))) ((= k half-fs)) (let ((rfs (min 1.0 ks))) (set! (inputs k) (+ (* rfs inval2) (* (- 1.0 rfs) inval1))) (set! (inputs hk) (inputs k)))) (outa i (* amp (formant-bank fs1 inputs)))))))) (do ((i ramp-end (+ i 1)) (bank2 1.0 (- bank2 bank-incr))) ((= i bank2-end)) ;; in bank2 section -- ramp out resonators (let ((inval (read-sample fil2))) (set! outval (formant-bank fs1 inval)) (outa i (* amp (+ (* bank2 outval) (* (- 1.0 bank2) inval)))))) (do ((i bank2-end (+ i 1))) ((= i end)) ;; in last section -- just mix file2 (outa i (* amp (read-sample fil2)))) ))))) ;;; (float-vector->channel (with-sound ((make-float-vector 22050)) (cross-fade 0 .1 1 0 1 .01 .01 0 .1 256 2))) ;;; (float-vector->channel (with-sound ((make-float-vector 44100)) (cross-fade 0 2 1.0 "oboe.snd" "trumpet.snd" 0.5 1.0 0 .1 256 2))) ;;; (with-sound (:statistics #t) (cross-fade 0 2 1.0 "oboe.snd" "trumpet.snd" 0.5 1.0 0 .1 256 2)) ;;; (with-sound () (cross-fade 0 2 1.0 "oboe.snd" "trumpet.snd" 0.5 1.0 0 .1 256 2)) ;;; these fades seem more successful to me when done relatively quickly (the opposite of the dissolve below ;;; which is best if done as slowly as possible). I like the sweep up best -- a sort of "evaporation" effect. (definstrument (dissolve-fade beg dur amp file1 file2 fsize r lo hi) (let ((fil1 (make-sampler 0 file1)) (fil2 (make-sampler 0 file2)) (start (seconds->samples beg)) (freq-inc (floor (/ fsize 2))) (ramp-inc (/ 1.0 1024.0))) (let ((end (+ start (seconds->samples dur))) (spectr (make-vector freq-inc #f)) (trigger (floor (/ (* dur *clm-srate*) freq-inc))) (fs (make-vector freq-inc #f)) (amps (make-float-vector freq-inc amp)) (ctr 0) (inputs (make-float-vector freq-inc)) (ramps (make-vector freq-inc -1)) (in2s (make-int-vector freq-inc)) (in2-ctr 0) (ramp-ctr 0)) (if (not (number? hi)) (set! hi freq-inc)) (let ((bin (floor (/ *clm-srate* fsize))) (radius (- 1.0 (/ r fsize)))) (do ((k lo (+ k 1))) ((= k hi)) (set! (fs k) (make-formant (* k bin) radius)))) (set! fs (make-formant-bank fs amps)) ; wrap it up... (do ((i start (+ i 1))) ((= i end)) ;; once a ramp is set in motion, it takes care of itself -- we need only choose which to trigger (set! ctr (+ ctr 1)) (if (> ctr trigger) (let ((next (floor (random freq-inc)))) ;; find next randomly chosen resonator to flip (if (not (spectr next)) (set! (spectr next) (- 1.0 ramp-inc)) (call-with-exit (lambda (bbreak) (do ((j next (+ j 1)) (k next (- k 1))) () (if (and (< j freq-inc) (not (spectr j))) (begin (set! (spectr j) (- 1.0 ramp-inc)) (set! next j) (bbreak))) (if (and (>= k 0) (not (spectr k))) (begin (set! (spectr k) (- 1.0 ramp-inc)) (set! next k) (bbreak))))))) (set! (ramps ramp-ctr) next) (set! ramp-ctr (+ ramp-ctr 1)) (set! ctr 0))) (let ((inval1 (read-sample fil1)) (inval2 (read-sample fil2))) (fill! inputs inval1) (float-vector-spatter inputs in2s in2-ctr inval2) ;; (do ((k 0 (+ k 1))) ((= k in2-ctr)) (float-vector-set! inputs (int-vector-ref in2s k) inval2)) (when (> ramp-ctr 0) (let ((rk 0) (sp 0.0) (fixup-ramps #f)) (do ((k 0 (+ k 1))) ((= k ramp-ctr)) (set! rk (ramps k)) (set! sp (vector-ref spectr rk)) (float-vector-set! inputs k (+ (* sp inval1) (* (- 1.0 sp) inval2))) (set! sp (- sp ramp-inc)) (if (> sp 0.0) (vector-set! spectr rk sp) (begin (set! (in2s in2-ctr) rk) (set! in2-ctr (+ in2-ctr 1)) (set! fixup-ramps #t) (set! (ramps k) -1)))) (if fixup-ramps (let ((j 0)) (do ((k 0 (+ k 1))) ((= k ramp-ctr)) (if (>= (ramps k) 0) (begin (set! (ramps j) (ramps k)) (set! j (+ j 1))))) (set! ramp-ctr j))))) (outa i (formant-bank fs inputs))))))) ;;; (with-sound (:statistics #t) (dissolve-fade 0 1 1.0 "oboe.snd" "trumpet.snd" 256 2 0 128)) ;;; (float-vector->channel (with-sound ((make-float-vector 44100)) (dissolve-fade 0 2 1 0 1 4096 2 2 #f))) ;;; ;;; another neat effect here is to simply let the random changes float along with no ;;; direction -- if the hit is 1.0 send it toward 0.0 and vice versa -- strange ;;; pitches emerge from noises etc #| ;;; make it easy to see and hear: (with-sound ("p1.snd") (let ((g (make-ncos 200 100))) (do ((i 0 (+ i 1))) ((= i 100000)) (outa i (ncos g))))) (with-sound ("p2.snd") (let ((g (make-ncos 123 100))) (do ((i 0 (+ i 1))) ((= i 100000)) (outa i (ncos g))))) (with-sound (:statistics #t) (cross-fade 0 2 1.0 "p1.snd" "p2.snd" 0.5 1.0 0 .1 256 2)) (with-sound (:statistics #t) (dissolve-fade 0 2 1.0 "p1.snd" "p2.snd" 256 2 0 128)) |#