(definstrument add-partials (start-time duration frequency amplitude partials
			  &key (amp-env '(0 0 5 1 10 1 100 0))
			       (noise-amp 0.0))
  (multiple-value-bind (beg end) (get-beg-end start-time duration)
    (let*
      ((partial-oscils (make-array (/ (length partials) 2) :element-type 'osc))
       (partial-amps (make-array (/ (length partials) 2)))
       (amp (make-env :envelope amp-env :scaler amplitude :duration duration))
       (noise (make-randh :frequency (* 0.49 sampling-rate) :amplitude noise-amp))
       (oscil-sum 0))
      (loop for j from 0 below (/ (length partials) 2) do
        (setf (aref partial-oscils j) (make-oscil :frequency 
			(* (nth (* 2 j) partials) frequency)))
        (setf (aref partial-amps j) (nth (+ (* 2 j) 1) partials)))
      (run
        (loop for i from beg to end do
          (setf oscil-sum 0)
          (loop for j from 0 below (length partial-amps) do
            (setf oscil-sum (+ oscil-sum (* (aref partial-amps j) 
					    (oscil (aref partial-oscils j))))))
          (outa i (* (env amp) (+ oscil-sum (randh noise))))
)))))

(definstrument add-freqs (start-time duration amplitude freqs
			  &key (amp-env '(0 0 5 1 10 1 100 0)))
  (multiple-value-bind (beg end) (get-beg-end start-time duration)
    (let* 
      ((freq-oscils (make-array (/ (length freqs) 2) :element-type 'osc))
       (freq-amps (make-array (/ (length freqs) 2)))
       (amp (make-env :envelope amp-env :scaler amplitude :duration duration))
       (oscil-sum 0))
      (loop for j from 0 below (/ (length freqs) 2) do
        (setf (aref freq-oscils j) (make-oscil :frequency (nth (* 2 j) freqs)))
        (setf (aref freq-amps j) (nth (+ (* 2 j) 1) freqs)))
      (run
        (loop for i from beg to end do
          (setf oscil-sum 0)
          (loop for j from 0 below (length freq-amps) do
            (setf oscil-sum (+ oscil-sum (* (aref freq-amps j) 
					    (oscil (aref freq-oscils j))))))
          (outa i (* (env amp) oscil-sum))
)))))

(definstrument add-noisy-freqs (start-time duration amplitude freqs noise-amp
			  &key (amp-env '(0 0 5 1 10 1 100 0)))
  (multiple-value-bind (beg end) (get-beg-end start-time duration)
    (let* 
      ((freq-oscils (make-array (/ (length freqs) 2) :element-type 'osc))
       (freq-amps (make-array (/ (length freqs) 2)))
       (freq-noises (make-array (/ (length freqs) 2)))
       (amp (make-env :envelope amp-env :scaler amplitude :duration duration))
       (oscil-sum 0))
      (loop for j from 0 below (/ (length freqs) 2) do
        (setf (aref freq-oscils j) (make-oscil :frequency (nth (* 2 j) freqs)))
        (setf (aref freq-amps j) (nth (+ (* 2 j) 1) freqs))
        (setf (aref freq-noises j) (make-randh :frequency (nth (* 2 j) freqs))))
      (run
        (loop for i from beg to end do
          (setf oscil-sum 0)
          (loop for j from 0 below (length freq-amps) do
            (setf oscil-sum (+ oscil-sum
			       (* (aref freq-amps j) (oscil (aref freq-oscils j)))
			       (* (aref freq-amps j) (randh (aref freq-noises j)) noise-amp))))
          (outa i (* (env amp) oscil-sum))
)))))

(definstrument add-noise (start-time duration amplitude freqs
			  &key (amp-env '(0 0 5 1 10 1 100 0))
			       (r 0.99))
  (multiple-value-bind (beg end) (get-beg-end start-time duration)
    (let*
      ((noises (make-array (/ (length freqs) 2)))
       (noise-filts (make-array (/ (length freqs) 2)))
       (noise-amps (make-array (/ (length freqs) 2)))
       (amp (make-env :envelope amp-env :scaler amplitude :duration duration))
       (noise-sum 0))
      (loop for j from 0 below (/ (length freqs) 2) do
        (setf (aref noises j) (make-randh :frequency (* .49 sampling-rate)))
	(setf (aref noise-filts j) (make-ppolar :r r :frequency (nth (* 2 j) freqs)))
        (setf (aref noise-amps j) (nth (+ (* 2 j) 1) freqs)))
      (run
        (loop for i from beg to end do
          (setf noise-sum 0)
          (loop for j from 0 below (length noises) do
            (setf noise-sum (+ noise-sum (* (aref noise-amps j)
		(ppolar (aref noise-filts j) (randh (aref noises j))))))
          (outa i (* (env amp) noise-sum)))
	)))))


#|
; add-partials: 

; Steel Drum
(setf steel-drum '(1 1 2 .2 2.6 .1 3.2 .1 5.6 .1 8.2 .1 2.9 .1 3 .1 4.2 .1 6.6 .1))
(with-sound () (add-partials 0 .5 300 .5 steel-drum))
(with-sound () (add-partials 0 .5 350 .5 steel-drum))
(with-sound () (add-partials 0 .5 390 .5 steel-drum))

; Clock Bell
(setf low-bell '(1 .5 1.3 .1 1.6 .1 1.9 .1 2.2 .1))
(with-sound () (add-partials 0 2 300 .5 low-bell :amp-env '(0 1 10 1 90 .05 100 0)))

; High Metallic Chime
(setf odd-chime '(1 .3  3 .2 5 .1 7 .1 9 .1))
(with-sound () (add-partials 0 1 1300 .5 odd-chime :amp-env '(0 1 10 1 100 0)))
(with-sound () (add-partials 0 1 2078 .5 odd-chime :amp-env '(0 1 10 1 100 0)))
(setf even-chime '(1 .3  2 .2 4 .1 6 .1 8 .1))
(with-sound () (add-partials 0 1 1300 .5 even-chime :amp-env '(0 1 10 1 100 0)))
(with-sound () (add-partials 0 1 2078 .5 even-chime :amp-env '(0 1 10 1 100 0)))


; add-freqs:
;
; Tubular Bell
;
; original
(with-sound (:sampling-rate 44100) 
  (mix-in "/usr/ccrma/web/CCRMA/Courses/220a/Lectures/5/Sounds/tubular-bell.snd" 0))
;
; using peaks from size 16384 FFT
(setf bell '(3.6 .199 161.9 .016 316.4 .038 520.6 .269 770.8 .476 
	     974.7 .007 1062 1.003 1163 .01 1266 .01 1391 .98 1537 .006
	     1752 1 1899 .012 2141 .134 2555 .345 2988 .124 3191 .01
	     3438 .047 3870 .009 3957 .009 4389 .014 4870 .037 5357 .013))
(with-sound () (add-freqs 0 2 .1 bell :amp-env '(0 1 10 1 100 0)))
;
; using peaks from size 65536 FFT
(setf bell '(.91 0.54 162 .017 317 .035 521 .409 771 .782 943 .005 1062.5 1.003
	     1182 .005 1266 .018 1391 .670 1511 .005 1633 .006 1752 .662 
	     1899 .009 2142 .057 2377 .005 2555 .118 2988 .019 3437 .015
	     3813 .006 4868 .004))
(with-sound () (add-freqs 0 2 .1 bell :amp-env '(0 1 10 1 100 0)))
;
; using peaks from size 262144 FFT
(setf bell '(.24 3.34 520.85 .342 770.95 .540 1062.6 .624 1391 .324 1752.3 .234))
(with-sound () (add-freqs 0 2 .1 bell :amp-env '(0 1 10 1 100 0)))
;
;
; Small Gong
;
; original
(with-sound (:sampling-rate 44100) 
  (mix-in "/usr/ccrma/web/CCRMA/Courses/220a/Lectures/5/Sounds/small-gong.snd" 0))
;
; using peaks from size 16384 FFT
(setf gong '(3.6 .110 273.2 1.101 371.7 .176 547.6 .352 644.6 .246 717.3 1.075
	     780 .074 991.5 .165 1082 .244 1150 .108 1203 .093 1257 .104 
	     1357 1.39 1908 .128 2014 .091 2089 .134 2167 .067 2551 .074
	     2638 .0153 2875 .104 2917 .068 3184 .101 3532 .073 3592 .092
	     3834 .07 4280 .069 4630 .062 4697 .071))
(with-sound () (add-freqs 0 1 .1 gong :amp-env '(0 0 1 1 10 1 100 0)))
;
;
; Turkish Cymbal
;
; original
(with-sound (:sampling-rate 44100) 
  (mix-in "/usr/ccrma/web/CCRMA/Courses/220a/Lectures/5/Sounds/turkish-cymbal-1.snd" 0))
;
; using peaks from size 262144 FFT
(setf cymbal '(.24 3.002 100.41 .163 194.65 .156 309.34 .357 399.6 .265 
	       503.7 .271 667 .276 922 .16 1037 .144 1449 .092 1524 .105
	       1699 .117 1871 .256 2047.6 .125 2920 .121 2196 .19 2269 .157
	       2415 .163 2720 .117 2867 .225 3540 .162 3644 .112 3733 .091
	       4430 .116))
(with-sound () (add-freqs 0 1 .1 cymbal :amp-env '(0 1 10 1 100 0)))
;
; using peaks from size 16384 FFT
(setf cymbal '(307 .573 398 .619 533 1.005 641 .329 689 .482 1449 .349 
	       1513 .319 2032 .390 3543 .502 3648 .445 3709 .310 
	       4324 .342 4556 .808 .4587 .467))
(with-sound () (add-freqs 0 1 .1 cymbal :amp-env '(0 1 10 1 100 0)))



; add-noisy-freqs:
;
; Turkish Cymbal
; using peaks from size 262144 FFT
(setf cymbal '(.24 3.002 100.41 .163 194.65 .156 309.34 .357 399.6 .265 
	       503.7 .271 667 .276 922 .16 1037 .144 1449 .092 1524 .105
	       1699 .117 1871 .256 2047.6 .125 2920 .121 2196 .19 2269 .157
	       2415 .163 2720 .117 2867 .225 3540 .162 3644 .112 3733 .091
	       4430 .116))
(with-sound () (add-noisy-freqs 0 1 .1 cymbal 1 :amp-env '(0 1 10 1 100 0)))

; add-noise:
;
; Noisy Bass Drum
(with-sound () (add-noise 0 .5 .0005 '(100 1 200 .5 400 .2) 
			  :amp-env '(0 0 1 1 10 1 100 0) :r .99))

|#
