=== MICrODEC: Stock Functions === ==== Mono Reverb ==== This function performs a simple reverb. This means it takes a series of delayed signals, and adds them together at varying amplitudes and polarities. It is in mono, and takes in data on the left channel. It presents the output on both the left and right channels. Neither MOD1 nor MOD2 do anything for this function. Because the 16b signed multiplies take up so much time, you can only get so many in before the next sample arrives. In this case, we can do 10 multiplies (with careful rewriting, this could probably go up to 12 or so). Each of these multiplies also requires a fetch of delayed data (often referred to as a Tap). Both the Tap time and the Tap weighting (multiply value) are defined as constants at the beginning of the code. The sum of these taps should be limited to keep the buffers from overflowing. You can hear the effect of overflowing buffers if you overdrive the input to the reverb. These multiplies actually implement a multiply-accumulate function (MAC). This means they both multiply the delayed sample and add it to the total sum, at the same time. It takes less time and registers to do it this way. If the Tap weightings were limited to 8b, you could probably get twice as many Taps (but limited resolution in the reverb sounds you could create). The complexity of the reverb sound increases with the number of Taps, but using feedback can also increase complexity, especially if prime Tap spacings are used (this way Taps wont overlap after coming in through the feedback). [[attachment:reverb_mono.asm|reverb_mono.asm]] ---- {{{#!highlight nasm ; program: reverb-16b.asm ; UID = 000009 - unique id to eliminate conflicts between variables ; 16b address space (.7s delay time) ; mono data ; program overview ; ; data is written to the memory as it arrives from the codec. data is ; read in from the memory and muliplied by a fixed constant. this is ; done for 10 delay times with different constants, and the result is ; accumulated and played out. data is taken in on the left channel, and ; played out on both left and right. ; reverb constants ; tap gains should sum to approximately 1 to keep the data normalized ; program assumes signed gain constants .equ tap1 = $3f45 ; tap1 gain constant .equ tap2 = $cab8 ; tap2 gain constant .equ tap3 = $2fe3 ; tap3 gain constant .equ tap4 = $d056 ; tap4 gain constant .equ tap5 = $1345 ; tap5 gain constant .equ tap6 = $ea48 ; tap6 gain constant .equ tap7 = $1be3 ; tap7 gain constant .equ tap8 = $e056 ; tap8 gain constant .equ tap9 = $0c45 ; tap9 gain constant .equ tap10 = $0a48 ; tap10 gain constant ; delay times are in samples (value/44.1kHz = delay time in ms) .equ tap_delay1 = $0146 ; tap1 delay time .equ tap_delay2 = $0205 ; tap2 delay time .equ tap_delay3 = $032f ; tap3 delay time .equ tap_delay4 = $04fe ; tap4 delay time .equ tap_delay5 = $0526 ; tap5 delay time .equ tap_delay6 = $06cc ; tap6 delay time .equ tap_delay7 = $0a23 ; tap7 delay time .equ tap_delay8 = $1deb ; tap8 delay time .equ tap_delay9 = $2f0b ; tap9 delay time .equ tap_delay10 = $395c ; tap10 delay time ; register usage - may be redefined in other sections ; ; r0 multiply result lsb ; r1 multiply result msb ; r2 accumulate lsb ; r3 accumulate mlb ; r4 right/left lsb out/accumulate mhb ; r5 right/left msb out/accumulate msb ; r6 left lsb in ; r7 left msb in ; r8 right lsb in ; r9 right msb in ; r10 ; r11 ; r12 ; r13 ; r14 ; r15 switch sample counter ; r16 temporary swap register ; r17 temporary swap register ; r18 tap multiply constant lsb ; r19 tap multiply constant msb ; r20 audio data multiply lsb ; r21 audio data multiply msb ; r22 write address third byte/null register ; r23 read address third byte ; r24 write address lsb ; r25 write address msb ; r26 ; r27 ; r28 read address lsb ; r29 read address msb ; r30 jump location for interrupt lsb ; r31 jump location for interrupt msb ; program starts here ; initiate data transfer to codec sbi portb,portb0 ; toggle slave select pin out spdr,r5 ; send out left channel msb cbi portb,portb0 adiw r25:r24,$01 ; increment write address ldi r23,$04 ; set up high byte read register ldi r22,$00 ; set up high byte write register wait1_000009: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait1_000009 in r7,spdr ; recieve in left channel msb out spdr,r4 ; send out left channel lsb out portg,r23 ; pull ce low, we high, and set high bits of register ;get delayed data movw r29:r28,r25:r24 ; move write register to read register subi r28,low(tap_delay1) ; remove delay time sbci r29,high(tap_delay1) out portd,r28 ; set address sts porth,r29 nop ; wait input latch time of 2 clock cycles nop ; wait input latch time of 2 clock cycles in r20,pina ; get data in r21,pinc ; get data wait2_000009: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait2_000009 in r6,spdr ; recieve in left channel lsb out spdr,r5 ; send out right channel msb ;write left channel data to sram out portd,r24 ; set address sts porth,r25 out portg,r22 ; pull ce low,we low,and set high bits of address ldi r17,$ff out ddra,r17 ; set porta as output for data write out ddrc,r17 ; set portc as output for data write out porta,r6 ; set data out portc,r7 ldi r17,$00 ; prepare for setting ports a,c as input sbi portg,portg2 ; pull we high to write out ddra,r17 ; set porta as input for data lines out ddrc,r17 ; set portc as input for data lines wait3_000009: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait3_000009 in r9,spdr ; recieve in right channel msb out spdr,r4 ; send out right channel lsb ;setup delay constant ldi r18,low(tap1) ldi r19,high(tap1) ;clear accumulation registers clr r5 clr r4 clr r3 clr r2 wait4_000009: ; check if byte has been sent in r17,spsr sbrs r17,spif rjmp wait4_000009 in r8,spdr ; recieve in left channel lsb ;multiply and accumulate - r5:r4:r3:r2 muls r19,r21 ; (signed)ah * (signed)bh add r4,r0 adc r5,r1 mul r18,r20 ; al * bl add r2,r0 adc r3,r1 adc r4,r22 ; r22 cleared earlier adc r5,r22 mulsu r19,r20 ; (signed)ah * bl sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 mulsu r21,r18 ; (signed)bh * al sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 ;get delayed data movw r29:r28,r25:r24 ; move write register to read register subi r28,low(tap_delay2) ; remove delay time sbci r29,high(tap_delay2) out portd,r28 ; set address sts porth,r29 nop ; wait input latch time of 2 clock cycles nop ; wait input latch time of 2 clock cycles in r20,pina ; get data in r21,pinc ; get data ;setup delay constant ldi r18,low(tap2) ldi r19,high(tap2) ;multiply and accumulate - r5:r4:r3:r2 muls r19,r21 ; (signed)ah * (signed)bh add r4,r0 adc r5,r1 mul r18,r20 ; al * bl add r2,r0 adc r3,r1 adc r4,r22 adc r5,r22 mulsu r19,r20 ; (signed)ah * bl sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 mulsu r21,r18 ; (signed)bh * al sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 ;get delayed data movw r29:r28,r25:r24 ; move write register to read register subi r28,low(tap_delay3) ; remove delay time sbci r29,high(tap_delay3) out portd,r28 ; set address sts porth,r29 nop ; wait input latch time of 2 clock cycles nop ; wait input latch time of 2 clock cycles in r20,pina ; get data in r21,pinc ; get data ;setup delay constant ldi r18,low(tap3) ldi r19,high(tap3) ;multiply and accumulate - r5:r4:r3:r2 muls r19,r21 ; (signed)ah * (signed)bh add r4,r0 adc r5,r1 mul r18,r20 ; al * bl add r2,r0 adc r3,r1 adc r4,r22 adc r5,r22 mulsu r19,r20 ; (signed)ah * bl sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 mulsu r21,r18 ; (signed)bh * al sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 ;get delayed data movw r29:r28,r25:r24 ; move write register to read register subi r28,low(tap_delay4) ; remove delay time sbci r29,high(tap_delay4) out portd,r28 ; set address sts porth,r29 nop ; wait input latch time of 2 clock cycles nop ; wait input latch time of 2 clock cycles in r20,pina ; get data in r21,pinc ; get data ;setup delay constant ldi r18,low(tap4) ldi r19,high(tap4) ;multiply and accumulate - r5:r4:r3:r2 muls r19,r21 ; (signed)ah * (signed)bh add r4,r0 adc r5,r1 mul r18,r20 ; al * bl add r2,r0 adc r3,r1 adc r4,r22 adc r5,r22 mulsu r19,r20 ; (signed)ah * bl sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 mulsu r21,r18 ; (signed)bh * al sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 ;get delayed data movw r29:r28,r25:r24 ; move write register to read register subi r28,low(tap_delay5) ; remove delay time sbci r29,high(tap_delay5) out portd,r28 ; set address sts porth,r29 nop ; wait input latch time of 2 clock cycles nop ; wait input latch time of 2 clock cycles in r20,pina ; get data in r21,pinc ; get data ;setup delay constant ldi r18,low(tap5) ldi r19,high(tap5) ;multiply and accumulate - r5:r4:r3:r2 muls r19,r21 ; (signed)ah * (signed)bh add r4,r0 adc r5,r1 mul r18,r20 ; al * bl add r2,r0 adc r3,r1 adc r4,r22 adc r5,r22 mulsu r19,r20 ; (signed)ah * bl sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 mulsu r21,r18 ; (signed)bh * al sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 ;get delayed data movw r29:r28,r25:r24 ; move write register to read register subi r28,low(tap_delay6) ; remove delay time sbci r29,high(tap_delay6) out portd,r28 ; set address sts porth,r29 nop ; wait input latch time of 2 clock cycles nop ; wait input latch time of 2 clock cycles in r20,pina ; get data in r21,pinc ; get data ;setup delay constant ldi r18,low(tap6) ldi r19,high(tap6) ;multiply and accumulate - r5:r4:r3:r2 muls r19,r21 ; (signed)ah * (signed)bh add r4,r0 adc r5,r1 mul r18,r20 ; al * bl add r2,r0 adc r3,r1 adc r4,r22 adc r5,r22 mulsu r19,r20 ; (signed)ah * bl sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 mulsu r21,r18 ; (signed)bh * al sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 ;get delayed data movw r29:r28,r25:r24 ; move write register to read register subi r28,low(tap_delay7) ; remove delay time sbci r29,high(tap_delay7) out portd,r28 ; set address sts porth,r29 nop ; wait input latch time of 2 clock cycles nop ; wait input latch time of 2 clock cycles in r20,pina ; get data in r21,pinc ; get data ;setup delay constant ldi r18,low(tap7) ldi r19,high(tap7) ;multiply and accumulate - r5:r4:r3:r2 muls r19,r21 ; (signed)ah * (signed)bh add r4,r0 adc r5,r1 mul r18,r20 ; al * bl add r2,r0 adc r3,r1 adc r4,r22 adc r5,r22 mulsu r19,r20 ; (signed)ah * bl sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 mulsu r21,r18 ; (signed)bh * al sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 ;get delayed data movw r29:r28,r25:r24 ; move write register to read register subi r28,low(tap_delay8) ; remove delay time sbci r29,high(tap_delay8) out portd,r28 ; set address sts porth,r29 nop ; wait input latch time of 2 clock cycles nop ; wait input latch time of 2 clock cycles in r20,pina ; get data in r21,pinc ; get data ;setup delay constant ldi r18,low(tap8) ldi r19,high(tap8) ;multiply and accumulate - r5:r4:r3:r2 muls r19,r21 ; (signed)ah * (signed)bh add r4,r0 adc r5,r1 mul r18,r20 ; al * bl add r2,r0 adc r3,r1 adc r4,r22 adc r5,r22 mulsu r19,r20 ; (signed)ah * bl sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 mulsu r21,r18 ; (signed)bh * al sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 ;get delayed data movw r29:r28,r25:r24 ; move write register to read register subi r28,low(tap_delay9) ; remove delay time sbci r29,high(tap_delay9) out portd,r28 ; set address sts porth,r29 nop ; wait input latch time of 2 clock cycles nop ; wait input latch time of 2 clock cycles in r20,pina ; get data in r21,pinc ; get data ;setup delay constant ldi r18,low(tap9) ldi r19,high(tap9) ;multiply and accumulate - r5:r4:r3:r2 muls r19,r21 ; (signed)ah * (signed)bh add r4,r0 adc r5,r1 mul r18,r20 ; al * bl add r2,r0 adc r3,r1 adc r4,r22 adc r5,r22 mulsu r19,r20 ; (signed)ah * bl sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 mulsu r21,r18 ; (signed)bh * al sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 ;get delayed data movw r29:r28,r25:r24 ; move write register to read register subi r28,low(tap_delay10) ; remove delay time sbci r29,high(tap_delay10) out portd,r28 ; set address sts porth,r29 nop ; wait input latch time of 2 clock cycles nop ; wait input latch time of 2 clock cycles in r20,pina ; get data in r21,pinc ; get data ;setup delay constant ldi r18,low(tap10) ldi r19,high(tap10) ;multiply and accumulate - r5:r4:r3:r2 muls r19,r21 ; (signed)ah * (signed)bh add r4,r0 adc r5,r1 mul r18,r20 ; al * bl add r2,r0 adc r3,r1 adc r4,r22 adc r5,r22 mulsu r19,r20 ; (signed)ah * bl sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 mulsu r21,r18 ; (signed)bh * al sbc r5,r22 add r3,r0 adc r4,r1 adc r5,r22 dec r15 brne done_000009 lds r31,pinj ; get switch data andi r31,$78 ; mask off rotary switch ldi r17,$02 lsr r31 lsr r31 add r31,r17 ; adjust switch position to program memory location done_000009: reti }}}