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.