;  filename:RVB1.ASM
;
;	This version of the reverberation program was written with the
;	objective of maintaining clarity, so one may easily vary different
;	parameters to hear their affect on the sound.  To this end, it was 
;	necessary to limit the use of the parallel moves.  Additionally,
;	there may be superflous MOVES and CLR instructions, to allow
;	one to disable certain functional blocks while still operating
;	other algorithm parts.   Final code implementation should
;	eventually use the parallel move feature to reduce code size
;	and execution time.
;
;				Motorola DSP Group
;				Austin, Tx
;
;**************************************************************************
; This program was originally available on the Motorola DSP bulletin board
; and is provided under a DISCLAIMER OF WARRANTY available from Motorola
; DSP Operation, 6501 William Cannon Dr. W Austin, Texas  78735-8598.
;**************************************************************************
;--------------------------------------------------------------------------
;	This reverberation program is a variation of the reverberation
;	system and structures as described by James Moorer's article entitled
;	 'About this Reverberation Business', Computer Music Journal,
;	 3(2):13-28, 1979
;
;	Structure is:
;                                                       .----------.
;                            .------------.   .-----.   | All Pass |
;                         +->| Comb Filter|-->| SUM |-->| Reverb   |
;   Note: All Comb        |  |   #1       |   '-----'   |          |
;         Filters         |  '------------'   ^  ^  ^   '----------'
;         Have a 1st      |  .------------.   |  |  |        |
;         Order IIR       |->| Comb Filter|---+  |  |    .---V---.
;         LPF in their    |  |   #2       |      |  |    | align |
;         feedback        |  '------------'      |  |    | delay |
;         loop            |  .------------.      |  |    '---|---'
;                         |->| Comb Filter|------+  |        |
;                         |  |   #3       |         |      -----   reverb	  
;                         |  '------------'         |       \./     gain
;                         |  .------------.         |        |
;                         |->| Comb Filter|---------+        |
;                         |  |   #4       |                  | 
;                         |  '------------'                  |
;                         |                                  V
;         .------------.  |        FIR gain          .----------.
;         |   Early    |  |         |\               |          | 
;input -->| Reflection |--+---------|  >------------>|  summer  |--- output
;      |  |    FIR     |            |/               |          |
;      |  '------------'                             '----------'      
;      |                                                  ^
;      |                                                  |
;      |                             dry gain             |
;      |                              |\                  |
;      +------------------------------|  >----------------+
;                                     |/
;	
;.............................................................................
;  COMB FILTER SUB STRUCTURE:
;                                .-------.
;      comb i        .-----.     | long  |                    comb i
;      input  ------>| sum |---->| delay |-------+--------->  output
;                    '-----'     '-------'       |
;                       ^                        |
;                       |                        V
;                       |       /|            .-----.
;                       +-----<   ------------| sum |<--------+
;                               \|            '-----'         |
;                            fdbck i             |           / \  lpf i gain
;                              gain              V         /_____\
;                                            .----------.     |
;                                            | 1 sample |     |
;                                            |   delay  |-----+
;                                            '----------'
;.............................................................................
;   UNIT (ALL PASS) REVERBERATOR STRUCTURE:
;   based on Schroeder as outlined in Griesinger: 'Practical Processors and
;   Programs for Digital Reverberation', Audio in Digital Times, 7th AES
;   conference, Toronto, Ontario, 1989
;   (the structure outlined in Moorer is a variation of this)
;
;                              -g
;                            |\
;                +---------->|  >--------------------------+
;                |           |/                            |
;                |                                         |
;                |                                         V
;    unit        |    .-----.   .--------.       |\     .-----.	      unit
;    input ------+--->| sum |-->| delay  |--+--->|  >-->| sum |-----> output
;                     '-----'   '--------'  |    |/     '-----'
;                        ^                  |    1-g**2
;                        |     g            | 
;                        |       /|         |
;                        +-----<  |---------+
;                                \|
;...........................................................................
;
;	one multi-tap fir structure - to handle early reflections
;
;	followed by 4 parallel comb (iir) filters (each comb having 
;	a first order LPF in its feedback loop
;	
;	followed by an 'allpass' reverberator whose output is then 
;	delayed so that its first output follows after the last "early
;	reflection" output 
;
;__________________________________________________________________________
;
	opt cex
	page 132

;--------------------------------------------------constant declarations
adc	equ	$ffef		; ADC address
dac	equ	$ffef		; DAC address

ntap	equ	7		; number of taps	EARLY REFLECTION FIR
tapmod	equ	ntap-1		; number of taps minus 1	 
dlymx 	equ	4000		; length of delay line in samples

cmbdly1 equ	2205		; COMB FILTER CONSTANTS
cmbdly2 equ	2690		; delay values (in samples)
cmbdly3 equ	3175
cmbdly4 equ	3440

cmbmod1 equ	  3490 	        ; modulo for comb #1 delay line   THESE ARE
cmbmod2 equ	  3490 		;   "         "   #2   "   "	  ALSO THE 
cmbmod3	equ	  3490 		;   "         "   #3  "    "	  MAX DELAYS
cmbmod4	equ	  3490 		;   "         "   #4  "    "	  ALLOWED FOR
				;				  CHOSEN DSM
				;				  VALUE

untrvbdly	equ	265		    ; delay	UNIT (or ALLPASS)
unt_g	     	equ	0.7		    ; gains (g)    REVERBERATOR
neg_g		equ	-unt_g		    ;	    (-g)
one_m_g2	equ	(1-unt_g*unt_g)	    ;	"   (1-g**2)


cmb_g		equ	0.85		; (OVERALL) COMB FILTER FEEDBACK GAIN 
					; controls reverb decay time: smaller
					; values give quicker decay, larger
					; values yield slower decay

lpf1		equ	0.408		; lpf filter coefficient in the 
lpf2		equ	0.448		; feedback loop of the combs,
lpf3		equ	0.476		; these LPF's simulate the high freq
lpf4		equ	0.496		; attentuation in real acoustic reverb

fdbck1		equ	cmb_g*(1-lpf1)	; actual comb feedback gain
fdbck2		equ	cmb_g*(1-lpf2)	; is determined by the lpf filter
fdbck3		equ	cmb_g*(1-lpf3)	; coefficient and the overall feed-
fdbck4		equ	cmb_g*(1-lpf4)	; back gain to insure stability


aligndly		equ	1305   	; alignment delay (see diagram above)
alignmod		equ	1390	;     "     mod

	
reverbg		equ	0.35		; reverberation output gain value
firg		equ	0.15		; early rflctn FIR output gain value
dryg		equ	0.9999-(reverbg+firg) ; dry signal gain is rest  
					; CHOOSE THE MIX YOU LIKE


	org x:0
chead1	dsm 3500		; allocates 3500 data spaces for use as
chead2	dsm 3500		; comb filter tap delay lines, CHEAD1 refers
chead3	dsm 3500		; to the Comb filter HEAD (beginning) for 
chead4	dsm 3500		; filter #1  

	org x:$0f00
ofst_bf	dsm	ntap		; this reserves "ntap" contiguous addresses
	org x:ofst_bf		; starting at the closest appropriate modulo
ofst0	dc	1		; x address space.  Then starts filling the 
ofst1	dc	877		; offset buffer at this location with   
ofst2	dc	1561		; the right delay values for the 
ofst3	dc	1716		; EARLY REFLECTION FIR
ofst4	dc	1826
ofst5	dc	3083	  ; IMPORTANT - to get no delay for the first 
ofst6   dc	3510	  ; early reflection, use a "1".  This is due the use
			  ; of an instruction code pre-decrement, a "0" value 
			  ; will cause a maximum delay equal to the tap delay
			  ; line length



untdly	dc	untrvbdly	; define the UNIT REVERBERATOR delay
untg1	dc	unt_g		;    "          "              g
untg2	dc	neg_g		;    "          "         "   -g
untg3	dc	one_m_g2	;    "          "          (1-g**2)
untmod	dc	untrvbdly-1	; modulo for    "         "

algndly	dc	aligndly
algnmod	dc	alignmod

	org y:$0f00
gain_bf dsm ntap
	org y:gain_bf		; starting at y address zero this reserves
				; "ntap" contiguous addresses then starts
				; filling these addresses with the desired
gain0	dc	0.213		; tap "gain" values for EARLY REFLECTION FIR
gain1	dc	0.217		; recommended by moorer
gain2	dc	0.174		;
gain3	dc	0.135		; it is recommended to keep many early 
gain4	dc	0.153		; reflection returns, as these are fed into
gain5	dc	0.157		; comb filters, than can contribute greatly
gain6	dc	0.051		; to the later impulse response density

rvbgain	dc	reverbg		; total reverberation gain
firgain dc	firg		; early reflection gain
drygain dc	dryg		; dry signal gain

	org y:0
c1g1	dc	lpf1		; comb #1 g1 (LPF gain)
c2g1	dc	lpf2		;      #2      
c3g1	dc	lpf3		;      #3
c4g1	dc	lpf4 		;      #4


c1g2	dc	fdbck1		; feedback gain derived from
c2g2	dc 	fdbck2 		; cig2= g * (1 - cig1) where i=comb#
c3g2	dc	fdbck3		
c4g2	dc	fdbck4


sample	 ds 1			; input sample storage address
firout   ds 1			; early ref FIR OUTput storage address

c1out  ds 1			; COMB filter #1 output storage address
c2out  ds 1			;  "      "   #2   "       "       "
c3out  ds 1			;  "	  "   #3   "	   "	   "
c4out  ds 1			;  "	  "   #4   "	   "	   "

lpfst1	ds 1			;  "	  "   #1 Low Pass Filter state
lpfst2	ds 1			;  "	  "   #2  "    "    "      "
lpfst3  ds 1			;  "	  "   #3  "    "    "      "
lpfst4	ds 1			;  "	  "   #4  "    "    "      "

				; allocates modulo memory for the unit
udlyln	dsm	300		; (allpass) reverberator delay line 

algndlyln dsm	1400		; allocates modulo memory for alignment delay  
				; line

dlyline	dsm dlymx		; allocates mod memory for the FIR delay line

;--------------------------------------------------------------------------
     org     p:$40		; program start address

; Set up ADS board in case of force break instead of force reset
       movep #0,x:$FFFE         ;set bcr to zero
       movec #0,sp              ;init stack pointer
       movec #0,sr              ;clear loop flag

; Set up the SSI for operation with the DSP56ADC16EVB
; The following code sets port C to function as SCI/SSI
       move #$0,a0              ;zero PCC to cycle it
       movep a0,x:$FFE1
       move #$0001ff,a0
       movep a0,x:$FFE1         ;write PCC

; The following code sets the SSI CRA and CRB control registers for external
; continuous clock, synchronous, normal mode.
       move #$004000,a0         ;CRA pattern for word length=16 bits
       movep a0,x:$FFEC
       move #$003200,a0    ;CRB pattern for continous ck,sych,normal mode
       movep a0,x:$FFED    ;word long frame sync: FSL=0;ext ck/fs 

; -------------------------------------------------------------------------
				; initialize registers MO,RO, etc
	move #dlymx-1,m0	; tap line modulus
	move #dlyline,r0 	; start of delay line
	move #0,n0	 	; 

	move #tapmod,m1		; tap gain line modulo
	move #gain_bf,r1 	; tap gain & tap delay pointer

	move #cmbmod1,m2	; initialize the modulo registers
	move #cmbmod2,m3	; for comb filter buffers 1 thru 5
	move #cmbmod3,m4
	move #cmbmod4,m5

	move #cmbdly1,n2	; initialize the offset register
	move #cmbdly2,n3	; for Comb filters 1 thru 5
	move #cmbdly3,n4
	move #cmbdly4,n5

	move #chead1,r2		; initialize the pointer values for
	move #chead2,r3		; Comb filters 1 thru 5
	move #chead3,r4
	move #chead4,r5

	move x:algnmod,m6	; initialize alignment delay line
	move x:algndly,n6	; offset, modulo, and pointer registers
	move #algndlyln,r6

	move x:untmod,m7	; initialize unit reverberator (allpass)
	move x:untdly,n7	; offset, modulo, and pointer registers
	move #udlyln,r7

;---------------------------------------------------------------------------
; The following code polls the RDF flag in the SSI-SR and waits for RDF=1
; and then reads the RX register to retrieve the data from the A/D converter.
; Sample rate is controlled by DSP56ADC16 board.   

poll    jclr #7,x:$FFEE,poll     ;loop until RDF bit = 1
        movep x:adc,a            ;get A/D converter data
;---------------------------------------------------------------------------
;	asr a
	asr a			; obtain data sample 
				; and shift right for headroom
	move a,y:sample		; keep dry sample

;  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
; FIR for early reflections
	move a,y:(r0)-		; push sample into delay line
	clr a
	do #ntap,fir	 	; loop over the (ntaps-1),exclude fb tap now
	   move x:(r1),n0	; put the tap offset value into N0
	   move y:(r1)+,y1	;  "   "   "   gain   "      "  Y
	   move y:(r0+n0),x1	; get delayed sample
	   mac x1,y1,a		; MAC gain and sample
fir  	move a,y:firout		; save FIR OUTput to y memory
;  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
; COMB 1
	move y:firout,a		; comb filter #1 with LPF in feed back
	move x:(r2+n2),b	; get delayed sample & put in b
	move b,y:c1out		; move output to y memory space

	move y:c1g1,x1		; get LPF filter coeff
	move y:lpfst1,y1	; get LPF filter state
	mac x1,y1,b		; compute LPF output
	move b,y:lpfst1		; save LPF output to LPF state

	move y:c1g2,x1		; get feedback coefficient
	move b,y1		; put LPF output in Y1
	mac x1,y1,a		; compute feedback term in A
	move a,x:(r2)-		; store output into delay queue

;  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
; COMB 2
	move y:firout,a		; comb filter #1 with LPF in feed back
	move x:(r3+n3),b	; get delayed sample & put in b
	move b,y:c2out		; move output to y memory space

	move y:c2g1,x1		; get LPF filter coeff
	move y:lpfst2,y1	; get LPF filter state
	mac x1,y1,b		; compute LPF output
	move b,y:lpfst2		; save LPF output to LPF state

	move y:c2g2,x1		; get feedback coefficient
	move b,y1		; put LPF output in Y1
	mac x1,y1,a		; compute feedback term in A
	move a,x:(r3)-		; store output into delay queue


;  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
; COMB 3
	move y:firout,a		; comb filter #1 with LPF in feed back
	move x:(r4+n4),b	; get delayed sample & put in b
	move b,y:c3out		; move output to y memory space

	move y:c3g1,x1		; get LPF filter coeff
	move y:lpfst3,y1	; get LPF filter state
	mac x1,y1,b		; compute LPF output
	move b,y:lpfst3		; save LPF output to LPF state

	move y:c3g2,x1		; get feedback coefficient
	move b,y1		; put LPF output in Y1
	mac x1,y1,a		; compute feedback term in A
	move a,x:(r4)-		; store output into delay queue
;  -  -  -  -  -  -   -    -    -    -   -   -   -    -   -     -   - 
; COMB 4
	move y:firout,a		; 
	move x:(r5+n5),b	; get delayed sample & put in b
	move b,y:c4out		; move output to y memory space

	move y:c4g1,x1		; get LPF filter coeff
	move y:lpfst4,y1	; get LPF filter state
	mac x1,y1,b		; compute LPF output
	move b,y:lpfst4		; save LPF output to LPF state

	move y:c4g2,x1		; get feedback coefficient
	move b,y1		; put LPF output in Y1
	mac x1,y1,a		; compute feedback term in A
	move a,x:(r5)-		; store output into delay queue
;  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
	move y:c1out,x1		; add output of all four combs
	move y:c2out,a
	add x1,a
	move y:c3out,x1
	add x1,a
	move y:c4out,x1
	add x1,a
;	asr a
;  -  -  -  -  -  -  -  -  -   -   -      -   -    -   -  -  -    -  
; 				all pass unit reverberator				
	clr b
	move a,x1
	move x:untg2,y1
	mac x1,y1,b

	move y:(r7+n7),x1	; get delayed sample
	move x:untg3,y1		; get gain (1-g**2)
	mac x1,y1,b		; MAC into b for output (B CONTAINS OUTPUT)

	move x:untg1,y1		; get gain g
	mac x1,y1,a
	move a,y:(r7)-		; put new+g*delayed into delay line/inc r7
	move b,y:(r6)-		;store the output in a queue for align delay
;  -    -     -     -     -     -     -     -     -     -     -      -     -
	move y:(r6+n6),y1	; get the delayed unit rvb sample
	move y:rvbgain,x1	; and the reverb gain
	mpy x1,y1,a

	move y:firout,y1	; get the early reflection FIR output sample
	move y:firgain,x1	; and FIR gain
	mac x1,y1,a

	move y:sample,y1	; mix in the dry sample
	move y:drygain,x1	; by the dry gain
	mac x1,y1,a		; A now contains the output sample
	asr a
;  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
; Write DSP56ADC16 A/D converter data to the PCM-56

           move a,x:dac          ;write the PCM-56 D/A via SSI xmt reg.
           jmp poll                ;loop indefinitely

           end
