welcome: please sign in
location: attachment:sampler_6s.asm of SamplerPitchShifter

Attachment 'sampler_6s.asm'

Download

   1 ; program: sampler-18b-pot.asm
   2 ; UID = 000058 - unique id to eliminate conflicts between variables
   3 ; 18b address space (6s sample time)
   4 ; mono data in on left channel, mono data out on left and right
   5 ; pot (MOD1) controlled playback speed
   6 
   7 ; program overview
   8 ;
   9 ; data is read in from the codec and placed into memory.  a memory address
  10 ; pointer is incrmented to find the next sample, and this is sent to the
  11 ; codec.  the pointer is incremented at a variable rate, with fractional
  12 ; values less than one slowing down the playback speed, and fractional
  13 ; values above one increasing the playback speed.  the output data is an
  14 ; interpolation of the two samples adjacent to the pointer.  left channel
  15 ; data is taken in, and the result is placed on both left and right.  ADC0
  16 ; is averaged over 256 samples and is used to create the pointer increment
  17 ; value.  the pushbutton takes in data when depressed, and plays back when
  18 ; released.  the volume is reduced around the sample boundary to reduce
  19 ; clicking sounds.
  20 
  21 ; constant definitions
  22 ;
  23 .equ stepsize_000058 = ($0100 / fade_000058) ; crossfade counter decrement
  24 .equ fade_000058 = $04 ; crossfade sample distance ($02 - $70 valid)
  25 ; crossfade time [ms] = ((fade x 256) / 44.1)
  26 .equ minbuff_000058 = (($0240 * fade_000058 * 2) + $0200)
  27 ; minimum buffer size to ensure that there is enough time for fading
  28 .equ mem_000058 = $0200 ; memory location for opposing buffer address
  29 ; i ran out of registers
  30 
  31 ; register usage - may be redefined in other sections
  32 ;
  33 ; r0  multiply result lsb
  34 ; r1  multiply result msb
  35 ; r2  left lsb in
  36 ; r3  left msb in
  37 ; r4  left/right lsb out
  38 ; r5  left/right msb out
  39 ; r6  temporary swap register
  40 ; r7  temporary swap register
  41 ; r8  playback speed fractional byte
  42 ; r9  adc accumulation fractional byte
  43 ; r10 adc accumulation lsb
  44 ; r11 adc accumulation msb
  45 ; r12 playback speed lsb
  46 ; r13 playback speed msb
  47 ; r14 null register
  48 ; r15 switch sample counter
  49 ; r16 temporary swap register
  50 ; r17 temporary swap register
  51 ; r18 temporary swap register
  52 ; r19 temporary swap register
  53 ; r20 fade state register
  54 ; r21 read address fractional byte
  55 ; r22 write address/buffer size high byte
  56 ; r23 read address high byte
  57 ; r24 write address/buffer size lsb
  58 ; r25 write address/buffer size msb
  59 ; r26 crossfade distance lsb
  60 ; r27 crossfade distance msb
  61 ; r28 read address lsb
  62 ; r29 read address msb
  63 ; r30 jump location for interrupt lsb
  64 ; r31 jump location for interrupt msb
  65 ; t   sampler record indicator
  66 
  67 ;program starts here first time
  68 ; initialize registers
  69 ; memory is not blanked in case you want to sample a neighboring function
  70 ldi r30,$11 ; set jump location to program start
  71 clr r14 ; set up null register
  72 clr r24 ; set initial buffer size to first 16b
  73 clr r25
  74 ldi r22,$01
  75 ldi r16,$01
  76 clr r12 ; initialize playback speed to normal
  77 mov r13,r16
  78 clr r9 ; clear accumulation registers
  79 clr r10
  80 clr r11
  81 clr r20 ; initialize fading state register
  82 clr r28 ; initialize read address
  83 clr r29
  84 clr r23
  85 clt ; initialize sampler indicator
  86 reti ; return and wait for next interrupt
  87 
  88 ;program starts here every time but first
  89 ; initiate data transfer to codec
  90 sbi portb,portb0 ; toggle slave select pin
  91 out spdr,r5 ; send out left channel msb
  92 cbi portb,portb0
  93 
  94 wait1_000058: ; check if byte has been sent
  95 
  96 in r17,spsr
  97 sbrs r17,spif
  98 rjmp wait1_000058
  99 in r3,spdr ; recieve in left channel msb
 100 out spdr,r4 ; send out left channel lsb
 101 
 102 wait2_000058: ; check if byte has been sent
 103 
 104 in r17,spsr
 105 sbrs r17,spif
 106 rjmp wait2_000058
 107 in r2,spdr ; recieve in left channel lsb
 108 out spdr,r5 ; send out right channel msb
 109 
 110 wait3_000058: ; check if byte has been sent
 111 
 112 in r17,spsr
 113 sbrs r17,spif
 114 rjmp wait3_000058
 115 in r17,spdr ; recieve in right channel msb
 116 out spdr,r4 ; send out right channel lsb
 117 
 118 wait4_000058: ; check if byte has been sent
 119 
 120 in r17,spsr
 121 sbrs r17,spif
 122 rjmp wait4_000058
 123 in r17,spdr ; recieve in left channel lsb
 124 
 125 ;check pushbutton
 126 lds r16,pinj ; get pushbutton data
 127 sbrc r16,$02 ; check if pushbutton depressed
 128 rjmp interpolate_000058 ; playback if button is not depressed
 129 brts write_000058 ; skip initialization if already done
 130 set ; set the t register to indicate sampling
 131 clr r24 ; initialize the write address
 132 clr r25
 133 clr r22
 134 clr r19 ; initialize buffer overflow indicator
 135 ; (r19 not used elsewhere during sampling period)
 136 
 137 write_000058: ; write left channel data to sram
 138 
 139 movw r5:r4,r3:r2 ; pass data through while recording
 140 sbrc r19,$00 ; check if overflow occured
 141 rjmp adcsample_000058 ; finish off if overflow
 142 out portd,r24 ; else set address
 143 sts porth,r25
 144 out portg,r22 ; pull ce low,we low,and set high bits of address
 145 ldi r17,$ff
 146 out ddra,r17 ; set porta as output for data write
 147 out ddrc,r17 ; set portc as output for data write
 148 out porta,r2 ; set data
 149 out portc,r3
 150 sbi portg,portg2 ; pull we high to write
 151 out ddra,r14 ; set porta as input for data lines
 152 out ddrc,r14 ; set portc as input for data lines
 153 adiw r25:r24,$01 ; increment write address
 154 adc r22,r14 ; r14 is cleared above
 155 sbrc r22,$02 ; check for buffer overflow
 156 ldi r19,$01 ; set overflow indicator if overflow
 157 rjmp adcsample_000058 ; else finish off
 158 
 159 interpolate_000058: ; interpolate data based upon speed setting
 160 
 161 brtc interpolate1_000058 ; check if pushbutton just released
 162 clr r28 ; initialize read address
 163 clr r29
 164 clr r23
 165 clt ; clear the sampling indicator
 166 ldi r17,high(minbuff_000058) ; check if buffer is too small
 167 cpi r24,low(minbuff_000058)
 168 cpc r25,r17
 169 cpc r22,r14 ; r14 is cleared above
 170 brsh interpolate1_000058 ; continue if large enough
 171 ldi r24,low(minbuff_000058) ; else set buffer size to minbuff
 172 mov r25,r17
 173 
 174 interpolate1_000058: ; continue with interpolation
 175 
 176 add r21,r12 ; increment read register
 177 adc r28,r13
 178 adc r29,r14 ; r14 is cleared above
 179 adc r23,r14
 180 
 181 read1_000058: ; get left channel sample 1 data from sram
 182 
 183 ori r23,$04 ; set we\ bit in high byte register
 184 out portg,r23 ; pull ce low, we high, and set high bits of register
 185 out portd,r28 ; set address
 186 sts porth,r29
 187 nop ; wait input latch time of 2 clock cycles
 188 nop
 189 in r4,pina ; get data
 190 in r5,pinc ; get data
 191 
 192 ;increment read address to next sample
 193 movw r17:r16,r29:r28 ; move read address to temporary register
 194 mov r18,r23
 195 ldi r19,$01 ; increment read address
 196 add r16,r19
 197 adc r17,r14 ; r14 is cleared above
 198 adc r18,r14
 199 
 200 read2_000058: ; get left channel sample 2 data from sram
 201 
 202 ori r18,$04 ; just to be sure we\ is high
 203 out portg,r18 ; pull ce low, we high, and set high bits of register
 204 out portd,r16 ; set address
 205 sts porth,r17
 206 nop ; wait input latch time of 2 clock cycles
 207 nop
 208 in r2,pina ; get data
 209 in r3,pinc ; get data
 210 
 211 ;multiply sample 1 by distance
 212 movw r17:r16,r5:r4 ; move sample to multiply register
 213 mov r18,r21 ; get distance from sample 1
 214 com r18
 215 mulsu r17,r18 ; (signed)Ah * (unsigned)B
 216 movw r5:r4,r1:r0
 217 mul	r16,r18	; (unsigned)Al * (unsigned)B
 218 add	r4,r1 ; accumulate result
 219 adc	r5,r14 ; r14 is cleared above
 220 mov r19,r0
 221 
 222 ;multiply sample 2 by distance
 223 movw r17:r16,r3:r2 ; move sample to multiply register
 224 mulsu r17,r21 ; (signed)Ah * (unsigned)B
 225 add r4,r0 ; accumulate result
 226 adc r5,r1
 227 mul	r16,r21	; (unsigned)Al * (unsigned)B
 228 add	r19,r0 ; accumulate result
 229 adc r4,r1
 230 adc	r5,r14 ; r14 is cleared above
 231 
 232 sbrc r20,$00 ; check if fading
 233 rjmp crossfade_000058 ; crossfade if appropriate
 234 ; else check if time to do so
 235 
 236 ;get distance to boundary
 237 movw r17:r16,r25:r24 ; move buffer size to temporary register
 238 clr r19
 239 mov r18,r22
 240 andi r23,$03 ; mask off unused bits in read high byte
 241 sub r19,r21 ; find distance to buffer boundary
 242 sbc r16,r28
 243 sbc r17,r29
 244 sbc r18,r23
 245 ;subi r16,$01 ; buffer boundary is 1 sample past last sample
 246 ;sbc r17,r14 ; uncomment this if glitches occur around buffer boundary
 247 ;sbc r18,r14 ; although its been fine so far
 248 
 249 ;check if within fade distance
 250 ldi r19,fade_000058 ; fetch fade distance
 251 
 252 ;scale fade distance by playback speed (r13:r12) 
 253 mul r13,r19 ; (unsigned)Ah x (unsigned)B
 254 movw r7:r6,r1:r0
 255 mul r12,r19 ; (unsigned)Al x (unsigned)B
 256 add r6,r1 ; accumulate result
 257 adc r7,r14 ; r14 is cleared above
 258 
 259 ;compare current distance to fade distance
 260 cp r0,r16 ; compare current distance to scaled fade distance
 261 cpc r6,r17
 262 cpc r7,r18
 263 brsh initialize_000058 ; initialize counters if within fade distance
 264 rjmp adcsample_000058 ; else finish off
 265 
 266 initialize_000058: ; initialize crossfade registers
 267 
 268 clr r26 ; initialize crossfade counter
 269 clr r27
 270 sts mem_000058,r26 ; initialize opposing buffer address
 271 sts (mem_000058 + 1),r27
 272 sts (mem_000058 + 2),r21
 273 subi r26,stepsize_000058 ; prepare crossfade counter for next cycle
 274 sbc r27,r14 ; r14 is cleared above
 275 ldi r20,$01 ; set crossfade indicator
 276 
 277 crossfade_000058: ; crossfade across sample boundary
 278 
 279 lds r16,mem_000058 ; fetch opposing buffer address
 280 lds r17,(mem_000058 + 1)
 281 lds r18,(mem_000058 + 2)
 282 add r18,r12 ; add in playback speed
 283 adc r16,r13
 284 adc r17,r14 ; r14 is cleared above
 285 sts mem_000058,r16 ; re-store opposing buffer address
 286 sts (mem_000058 + 1),r17
 287 sts (mem_000058 + 2),r18
 288 
 289 ;get left channel sample 3 data from sram
 290 ldi r19,$04
 291 out portg,r19 ; pull ce low, we high, and set high bits of register
 292 out portd,r16 ; set address
 293 sts porth,r17
 294 nop ; wait input latch time of 2 clock cycles
 295 nop
 296 in r2,pina ; get data
 297 in r3,pinc ; get data
 298 
 299 ;increment read address to next sample
 300 ldi r19,$01 ; increment read address to next sample
 301 add r16,r19
 302 adc r17,r14 ; r14 is cleared above
 303 
 304 ;get left channel sample 4 data from sram
 305 ;ldi r19,$04 ; portg already set above
 306 ;out portg,r19 ; pull ce low, we high, and set high bits of register
 307 out portd,r16 ; set address
 308 sts porth,r17
 309 nop ; wait input latch time of 2 clock cycles
 310 nop
 311 in r16,pina ; get data
 312 in r17,pinc ; get data
 313 
 314 ;multiply sample 4 by distance
 315 mulsu r17,r18 ; (signed)Ah * (unsigned)B
 316 movw r7:r6,r1:r0
 317 mul	r16,r18	; (unsigned)Al * (unsigned)B
 318 add	r6,r1 ; accumulate result
 319 adc	r7,r14 ; r14 is cleared above
 320 mov r19,r0
 321 
 322 ;multiply sample 3 by distance
 323 com r18 ; get distance from sample 3
 324 movw r17:r16,r3:r2 ; move sample to multiply register
 325 mulsu r17,r18 ; (signed)Ah * (unsigned)B
 326 add r6,r0 ; accumulate result
 327 adc r7,r1
 328 mul	r16,r18	; (unsigned)Al * (unsigned)B
 329 add	r19,r0 ; accumulate result
 330 adc r6,r1
 331 adc	r7,r14 ; r14 is cleared above
 332 
 333 ;add samples 1/2 and 3/4 together
 334 ;multiply sample 1/2
 335 movw r17:r16,r5:r4 ; move sample 1/2 to signed multiply register
 336 movw r19:r18,r27:r26 ; move fade distance to multiply register
 337 mulsu r17,r19 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 338 movw r5:r4,r1:r0 ; store high bytes result for later
 339 mul	r16,r18	; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 340 movw r3:r2,r1:r0 ; store low byets for later
 341 mulsu r17,r18 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 342 sbc	r5,r14 ; r14 is cleared above - subtract sign bit
 343 add	r3,r0 ; accumulate result
 344 adc	r4,r1
 345 adc	r5,r14 ; r14 is cleared above
 346 mul r19,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 347 add	r3,r0 ; accumulate result
 348 adc	r4,r1
 349 adc	r5,r14 ; r14 is cleared above
 350 
 351 ;multiply and accumulate sample 3/4
 352 movw r17:r16,r7:r6 ; move data to signed multiply register
 353 movw r19:r18,r27:r26 ; move fade distance to multiply register
 354 com r18 ; invert distance for sample 2
 355 com r19
 356 mulsu r17,r19 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 357 add r4,r0 ; accumulate result
 358 adc r5,r1
 359 mul	r16,r18	; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 360 add r2,r0 ; accumulate result
 361 adc r3,r1
 362 adc r4,r14
 363 adc r5,r14
 364 mulsu r17,r18 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 365 sbc	r5,r14 ; r14 is cleared above - subtract sign bit
 366 add	r3,r0 ; accumulate result
 367 adc	r4,r1
 368 adc	r5,r14 ; r14 is cleared above
 369 mul r19,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 370 add	r3,r0 ; accumulate result
 371 adc	r4,r1
 372 adc	r5,r14 ; r14 is cleared above
 373 
 374 ;check if done crossfading
 375 subi r26,stepsize_000058 ; reduce crossfade counter
 376 sbc r27,r14 ; r14 is cleared above
 377 breq fadedone_000058 ; reset if crossfade over
 378 brcs fadedone_000058 ; reset if crossfade over
 379 rjmp adcsample_000058 ; else finish off
 380 
 381 fadedone_000058: ; turn off crossfade
 382 
 383 lds r28,mem_000058 ; set new buffer read address
 384 lds r29,(mem_000058 + 1)
 385 lds r21,(mem_000058 + 2)
 386 clr r23
 387 clr r20 ; reset crossfade indicator
 388 
 389 adcsample_000058: ; get speed settings
 390 
 391 lds r17,adcsra ; get adc control register
 392 sbrs r17,adif ; check if adc conversion is complete
 393 rjmp done_000058 ; skip adc sampling
 394 lds r16,adcl ; get low byte adc value
 395 lds r17,adch ; get high byte adc value
 396 add r9,r16 ; accumulate adc samples
 397 adc r10,r17
 398 adc r11,r14 ; r14 is cleared above
 399 ldi r17,$f7
 400 sts adcsra,r17 ; clear interrupt flag
 401 dec r15 ; countdown adc sample clock
 402 brne switchsample_000058 ; get adc value if its been long enough
 403 lsr r11 ; divide accumulated value by 2
 404 ror r10
 405 ror r9
 406 ldi r17,$40 ; place in offset
 407 add r10,r17
 408 adc r11,r14 ; r14 is cleared above
 409 
 410 ;check for deadband
 411 movw r17:r16,r11:r10 ; move adc sample to temporary register
 412 mov r18,r9
 413 sub r18,r8
 414 sbc r16,r12 ; find difference between adc sample and playback speed
 415 sbc r17,r13
 416 brsh check_000058 ; check for deadband if positive
 417 com r18 ; invert if negative
 418 com r16 ; only 1 lsb error with ones complement
 419 com r17
 420 
 421 check_000058: ; check if difference is greater than deadband
 422 
 423 cpi r18,$80 ; check if difference is less than 1 lsb
 424 cpc r16,r14
 425 cpc r17,r14 ; r14 cleared above
 426 brlo empty_000058 ; do nothing if less than $02
 427 movw r13:r12,r11:r10 ; move adc sample to playback speed
 428 mov r8,r9 ; if large enough change
 429 
 430 empty_000058: ; empty accumulation registers and finish off
 431 
 432 clr r9 ; empty accumulation registers
 433 clr r10
 434 clr r11
 435 
 436 switchsample_000058: ;check switch
 437 
 438 lds r16,pinj ; get switch data
 439 andi r16,$78 ; mask off rotary switch
 440 lsr r16 ; adjust switch position to program memory location
 441 lsr r16
 442 subi r16,$fe ; same as adding $02
 443 cpse r16,r31 ; check if location has changed
 444 clr r30 ; reset jump register to intial state
 445 mov r31,r16
 446 
 447 done_000058:
 448 
 449 reti ; return to waiting
 450 

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.