;;; -*- Lisp -*-

(definstrument (Reson :exp-env nil)
    (start-time duration pitch amp numformants indxFun skewFun pcSkew SkewAt SkewDc
		      vibfreq vibpc ranvibfreq ranvibpc degree distance reverb-amount &rest data)
  ;; data is a list of lists of form '(ampf resonfrq resonamp ampat ampdc dev0 dev1 indxat indxdc)
  (let* ((beg (floor (* start-time sampling-rate)))
	 (end (+ beg (floor (* duration sampling-rate))))
	 (carriers (make-array numFormants :element-type 'osc))
	 (modulator (make-oscil :frequency pitch))
	 (ampfs (make-array numFormants :element-type 'envelope))
	 (indfs (make-array numFormants :element-type 'envelope))
	 (c-rats (make-array numFormants :element-type 'fixnum))
	 (frqf (make-func :envelope (divseg skewfun 25 (* 100 (/ skewat duration)) 75 (- 100 (* 100 (/ Skewdc duration))))
			  :scaler (in-Hz (* pcSkew pitch))
			  :start-time start-time :duration duration))
	 (vib 0.0)
	 (outsum 0.0)
	 (totalAmp 0.0)
	 (modsig 0.0)
	 (loc (make-locsig :degree degree :distance distance :revscale reverb-amount))
	 (pervib (make-triangle-wave :frequency vibfreq
				     :amplitude (in-Hz (* vibpc pitch))))
	 (ranvib (make-randi :frequency ranvibfreq
			     :amplitude (in-Hz (* ranvibpc pitch)))))

    ;; initialize the "formant" generators
    (loop for i from 0 below numFormants do (incf totalAmp (nth 2 (nth i data))))
    (loop for i from 0 below numFormants do
      (let* ((frmdat (nth i data))
	     (Freq (nth 1 frmdat))
	     (ampf (nth 0 frmdat))
	     (rfamp  (nth 2 frmdat))
	     (ampat (* 100 (/ (nth 3 frmdat) duration)))
	     (ampdc (- 100 (* 100 (/ (nth 4 frmdat) duration))))
	     (dev0 (in-Hz (* (nth 5 frmdat) freq)))
	     (dev1 (in-Hz (* (nth 6 frmdat) freq)))
	     (indxat (* 100 (/ (nth 7 frmdat) duration)))
	     (indxdc (- 100 (* 100 (/ (nth 8 frmdat) duration))))
	     (harm (round Freq pitch))
	     (rsamp (- 1.0 (abs (- harm (/ freq pitch)))))
	     (cfq (* pitch harm)))
	(if (zerop ampat) (setf ampat 25))
	(if (zerop ampdc) (setf ampdc 75))
	(if (zerop indxat) (setf indxat 25))
	(if (zerop indxdc) (setf indxdc 75))
	(setf (aref indfs i) (make-func :envelope (divseg indxFun 25 indxat 75 indxdc)
					:scaler (- dev1 dev0) :offset dev0
					:start-time start-time :duration duration))
	(setf (aref ampfs i) (make-func :envelope (divseg ampF 25 ampat 75 ampdc)
					:scaler (* rsamp amp (/ rfamp totalAmp))
					:start-time start-time :duration duration))
	(setf (aref c-rats i) harm)
	(setf (aref carriers i) (make-oscil :frequency cfq))))
    (Run
     (loop for i from beg to end do 
       (setf outsum 0.0)
       (setf vib (+ (triangle-wave pervib) (randi ranvib) (env frqf)))
       (setf modsig (oscil modulator vib))
       (dotimes (k numFormants)
	 (incf outsum (* (env (aref ampfs k)) 
			 (oscil (aref carriers k) (+ (* vib (aref c-rats k))
						     (* (env (aref indfs k)) modsig))))))
       (locsig loc i outsum)))))

#|

(reson 0 1.0 440 .1 2 '(0 0 100 1) '(0 0 100 1) .1 .1 .1 5 .01 5 .01 0 1.0 0.01
         '((0 0 100 1) 1200 .5 .1 .1 0 1.0 .1 .1)
         '((0 1 100 0) 2400 .5 .1 .1 0 1.0 .1 .1))

|#
