;;; -*- Lisp -*-

;;; NREV (the most popular Samson box reverb)

(defun prime (val)
  (or (= val 2)
      (and (oddp val)
	   (do ((i 3 (+ i 2))
		(lim (sqrt val)))
	       ((or (= 0 (mod val i)) (> i lim))
		(> i lim))))))
       
(defvar nrev-reverb-factor 1.09)
(defvar nrev-lp-coeff 0.7)
(defvar nrev-output-scale 1.0)
(defvar nrev-volume 1.0)

(definstrument nrev (start-time duration &key (reverb-factor nrev-reverb-factor)
					      (lp-coeff nrev-lp-coeff)
					      (output-scale nrev-output-scale)
					      (volume nrev-volume))

  ;; reverb-factor controls the length of the decay -- it should not exceed (/ 1.0 .823)
  ;; lp-coeff controls the strength of the low pass filter inserted in the feedback loop
  ;; output-scale can be used to boost the reverb output

  (let* ((srscale (/ sampling-rate 25641))
	 (val 0)
	 (dly-len (make-array 15 :element-type 'fixnum 
			      :initial-contents '(1433 1601 1867 2053 2251 2399 347 113 37 59 53 43 37 29 19))))
    ; was backwards??? --  '(19 29 37 43 53 59 37 113 347 2399 2251 2053 1867 1601 1433))))
    (loop for i below 15 do
      (setf val (floor (* srscale (aref dly-len i))))
      (if (= 0 (mod val 2)) (incf val))
      (loop while (not (prime val)) do (incf val 2))
      (setf (aref dly-len i) val))
    (let* ((comb1 (make-comb (* .822 reverb-factor) (aref dly-len 0)))
	   (comb2 (make-comb (* .802 reverb-factor) (aref dly-len 1)))
	   (comb3 (make-comb (* .773 reverb-factor) (aref dly-len 2)))
	   (comb4 (make-comb (* .753 reverb-factor) (aref dly-len 3)))
	   (comb5 (make-comb (* .753 reverb-factor) (aref dly-len 4)))
	   (comb6 (make-comb (* .733 reverb-factor) (aref dly-len 5)))
	   (low (make-one-pole lp-coeff (- lp-coeff 1.0)))
	   (chan2 (or (stereo) (quad)))
	   (chan4 (quad))
	   (allpass1 (make-all-pass 0.700 -0.700 (aref dly-len 6)))
	   (allpass2 (make-all-pass 0.700 -0.700 (aref dly-len 7)))
	   (allpass3 (make-all-pass 0.700 -0.700 (aref dly-len 8)))
	   (allpass4 (make-all-pass 0.700 -0.700 (aref dly-len 9))) ; 10 for quad
	   (allpass5 (make-all-pass 0.700 -0.700 (aref dly-len 11)))
	   (allpass6 (if chan2 (make-all-pass 0.700 -0.700 (aref dly-len 12))))
	   (allpass7 (if chan4 (make-all-pass 0.700 -0.700 (aref dly-len 13))))
	   (allpass8 (if chan4 (make-all-pass 0.700 -0.700 (aref dly-len 14))))
	   (rev 0.0)
	   (outrev 0.0)
	   (beg (floor (* start-time sampling-rate)))
	   (end (+ beg (floor (* duration sampling-rate)))))
      (Run
       (loop for i from beg to end do
	 (setf rev (* volume (revin i)))
	 (setf outrev
	   (all-pass allpass4
		     (one-pole low
			       (all-pass allpass3
					 (all-pass allpass2
						   (all-pass allpass1
							     (+ (comb comb1 rev)
								(comb comb2 rev)
								(comb comb3 rev)
								(comb comb4 rev)
								(comb comb5 rev)
								(comb comb6 rev))))))))
	 (outa i (* output-scale (all-pass allpass5 outrev)))
	 (if chan2 (outb i (* output-scale (all-pass allpass6 outrev))))
	 (if chan4 (outc i (* output-scale (all-pass allpass7 outrev))))
	 (if chan4 (outd i (* output-scale (all-pass allpass8 outrev))))))
      (End-Run))))



