ReverbMono

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).

reverb_mono.asm


   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 

ReverbMono (last edited 2010-08-21 02:09:51 by guest)