;;; -*- Lisp -*-

(defun bird-normalize-to-power-of-two (coeffs)
  (let ((maxval (abs (aref coeffs 0)))
	(scaler 0.0))
    (loop for i from 1 below (array-total-size coeffs) do (setf maxval (max maxval (abs (aref coeffs i)))))
    (setf maxval (expt 2 (+ 3 (ceiling (/ (log maxval) (log 2))))))
    (setf scaler (/ 1.0 maxval))
    (loop for i from 0 below (array-total-size coeffs) do (setf (aref coeffs i) (* scaler (aref coeffs i))))
    maxval))

(defvar Bigbird-2-freq-envelope '(0 0 100 1))
(defvar Bigbird-2-amp-envelope '(0 0 25 1 75 1 100 0))
(defvar Bigbird-2-partials '(1 .5 2 .25 3 .2))

(definstrument BigBird-2 (start duration frequency freqskew amplitude
			  &key (Freq-envelope Bigbird-2-Freq-envelope)
			       (Amp-envelope Bigbird-2-amp-envelope)
			       (Partials Bigbird-2-partials)
			       (lpcoeff 1.0)
			       (degree 0.0)
			       (reverb-amount 0.0))
  (multiple-value-bind (beg end) (get-beg-end start duration)
    (let* ((gls-env (make-func :envelope freq-envelope :scaler (in-Hz freqskew) :start-time start :duration duration))
	   (os (make-oscil :frequency frequency))
	   (fil (make-one-pole lpcoeff (- 1.0 lpcoeff)))
	   (coeffs (get-chebychev-coefficients (normalize-partials partials)))
	   (norm (bird-normalize-to-power-of-two coeffs))
	   (loc (make-locsig :degree degree :distance 1.0 :revscale reverb-amount))
	   (amp-env (make-func :envelope amp-envelope :scaler (* norm amplitude) :start-time start :duration duration)))
      (Run
       (loop for i from beg to end do
	 (locsig loc i (one-pole fil (* (env amp-env) (polynomial coeffs (oscil os (env gls-env)))))))))))

(defun scissor (begin-time)
  (let ((scissorf '(0 0  40 1  60 1  100 0)))
    (bigbird-2 begin-time 0.05 1800 1800 .2 
	       :freq-envelope scissorf 
	       :amp-envelope '(0 0  25 1  75 1  100 0) 
	       :partials '(1 .5  2 1  3 .5  4 .1  5 .01))))



(definstrument BigBird (start duration frequency freqskew amplitude Freq-envelope Amp-envelope Partials
			&optional (lpcoeff 1.0) (degree 0.0) (reverb-amount 0.0))
  (multiple-value-bind (beg end) (get-beg-end start duration)
    (let* ((gls-env (make-func :envelope freq-envelope :scaler (in-Hz freqskew) :start-time start :duration duration))
	   (os (make-oscil :frequency frequency))
	   (fil (make-one-pole lpcoeff (- 1.0 lpcoeff)))
	   (coeffs (get-chebychev-coefficients (normalize-partials partials)))
	   (norm (bird-normalize-to-power-of-two coeffs))
	   (loc (make-locsig :degree degree :distance 1.0 :revscale reverb-amount))
	   (amp-env (make-func :envelope amp-envelope :scaler (* norm amplitude) :start-time start :duration duration)))
      (Run
       (loop for i from beg to end do
	 (locsig loc i (one-pole fil (* (env amp-env) (polynomial coeffs (oscil os (env gls-env)))))))))))
