welcome: please sign in
location: attachment:reverser_crossfade.asm of ReverserCrossfade

Attachment 'reverser_crossfade.asm'

Download

   1 ; program: reverser-16b-pot-crossfade.asm
   2 ; UID = 000044 - unique id to eliminate conflicts between variables
   3 ; 16b address space (1.5s sample time)
   4 ; mono data in on left channel, mono data out on left and right
   5 ; pot (MOD1) controlled buffer size
   6 
   7 ; program overview
   8 ;
   9 ; data is read in from memory and written out the codec at the same time
  10 ; new data is written to the memory from the codec.  left channel data
  11 ; is read in, and presented on both right and left out.  the write address
  12 ; increments until it reaches the top of the buffer and then starts at
  13 ; zero.  the read address does the same thing, but in reverse.  the adc
  14 ; value sets the buffer size, and is determined by the pot (MOD1) value,
  15 ; which is multiplied up to a 16b value.  the buffer size is adjusted at a
  16 ; rate of 2 lsb per sample period, until it matches to what the pot says
  17 ; it should be.  the samples are played normally, until within a fixed
  18 ; distance of the buffer boundary.  at this point, the samples are
  19 ; crossfaded with the first samples on the other side of the boundary.  this
  20 ; reduces the appearance of clicks at buffer transistions, without giving
  21 ; the reverb effect of the fading method, and with a little less tremolo
  22 ; than the ducking method.
  23 
  24 ; constant definitions
  25 ;
  26 .equ stepsize_000044 = $0080 ; 65536/(stepsize * 44.1) = crossfade time (ms)
  27 .equ buffer_min_000044 = (4 * ($10000 / stepsize_000044))
  28 ; minimum sample buffer size to accomodate crossfade time
  29 
  30 ; register usage - may be redefined in other sections
  31 ;
  32 ; r0  multiply result lsb
  33 ; r1  multiply result msb
  34 ; r2  multiply accumulate lsb
  35 ; r3  multiply accumulate mlb
  36 ; r4  left/right lsb out / sample 1 lsb / multiply accumulate mhb
  37 ; r5  left/right msb out / smaple 2 msb / multiply accumulate msb
  38 ; r6  left lsb in / sample 2 lsb
  39 ; r7  left msb in / sample 2 msb
  40 ; r8  
  41 ; r9  adc msb accumulator
  42 ; r10 adc fractional byte accumulator
  43 ; r11 adc lsb accumulator
  44 ; r12 desired buffer size lsb
  45 ; r13 desired buffer size msb
  46 ; r14 null register
  47 ; r15 switch/adc counter
  48 ; r16 temporary swap register
  49 ; r17 temporary swap register
  50 ; r18 crossfade address temporary lsb
  51 ; r19 crossfade address temporary msb
  52 ; r20 crossfade distance lsb
  53 ; r21 crossfade distance msb
  54 ; r22 multiplicand lsb 
  55 ; r23 multiplicand msb
  56 ; r24 write address lsb
  57 ; r25 write address msb
  58 ; r26 buffer size lsb
  59 ; r27 buffer size msb
  60 ; r28 read address lsb
  61 ; r29 read address msb
  62 ; r30 jump location for interrupt lsb
  63 ; r31 jump location for interrupt msb
  64 ; t   crossfading indicator
  65 
  66 ; program starts here first time
  67 ; initialze z pointer for correct jump
  68 ; this assumes a less than 256 word jump
  69 ldi r30,$20 ; set jump location to program start
  70 clr r24 ; clear write register
  71 clr r25
  72 ldi r22,$00 ; setup write address high byte
  73 clr r18 ; setup r18 as null register for carry addition and ddr setting
  74 ldi r17,$ff ; setup r17 for ddr setting
  75 
  76 clear_000044: ; clear delay buffer
  77 ; eliminates static when first switching to the delay setting
  78 
  79 adiw r25:r24,$01 ; increment write register
  80 adc r22,r18 ; increment write third byte
  81 cpi r22,$01 ; check if 16b memory space has been cleared
  82 breq cleardone_000044 ; continue until end of buffer reached
  83 out portd,r24 ; set address
  84 sts porth,r25
  85 out portg,r22 ; pull ce low,we low,and set high bits of address
  86 out ddra,r17 ; set porta as output for data write
  87 out ddrc,r17 ; set portc as output for data write
  88 out porta,r18 ; set data
  89 out portc,r18 ; r18 is cleared above
  90 sbi portg,portg2 ; pull we high to write
  91 out ddra,r18 ; set porta as input for data lines
  92 out ddrc,r18 ; set portc as input for data lines
  93 rjmp clear_000044 ; continue clearing
  94 
  95 cleardone_000044: ; reset registers
  96 
  97 ldi r24,$00 ; initialize write register
  98 ldi r25,$00
  99 clr r14 ; setup null register
 100 ldi r28,$00 ; set read address to minimum delay
 101 ldi r29,$fd
 102 clr r4 ; initialize data output registers
 103 clr r5
 104 ldi r26,$00 ; initialize buffer size
 105 ldi r27,$06
 106 reti ; finish with initialization and wait for next interrupt
 107 
 108 ; program starts here every time but first
 109 ; initiate data transfer to codec
 110 sbi portb,portb0 ; toggle slave select pin
 111 out spdr,r5 ; send out left channel msb
 112 cbi portb,portb0
 113 
 114 ;increment write address
 115 adiw r25:r24,$01 ; increment write address
 116 cp r24,r26 ; check if at buffer boundary
 117 cpc r25,r27
 118 brlo wait1_000044 ; continue if not
 119 clr r24 ; set write address to bottom
 120 clr r25
 121 
 122 wait1_000044: ; check if byte has been sent
 123 
 124 in r17,spsr
 125 sbrs r17,spif
 126 rjmp wait1_000044
 127 in r7,spdr ; recieve in left channel msb
 128 out spdr,r4 ; send out left channel lsb
 129 
 130 ;decrement read address
 131 sbiw r29:r28,$01 ; decrement read address
 132 brsh wait2_000044 ; check if at bottom of buffer
 133 movw r29:r28,r27:r26 ; set counter to top
 134 sbiw r29:r28,$01 ; decrement read address
 135 
 136 wait2_000044: ; check if byte has been sent
 137 
 138 in r17,spsr
 139 sbrs r17,spif
 140 rjmp wait2_000044
 141 in r6,spdr ; recieve in left channel lsb
 142 out spdr,r5 ; send out right channel msb
 143 
 144 ;write left channel data to sram
 145 out portd,r24 ; set address
 146 sts porth,r25
 147 out portg,r14 ; pull ce low,we low,and set high bits of address
 148 ldi r17,$ff
 149 out ddra,r17 ; set porta as output for data write
 150 out ddrc,r17 ; set portc as output for data write
 151 out porta,r6 ; set data
 152 out portc,r7
 153 sbi portg,portg2 ; pull we high to write
 154 out ddra,r14 ; set porta as input for data lines
 155 out ddrc,r14 ; set portc as input for data lines
 156 
 157 wait3_000044: ; check if byte has been sent
 158 
 159 in r17,spsr
 160 sbrs r17,spif
 161 rjmp wait3_000044
 162 in r17,spdr ; recieve in right channel msb
 163 out spdr,r4 ; send out right channel lsb
 164 
 165 ;get left/right channel data from sram
 166 out portd,r28 ; set address
 167 sts porth,r29
 168 nop ; wait input latch time of 2 clock cycles
 169 nop
 170 in r4,pina ; get data
 171 in r5,pinc ; get data
 172 
 173 wait4_000044: ; check if byte has been sent
 174 
 175 in r17,spsr
 176 sbrs r17,spif
 177 rjmp wait4_000044
 178 in r17,spdr ; recieve in left channel lsb
 179 
 180 ;get crossfade distance
 181 movw r17:r16,r29:r28 ; move read address to temporary register
 182 sub r16,r24 ; find distance to loop boundary
 183 sbc r17,r25
 184 brcc attenuate_000044 ; check if within crossfade distance if positive
 185 add r16,r26 ; flip result around boundary if negative
 186 adc r17,r27
 187 
 188 attenuate_000044: ; multiply signal by distance to boundary
 189 
 190 brts crossfade1_000044 ; skip if already crossfading
 191 ldi r18,low(2 * ($10000 / stepsize_000044)) ; get crossfade distance
 192 ldi r19,high(2 * ($10000 / stepsize_000044))
 193 cp r16,r18 ; check if less than crossfade distance
 194 cpc r17,r19
 195 brsh check_000044 ; do nothing if not
 196 set ; set t register to indicate crossfade and downcounting
 197 clr r20 ; set crossfade counter to top
 198 clr r21
 199 subi r20,low(stepsize_000044) ; decrement for first sample
 200 sbci r21,high(stepsize_000044)
 201 
 202 crossfade1_000044: ; crossfade the signal
 203 
 204 ;setup sample 2 read address
 205 movw r19:r18,r29:r28 ; move read address to temporary register
 206 subi r18,low(2 * ($10000 / stepsize_000044)) ; get sample from other side of boundary
 207 sbci r19,high(2 * ($10000 / stepsize_000044))
 208 brcc crossfade2_000044 ; continue if no buffer underflow
 209 add r18,r26 ; wrap read address around buffer
 210 adc r19,r27
 211 
 212 crossfade2_000044: ; continue crossfading signal
 213 
 214 ;get sample 2 from sram
 215 out portd,r18 ; set address
 216 sts porth,r19
 217 nop ; wait input latch time of 2 clock cycles
 218 nop
 219 in r6,pina ; get data
 220 in r7,pinc ; get data
 221 
 222 ;multiply sample 1
 223 movw r17:r16,r5:r4 ; move data to signed multiply register
 224 mulsu r17,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 225 movw r5:r4,r1:r0 ; store high bytes result for later
 226 mul	r16,r20	; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 227 movw r3:r2,r1:r0 ; store low byets for later
 228 mulsu r17,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 229 sbc	r5,r14 ; r14 is cleared above - subtract sign bit
 230 add	r3,r0 ; accumulate result
 231 adc	r4,r1
 232 adc	r5,r14 ; r14 is cleared above
 233 mul r21,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 234 add	r3,r0 ; accumulate result
 235 adc	r4,r1
 236 adc	r5,r14 ; r14 is cleared above
 237 
 238 ;multiply and accumulate sample 2
 239 movw r17:r16,r7:r6 ; move data to signed multiply register
 240 movw r23:r22,r21:r20 ; move distance counter to temporary register
 241 com r22 ; invert distance for sample 2
 242 com r23
 243 mulsu r17,r23 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 244 add r4,r0 ; accumulate result
 245 adc r5,r1
 246 mul	r16,r22	; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 247 add r2,r0 ; accumulate result
 248 adc r3,r1
 249 adc r4,r14
 250 adc r5,r14
 251 mulsu r17,r22 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 252 sbc	r5,r14 ; r14 is cleared above - subtract sign bit
 253 add	r3,r0 ; accumulate result
 254 adc	r4,r1
 255 adc	r5,r14 ; r14 is cleared above
 256 mul r23,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 257 add	r3,r0 ; accumulate result
 258 adc	r4,r1
 259 adc	r5,r14 ; r14 is cleared above
 260 
 261 ;check if done crossfading
 262 subi r20,low(stepsize_000044) ; decrement crossfade
 263 sbci r21,high(stepsize_000044)
 264 brcc check1_000044 ; check if crossfade time is negative
 265 movw r29:r28,r19:r18 ; move crossfade address to current address
 266 clt ; clear the t register to indicate done
 267 rjmp check_000044 ; finish off
 268 
 269 check1_000044: ; continue checking crossfade time
 270 
 271 brne check_000044 ; check if crossfade time is zero
 272 movw r29:r28,r19:r18 ; move crossfade address to current address
 273 clt ; clear the t register to indicate done
 274 
 275 check_000044: ; check if buffer size is correct
 276 
 277 cp r26,r12 ; compare current delay to desired delay
 278 cpc r27,r13
 279 brlo upcount2_000044 ; increment if smaller than
 280 breq adcsample_000044 ; do nothing if they are same size
 281 sbiw r27:r26,$02 ; decrement buffer size
 282 rjmp adcsample_000044 ; finish off
 283 
 284 upcount2_000044: ; increment buffer size register
 285 
 286 adiw r27:r26,$02 ; increment buffer size
 287 
 288 adcsample_000044: ; get loop setting
 289 
 290 lds r17,adcsra ; get adc control register
 291 sbrs r17,adif ; check if adc conversion is complete
 292 rjmp done_000044 ; skip adc sampling
 293 lds r16,adcl ; get low byte adc value
 294 lds r17,adch ; get high byte adc value
 295 add r10,r16
 296 adc r11,r17 ; accumulate adc samples
 297 adc r9,r14 ; accumulate adc samples - r14 is cleared above
 298 ldi r17,$f7
 299 sts adcsra,r17 ; clear interrupt flag
 300 dec r15 ; countdown adc sample clock
 301 brne done_000044 ; move adc value to loop setting after 256 samples
 302 lsr r9 ; divide accumulated value by 4 to get 16b value
 303 ror r11
 304 ror r10
 305 lsr r9
 306 ror r11
 307 ror r10
 308 ldi r16,low(buffer_min_000044) ; load minimum buffer size
 309 ldi r17,high(buffer_min_000044)
 310 cp r10,r16 ; check if less than minimum
 311 cpc r11,r17
 312 brsh compare_000044 ; compare to previous value if above min
 313 movw r11:r10,r17:r16 ; set buffer size to minimum
 314 
 315 compare_000044: ; compare to previous value
 316 
 317 movw r17:r16,r13:r12 ; make a copy of current loop time for comparison
 318 sub r16,r10 ; find difference between current loop time and last loop time
 319 sbc r17,r11
 320 brcc deadband_000044 ; see if difference is large enough to indicate a change
 321 neg r16 ; invert difference if negative
 322 adc r17,r14 ; r14 is cleared above
 323 neg r17
 324 
 325 deadband_000044: ; see if pot has moved or if its just noise
 326 
 327 cpi r16,$40 ; see if difference is greater than 1 lsb
 328 cpc r17,r14 ; r14 is cleared above
 329 brlo nochange_000044 ; dont update loop time if difference is not large enough
 330 ldi r16,$fe ; make sure buffer size is even
 331 and r10,r16
 332 movw r13:r12,r11:r10 ; move adc value to loop time register
 333 
 334 nochange_000044: ; clear accumulation registers
 335 
 336 clr r10 ; empty accumulation registers
 337 clr r11
 338 clr r9
 339 
 340 ;check rotary switch state
 341 lds r16,pinj ; get switch data
 342 andi r16,$78 ; mask off rotary switch
 343 lsr r16 ; adjust switch position to program memory location
 344 lsr r16
 345 ldi r17,$02
 346 add r16,r17
 347 cpse r16,r31 ; check if location has changed
 348 clr r30 ; reset jump register to intial state
 349 mov r31,r16
 350 
 351 done_000044:
 352 
 353 reti ; return to waiting
 354 

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.

You are not allowed to attach a file to this page.