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).
1 ; program: reverb-16b.asm
2 ; UID = 000009 - unique id to eliminate conflicts between variables
3 ; 16b address space (.7s delay time)
4 ; mono data
5
6 ; program overview
7 ;
8 ; data is written to the memory as it arrives from the codec. data is
9 ; read in from the memory and muliplied by a fixed constant. this is
10 ; done for 10 delay times with different constants, and the result is
11 ; accumulated and played out. data is taken in on the left channel, and
12 ; played out on both left and right.
13
14 ; reverb constants
15 ; tap gains should sum to approximately 1 to keep the data normalized
16 ; program assumes signed gain constants
17 .equ tap1 = $3f45 ; tap1 gain constant
18 .equ tap2 = $cab8 ; tap2 gain constant
19 .equ tap3 = $2fe3 ; tap3 gain constant
20 .equ tap4 = $d056 ; tap4 gain constant
21 .equ tap5 = $1345 ; tap5 gain constant
22 .equ tap6 = $ea48 ; tap6 gain constant
23 .equ tap7 = $1be3 ; tap7 gain constant
24 .equ tap8 = $e056 ; tap8 gain constant
25 .equ tap9 = $0c45 ; tap9 gain constant
26 .equ tap10 = $0a48 ; tap10 gain constant
27
28 ; delay times are in samples (value/44.1kHz = delay time in ms)
29 .equ tap_delay1 = $0146 ; tap1 delay time
30 .equ tap_delay2 = $0205 ; tap2 delay time
31 .equ tap_delay3 = $032f ; tap3 delay time
32 .equ tap_delay4 = $04fe ; tap4 delay time
33 .equ tap_delay5 = $0526 ; tap5 delay time
34 .equ tap_delay6 = $06cc ; tap6 delay time
35 .equ tap_delay7 = $0a23 ; tap7 delay time
36 .equ tap_delay8 = $1deb ; tap8 delay time
37 .equ tap_delay9 = $2f0b ; tap9 delay time
38 .equ tap_delay10 = $395c ; tap10 delay time
39
40 ; register usage - may be redefined in other sections
41 ;
42 ; r0 multiply result lsb
43 ; r1 multiply result msb
44 ; r2 accumulate lsb
45 ; r3 accumulate mlb
46 ; r4 right/left lsb out/accumulate mhb
47 ; r5 right/left msb out/accumulate msb
48 ; r6 left lsb in
49 ; r7 left msb in
50 ; r8 right lsb in
51 ; r9 right msb in
52 ; r10
53 ; r11
54 ; r12
55 ; r13
56 ; r14
57 ; r15 switch sample counter
58 ; r16 temporary swap register
59 ; r17 temporary swap register
60 ; r18 tap multiply constant lsb
61 ; r19 tap multiply constant msb
62 ; r20 audio data multiply lsb
63 ; r21 audio data multiply msb
64 ; r22 write address third byte/null register
65 ; r23 read address third byte
66 ; r24 write address lsb
67 ; r25 write address msb
68 ; r26
69 ; r27
70 ; r28 read address lsb
71 ; r29 read address msb
72 ; r30 jump location for interrupt lsb
73 ; r31 jump location for interrupt msb
74
75 ; program starts here
76 ; initiate data transfer to codec
77 sbi portb,portb0 ; toggle slave select pin
78 out spdr,r5 ; send out left channel msb
79 cbi portb,portb0
80 adiw r25:r24,$01 ; increment write address
81 ldi r23,$04 ; set up high byte read register
82 ldi r22,$00 ; set up high byte write register
83
84 wait1_000009: ; check if byte has been sent
85
86 in r17,spsr
87 sbrs r17,spif
88 rjmp wait1_000009
89 in r7,spdr ; recieve in left channel msb
90 out spdr,r4 ; send out left channel lsb
91 out portg,r23 ; pull ce low, we high, and set high bits of register
92 ;get delayed data
93 movw r29:r28,r25:r24 ; move write register to read register
94 subi r28,low(tap_delay1) ; remove delay time
95 sbci r29,high(tap_delay1)
96 out portd,r28 ; set address
97 sts porth,r29
98 nop ; wait input latch time of 2 clock cycles
99 nop ; wait input latch time of 2 clock cycles
100 in r20,pina ; get data
101 in r21,pinc ; get data
102
103 wait2_000009: ; check if byte has been sent
104
105 in r17,spsr
106 sbrs r17,spif
107 rjmp wait2_000009
108 in r6,spdr ; recieve in left channel lsb
109 out spdr,r5 ; send out right channel msb
110 ;write left channel data to sram
111 out portd,r24 ; set address
112 sts porth,r25
113 out portg,r22 ; pull ce low,we low,and set high bits of address
114 ldi r17,$ff
115 out ddra,r17 ; set porta as output for data write
116 out ddrc,r17 ; set portc as output for data write
117 out porta,r6 ; set data
118 out portc,r7
119 ldi r17,$00 ; prepare for setting ports a,c as input
120 sbi portg,portg2 ; pull we high to write
121 out ddra,r17 ; set porta as input for data lines
122 out ddrc,r17 ; set portc as input for data lines
123
124 wait3_000009: ; check if byte has been sent
125
126 in r17,spsr
127 sbrs r17,spif
128 rjmp wait3_000009
129 in r9,spdr ; recieve in right channel msb
130 out spdr,r4 ; send out right channel lsb
131 ;setup delay constant
132 ldi r18,low(tap1)
133 ldi r19,high(tap1)
134 ;clear accumulation registers
135 clr r5
136 clr r4
137 clr r3
138 clr r2
139
140 wait4_000009: ; check if byte has been sent
141
142 in r17,spsr
143 sbrs r17,spif
144 rjmp wait4_000009
145 in r8,spdr ; recieve in left channel lsb
146
147 ;multiply and accumulate - r5:r4:r3:r2
148 muls r19,r21 ; (signed)ah * (signed)bh
149 add r4,r0
150 adc r5,r1
151 mul r18,r20 ; al * bl
152 add r2,r0
153 adc r3,r1
154 adc r4,r22 ; r22 cleared earlier
155 adc r5,r22
156 mulsu r19,r20 ; (signed)ah * bl
157 sbc r5,r22
158 add r3,r0
159 adc r4,r1
160 adc r5,r22
161 mulsu r21,r18 ; (signed)bh * al
162 sbc r5,r22
163 add r3,r0
164 adc r4,r1
165 adc r5,r22
166
167 ;get delayed data
168 movw r29:r28,r25:r24 ; move write register to read register
169 subi r28,low(tap_delay2) ; remove delay time
170 sbci r29,high(tap_delay2)
171 out portd,r28 ; set address
172 sts porth,r29
173 nop ; wait input latch time of 2 clock cycles
174 nop ; wait input latch time of 2 clock cycles
175 in r20,pina ; get data
176 in r21,pinc ; get data
177
178 ;setup delay constant
179 ldi r18,low(tap2)
180 ldi r19,high(tap2)
181
182 ;multiply and accumulate - r5:r4:r3:r2
183 muls r19,r21 ; (signed)ah * (signed)bh
184 add r4,r0
185 adc r5,r1
186 mul r18,r20 ; al * bl
187 add r2,r0
188 adc r3,r1
189 adc r4,r22
190 adc r5,r22
191 mulsu r19,r20 ; (signed)ah * bl
192 sbc r5,r22
193 add r3,r0
194 adc r4,r1
195 adc r5,r22
196 mulsu r21,r18 ; (signed)bh * al
197 sbc r5,r22
198 add r3,r0
199 adc r4,r1
200 adc r5,r22
201
202 ;get delayed data
203 movw r29:r28,r25:r24 ; move write register to read register
204 subi r28,low(tap_delay3) ; remove delay time
205 sbci r29,high(tap_delay3)
206 out portd,r28 ; set address
207 sts porth,r29
208 nop ; wait input latch time of 2 clock cycles
209 nop ; wait input latch time of 2 clock cycles
210 in r20,pina ; get data
211 in r21,pinc ; get data
212
213 ;setup delay constant
214 ldi r18,low(tap3)
215 ldi r19,high(tap3)
216
217 ;multiply and accumulate - r5:r4:r3:r2
218 muls r19,r21 ; (signed)ah * (signed)bh
219 add r4,r0
220 adc r5,r1
221 mul r18,r20 ; al * bl
222 add r2,r0
223 adc r3,r1
224 adc r4,r22
225 adc r5,r22
226 mulsu r19,r20 ; (signed)ah * bl
227 sbc r5,r22
228 add r3,r0
229 adc r4,r1
230 adc r5,r22
231 mulsu r21,r18 ; (signed)bh * al
232 sbc r5,r22
233 add r3,r0
234 adc r4,r1
235 adc r5,r22
236
237 ;get delayed data
238 movw r29:r28,r25:r24 ; move write register to read register
239 subi r28,low(tap_delay4) ; remove delay time
240 sbci r29,high(tap_delay4)
241 out portd,r28 ; set address
242 sts porth,r29
243 nop ; wait input latch time of 2 clock cycles
244 nop ; wait input latch time of 2 clock cycles
245 in r20,pina ; get data
246 in r21,pinc ; get data
247
248 ;setup delay constant
249 ldi r18,low(tap4)
250 ldi r19,high(tap4)
251
252 ;multiply and accumulate - r5:r4:r3:r2
253 muls r19,r21 ; (signed)ah * (signed)bh
254 add r4,r0
255 adc r5,r1
256 mul r18,r20 ; al * bl
257 add r2,r0
258 adc r3,r1
259 adc r4,r22
260 adc r5,r22
261 mulsu r19,r20 ; (signed)ah * bl
262 sbc r5,r22
263 add r3,r0
264 adc r4,r1
265 adc r5,r22
266 mulsu r21,r18 ; (signed)bh * al
267 sbc r5,r22
268 add r3,r0
269 adc r4,r1
270 adc r5,r22
271
272 ;get delayed data
273 movw r29:r28,r25:r24 ; move write register to read register
274 subi r28,low(tap_delay5) ; remove delay time
275 sbci r29,high(tap_delay5)
276 out portd,r28 ; set address
277 sts porth,r29
278 nop ; wait input latch time of 2 clock cycles
279 nop ; wait input latch time of 2 clock cycles
280 in r20,pina ; get data
281 in r21,pinc ; get data
282
283 ;setup delay constant
284 ldi r18,low(tap5)
285 ldi r19,high(tap5)
286
287 ;multiply and accumulate - r5:r4:r3:r2
288 muls r19,r21 ; (signed)ah * (signed)bh
289 add r4,r0
290 adc r5,r1
291 mul r18,r20 ; al * bl
292 add r2,r0
293 adc r3,r1
294 adc r4,r22
295 adc r5,r22
296 mulsu r19,r20 ; (signed)ah * bl
297 sbc r5,r22
298 add r3,r0
299 adc r4,r1
300 adc r5,r22
301 mulsu r21,r18 ; (signed)bh * al
302 sbc r5,r22
303 add r3,r0
304 adc r4,r1
305 adc r5,r22
306
307 ;get delayed data
308 movw r29:r28,r25:r24 ; move write register to read register
309 subi r28,low(tap_delay6) ; remove delay time
310 sbci r29,high(tap_delay6)
311 out portd,r28 ; set address
312 sts porth,r29
313 nop ; wait input latch time of 2 clock cycles
314 nop ; wait input latch time of 2 clock cycles
315 in r20,pina ; get data
316 in r21,pinc ; get data
317
318 ;setup delay constant
319 ldi r18,low(tap6)
320 ldi r19,high(tap6)
321
322 ;multiply and accumulate - r5:r4:r3:r2
323 muls r19,r21 ; (signed)ah * (signed)bh
324 add r4,r0
325 adc r5,r1
326 mul r18,r20 ; al * bl
327 add r2,r0
328 adc r3,r1
329 adc r4,r22
330 adc r5,r22
331 mulsu r19,r20 ; (signed)ah * bl
332 sbc r5,r22
333 add r3,r0
334 adc r4,r1
335 adc r5,r22
336 mulsu r21,r18 ; (signed)bh * al
337 sbc r5,r22
338 add r3,r0
339 adc r4,r1
340 adc r5,r22
341
342 ;get delayed data
343 movw r29:r28,r25:r24 ; move write register to read register
344 subi r28,low(tap_delay7) ; remove delay time
345 sbci r29,high(tap_delay7)
346 out portd,r28 ; set address
347 sts porth,r29
348 nop ; wait input latch time of 2 clock cycles
349 nop ; wait input latch time of 2 clock cycles
350 in r20,pina ; get data
351 in r21,pinc ; get data
352
353 ;setup delay constant
354 ldi r18,low(tap7)
355 ldi r19,high(tap7)
356
357 ;multiply and accumulate - r5:r4:r3:r2
358 muls r19,r21 ; (signed)ah * (signed)bh
359 add r4,r0
360 adc r5,r1
361 mul r18,r20 ; al * bl
362 add r2,r0
363 adc r3,r1
364 adc r4,r22
365 adc r5,r22
366 mulsu r19,r20 ; (signed)ah * bl
367 sbc r5,r22
368 add r3,r0
369 adc r4,r1
370 adc r5,r22
371 mulsu r21,r18 ; (signed)bh * al
372 sbc r5,r22
373 add r3,r0
374 adc r4,r1
375 adc r5,r22
376
377 ;get delayed data
378 movw r29:r28,r25:r24 ; move write register to read register
379 subi r28,low(tap_delay8) ; remove delay time
380 sbci r29,high(tap_delay8)
381 out portd,r28 ; set address
382 sts porth,r29
383 nop ; wait input latch time of 2 clock cycles
384 nop ; wait input latch time of 2 clock cycles
385 in r20,pina ; get data
386 in r21,pinc ; get data
387
388 ;setup delay constant
389 ldi r18,low(tap8)
390 ldi r19,high(tap8)
391
392 ;multiply and accumulate - r5:r4:r3:r2
393 muls r19,r21 ; (signed)ah * (signed)bh
394 add r4,r0
395 adc r5,r1
396 mul r18,r20 ; al * bl
397 add r2,r0
398 adc r3,r1
399 adc r4,r22
400 adc r5,r22
401 mulsu r19,r20 ; (signed)ah * bl
402 sbc r5,r22
403 add r3,r0
404 adc r4,r1
405 adc r5,r22
406 mulsu r21,r18 ; (signed)bh * al
407 sbc r5,r22
408 add r3,r0
409 adc r4,r1
410 adc r5,r22
411
412 ;get delayed data
413 movw r29:r28,r25:r24 ; move write register to read register
414 subi r28,low(tap_delay9) ; remove delay time
415 sbci r29,high(tap_delay9)
416 out portd,r28 ; set address
417 sts porth,r29
418 nop ; wait input latch time of 2 clock cycles
419 nop ; wait input latch time of 2 clock cycles
420 in r20,pina ; get data
421 in r21,pinc ; get data
422
423 ;setup delay constant
424 ldi r18,low(tap9)
425 ldi r19,high(tap9)
426
427 ;multiply and accumulate - r5:r4:r3:r2
428 muls r19,r21 ; (signed)ah * (signed)bh
429 add r4,r0
430 adc r5,r1
431 mul r18,r20 ; al * bl
432 add r2,r0
433 adc r3,r1
434 adc r4,r22
435 adc r5,r22
436 mulsu r19,r20 ; (signed)ah * bl
437 sbc r5,r22
438 add r3,r0
439 adc r4,r1
440 adc r5,r22
441 mulsu r21,r18 ; (signed)bh * al
442 sbc r5,r22
443 add r3,r0
444 adc r4,r1
445 adc r5,r22
446
447 ;get delayed data
448 movw r29:r28,r25:r24 ; move write register to read register
449 subi r28,low(tap_delay10) ; remove delay time
450 sbci r29,high(tap_delay10)
451 out portd,r28 ; set address
452 sts porth,r29
453 nop ; wait input latch time of 2 clock cycles
454 nop ; wait input latch time of 2 clock cycles
455 in r20,pina ; get data
456 in r21,pinc ; get data
457
458 ;setup delay constant
459 ldi r18,low(tap10)
460 ldi r19,high(tap10)
461
462 ;multiply and accumulate - r5:r4:r3:r2
463 muls r19,r21 ; (signed)ah * (signed)bh
464 add r4,r0
465 adc r5,r1
466 mul r18,r20 ; al * bl
467 add r2,r0
468 adc r3,r1
469 adc r4,r22
470 adc r5,r22
471 mulsu r19,r20 ; (signed)ah * bl
472 sbc r5,r22
473 add r3,r0
474 adc r4,r1
475 adc r5,r22
476 mulsu r21,r18 ; (signed)bh * al
477 sbc r5,r22
478 add r3,r0
479 adc r4,r1
480 adc r5,r22
481
482 dec r15
483 brne done_000009
484 lds r31,pinj ; get switch data
485 andi r31,$78 ; mask off rotary switch
486 ldi r17,$02
487 lsr r31
488 lsr r31
489 add r31,r17 ; adjust switch position to program memory location
490
491 done_000009:
492
493 reti
494