;;; ;;; ;;; rec.ins: Simulation of Baroque Soprano recorder ;;; ;;; Bob Lantz, Music 220B ;;; ;;; final project/assignment 6 ;;; ;;; "rec" instrument features: ;;; ;;; 2 FM pairs, generating odd and even harmonics ;;; Periodic & Random Vibrato ;;; Pitch Skew ;;; Slightly varying attack times ;;; Filtered noise ;;; ;;; Borrows from: bsn2ex.ins (mainly) (defInstrument rec (start-time duration frequency amplitude &key (odd-C-ratio 1.0) (odd-M-ratio 2.0) (odd-index0 0.0) (odd-index1 .9) (odd-index-env '(0 0 20 1 40 1 60 1 80 1 100 .5)) (even-C-ratio 2.0) (even-M-ratio 2.0) (even-index0 0.0) (even-index1 1.0) (even-index-env '(0 0 20 1 40 .9 60 .9 80 .1 100 .5)) (amp-env '(0 0 20 .7 40 1 60 1 80 .10 100 0)) (degree 45.0) (distance 1.0) (reverb-amount 0.005) ; default attack and decay times (at1-time .06) (at2-time .11) (dc1-time 0.011) (dc2-time .1) ; pitch skew function (skew-fun '(0 -1.0 20 -.4 40 0 60 0 80 .1 100 .2)) ; vibrato, stolen from bsn2ex (vib-freq 4) (vib-depth .01) (ran-frq 5) (ran-depth .005) ) (let* ((beg (floor (* start-time sampling-rate))) (end (+ beg (floor (* duration sampling-rate)))) ; attack time gets smaller as pitch goes higher. ; ; pitch at1-time at2-time ; c5 .08 .09 ; c6 .011 .01 ; c7 .01 .4 ; for now, I will just interpolate, more or less, among these times ; as follows: ; if pitch <= c5, at1-time = .08 and at2-time = .09 ; if c6 <= pitch < c6, interp-val = (pitch - c6)/(c5 - c6) ; and at1-time = .08 - some-factor * interp-val ; and at2-time likewise (interp-val (cond ((< frequency (pitch 'c5)) 0) ((< frequency (pitch 'c6)) (/ (- frequency (pitch 'c6)) (- (pitch 'c6) (pitch 'c5)))) (t 1))) (at1-time (- at1-time (* .03 interp-val))) (at2-time (- at2-time (* .02 interp-val))) ; note that c7 actually has an amplitude envelope quite different ; from c5 or c6, so the above (e.g. .4) is just an approximation ; additionally, I would like to scale the even harmonics' amplitude so that ; by the time c7 is reached, the even component is much smaller ; even-scaler = (1 - .75 * interp-val) (even-scaler (- 1.0 (* .75 interp-val))) ; so, the even-amp-scaler will be 1 at c5, and .01 at c7 ; Odd harmonics fm pair ; note that oscillators have a frequency of zero because ; the frequency is determined by the modulating input, ; which combines vibrato, pitch skew, and fm (odd-C-frq (* odd-C-ratio frequency)) (odd-carrier (make-oscil :frequency 0.0)) (odd-M-frq (* odd-M-ratio frequency)) (odd-modulator (make-oscil :frequency 0.0)) (odd-fm-env (make-env :envelope odd-index-env :offset (* odd-index0 odd-M-ratio frequency) :scaler (* (- odd-index1 odd-index0) odd-M-ratio frequency) :start-time start-time :duration duration)) ; even-harmonics fm pair (even-C-frq (* even-C-ratio frequency)) (even-carrier (make-oscil :frequency 0)) (even-M-frq (* even-M-ratio frequency)) (even-modulator (make-oscil :frequency 0.0)) (even-fm-env (make-env :envelope even-index-env :offset (* even-index0 even-M-ratio frequency) :scaler (* (- even-index1 even-index0) even-M-ratio frequency) :start-time start-time :duration duration)) ; location and amplitude envelope (loc (make-locsig :degree degree :distance distance :revscale reverb-amount)) ; note we want to use the *original* amplitude envelope for ; both amp-env and vib-fun; so, we duplicate it as "amp1-env" (amp-env1 amp-env) ; amplitude env (amp-env (make-env :envelope (divenv amp-env1 duration 20 at1-time 40 at2-time 60 (- duration at1-time at2-time dc1-time dc2-time) 80 dc1-time 100 dc2-time ) :scaler amplitude :start-time start-time :duration duration)) ; pitch skew, stolen from bsn2ex (skew-env (make-env :envelope (divenv skew-fun duration 20 at1-time 40 at1-time 60 (- duration at1-time at1-time dc2-time dc2-time) 80 dc2-time 100 dc2-time ) :scaler (* .02 amplitude) :start-time start-time :duration duration)) ; periodic & random vibrato, stolen from bsn2ex (ran-dev (make-randi :frequency ran-frq :amplitude ran-depth)) (vib-frq (make-oscil :frequency vib-freq)) (vib-fun (make-env :envelope (divenv amp-env1 duration 20 at1-time 40 at2-time 60 (- duration at1-time at2-time dc1-time dc2-time) 80 dc1-time 100 dc2-time ) :scaler vib-depth :start-time start-time :duration duration)) ; noise, for simulation of air/breath (noise (make-randi :frequency sampling-rate :amplitude .003 )) ; sum-frq is our scaler for input frequency (i.e. for pitch skew ; as well as vibrato, and sum-val is the raw value... (sum-frq 0.0) (sum-val 0.0) ; we want to filter the noise a bit so that it sounds like air ; going through the instrument (bandwidth .99) (gain 1.0) (noise-filter (make-formnt bandwidth frequency gain)) ) ; let* (Run (loop for i from beg to end do ; sum-val is the sum of all pitch skews, and is also ; used for tremolo (setf sum-val (+ 1.0 (env skew-env) (randi ran-dev) (* (env vib-fun) (oscil vib-frq)) )) ; set sum-frq to be sum of current pitch skew and random + periodic vibrato (setf sum-frq (In-hz sum-val)) (locsig loc i (* (env amp-env) ; scale everything by sum-val for tremolo sum-val ; odd is scaled by .9, even by .09, and noise is very small... (+ (* .9 (oscil odd-carrier (* sum-frq ; base frequency = sum-frq * odd-C-frq (+ odd-C-frq ; we also scale the modulating frequency (* (env odd-fm-env) (oscil odd-modulator (* sum-frq odd-M-frq))))))) (* even-scaler .09 (oscil even-carrier (* sum-frq (+ even-C-frq (* (env even-fm-env) (oscil even-modulator (* sum-frq even-M-frq))))))) ; add in filtered noise (* 100 (formnt noise-filter (randi noise))) ) )))))) ; Part definition (defpart rec (clm-part) (name time duration frequency amplitude &message odd-C-ratio odd-M-Ratio even-C-ratio even-M-ratio even-index0 even-index1 even-index-env amp-env degree distance odd-index0 odd-index1 odd-index-env reverb-amount at1-time at2-time dc1-time dc2-time vib-frq vib-depth vib-fun ran-dev ran-frq ran-depth skew-env skew-fun skew-amt sum-frq) (duration frequency amplitude odd-C-ratio odd-M-Ratio even-C-ratio even-M-ratio even-index0 even-index1 even-index-env odd-index0 odd-index1 odd-index-env amp-env degree distance odd-C-frq odd-M-frq even-C-frq even-M-frq reverb-amount beg end odd-carrier odd-modulator loc fm-env at1-time at2-time dc1-time dc2-time vib-frq vib-depth ran-frq ran-depth vib-fun ran-dev skew-env skew-fun skew-amt sum-frq) )