;;; -*- Lisp -*-

(defvar jc-reverb-volume 1.0)

(definstrument JC-reverb
  (start-time duration &key (low-pass nil) 
	      (volume jc-reverb-volume) 
	      (double nil)
	      (delay1 .013) 
	      (delay2 .011)
	      (delay3 .015)
	      (delay4 .017))
  (let* ((allpass1 (make-all-pass 0.700 -0.700 1051))
	 (allpass2 (make-all-pass 0.700 -0.700  337))
	 (allpass3 (make-all-pass 0.700 -0.700  113))
	 (comb1 (make-comb 0.742 4799))
	 (comb2 (make-comb 0.733 4999))
	 (comb3 (make-comb 0.715 5399))
	 (comb4 (make-comb 0.697 5801))
	 (chan2 (or (stereo) (quad)))
	 (chan4 (quad))
	 (outdel1 (make-delay (* delay1 sampling-rate)))
	 (outdel2 (if chan2 (make-delay (* delay2 sampling-rate))))
	 (outdel3 (if (or double chan4) (make-delay (* delay3 sampling-rate))))
	 (outdel4 (if (or chan4 (and double chan2)) (make-delay (* delay4 sampling-rate))))
	 (allpass-sum 0.0)
	 (comb-sum 0.0)
	 (comb-sum-1 0.0)
	 (comb-sum-2 0.0)
	 (all-sums 0.0)
	 (delA 0.0)
	 (delB 0.0)
	 (beg (floor (* start-time sampling-rate)))
	 (end (+ beg (floor (* duration sampling-rate)))))
    (if (and double chan4) (warn "jc-reverb is not set up for doubled reverb in quad"))
    (Run
     (loop for i from beg to end do
       (setf allpass-sum (all-pass allpass3
				   (all-pass allpass2
					     (all-pass allpass1 (revin i)))))
       (setf comb-sum-2 comb-sum-1)
       (setf comb-sum-1 comb-sum)
       (setf comb-sum 
	 (+ (comb comb1 allpass-sum)
	    (comb comb2 allpass-sum)
	    (comb comb3 allpass-sum)
	    (comb comb4 allpass-sum)))
       (if low-pass
	   (setf all-sums (+ (* .25 (+ comb-sum comb-sum-2)) (* .5 comb-sum-1)))
	 (setf all-sums comb-sum))
       ;; "modified least squares low pass filter"
       (setf delA (delay outdel1 all-sums))
       (if double (incf delA (delay outdel3 all-sums)))
       (outa i (* volume delA))
       (when chan2
	 (setf delB (delay outdel2 all-sums))
	 (if double (incf delB (delay outdel4 all-sums)))
	 (outb i (* volume delB))
	 (when chan4
	   (outc i (* volume (delay outdel3 all-sums)))
	   (outd i (* volume (delay outdel4 all-sums)))))))
    (End-Run)))
  
