welcome: please sign in
location: attachment:tremolo_stereo.asm of TremoloStereo

Attachment 'tremolo_stereo.asm'

Download

   1 ; program: tremolo-stereo.asm
   2 ; UID = 000057 - unique id to eliminate conflicts between variables
   3 ; memory is not used
   4 ; stereo in and out
   5 ; pot (MOD1) controls the lfo frequency
   6 ; pushbutton (on MOD2) controls phase between left and right output
   7 
   8 ; program overview
   9 ;
  10 ; data is read in from the codec, and multiplied by an lfo that is internally
  11 ; generated using a 512s/16b sinewave lookup table.  the frequency of this
  12 ; lfo is determined by the adc input, which is oversampled 256 times and
  13 ; compared to the previous value with a deadband.  this helps reduce jitter.
  14 ; the left and right channels are mutiplied by opposite signals, so the
  15 ; sound bounces back and forth between left and right.  depressing the
  16 ; pushbutton (on MOD2) changes this so that the left and right are in phase.
  17 
  18 ; register usage - may be redefined in other sections
  19 ;
  20 ; r0  multiply result lsb
  21 ; r1  multiply result msb
  22 ; r2  accumulation lsb
  23 ; r3  accumulation mlb
  24 ; r4  left lsb out/accumulation mhb
  25 ; r5  left msb out/accumulation msb
  26 ; r6  right in/out lsb
  27 ; r7  right in/out msb
  28 ; r8  adc accumulator fractional byte
  29 ; r9  adc accumulator lsb
  30 ; r10 adc accumulator msb
  31 ; r11 lfo control signal fractional byte
  32 ; r12 lfo control signal lsb
  33 ; r13 lfo control signal msb
  34 ; r14 null register
  35 ; r15 switch/adc sample counter
  36 ; r16 temporary swap register
  37 ; r17 temporary swap register
  38 ; r18 sine wave buffer/multiply lsb
  39 ; r19 sine wave buffer/multiply msb
  40 ; r20 multiply swap register
  41 ; r21 multiply swap register
  42 ; r22 sinetable lookup address lsb
  43 ; r23 sinetable lookup address mlb
  44 ; r24 left data in lsb
  45 ; r25 left data in msb
  46 ; r26 sinetable lookup address mhb
  47 ; r27 sinetable lookup address msb
  48 ; r28 phase indicator
  49 ; r29 
  50 ; r30 jump location for interrupt lsb
  51 ; r31 jump location for interrupt msb
  52 ; t   pushbutton state indicator
  53 
  54 ;program starts here first time
  55 ; intialize registers
  56 ldi r30,$07 ; increment z pointer to new jump location
  57 clr r14 ; clear null register
  58 ldi r16,$10 ; initialize lfo rate
  59 ldi r17,$00
  60 movw r13:r12,r17:r16 ;  move to lfo rate register
  61 clr r28 ; initialize phase mode register
  62 reti ; finish with initialization and wait for next interrupt
  63 
  64 ;program starts here every time but first
  65 ; initiate data transfer to codec
  66 sbi portb,portb0 ; toggle slave select pin
  67 out spdr,r5 ; send out left channel msb
  68 cbi portb,portb0
  69 
  70 wait1_000057: ; check if byte has been sent
  71 
  72 in r17,spsr
  73 sbrs r17,spif
  74 rjmp wait1_000057
  75 in r25,spdr ; recieve in left channel msb
  76 out spdr,r4 ; send out left channel lsb
  77 
  78 wait2_000057: ; check if byte has been sent
  79 
  80 in r17,spsr
  81 sbrs r17,spif
  82 rjmp wait2_000057
  83 in r24,spdr ; recieve in left channel lsb
  84 out spdr,r7 ; send out right channel msb
  85 
  86 wait3_000057: ; check if byte has been sent
  87 
  88 in r17,spsr
  89 sbrs r17,spif
  90 rjmp wait3_000057
  91 in r7,spdr ; recieve in right channel msb
  92 out spdr,r6 ; send out right channel lsb
  93 
  94 wait4_000057: ; check if byte has been sent
  95 
  96 in r17,spsr
  97 sbrs r17,spif
  98 rjmp wait4_000057
  99 in r6,spdr ; recieve in right channel lsb
 100 
 101 ;vco generation
 102 movw r17:r16,r31:r30 ; store z register
 103 ;get sample 1
 104 add r22,r11 ; increment sinetable address
 105 adc r23,r12
 106 adc r26,r13
 107 adc r27,r14 ; r14 is cleared above
 108 movw r31:r30,r27:r26 ; move to z register for data fetch
 109 lsl r30 ; adjust pointer for 16b fetch
 110 rol r31
 111 andi r31,$03 ; limit value to 10b (512 samples x 2 bytes)
 112 ori r31,$48 ; set to memory address location where table is stored
 113 lpm r18,z+ ; get sine value lsb, increment z register
 114 lpm r19,z ; get sine value msb
 115 sbrc r27,$01 ; flip sign for half of the values
 116 rjmp interpolate_000057 ; interpolate if even
 117 neg r18 ; invert if odd
 118 adc r19,r14 ; r14 is cleared above
 119 neg r19
 120 
 121 interpolate_000057: ; multiply sample 1 by distance
 122 
 123 movw r21:r20,r23:r22 ; get distance from sample 1
 124 com r20 ; invert distance
 125 com r21
 126 mulsu r19,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 127 movw r5:r4,r1:r0 ; store high bytes result for later
 128 mul	r18,r20	; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 129 movw r3:r2,r1:r0 ; store low byets for later
 130 mulsu r19,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 131 sbc	r5,r14 ; r14 is cleared above - subtract sign bit
 132 add	r3,r0 ; accumulate result
 133 adc	r4,r1
 134 adc	r5,r14 ; r14 is cleared above
 135 mul r21,r18 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 136 add	r3,r0 ; accumulate result
 137 adc	r4,r1
 138 adc	r5,r14 ; r14 is cleared above
 139 
 140 ;get sample 2
 141 adiw r27:r26,$01 ; set to next sample
 142 movw r31:r30,r27:r26 ; move to z register for data fetch
 143 lsl r30 ; adjust pointer for 16b fetch
 144 rol r31
 145 andi r31,$03 ; limit value to 10b (512 samples x 2 bytes)
 146 ori r31,$48 ; set to memory address location where table is stored
 147 lpm r18,z+ ; get sine value lsb, increment z register
 148 lpm r19,z ; get sine value msb
 149 sbrc r27,$01 ; flip sign for half of the values
 150 rjmp interpolate1_000057
 151 neg r18
 152 adc r19,r14 ; r14 is cleared above
 153 neg r19
 154 
 155 interpolate1_000057: ; multiply sample 2 by distance and accumulate
 156 
 157 sbiw r27:r26,$01 ; reset address
 158 movw r31:r30,r17:r16 ; restore z register
 159 mulsu r19,r23 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 160 add r4,r0 ; accumulate result
 161 adc r5,r1
 162 mul	r18,r22	; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 163 add r2,r0 ; accumulate result
 164 adc r3,r1
 165 adc r4,r14 ; r14 is cleared above
 166 adc r5,r14
 167 mulsu r19,r22 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 168 sbc	r5,r14 ; r14 is cleared above - subtract sign bit
 169 add	r3,r0 ; accumulate result
 170 adc	r4,r1
 171 adc	r5,r14 ; r14 is cleared above
 172 mul r23,r18 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 173 add	r3,r0 ; accumulate result
 174 adc	r4,r1
 175 adc	r5,r14 ; r14 is cleared above
 176 
 177 ;add in offset so lfo is always positive
 178 ; (the difference between tremolo and ring modulation)
 179 ldi r16,$80 ; turn signed value to unsigned value
 180 add r5,r16
 181 
 182 ;multiply left data by lfo
 183 movw r21:r20,r5:r4 ; move lfo to multiply register
 184 movw r19:r18,r25:r24 ; move left data to multiply register
 185 mulsu r19,r21 ; (signed)ah * (unsigned)bh
 186 movw r5:r4,r1:r0
 187 mul	r18,r20	; (unsigned)al * (unsigned)bl
 188 movw r3:r2,r1:r0
 189 mulsu r19,r20 ; (signed)ah * (unsigned)bl
 190 sbc	r5,r14 ; r14 is cleared above
 191 add	r3,r0 ; accumulate result
 192 adc	r4,r1
 193 adc	r5,r14 ; r14 is cleared above
 194 mul r21,r18 ; (unsigned)bh * (unsigned)al
 195 add	r3,r0 ; accumulate result
 196 adc	r4,r1
 197 adc	r5,r14 ; r14 is cleared above
 198 
 199 ;check if in or out of phase mode
 200 sbrs r28,$00 ; check if phase inversion bit is set
 201 rjmp rightmultiply_000057 ; skip inversion if in phase
 202 com r20 ; else invert lfo signal
 203 com r21 ; ones complement used to avoid $0000 problem
 204 
 205 rightmultiply_000057: ; multiply right data by lfo
 206 
 207 movw r19:r18,r7:r6 ; move right data to multiply register
 208 mulsu r19,r21 ; (signed)ah * (unsigned)bh
 209 movw r7:r6,r1:r0
 210 mul	r18,r20	; (unsigned)al * (unsigned)bl
 211 movw r3:r2,r1:r0
 212 mulsu r19,r20 ; (signed)ah * (unsigned)bl
 213 sbc	r7,r14 ; r14 is cleared above
 214 add	r3,r0 ; accumulate result
 215 adc	r6,r1
 216 adc	r7,r14 ; r14 is cleared above
 217 mul r21,r18 ; (unsigned)bh * (unsigned)al
 218 add	r3,r0 ; accumulate result
 219 adc	r6,r1
 220 adc	r7,r14 ; r14 is cleared above
 221 
 222 adcsample_000057: ; sample adc for lfo rate
 223 
 224 lds r17,adcsra ; get adc control register
 225 sbrs r17,adif ; check if adc conversion is complete
 226 rjmp done_000057 ; skip adc sampling
 227 lds r16,adcl ; get low byte adc value
 228 lds r17,adch ; get high byte adc value
 229 add r8,r16 ; accumulate adc samples
 230 adc r9,r17
 231 adc r10,r14 ; r14 is cleared above
 232 ldi r17,$f7
 233 sts adcsra,r17 ; clear interrupt flag
 234 dec r15 ; countdown adc sample clock
 235 brne done_000057 ; get delay time if its been long enough
 236 lsr r10 ; divide adc value by 4 to make 16b value
 237 ror r9
 238 ror r8
 239 lsr r10
 240 ror r9
 241 ror r8
 242 movw r17:r16,r9:r8 ; move adc sample to temporary register
 243 clr r20
 244 ldi r21,$01 ; add in offset of min lfo rate ($000100)
 245 add r17,r21
 246 adc r20,r14 ; r14 is cleared above
 247 sub r16,r11 ; find difference between adc sample and current lfo rate
 248 sbc r17,r12
 249 sbc r20,r13
 250 brsh check_000057 ; check for deadband if positive
 251 com r16 ; else invert if negative
 252 com r17 ; only 1 lsb error doing it this way
 253 com r20
 254 
 255 check_000057: ; check if difference is greater than deadband
 256 
 257 cpi r16,$40 ; check if difference is less than 1 adc lsb
 258 cpc r17,r14 ; r14 cleared above
 259 cpc r20,r14
 260 brlo empty_000057 ; do nothing if less than 1 adc lsb
 261 mov r11,r8 ; else move to lfo rate register
 262 mov r12,r9
 263 mov r13,r10
 264 add r12,r21 ; add in offset
 265 adc r13,r14 ; r14 is cleared above
 266 
 267 empty_000057: ; empty accumulation registers and finish off
 268 
 269 clr r8 ; empty accumulation registers
 270 clr r9
 271 clr r10
 272 
 273 ;check if phase mode should change
 274 lds r16,pinj ; get switch data
 275 sbrs r16,$02 ; check if pushbutton is released
 276 rjmp edge_000057 ; check if pushbutton was low on previous sample
 277 clt ;  clear state register if back high
 278 rjmp switchsample_000057 ; finish off
 279 
 280 edge_000057: ; check for falling edge
 281 
 282 brts adcsample_000057 ; do nothing if edge was already detected
 283 set ; set t register to indicate edge detected
 284 ldi r17,$01 ; toggle phase inversion mode
 285 eor r28,r17
 286 
 287 switchsample_000057: ; check rotary switch for new function
 288 
 289 andi r16,$78 ; mask off rotary switch
 290 lsr r16 ; adjust switch position to program memory location
 291 lsr r16
 292 ldi r17,$02
 293 add r16,r17
 294 cpse r16,r31 ; check if location has changed
 295 clr r30 ; reset jump register to intial state
 296 mov r31,r16
 297 
 298 done_000057:
 299 
 300 reti ; return to waiting
 301 

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.