welcome: please sign in
location: attachment:pitchshifter_chromatic.asm of PitchShifterChromatic

Attachment 'pitchshifter_chromatic.asm'

Download

   1 ; program: pitch_shifter-16b-fading.asm
   2 ; UID = 000039 - this is a unique id so variables dont conflict
   3 ; 16b address space (1.5s sample time)
   4 ; mono data in on left channel, mono out on both left and right
   5 ; rotary encoder (MOD2) controlled playback speed
   6 ; pot (MOD1) controlled buffer size
   7 
   8 ; program overview
   9 ;
  10 ; data is sent out and taken in from the codec.  data is taken in on the
  11 ; left channel, and played out on both left and right.  a buffer of the
  12 ; past n seconds is kept and the output is the result of sampling this
  13 ; buffer at varying playback speeds. the speed at which it plays through
  14 ; the memory is controlled by the rotary encoder (MOD2).  turning the
  15 ; encoder to the right speeds playback up, and turning it the left slows
  16 ; playback down.  this playback speed is limited to chromatic steps by
  17 ; using a lookup table in program memory to determine playback speed.  the
  18 ; audio is kept clean over fractional sample periods by interpolating
  19 ; between the two closest samples.  the output is a mix of the current
  20 ; sample, and a sample from the opposite side of the buffer, with the
  21 ; relative mix being determined by the distance to the buffer boundary.
  22 ; in this way, the audio is faded down as it crosses the buffer boundary.
  23 ; the pot (MOD1) controls the buffer size.  the adc samples the pot 256
  24 ; times and deadbands the signal to remove glitches.
  25 
  26 ; constant definitions
  27 ;
  28 .equ buffer_min_000039 = $0200 ; minimum buffer size
  29 .equ delay_mem_000039 = $0200 ; memory position for desired delay time
  30 ;
  31 ;.equ step-12_000039 = $0080 ; these are the playback speeds used
  32 ;.equ step-11_000039 = $0088 ; they are stored in program memory
  33 ;.equ step-10_000039 = $0090 ; and not used here
  34 ;.equ step-9_000039 = $0098
  35 ;.equ step-8_000039 = $00A1
  36 ;.equ step-7_000039 = $00AB
  37 ;.equ step-6_000039 = $00B5
  38 ;.equ step-5_000039 = $00C0
  39 ;.equ step-4_000039 = $00CB
  40 ;.equ step-3_000039 = $00D7
  41 ;.equ step-2_000039 = $00E4
  42 ;.equ step-1_000039 = $00F2
  43 ;.equ step00_000039 = $0100
  44 ;.equ step01_000039 = $010F
  45 ;.equ step02_000039 = $011F
  46 ;.equ step03_000039 = $0130
  47 ;.equ step04_000039 = $0143
  48 ;.equ step05_000039 = $0156
  49 ;.equ step06_000039 = $016A
  50 ;.equ step07_000039 = $0180
  51 ;.equ step08_000039 = $0196
  52 ;.equ step09_000039 = $01AF
  53 ;.equ step10_000039 = $01C8
  54 ;.equ step11_000039 = $01E3
  55 ;.equ step12_000039 = $0200
  56 
  57 ; register usage - may be redefined in other sections
  58 ;
  59 ; r0  multiply result lsb
  60 ; r1  multiply result msb
  61 ; r2  sample 3/4 lsb
  62 ; r3  sample 3/4 msb
  63 ; r4  left/right lsb out
  64 ; r5  left/right msb out
  65 ; r6  left lsb in/temporary swap register
  66 ; r7  left msb in/temporary swap register
  67 ; r8  rotary encoder position counter
  68 ; r9  adc msb accumulator
  69 ; r10 adc fractional byte accumulator
  70 ; r11 adc lsb accumulator
  71 ; r12 playback speed increment lsb value ($0100 is normal speed)
  72 ; r13 playback speed increment msb value
  73 ; r14 rotary encoder counter
  74 ; r15 switch\adc counter
  75 ; r16 temporary swap register
  76 ; r17 temporary swap register
  77 ; r18 signed multiply register
  78 ; r19 signed multiply register
  79 ; r20 unsigned multiply register
  80 ; r21 unsigned multiply register
  81 ; r22 write address third byte/null register
  82 ; r23 read address fractional byte
  83 ; r24 write address lsb
  84 ; r25 write address msb
  85 ; r26 buffer length lsb
  86 ; r27 buffer length msb
  87 ; r28 read address lsb
  88 ; r29 read address msb
  89 ; r30 jump location for interrupt lsb
  90 ; r31 jump location for interrupt msb
  91 ; t   rotary encoder edge indicator
  92 
  93 ;program starts here first time
  94 ; intialize registers
  95 ldi r30,$29 ; set jump location to program start
  96 clr r24 ; clear write register
  97 clr r25
  98 ldi r22,$00 ; setup write address high byte
  99 clr r18 ; setup r18 as null register for carry addition and ddr setting
 100 ldi r17,$ff ; setup r17 for ddr setting
 101 
 102 clear_000039: ; clear delay buffer
 103 ; eliminates static when first switching to the delay setting
 104 
 105 adiw r25:r24,$01 ; increment write register
 106 adc r22,r18 ; increment write third byte
 107 cpi r22,$01 ; check if 16b memory space has been cleared
 108 breq cleardone_000039 ; continue until end of buffer reached
 109 out portd,r24 ; set address
 110 sts porth,r25
 111 out portg,r22 ; pull ce low,we low,and set high bits of address
 112 out ddra,r17 ; set porta as output for data write
 113 out ddrc,r17 ; set portc as output for data write
 114 out porta,r18 ; set data
 115 out portc,r18 ; r18 is cleared above
 116 sbi portg,portg2 ; pull we high to write
 117 out ddra,r18 ; set porta as input for data lines
 118 out ddrc,r18 ; set portc as input for data lines
 119 rjmp clear_000039 ; continue clearing
 120 
 121 cleardone_000039: ; reset registers
 122 
 123 ldi r24,$00 ; initialize write register
 124 ldi r25,$00
 125 clr r22 ; setup null register
 126 ldi r28,$00 ; set read address to minimum delay
 127 ldi r29,$fd
 128 clr r4 ; initialize data output registers
 129 clr r5
 130 ldi r26,$00 ; initialize buffer size
 131 ldi r27,$06
 132 sts delay_mem_000039,r26 ; store desired buffer size
 133 sts (delay_mem_000039 + 1),r27 ; i ran out of registers
 134 clr r12 ; initialize playback speed
 135 ldi r16,$01
 136 mov r13,r16
 137 ldi r16,$0c ; initialize playback speed pointer
 138 mov r8,r16
 139 reti ; return and wait for next interrupt
 140 
 141 ;program begins here every time but first
 142 ; initiate data transfer to codec
 143 sbi portb,portb0 ; toggle slave select pin
 144 out spdr,r5 ; send out left channel msb
 145 cbi portb,portb0
 146 
 147 ;increment write address
 148 adiw r25:r24,$01 ; increment write address
 149 cp r24,r26 ; check if at end of buffer
 150 cpc r25,r27
 151 brlo wait1_000039 ; do nothing if not at end of buffer
 152 clr r24 ; reset buffer to bottom
 153 clr r25
 154 
 155 wait1_000039: ; check if byte has been sent
 156 
 157 in r17,spsr
 158 sbrs r17,spif
 159 rjmp wait1_000039
 160 in r7,spdr ; recieve in left channel msb
 161 out spdr,r4 ; send out left channel lsb
 162 
 163 ;increment read address
 164 add r23,r12 ; increment read register
 165 adc r28,r13
 166 adc r29,r22 ; r22 is cleared above
 167 cp r28,r26 ; check if at end of buffer
 168 cpc r29,r27
 169 brlo wait2_000039 ; do nothing if not at end of buffer
 170 clr r28 ; reset buffer to bottom
 171 clr r29
 172 
 173 wait2_000039: ; check if byte has been sent
 174 
 175 in r17,spsr
 176 sbrs r17,spif
 177 rjmp wait2_000039
 178 in r6,spdr ; recieve in left channel lsb
 179 out spdr,r5 ; send out right channel msb
 180 
 181 ;write left channel data to sram
 182 out portd,r24 ; set address
 183 sts porth,r25
 184 out portg,r22 ; pull ce low,we low,and set high bits of address
 185 ldi r17,$ff
 186 out ddra,r17 ; set porta as output for data write
 187 out ddrc,r17 ; set portc as output for data write
 188 out porta,r6 ; set data
 189 out portc,r7
 190 sbi portg,portg2 ; pull we high to write
 191 out ddra,r22 ; set porta as input for data lines
 192 out ddrc,r22 ; set portc as input for data lines
 193 
 194 wait3_000039: ; check if byte has been sent
 195 
 196 in r17,spsr
 197 sbrs r17,spif
 198 rjmp wait3_000039
 199 in r17,spdr ; recieve in right channel msb
 200 out spdr,r4 ; send out right channel lsb
 201 
 202 ;get left channel sample 1 data from sram
 203 movw r17:r16,r29:r28 ; move read address to temporary register
 204 out portd,r16 ; set address
 205 sts porth,r17
 206 ldi r21,$01 ; increment read address
 207 add r16,r21 ; placed here to use 2 cycle wait
 208 adc r17,r22 ; r22 is cleared above
 209 in r6,pina ; get data
 210 in r18,pinc ; get data
 211 cp r16,r26 ; check if at end of buffer
 212 cpc r17,r27
 213 brlo wait4_000039 ; do nothing if not at end of buffer
 214 clr r16 ; reset buffer to bottom
 215 clr r17
 216 
 217 wait4_000039: ; check if byte has been sent
 218 
 219 in r19,spsr
 220 sbrs r19,spif
 221 rjmp wait4_000039
 222 in r19,spdr ; recieve in right channel lsb
 223 
 224 ;get left channel sample 2 data from sram
 225 out portd,r16 ; set address
 226 sts porth,r17
 227 nop ; wait 2 cycle setup time
 228 nop
 229 in r7,pina ; get data
 230 in r19,pinc ; get data
 231 
 232 ;multiply sample 1 by distance
 233 mov r20,r23 ; get distance from sample 1
 234 com r20
 235 mulsu r18,r20 ; (signed)Ah * (unsigned)B
 236 movw r5:r4,r1:r0
 237 mul	r6,r20	; (unsigned)Al * (unsigned)B
 238 add	r4,r1
 239 adc	r5,r22 ; r22 is cleared above
 240 mov r17,r0
 241 
 242 ;multiply and accumulate sample 2 by distance
 243 mulsu r19,r23 ; (signed)Ah * (unsigned)B
 244 add r4,r0 ; accumulate result
 245 adc r5,r1
 246 mul	r7,r23	; (unsigned)Al * (unsigned)B
 247 add r17,r0 ; accumulate result
 248 adc	r4,r1
 249 adc	r5,r22 ; r22 is cleared above
 250 
 251 ;get sample from other side of buffer
 252 movw r17:r16,r29:r28 ; move current position to temporary register
 253 movw r7:r6,r27:r26 ; move buffer size to temporary register
 254 lsr r7 ; divide buffer size by 2
 255 ror r6
 256 cp r16,r6 ; check if in lower or upper half of buffer
 257 cpc r17,r7
 258 brsh buffer_flip_000039 ; subtract half buffer if in upper half
 259 add r16,r6 ; add half buffer size if in lower half
 260 adc r17,r7
 261 rjmp getsample3_000039 ; continue
 262 
 263 buffer_flip_000039: ; adjust to opposite side of memory
 264 
 265 sub r16,r6 ; subtract half buffer size if in upper half
 266 sbc r17,r7
 267 
 268 getsample3_000039: ;get left channel sample 3 data from sram
 269 
 270 out portd,r16 ; set address
 271 sts porth,r17
 272 add r16,r21 ; increment read address - r21 set to $01 above
 273 adc r17,r22 ; r22 is cleared above
 274 in r6,pina ; get data
 275 in r18,pinc ; get data
 276 cp r16,r26 ; check if at end of buffer
 277 cpc r17,r27
 278 brlo getsample4_000039 ; do nothing if not at end of buffer
 279 clr r16 ; reset buffer to bottom
 280 clr r17
 281 
 282 getsample4_000039: ;get left channel sample 4 data from sram
 283 
 284 out portd,r16 ; set address
 285 sts porth,r17
 286 nop ; wait 2 cycle setup time
 287 nop
 288 in r7,pina ; get data
 289 in r19,pinc ; get data
 290 
 291 ;multiply sample 3 by distance
 292 mulsu r18,r20 ; (signed)ah * b
 293 movw r3:r2,r1:r0
 294 mul	r6,r20 ; al * b
 295 add	r2,r1
 296 adc	r3,r22 ; r22 is cleared above
 297 mov r17,r0
 298 
 299 ;multiply sample 4 by distance
 300 mulsu r19,r23 ; (signed)ah * b
 301 add r2,r0 ; accumulate result
 302 adc r3,r1
 303 mul	r7,r23	; al * b
 304 add r17,r0 ; accumulate result
 305 adc	r2,r1
 306 adc	r3,r22 ; r22 is cleared above
 307 
 308 ;get distance to boundary
 309 movw r17:r16,r29:r28 ; move read address to temporary register
 310 mov r18,r23
 311 sub r16,r24 ; find distance to loop boundary
 312 sbc r17,r25
 313 brcc half_000039 ; check if result is negative
 314 com r16 ; invert distance if negative
 315 com r17
 316 com r18
 317 add r18,r21 ; r21 set to $01 above
 318 adc r16,r22 ; r22 cleared above
 319 adc r17,r22
 320 
 321 half_000039: ; check if result is greater than half the buffer size
 322 
 323 movw r7:r6,r27:r26 ; move buffer size to temporary register
 324 lsr r7 ; divide buffer size by 2
 325 ror r6
 326 cp r16,r6 ; check if result is greater than half the buffer size
 327 cpc r17,r7
 328 brlo scale_000039 ; skip flip if not
 329 sub r16,r26 ; flip result around boundary
 330 sbc r17,r27
 331 com r16
 332 com r17
 333 com r18
 334 add r18,r21 ; r21 set to $01 above
 335 adc r16,r22
 336 adc r17,r22
 337 
 338 scale_000039: ; scale distance to match buffer size - 50% accurate
 339 
 340 movw r7:r6,r27:r26 ; move buffer size to temporary register
 341 sbrc r7,$07 ; check if msb of buffer size is set
 342 rjmp attenuate_000039 ; attenuate signal if 16b value
 343 
 344 shift_000039: ; shift buffer size till it occupies full 16b
 345 
 346 lsl r6 ; multiply buffer size by 2
 347 rol r7
 348 lsl r18 ; multiply distance by 2
 349 rol r16
 350 rol r17
 351 sbrs r7,$07 ; check if msb of buffer size is set
 352 rjmp shift_000039 ; keep checking if not set
 353 
 354 attenuate_000039: ; multiply sample 1/2 by distance
 355 
 356 lsl r18 ; multiply distance by 2 since max value is 1/2 buffer size
 357 rol r16
 358 rol r17
 359 sub r6,r16 ; find complementary distance of sample 3/4
 360 sbc r7,r17 ; only 1 bit error for not subtracting r18 as well
 361 movw r21:r20,r7:r6 ; move distance to signed multiply register
 362 movw r19:r18,r5:r4 ; move value to signed multiply register
 363 mulsu r19,r17 ; (signed)ah * bh
 364 movw r5:r4,r1:r0
 365 mul	r18,r16	; al * bl
 366 movw r7:r6,r1:r0
 367 mulsu r19,r16 ; (signed)ah * bl
 368 sbc	r5,r22 ; r22 is cleared above
 369 add	r7,r0
 370 adc	r4,r1
 371 adc	r5,r22
 372 mul r17,r18 ; bh * al
 373 add	r7,r0
 374 adc	r4,r1
 375 adc	r5,r22
 376 
 377 ;multiply and accumulate sample 3/4 with result from above
 378 movw r19:r18,r3:r2 ; move value to signed multiply register
 379 mulsu r19,r21 ; (signed)ah * bh
 380 add	r4,r0 ; accumulate result
 381 adc	r5,r1
 382 mul	r18,r20 ; al * bl
 383 add	r6,r0 ; accumulate result
 384 adc	r7,r1
 385 adc	r4,r22 ; r22 is cleared above
 386 adc	r5,r22
 387 mulsu r19,r20 ; (signed)ah * bl
 388 sbc	r5,r22 ; accumulate result
 389 add	r7,r0
 390 adc	r4,r1
 391 adc	r5,r22
 392 mul r21,r18 ; bh * al
 393 add	r7,r0
 394 adc	r4,r1
 395 adc	r5,r22
 396 
 397 rotary_000039: ; check rotary encoder and adjust playback rate
 398 ; rotary encoder is externally debounced, so that is not done here.
 399 ; pin1 is sampled on a transition from high to low on pin0.  if pin1 is
 400 ; high, a left turn occured, if pin1 is low, a right turn occured.
 401 dec r14 ; reduce the sampling rate to help with debounce
 402 brne check_000039 ; continue if not ready yet
 403 ldi r17,$40 ; adjust sample frequency to catch all rising edges (1.5ms)
 404 mov r14,r17
 405 lds r17,pinj ; get switch data
 406 sbrs r17,$00 ; check if pin0 is low
 407 rjmp edge_000039 ; check if pin0 was low on previous sample
 408 clt ;  clear state register if back high
 409 rjmp check_000039 ; finish off
 410 
 411 edge_000039: ; check for falling edge
 412 
 413 brts check_000039 ; do nothing if the edge was already detected
 414 set ; set state register to indicate a falling edge occured
 415 sbrs r17,$01 ; check if pin1 is high
 416 rjmp increment_000039 ; increment playback if right rotation
 417 ldi r16,$01 ; check if pitch at min
 418 cp r8,r16
 419 brlo check_000039 ; do nothing it at bottom
 420 dec r8 ; decrement rotary encoder position counter
 421 movw r17:r16,z ; store z register
 422 ldi zh,$4c ; setup z pointer to fetch tone from lookup table
 423 mov zl,r8
 424 lsl zl
 425 lpm r12,z+ ; move tone to pitch register
 426 lpm r13,z
 427 movw z,r17:r16 ; restore z register
 428 rjmp check_000039 ; finish off
 429 
 430 increment_000039: ; increment playback speed
 431 
 432 ldi r16,$18 ; check if pitch at max
 433 cp r8,r16
 434 brsh reset1_000039 ; do nothing if at max already
 435 inc r8 ; increment rotary encoder position counter
 436 movw r17:r16,z ; store z register
 437 ldi zh,$4c ; setup z pointer to fetch tone from lookup table
 438 mov zl,r8
 439 lsl zl
 440 lpm r12,z+ ; move tone to pitch register
 441 lpm r13,z
 442 movw z,r17:r16 ; restore z register
 443 rjmp check_000039 ; finish off
 444 
 445 reset1_000039: ; reset tone register in case it goes too high
 446 
 447 mov r8,r16 ; set tone register to max
 448 
 449 check_000039: ; check if buffer size is correct
 450 
 451 lds r16,delay_mem_000039 ; fetch desired buffer size
 452 lds r17,(delay_mem_000039 + 1) ; i ran out of registers
 453 cp r26,r16 ; compare current delay to desired delay
 454 cpc r27,r17
 455 brlo upcount_000039 ; increment if smaller than
 456 breq adcsample_000039 ; do nothing if they are same size
 457 sbiw r27:r26,$02 ; decrement buffer size
 458 rjmp adcsample_000039 ; finish off
 459 
 460 upcount_000039: ; increment buffer size register
 461 
 462 adiw r27:r26,$02 ; increment buffer size
 463 
 464 adcsample_000039: ; get loop setting
 465 
 466 lds r17,adcsra ; get adc control register
 467 sbrs r17,adif ; check if adc conversion is complete
 468 rjmp done_000039 ; skip adc sampling
 469 lds r16,adcl ; get low byte adc value
 470 lds r17,adch ; get high byte adc value
 471 add r10,r16 ; accumulate adc samples
 472 adc r11,r17
 473 adc r9,r22 ; r22 is cleared above
 474 ldi r17,$f7
 475 sts adcsra,r17 ; clear interrupt flag
 476 dec r15 ; countdown adc sample clock
 477 brne done_000039 ; move adc value to loop setting after 256 samples
 478 lsr r9 ; divide accumulated value by 4 to make a 16b value
 479 ror r11
 480 ror r10
 481 lsr r9
 482 ror r11
 483 ror r10
 484 ldi r16,low(buffer_min_000039) ; fetch min buffer size
 485 ldi r17,high(buffer_min_000039)
 486 cp r10,r16 ; compare adc value to min buffer size
 487 cpc r11,r17
 488 brsh compare_000039 ; skip if above minimum buffer size
 489 movw r11:r10,r17:r16 ; else set to minimum buffer size
 490 
 491 compare_000039: ; compare to previous value
 492 
 493 lds r16,delay_mem_000039 ; fetch desired delay time
 494 lds r17,(delay_mem_000039 + 1) ; i ran out of registers
 495 sub r16,r10 ; find difference between adc value and desired buffer size
 496 sbc r17,r11
 497 brcc deadband_000039 ; check for magnitude of change if positive
 498 neg r16 ; else invert difference if negative
 499 adc r17,r22 ; r22 is cleared above
 500 neg r17
 501 
 502 deadband_000039: ; see if pot has moved or if its just noise
 503 
 504 cpi r16,$40 ; see if difference is greater than 1 lsb
 505 cpc r17,r22 ; r22 is cleared above
 506 brlo nochange_000039 ; dont update loop time if difference is not large enough
 507 ldi r16,$fe ; make sure buffer size is even
 508 and r10,r16
 509 sts delay_mem_000039,r10 ; store new desired buffer size
 510 sts (delay_mem_000039 + 1),r11 ; i ran out of registers
 511 
 512 nochange_000039: ; clear accumulation registers
 513 
 514 clr r10 ; empty accumulation registers
 515 clr r11
 516 clr r9
 517 
 518 switchsample_000039: ; check rotary switch state
 519 
 520 lds r16,pinj ; get switch data
 521 andi r16,$78 ; mask off rotary switch
 522 lsr r16 ; adjust switch position to program memory location
 523 lsr r16
 524 ldi r17,$02
 525 add r16,r17
 526 cpse r16,r31 ; check if location has changed
 527 clr r30 ; reset jump register to intial state
 528 mov r31,r16
 529 
 530 done_000039:
 531 
 532 reti ; return to waiting
 533 

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.