;;; 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))))))
       
(definstrument nrev (startime dur &key (reverb-factor 1.09)
			      (lp-coeff 0.7)
			      (output-scale 1.0)
			      (volume 1.0) amp-env)

  ;; 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 (/ *srate* 25641))
	 (val 0)
	 (envA (if amp-env (make-env :envelope amp-env :scaler output-scale :duration dur)))
	 (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 (> (mus-channels *output*) 1))
	   (chan4 (= (mus-channels *output*) 4))
	   (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 (* startime *srate*)))
	   (end (+ beg (floor (* dur *srate*)))))
      (run
       (loop for i from beg to end do
	 (setf rev (* volume (ina i *reverb*)))
	 (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))))))))
	 (if envA (setf output-scale (env envA)))
	 (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))))))
      )))


