← Revision 3 as of 2010-08-14 00:24:18
|Deletions are marked like this.||Additions are marked like this.|
|Line 7:||Line 7:|
|The pot (MOD1) varies the delay after the input crosses the threshold, until the output starts reversing, from 6ms to 3s.||The pot (MOD1) varies the delay time the function waits after the input crosses the threshold, before it starts reversing (from 6ms to 3s). This lets you trigger the device, and have it play the following notes backwards. There is also a backtrack time, which is a fixed amount of time that the function will continue playing after it has reached the beginning of the buffer (the trigger point). This allows the sampler to catch the rising edge of notes, before they cross the treshold. After this backtrack time, the reverser then crossfades to the currently forward moving signal.|
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. The pot (MOD1) controls the delay time, and subsequently the buffer size.
A reverser is created by playing all the samples in reverse order. Unfortunately, you end up hitting the beginning of your buffer at some point, and need to start over again. This creates an audible click in the sample playback. To eliminate this click, we are using a cross-fading method. This is the same as cross-fading between records when DJing. As one sample gets close to the buffer boundary, its volume is faded down, and a sample from the other side of the boundary is faded up. This continues as the sample moves forward in the buffer, with the volume of the first sample being reduced to zero by the time it gets to the buffer boundary. At this point, the sample on the other side is playing full volume, and takes over. This gives a relatively smooth transition across the buffer boundary, with only a slight dipping noticeable, but also keeps the playback very true to the original signal during the majority of playback, which is not near the boundary. The crossfade time is preset at the begining of the code, which also determines the minimum sample size, as there has to be enough data for both fading up and down on either side of the boundary.
The pot (MOD1) varies the delay time the function waits after the input crosses the threshold, before it starts reversing (from 6ms to 3s). This lets you trigger the device, and have it play the following notes backwards. There is also a backtrack time, which is a fixed amount of time that the function will continue playing after it has reached the beginning of the buffer (the trigger point). This allows the sampler to catch the rising edge of notes, before they cross the treshold. After this backtrack time, the reverser then crossfades to the currently forward moving signal.
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