;***************************************************************
; 
; A stereo reverb for the DSP56001 signal processor.  Based on,
; 
;	Moorer, James A. "About This Reverberation Business."
;	Computer Music Journal Vol 3, No. 2 (1979), pp. 13-28.
;
;   reprinted in,
;
;	Roads, Curtis, and Strawn, John, ed., _Foundations
;	of Computer Music_, pp. 605-639, MIT Press, 1985.
;	ISBN 0-262-68051-3 (paper)
;	ISBN 0-262-181142 (hard)
;
; Each comb filter uses a low-pass filter in the feedback path.
; The combs and all-pass filter delay lines use a prime-number
; of stages to improve diffusion.
;
; The output all-pass stage is replicated for left/right
; decorrelation.  Each side uses slightly different gains
; and delay lengths.  This works a lot better than just inverting
; one side and adding in the input.
;
; I left out the early-reflection FIR filter because I needed the cycles
; for other effects.
;
; Quinn Jensen (jensenq@qcj.icon.com)
;
;***************************************************************
	psect	vectors		p:$0000:$0040
	psect	hf_code		p:$0040:$0200
	psect	hf_datax	x:$0000:$0040
	psect	hf_datax1	x:$0040:$0100
	psect	hf_datay	y:$0000:$0040
	psect	hf_datay1	y:$0040:$0100
	psect	midi_data	x:$0400:$1000
	psect	lo_data		x:$1000:$F000
	psect	lo_code		p:$F000:$FE00
	psect	loader		p:$FE00:$FFFF
	psect	iox		x:$FFC0:$FFFF
	psect	ioy		y:$FFC0:$FFFF
;
; some oft-used constants
;
	psect	hf_datax
ffff	dc	$FFFF		;used a lot for modulus
ONE	equ	$7FFFFF		;"one"
one	dc	ONE		;"one"
;
; L/R inputs and outputs
;
in_l	dc	0.0      
in_r	dc	0.0      
out_l	dc	0.0      
out_r	dc	0.0      
;
; recompute comb gains g1 and g2
;
recalc_comb_gains
	move		x:<constsp,r0
	movec		x:<ffff,m0
	move		x:lowpass_cutoff_start,b
	move		x:lowpass_cutoff_slope,y1
	move		x:comb_g,x1
	move		#0.5,x0

	do	#6,recalc_loop
	  clr	a	(r0)+		;skip over the modulus const
	  add	x0,a	b,y0
	  mac	x0,y0,a			;g1 = .5 * b + .5
	  clr	a	a,y0		;y0 = g1
	  add	x1,a	y0,y:(r0)+	;store g1 in table
	  macr	-x1,y0,a		;g2 = g(1-g1) = g - g*g1 with limiting
	  add	y1,b	a,y:(r0)+	;update b, store g2 in table
recalc_loop
	rts

	psect	midi_data
;
; default values for midi-derived parameters
;
lowpass_cutoff_start
	dc	-0.3906250	; ctl value of 39
lowpass_cutoff_slope
	dc	0.0468750	; ctl value of 67
comb_g
	dc	0.8325507974	; ctl value of 57
