If we want our instrument to change vowels on the fly, we should provide it with a kind of parametric data base. There are tons of ways to do this, maybe the easiest one is to create the data base locally inside the Run-Loop, doing so we will be able to restore whatever vowel we want on run time. Other thing we may want our instrument being capable of is changing the frequency of the source and (why not) changing the source itself from pulses to noise. Here is our instrument:
;;; vowels.cl ;;; real-time subtractive synthesis ;;; producing vocal like sounds ;;; formant data is stored as a set of presets ;;; instrument on/off (defparameter vowels-recon (control-allocate)) ;;; input level control (defparameter vowels-in-level (control-allocate)) ;;; filter frequencies (defparameter vowels-1-frq (control-allocate)) (defparameter vowels-2-frq (control-allocate)) (defparameter vowels-3-frq (control-allocate)) ;;; filter radius (defparameter vowels-1-bw (control-allocate)) (defparameter vowels-2-bw (control-allocate)) (defparameter vowels-3-bw (control-allocate)) ;;; filter gains (defparameter vowels-1-g (control-allocate)) (defparameter vowels-2-g (control-allocate)) (defparameter vowels-3-g (control-allocate)) ;;; input monitor (defparameter vowels-in-frq (control-allocate)) (defparameter vowels-in-sel (control-allocate)) (defparameter vowels-line-in (control-allocate)) ;;; output level (defparameter vowels-out (control-allocate)) ;;; presets (defparameter vowels-set-1 (control-allocate)) (defparameter vowels-set-2 (control-allocate)) (defparameter vowels-set-3 (control-allocate)) (defparameter vowels-set-4 (control-allocate)) (defparameter vowels-set-5 (control-allocate)) ;;; macro needed to properly compute filter's radius ;;; from a given bandwidth in Hertz (defmacro compute-radius (bw) `(- 1 (/ (* pi ,bw) ,sampling-rate))) ;;; instrument (defpinstrument vowels (&key (tester nil)) (let* ((noi (make-randh :frequency 5000 :amplitude .1)) ;;; noise generator (pulse (make-sum-of-cosines :cosines 30 ;;; pulse train generator :frequency 5000)) ;;; filters (filter-1 (make-formant 0.99 175.0)) (filter-2 (make-formant 0.99 610.0)) (filter-3 (make-formnt 0.99 1600.0)) ;;; input level contol (levelf (make-fcontrol vowels-in-level)) ;;; noise/pulses frequency (frq-inf (make-fcontrol vowels-in-frq)) ;;; output level control (outf (make-fcontrol vowels-out)) ;;; frequency controls (frqf-1 (make-fcontrol vowels-1-frq)) (frqf-2 (make-fcontrol vowels-2-frq)) (frqf-3 (make-fcontrol vowels-3-frq)) ;;; radius controls (rf-1 (make-fcontrol vowels-1-bw)) (rf-2 (make-fcontrol vowels-2-bw)) (rf-3 (make-fcontrol vowels-3-bw)) ;;; gain controls (gf-1 (make-fcontrol vowels-1-g)) (gf-2 (make-fcontrol vowels-2-g)) (gf-3 (make-fcontrol vowels-3-g))) (run (loop for i from 0 do (when (= (control vowels-recon) 0.0) (loop-finish)) ;;; some male bass formants as presets ;;; A (cond ((= (control vowels-set-1) 1.0) ;;; frq (setf (control vowels-1-frq) 600.0) (setf (control vowels-2-frq) 1040.0) (setf (control vowels-3-frq) 2250.0) ;;; bw (setf (control vowels-1-bw) 60.0) (setf (control vowels-2-bw) 70.0) (setf (control vowels-3-bw) 110.0) ;;; g (setf (control vowels-1-g) 1.0) (setf (control vowels-2-g) 0.5) (setf (control vowels-3-g) 0.35) ;;; release button (setf (control vowels-set-1) 0.0) ) ;;; E ((= (control vowels-set-2) 1.0) ;;; frq (setf (control vowels-1-frq) 400.0) (setf (control vowels-2-frq) 1620.0) (setf (control vowels-3-frq) 2400.0) ;;; bw (setf (control vowels-1-bw) 40.0) (setf (control vowels-2-bw) 80.0) (setf (control vowels-3-bw) 100.0) ;;; g (setf (control vowels-1-g) 1.0) (setf (control vowels-2-g) 0.25) (setf (control vowels-3-g) 0.35) ;;; release button (setf (control vowels-set-2) 0.0)) ;;; I ((= (control vowels-set-3) 1.0) ;;; frq (setf (control vowels-1-frq) 250.0) (setf (control vowels-2-frq) 1750.0) (setf (control vowels-3-frq) 2600.0) ;;; bw (setf (control vowels-1-bw) 60) (setf (control vowels-2-bw) 90.0) (setf (control vowels-3-bw) 100.0) ;;; g (setf (control vowels-1-g) 1.0) (setf (control vowels-2-g) 0.1) (setf (control vowels-3-g) 0.2) ;;; release button (setf (control vowels-set-3) 0.0)) ;;; O ((= (control vowels-set-4) 1.0) ;;; frq (setf (control vowels-1-frq) 400.0) (setf (control vowels-2-frq) 750.0) (setf (control vowels-3-frq) 2400.0) ;;; bw (setf (control vowels-1-bw) 40.0) (setf (control vowels-2-bw) 80.0) (setf (control vowels-3-bw) 100.0) ;;; g (setf (control vowels-1-g) 1.0) (setf (control vowels-2-g) 0.3) (setf (control vowels-3-g) 0.1) ;;; release button (setf (control vowels-set-4) 0.0)) ;;; U ((= (control vowels-set-5) 1.0) ;;; frq (setf (control vowels-1-frq) 350.0) (setf (control vowels-2-frq) 600.0) (setf (control vowels-3-frq) 2400.0) ;;; bw (setf (control vowels-1-bw) 40.0) (setf (control vowels-2-bw) 80.0) (setf (control vowels-3-bw) 100.0) ;;; g (setf (control vowels-1-g) 1.0) (setf (control vowels-2-g) 0.1) (setf (control vowels-3-g) 0.03) ;;; release button (setf (control vowels-set-5) 0.0)) (t nil)) ;;; set noise/pulses frq input (if (= (control vowels-in-sel) 1.0) (setf (frequency noi)(fcontrol frq-inf)) (setf (frequency pulse)(fcontrol frq-inf))) ;;; set frequencies (setf (frequency filter-1)(fcontrol frqf-1)) (setf (frequency filter-2)(fcontrol frqf-2)) (setf (frequency filter-3)(fcontrol frqf-3)) ;;; set radius (setf (formant-radius filter-1)(compute-radius (fcontrol rf-1))) (setf (formant-radius filter-2)(compute-radius (fcontrol rf-2))) (setf (formant-radius filter-3)(compute-radius (fcontrol rf-3))) ;;; set gains (setf (frmnt-g filter-1)(/ (fcontrol gf-1) 10.0)) (setf (frmnt-g filter-2)(/ (fcontrol gf-2) 10.0)) (setf (frmnt-g filter-3)(/ (fcontrol gf-3) 10.0)) ;;; select the input we want (let* ((in-val (* (fcontrol levelf) (if (= (control vowels-line-in) 1.0) (rec-any 0) (if (= (control vowels-in-sel) 1.0) (randh noi) (sum-of-cosines pulse))))) ;;; add output of the filters together (out-val (+ (formant filter-1 in-val) (formant filter-2 in-val) (formant filter-3 in-val)))) ;;; send scaled value to the output (outa i (* (fcontrol outf) out-val)) ;;; if tester is on send output to it (if tester (setf (tester-in) out-val)))))))
(open-controls 2048)Now you are ready to go, start your controllers in a Xterm:
tester_lnx & ; vowels_lnx &Once you place the controllers in your window you can play the instrument pasting this line to the Lisp interpreter:
(with-psound (:srate 22050)(tester) (vowels :tester t))