welcome: please sign in

Revision 2 as of 2010-08-14 00:17:45

Clear message
location: ReverserGatedDelay

Gated Reverser with Delay

This function implements a reverser which is triggered by sounds above a certain threshold (gating). It takes in stereo data and outputs stereo data.

reverser_gated_delay.asm


   1 ; program: reverser-18b-gated-delay.asm
   2 ; UID = 000050 - unique id to eliminate conflicts between variables
   3 ; 18b address space (3s sample time)
   4 ; stereo data, in and out
   5 ; pot (MOD1) controlled delay
   6 
   7 ; program overview
   8 ;
   9 ; data is read in from memory and written out to the codec at the same time
  10 ; new data is written to the memory from the codec.  the left channel input
  11 ; data is compared to a predetermined threshold level, and if it crosses
  12 ; this level, the reverser function is initiated after a delay.  the delay
  13 ; is set via the adc reading from the pot (MOD1).  this value is sampled
  14 ; 256 times and deadbanded to reduce jitter.  the codec passes data
  15 ; through while in forward mode, and continues to do so for the delay
  16 ; period after the input has crossed the threshold.  after this time, the
  17 ; input data is no longer written to memory, in order to increase the
  18 ; available buffer size.  the reverse data is played out back to the
  19 ; beginning, plus a predetermined backtrack amount to catch the rising
  20 ; edge of notes.  at this point, the forward data saving is resumed, and
  21 ; the reverse data is faded while the current data is faded in.  this
  22 ; crossfade size is determined via a constant at the beginning of the code.
  23 ; there is also a holdoff time after the reverser function has finished,
  24 ; before it can be retriggered, in order to reduce constant triggering and
  25 ; glitches from not having enough forward data stored.
  26 
  27 ; constant definitions
  28 ;
  29 .equ backtrack_000050 = $0800 ; past memory used as starting point
  30 ; (must be even)
  31 .equ holdoff_000050 = $0f00 ; holdoff before retriggering
  32 ; must be larger than backtrack (must be even)
  33 .equ stepsize_000050 = $0080 ; 65536/(stepsize * 44.1) = crossfade time (ms)
  34 .equ threshold_000050 = $3900 ; threshold for turn on of reverser ($7fff max)
  35 .equ minbuff_000050 = $02 ; minimum buffer time in multiples of 5.8ms
  36 .equ maxbuff_000050 = ($03ff00 - (2 * ($010000 / stepsize_000050)) - holdoff_000050)
  37 ; maximum buffer time to keep from overlapping
  38 .equ mem_000050 = $0200 ; memory location for storage in internal sram
  39 
  40 ; register usage - may be redefined in other sections
  41 ;
  42 ; r0  multiply result lsb
  43 ; r1  multiply result msb
  44 ; r2  left lsb out
  45 ; r3  left msb out
  46 ; r4  right lsb out
  47 ; r5  right msb out
  48 ; r6  left lsb in
  49 ; r7  left msb in
  50 ; r8  right lsb in
  51 ; r9  right msb in
  52 ; r10 adc accumulation lsb
  53 ; r11 adc accumulation msb
  54 ; r12 buffer bottom / crossfade lsb
  55 ; r13 buffer bottom / crossfade msb
  56 ; r14 adc accumulation fractional byte
  57 ; r15 switch/adc sample counter
  58 ; r16 temporary swap register
  59 ; r17 temporary swap register
  60 ; r18 null register
  61 ; r19 reverse mode indicator
  62 ; r20 temporary swap regiser
  63 ; r21 buffer bottom third byte
  64 ; r22 write address third byte
  65 ; r23 read address third byte
  66 ; r24 write address lsb
  67 ; r25 write address msb
  68 ; r26 desired buffer size lsb
  69 ; r27 desired buffer size msb
  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 ; t   foward/reverse indicator
  75 
  76 ; program starts here first time
  77 ; initialze z pointer for correct jump
  78 ; this assumes a less than 256 word jump
  79 ldi r30,$23 ; set jump location to program start
  80 clr r24 ; clear write register
  81 clr r25
  82 ldi r22,$00 ; setup write address high byte
  83 clr r18 ; setup r18 as null register for carry addition and ddr setting
  84 ldi r17,$ff ; setup r17 for ddr setting
  85 
  86 clear_000050: ; clear delay buffer
  87 ; eliminates static when first switching to the delay setting
  88 
  89 adiw r25:r24,$01 ; increment write register
  90 adc r22,r18 ; increment write third byte
  91 cpi r22,$04 ; check if full memory space has been cleared
  92 breq cleardone_000050 ; continue until end of buffer reached
  93 out portd,r24 ; set address
  94 sts porth,r25
  95 out portg,r22 ; pull ce low,we low,and set high bits of address
  96 out ddra,r17 ; set porta as output for data write
  97 out ddrc,r17 ; set portc as output for data write
  98 out porta,r18 ; set data
  99 out portc,r18 ; r18 is cleared above
 100 sbi portg,portg2 ; pull we high to write
 101 out ddra,r18 ; set porta as input for data lines
 102 out ddrc,r18 ; set portc as input for data lines
 103 rjmp clear_000050 ; continue clearing
 104 
 105 cleardone_000050: ; reset registers
 106 
 107 ldi r24,$01 ; initialize write register
 108 ldi r25,$00
 109 ldi r22,$00 ; setup write address high byte
 110 ldi r28,$01 ; set read address to minimum delay
 111 ldi r29,$ff
 112 ldi r23,$07 ; setup read address high byte
 113 clr r19 ; initialize reverse mode register
 114 clr r2 ; initialize data output registers
 115 clr r3
 116 clr r4
 117 clr r5
 118 clt ; clear t register to start with forward play
 119 reti ; finish with initialization and wait for next interrupt
 120 
 121 ; initiate data transfer to codec
 122 ; this is the point the z-pointer is incremented to
 123 ; program starts here all but first time
 124 sbi portb,portb0 ; toggle slave select pin
 125 out spdr,r3 ; send out left channel msb
 126 cbi portb,portb0
 127 
 128 ;increment write addresses
 129 brts wait1_000050 ; dont write data to memory if reversing
 130 adiw r25:r24,$01 ; increment write address
 131 adc r22,r18 ; increment write third byte
 132 andi r22,$03 ; mask off unsed bits
 133 
 134 wait1_000050: ; check if byte has been sent
 135 
 136 in r17,spsr
 137 sbrs r17,spif
 138 rjmp wait1_000050
 139 in r7,spdr ; recieve in left channel msb
 140 out spdr,r2 ; send out left channel lsb
 141 
 142 wait2_000050: ; check if byte has been sent
 143 
 144 in r17,spsr
 145 sbrs r17,spif
 146 rjmp wait2_000050
 147 in r6,spdr ; recieve in left channel lsb
 148 out spdr,r5 ; send out right channel msb
 149 
 150 ;write left channel data to sram
 151 brts wait3_000050 ; dont write data to memory if reversing
 152 out portd,r24 ; set address
 153 sts porth,r25
 154 out portg,r22 ; pull ce low,we low,and set high bits of address
 155 ldi r17,$ff
 156 out ddra,r17 ; set porta as output for data write
 157 out ddrc,r17 ; set portc as output for data write
 158 out porta,r6 ; set data
 159 out portc,r7
 160 sbi portg,portg2 ; pull we high to write
 161 out ddra,r18 ; set porta as input for data lines
 162 out ddrc,r18 ; set portc as input for data lines
 163 
 164 wait3_000050: ; check if byte has been sent
 165 
 166 in r17,spsr
 167 sbrs r17,spif
 168 rjmp wait3_000050
 169 in r9,spdr ; recieve in right channel msb
 170 out spdr,r4 ; send out right channel lsb
 171 
 172 ;increment write address
 173 brts wait4_000050 ; dont write data to memory if reversing
 174 adiw r25:r24,$01 ; increment write address
 175 adc r22,r18 ; increment write third byte
 176 andi r22,$03 ; mask off unsed bits
 177 
 178 wait4_000050: ; check if byte has been sent
 179 
 180 in r17,spsr
 181 sbrs r17,spif
 182 rjmp wait4_000050
 183 in r8,spdr ; recieve in left channel lsb
 184 
 185 ;write right channel data to sram
 186 brts dataload_000050 ; dont write data to memory if reversing
 187 out portd,r24 ; set address
 188 sts porth,r25
 189 out portg,r22 ; pull ce low,we low,and set high bits of address
 190 ldi r17,$ff
 191 out ddra,r17 ; set porta as output for data write
 192 out ddrc,r17 ; set portc as output for data write
 193 out porta,r8 ; set data
 194 out portc,r9
 195 sbi portg,portg2 ; pull we high to write
 196 out ddra,r18 ; set porta as input for data lines
 197 out ddrc,r18 ; set portc as input for data lines
 198 
 199 ;check if input signal is above threshold
 200 movw r3:r2,r7:r6 ; backup input values as they get modified
 201 movw r5:r4,r9:r8 ; move input data to output
 202 sbrc r19,$04 ; check if holding off after last trigger
 203 rjmp holdtime_000050 ; countdown holdoff timer if waiting
 204 sbrc r19,$07 ; check if already in reverse mode
 205 rjmp reverse_000050 ; go to reverse function - else check threshold
 206 ldi r16,low(threshold_000050) ; get threshold value
 207 ldi r17,high(threshold_000050)
 208 tst r7 ; check if negative
 209 brpl compare_000050 ;  compare if positive
 210 com r6 ; invert if negative
 211 com r7 ; ones complement used for simplicity
 212 
 213 compare_000050: ; compare input value to threshold
 214 
 215 cp r6,r16 ; compare to left channel input
 216 cpc r7,r17
 217 brsh start_000050 ; start reversing if above threshold
 218 rjmp adcsample_000050 ; else finish off
 219 
 220 holdtime_000050: ; decrement holdoff timer
 221 
 222 ldi r17,$02 ; subtract 2 from holdoff timer
 223 sub r12,r17 ; 2 is used to have holdoff and backup match scaling
 224 sbc r13,r18 ; r18 is cleared above
 225 brne finishoff_000050 ; finish off if it not done holding off
 226 clr r19 ; set mode to forward and clear hold off bit
 227 
 228 finishoff_000050: ; finish off if not done holding off
 229 
 230 rjmp adcsample_000050 ; finish off - too long for a branch instruction
 231 
 232 start_000050: ; intialize reversing
 233 
 234 ldi r19,$80 ; indicate that reverser is active, waiting for delay
 235 movw r17:r16,r25:r24 ; move write address to temporary register
 236 mov r21,r22
 237 subi r16,low(backtrack_000050) ; remove initial buffer size
 238 sbci r17,high(backtrack_000050)
 239 sbc r21,r18 ; r18 cleared above
 240 andi r21,$03 ; mask off low bits
 241 movw r13:r12,r17:r16 ; move buffer bottom to its register
 242 rjmp adcsample_000050 ; finish off
 243 
 244 reverse_000050: ; check for reverse function
 245 
 246 sbrc r19,$06 ; check if delay time has been met
 247 rjmp dataload_000050 ; get data from memory if delay time has been met
 248 ; else check if delay time is up yet
 249 movw r17:r16,r13:r12 ; move bottom of buffer to temporary register
 250 mov r20,r21
 251 add r17,r26 ; add in buffer size
 252 adc r20,r27
 253 andi r20,$03 ; mask off unused bits
 254 cp r24,r16 ; check if write address is at top of buffer
 255 cpc r25,r17
 256 cpc r22,r20
 257 breq bufferset_000050 ; set the read address to the top of the buffer
 258 rjmp adcsample_000050 ; else finish off
 259 
 260 bufferset_000050: ; set the read address to the top of the buffer
 261 
 262 movw r29:r28,r25:r24 ; else set read address equal to write address
 263 mov r23,r22
 264 ori r19,$40 ; set delay time bit in function register
 265 set ; set the t register to indicate reversing
 266 rjmp dataload1_000050 ; get data from sram
 267 
 268 dataload_000050: ; get data from sram
 269 
 270 sbrc r19,$05 ; check if crossfading
 271 rjmp dataload1_000050 ; skip buffer check if crossfading
 272 andi r23,$03 ; mask off unused bits
 273 cp r28,r12 ; check if at bottom of buffer
 274 cpc r29,r13
 275 cpc r23,r21
 276 brne dataload1_000050 ; continue if not at bottom
 277 ori r19,$20 ; set crossfade bit
 278 ldi r16,$ff ; set crossfade distance to max value
 279 mov r12,r16 ; buffer bottom value no longer needed
 280 mov r13,r16
 281 clt ; clear the t register to start recording forward again
 282 
 283 dataload1_000050: ; continue getting data from sram
 284 
 285 sbiw r29:r28,$03 ; decrement read address
 286 sbc r23,r18 ;  r18 is cleared above
 287 andi r23,$03 ; mask off unused bits
 288 ori r23,$04 ; set we/ bit in high byte register
 289 
 290 ;get left channel data from sram
 291 out portg,r23 ; pull ce low, we high, and set high bits of register
 292 out portd,r28 ; set address
 293 sts porth,r29
 294 adiw r29:r28,$01 ; increment read address
 295 adc r23,r18 ; increment write third byte
 296 andi r23,$03 ; mask off unsed bits
 297 ori r23,$04 ; set we/ bit in high byte register
 298 in r2,pina ; get data
 299 in r3,pinc ; get data
 300 
 301 ;get right channel data from sram
 302 out portg,r23 ; pull ce low, we high, and set high bits of register
 303 out portd,r28 ; set address
 304 sts porth,r29
 305 nop ; wait 2 cycle setup time
 306 nop
 307 in r4,pina ; get data
 308 in r5,pinc ; get data
 309 
 310 ;check if crossfading
 311 sbrs r19,$05 ; check if crossfading
 312 rjmp adcsample_000050 ; finish off if not crossfading
 313 ldi r16,low(stepsize_000050) ; get crossfade stepsize
 314 ldi r17,high(stepsize_000050)
 315 sub r12,r16 ; decrement crossfade distance counter
 316 sbc r13,r17
 317 breq crossfade_done_000050 ; stop crossfading if done
 318 brcs crossfade_done_000050 ; stop crossfading if done
 319 rjmp crossfade_000050
 320 
 321 crossfade_done_000050: ; stop crossfading
 322 
 323 movw r3:r2,r7:r6 ; move forward data to output
 324 movw r5:r4,r9:r8
 325 ldi r16,low(holdoff_000050) ; setup holdoff counter
 326 ldi r17,high(holdoff_000050)
 327 movw r13:r12,r17:r16 ; r13:r12 no longer needed for crossfading
 328 ori r19,$10 ; set reverse mode to holdoff
 329 rjmp adcsample_000050 ; finish off
 330 
 331 crossfade_000050: ; crossfade between forward and reverse signals
 332 
 333 sts mem_000050,r6 ; backup data to free a register
 334 sts (mem_000050 + 1),r7
 335 
 336 ;multiply left reverse sample by crossfade distance
 337 movw r17:r16,r3:r2 ; move left reverse data to multiply register
 338 movw r21:r20,r13:r12 ; move crossfade distance to multiply register
 339 mulsu r17,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 340 movw r3:r2,r1:r0 ; store high bytes result for later
 341 mul     r16,r20 ; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 342 movw r7:r6,r1:r0 ; store low byets for later
 343 mulsu r17,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 344 sbc     r3,r18 ; r18 is cleared above - subtract sign bit
 345 add     r7,r0 ; accumulate result
 346 adc     r2,r1
 347 adc     r3,r18 ; r18 is cleared above
 348 mul r21,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 349 add     r7,r0 ; accumulate result
 350 adc     r2,r1
 351 adc     r3,r18 ; r18 is cleared above
 352 
 353 ;multiply and accumulate left forward channel by crossfade distance
 354 lds r16,mem_000050 ; fetch left forward channel from memory
 355 lds r17,(mem_000050 + 1)
 356 com r20 ; invert crossfade distance for forward channel
 357 com r21
 358 mulsu r17,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 359 add r2,r0 ; accumulate result
 360 adc r3,r1
 361 mul     r16,r20 ; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 362 add r6,r0 ; accumulate result
 363 adc r7,r1
 364 adc r2,r18 ; r18 cleared above
 365 adc r3,r18
 366 mulsu r17,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 367 sbc     r3,r18 ; r18 is cleared above - subtract sign bit
 368 add     r7,r0 ; accumulate result
 369 adc     r2,r1
 370 adc     r3,r18 ; r18 is cleared above
 371 mul r21,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 372 add     r7,r0 ; accumulate result
 373 adc     r2,r1
 374 adc     r3,r18 ; r18 is cleared above
 375 
 376 ;multiply right reverse sample by crossfade distance
 377 movw r17:r16,r5:r4 ; move right reverse data to multiply register
 378 movw r21:r20,r13:r12 ; move crossfade distance to multiply register
 379 mulsu r17,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 380 movw r5:r4,r1:r0 ; store high bytes result for later
 381 mul     r16,r20 ; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 382 movw r7:r6,r1:r0 ; store low byets for later
 383 mulsu r17,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 384 sbc     r5,r18 ; r18 is cleared above - subtract sign bit
 385 add     r7,r0 ; accumulate result
 386 adc     r4,r1
 387 adc     r5,r18 ; r18 is cleared above
 388 mul r21,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 389 add     r7,r0 ; accumulate result
 390 adc     r4,r1
 391 adc     r5,r18 ; r18 is cleared above
 392 
 393 ;multiply and accumulate right forward channel by crossfade distance
 394 movw r17:r16,r9:r8 ; move left forward data to multiply register
 395 com r20 ; invert crossfade distance for forward channel
 396 com r21
 397 mulsu r17,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 398 add r4,r0 ; accumulate result
 399 adc r5,r1
 400 mul     r16,r20 ; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 401 add r6,r0 ; accumulate result
 402 adc r7,r1
 403 adc r4,r18 ; r18 cleared above
 404 adc r5,r18
 405 mulsu r17,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 406 sbc     r5,r18 ; r18 is cleared above - subtract sign bit
 407 add     r7,r0 ; accumulate result
 408 adc     r4,r1
 409 adc     r5,r18 ; r18 is cleared above
 410 mul r21,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 411 add     r7,r0 ; accumulate result
 412 adc     r4,r1
 413 adc     r5,r18 ; r18 is cleared above
 414 
 415 adcsample_000050: ; get buffer size from adc
 416 
 417 lds r17,adcsra ; get adc control register
 418 sbrs r17,adif ; check if adc conversion is complete
 419 rjmp done_000050 ; skip adc sampling
 420 lds r16,adcl ; get low byte adc value
 421 lds r17,adch ; get high byte adc value
 422 add r14,r16 ; accumulate adc samples
 423 adc r10,r17
 424 adc r11,r18 ; r18 is cleared above
 425 ldi r17,$f7
 426 sts adcsra,r17 ; clear interrupt flag
 427 dec r15 ; countdown adc sample clock
 428 brne done_000050 ; dont get buffer size till its been long enough
 429 ldi r17,minbuff_000050 ; fetch minimum buffer size
 430 cp r10,r17 ; check if adc value is less than minimum buffer size
 431 cpc r11,r18 ; r18 is cleared above
 432 brsh high_000050 ; check if above max buffer size if not below min
 433 mov r10,r17 ; set to minimum buffer size
 434 rjmp deadband_000050 ; check if adc value changed enough
 435 
 436 high_000050: ; check max value of adc
 437 
 438 ldi r16,low(maxbuff_000050) ; fetch max buffer size
 439 ldi r17,high(maxbuff_000050)
 440 cp r10,r16 ; check if adc value larger than max buffer size
 441 cpc r11,r17
 442 brlo deadband_000050 ; check for value chnage if lower than max size
 443 mov r10,r16 ; set buffer size to max value
 444 mov r11,r17
 445 
 446 deadband_000050: ; check if adc value changed enough to warrant update
 447 
 448 movw r17:r16,r11:r10 ; move adc sample to temporary register
 449 sub r16,r26 ; find difference between adc sample and desired delay time
 450 sbc r17,r27
 451 brsh check_000050 ; check for deadband if positive
 452 neg r16 ; invert if negative
 453 adc r17,r18 ; r18 is cleared above
 454 neg r17
 455 
 456 check_000050: ; check if difference is greater than deadband
 457 
 458 cpi r16,$02 ; check if difference is less than 2 lsb
 459 cpc r17,r18 ; r18 cleared above
 460 brlo empty_000050 ; do nothing if less than $02
 461 movw r27:r26,r11:r10 ; move adc sample to delay time if large enough change
 462 
 463 empty_000050: ; empty accumulation registers and finish off
 464 
 465 clr r10 ; empty accumulation registers
 466 clr r11
 467 clr r14
 468 
 469 switchsample_000050: ; check if at same function
 470 
 471 lds r16,pinj ; get switch data
 472 andi r16,$78 ; mask off rotary switch
 473 lsr r16 ; adjust switch position to program memory location
 474 lsr r16
 475 ldi r17,$02
 476 add r16,r17
 477 cpse r16,r31 ; check if location has changed
 478 clr r30 ; reset jump register to new value
 479 mov r31,r16
 480 
 481 done_000050:
 482 
 483 reti ; return to waiting
 484