;
; preset comb-length arrays
;
define(COMBLEN, `
; comb lenths $2,$3,$4,$5,$6,$7
comblen_$1
	dc	$2-1
	dc	$3-1
	dc	$4-1
	dc	$5-1
	dc	$6-1
	dc	$7-1
')

COMBLEN(1, 383, 433, 467, 523, 557, 601)
COMBLEN(2, 509, 577, 631, 701, 743, 797)
COMBLEN(3, 683, 769, 839, 937, 991, 1069)
COMBLEN(4, 919, 1021, 1117, 1249, 1319, 1427)
COMBLEN(5, 1223, 1367, 1489, 1657, 1759, 1901)
COMBLEN(6, 1627, 1823, 1987, 2213, 2341, 2539)

;;;;;;;;;;;;;;;;;;;;;;;
; reverb filters
;;;;;;;;;;;;;;;;;;;;;;;

;  Reverb filter lengths and coefficients     
;  6 comb reverb with prime delay lines
;  Sun Oct 24 13:53:51 1993
;  
;                          Sample rate        32.5520830 kHz      
;                          g                   0.8400000
;  
;                    status      STABLE       
;         delay      near prime lengths actual
;  stage   (ms)   len  high   low  best  delay        g1        g2
;  ---------------------------------------------------------------
;  Comb 1  50.0  1628  1637  1627  1627 49.981 0.3064583 0.5825750
;  Comb 2  56.0  1823  1823  1823  1823 56.003 0.3264583 0.5657750
;  Comb 3  61.0  1986  1987  1979  1987 61.041 0.3464583 0.5489750
;  Comb 4  68.0  2214  2221  2213  2213 67.983 0.3594792 0.5380375
;  Comb 5  72.0  2344  2347  2341  2341 71.916 0.3694792 0.5296375
;  Comb 6  78.0  2539  2539  2539  2539 77.998 0.4243750 0.4835250
;  All      6.0   195   197   193   193  5.929 0.7000000

; COMB(name, length, modulus, g1, g2)

define(COMB, `
; storage for "$1" length=$2 modulus=$3 g1=$4 g2=$5

	psect	lo_data
	align	$3
$1d
$1m	equ	$2-1
	org	x:$1d+$1m
	psect	hf_datax
$1g1	equ	$4
$1g2	equ	$5
')

COMB(c1, 1627, 2048, 0.3046875, 0.5812382)
COMB(a1, 193, 256, 0.7000000, 0.0000000)
COMB(c2, 1823, 2048, 0.3281250, 0.5616459)
COMB(c3, 1987, 2048, 0.3515625, 0.5420536)
COMB(c4, 2213, 4096, 0.3750000, 0.5224613)
COMB(a2, 207, 256, 0.7500000, 0.0000000)
COMB(c5, 2341, 4096, 0.3984375, 0.5028690)
COMB(c6, 2539, 4096, 0.4218750, 0.4832767)

	psect	hf_datax
a1r	dc	a1d
a1md	dc	a1m
a1g1d	dc	a1g1
a2r	dc	a2d
a2md	dc	a2m
a2g1d	dc	a2g1
	psect	hf_datay
curaddrp
	dc	curaddr
	psect	hf_datax
constsp	dc	consts
lowstatep
	dc	lowstate

	psect	hf_datax1
curaddr
	dc	c1d
	dc	c2d
	dc	c3d
	dc	c4d
	dc	c5d
	dc	c6d

	psect	hf_datay1
consts
	dc	c1m
	dc	c1g1
	dc	c1g2
	dc	c2m
	dc	c2g1
	dc	c2g2
	dc	c3m
	dc	c3g1
	dc	c3g2
	dc	c4m
	dc	c4g1
	dc	c4g2
	dc	c5m
	dc	c5g1
	dc	c5g2
	dc	c6m
	dc	c6g1
	dc	c6g2

	psect	hf_datax1
lowstate
	dc	0
	dc	0
	dc	0
	dc	0
	dc	0
	dc	0

;;;;;;;;;;;;;;;;;;;;;;;
; miscellaneous signals
;;;;;;;;;;;;;;;;;;;;;;;

	psect	hf_datax
L_overall
	dc	$7FFFFF
R_overall
	dc	$7FFFFF

;;;;;;;;;;;;;;;;;;;;;;;
; signal vector
;;;;;;;;;;;;;;;;;;;;;;;
	psect	hf_datax
	align 8
signal_vector
Lin	dc	0.0
Rin	dc	0.0
Reverb_L
	dc	0.0
Reverb_R	
	dc	0.0

Lout
	dc	0
Rout
	dc	0

	psect hf_datay
signal_vectorp
	dc	signal_vector
signal_mod
	dc	4-1

gain_vectorsp
	dc	gain_vectors
;;;;;;;;;;;;;;;;;;;;;;;
; gain matrix
;;;;;;;;;;;;;;;;;;;;;;;
	psect	hf_datay1
gain_vectors
Reverb_gain_vector
Reverb_Lin	dc 0.5
Reverb_Rin	dc 0.5
Reverb_Reverb_L	dc 0.0
Reverb_Reverb_R	dc 0.0

Lout_gain_vector
Lout_Lin	dc 0.0
Lout_Rin	dc 0.0
Lout_Reverb_L	dc ONE
Lout_Reverb_R	dc 0.0

Rout_gain_vector
Rout_Lin	dc 0.0
Rout_Rin	dc 0.0
Rout_Reverb_L	dc 0.0
Rout_Reverb_R	dc -1.0

;***************************************************************
;
;	init code - call hf_init at first and any time when
;	parameters change
;
;***************************************************************
	psect	lo_code

hf_init
;
;	clear out the filter delay lines
;
define(CLEAR_LINE, `
	move		#$1d,r0
	movec		#$1m,m0
	jsr	clear_line_r0
')

CLEAR_LINE(c1)
CLEAR_LINE(c2)
CLEAR_LINE(c3)
CLEAR_LINE(c4)
CLEAR_LINE(c5)
CLEAR_LINE(c6)
CLEAR_LINE(a1)
CLEAR_LINE(a2)
	jsr	recalc_comb_gains
	rts

clear_line_r0
	clr	a
	rep	#0
	  move		a,x:(r0)+
	rts

;***************************************************************
;
;	sample rate computations
;
;	Call hf_comp once per sample.
;	Globals in_l and in_r should have the left and right
;	input samples.  When hf_comp returns, out_l and out_r
;	will be ready.
;
;***************************************************************

;
; fs = 32.552083 kHz
;
	psect	hf_code

hf_comp
;
;	copy inputs
;
	move		x:<in_l,a
	move		a,x:<Lin
	move		x:<in_r,a
	move		a,x:<Rin
;
;	compute outputs using matrix multiply
;
; [reverb_in out_l out_r] = [gain_vector] * [signal_vector]
;
	move		y:<signal_vectorp,r0
	movec		y:<signal_mod,m0
	move		y:<gain_vectorsp,r4
	movec		x:<ffff,m4
	move		x:<L_overall,y1		;and wait for m4
	clr	a	x:(r0)+,x0 y:(r4)+,y0
	mac	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	mac	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	mac	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	macr	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	clr	a	a,b			;b is reverb_in
	mac	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	mac	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	mac	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	macr	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	clr	a	a,x1
	mpy	x1,y1,a	x:<R_overall,y1
	clr	a	a,x:<out_l
	mac	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	mac	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	mac	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	macr	x0,y0,a	x:(r0)+,x0 y:(r4)+,y0
	clr	a	a,x1
	mpy	x1,y1,a
	clr	a	a,x:<out_r
;
; r1	lowstate vector
; m1	-1
; r4	ptr to modulus,g1,g2 constants
; m4	-1
; r5	curaddr ptr
; m5	-1
; b	comb out accum
; x0	scaled comb in
;
;
;	set up reverb input
;
	clr	b	b,x0			;get reverb_in
	move		#1.0/16,x1		;allow 4 bits of headroom
	mpyr	x0,x1,a				;and 4 bits of noise
	move		a,x0
	move		x:<lowstatep,r1
	movec		x:<ffff,m1
	move		x:<constsp,r4
	movec		m1,m4
	move			y:<curaddrp,r5
	movec		m1,m5
;
;	do the six combs
;
	do	#6,comb_loop
	  move		x:(r5),r0		;r0=curaddr
	  movec		y:(r4)+,m0		;m0=modulus
	  move		x:(r1),x1 y:(r4)+,y1	;x1=lowstate, y1=g1, wait for m0
	  move		x:(r0)+,y0		;y0=delay out
	  add	y0,b		y0,a		;a=delay out
	  macr	x1,y1,a		y:(r4)+,y1	;a=out+g1*lowstate, y1=g2
	  clr	a      	a,x:(r1)+ a,y0		;y0=new lowstate
	  add	x0,a	r0,x:(r5)+		;a=in, save ptr
	  macr	y0,y1,a				;a=in+g2*g1*lowstate
	  move		a,x:-(r0)		;store delay in (takes 2 cyc)
comb_loop
;
;	scale
;
	rnd	b	#$15,x0		;scale by ~1/6
	move		b,y0
	mpyr	x0,y0,b
	move		b,y1		;save b for right chan
;
;	allpass L
;
	move		x:<a1r,r0
	movec		x:<a1md,m0
	move		x:<a1g1d,x0
	move		x:(r0),x1
	macr	x0,x1,b	x1,a
	move			b,y0
	macr	-x0,y0,a b,x:(r0)+
	asl	a      	r0,x:<a1r
	asl	a			;get rid of the headroom
	asl	a
	asl	a
	move		a,x:<Reverb_L
;
;	allpass R
;
	tfr	y1,b	x:<a2r,r0
	movec		x:<a2md,m0
	neg	b	x:<a2g1d,x0
	move		x:(r0),x1
	macr	x0,x1,b	x1,a
	move			b,y0
	macr	-x0,y0,a b,x:(r0)+
	asl	a	r0,x:<a2r
	asl	a
	asl	a
	asl	a
	move		a,x:<Reverb_R
;
;	done
;
	rts

	end
