;;; -*- syntax: common-lisp; base: 10; mode: lisp -*- ;;; macro for implementing the embouchure feeback non-linearity (x - x-cubed) (defmacro cubic-polynomial (x) `(let () (+ ,x (* -1 ,x ,x ,x)))) ;;; macro for imlementing DC Blocker (a one pole, one zero filter) ;;; equation: y_m = (x_m - x_m-1) + (0.995 * y_m-1) (defmacro dc-blocker (curr-excit prev-excit prev-val) `(+ (- ,curr-excit ,prev-excit) (* 0.995 ,prev-val))) (definstrument stereo-flute (start dur freq flow &key (flow-envelope '(0 1 100 1)) (decay 0.01) ; additional time for instrument to decay (noise 0.0356) (embouchure-size 0.5) (fbk-scl1 0.5) ; these two are crucial for good results (fbk-scl2 0.55) (offset-pos 0.764264) ; from 0.0 to 1.0 along the bore (out-scl 1.0) (a0 0.7) (b1 -0.3) ; filter coefficients (vib-rate 5) (vib-amount 0.03) (ran-rate 5) (ran-amount 0.03)) (let* ((current-excitation 0.0) (current-difference 0.0) (current-flow 0.0) (out-sig 0.0) (tap-sig 0.0) (previous-out-sig 0.0) (previous-tap-sig 0.0) (dc-blocked-a 0.0) (dc-blocked-b 0.0) (previous-dc-blocked-a 0.0) (previous-dc-blocked-b 0.0) (delay-sig 0.0) (emb-sig 0.0) (beg (floor (* start *srate*))) (end (+ beg (floor (* dur *srate*)))) (flowf (make-env :envelope flow-envelope :scaler flow :start beg :end (+ beg (* (- dur decay) *srate*)))) (periodic-vibrato (make-oscil :frequency vib-rate)) (random-vibrato (make-rand-interp :frequency ran-rate)) (breath (make-rand :frequency (/ *srate* 2) :amplitude 1)) (period-samples (floor (/ *srate* freq))) (embouchure-samples (floor (* embouchure-size period-samples))) (embouchure (make-delay embouchure-samples :initial-element 0.0)) (bore (make-delay period-samples :initial-element 0.0)) (offset (floor (* period-samples offset-pos))) (reflection-lowpass-filter (make-one-pole a0 b1))) (run (loop for i from beg to end do (setf delay-sig (delay bore out-sig)) (setf emb-sig (delay embouchure current-difference)) (setf current-flow (+ (* vib-amount (oscil periodic-vibrato)) (* ran-amount (rand-interp random-vibrato)) (env flowf))) (setf current-difference (+ (+ current-flow (* noise (* current-flow (rand breath)))) (* fbk-scl1 delay-sig))) (setf current-excitation (cubic-polynomial emb-sig)) (setf out-sig (one-pole reflection-lowpass-filter (+ current-excitation (* fbk-scl2 delay-sig)))) (setf tap-sig (tap bore offset)) ;; NB the DC blocker is not in the cicuit. It is applied to the out-sig ;; but the result is not fed back into the system. (setf dc-blocked-a (dc-blocker out-sig previous-out-sig previous-dc-blocked-a)) (setf dc-blocked-b (dc-blocker tap-sig previous-tap-sig previous-dc-blocked-b)) (outa i (* out-scl dc-blocked-a)) (outb i (* out-scl dc-blocked-b)) (setf previous-out-sig out-sig previous-dc-blocked-a dc-blocked-a) (setf previous-tap-sig tap-sig previous-dc-blocked-b dc-blocked-b))))) #| a richer tone as left and right channels are now mutually out of phase (with-sound (:channels 2) (stereo-flute 0 3 220 0.55 :flow-envelope '(0 0 25 1 75 1 100 0))) positioning the offset on harmonic nodes can cause cancellation effects, hence the irrational number for the default (0.764264) (with-sound (:channels 2) (stereo-flute 0 3 220 0.55 :flow-envelope '(0 0 25 1 75 1 100 0) :offset-pos 0.5)) |#