Attachment 'reverser_gated_delay.asm'
Download 1 ; program: reverser-18b-gated-delay.asm
2 ; UID = 000050 - unique id to eliminate conflicts between variables
3 ; 18b address space (3s sample time)
4 ; stereo data, in and out
5 ; pot (MOD1) controlled delay
6
7 ; program overview
8 ;
9 ; data is read in from memory and written out to the codec at the same time
10 ; new data is written to the memory from the codec. the left channel input
11 ; data is compared to a predetermined threshold level, and if it crosses
12 ; this level, the reverser function is initiated after a delay. the delay
13 ; is set via the adc reading from the pot (MOD1). this value is sampled
14 ; 256 times and deadbanded to reduce jitter. the codec passes data
15 ; through while in forward mode, and continues to do so for the delay
16 ; period after the input has crossed the threshold. after this time, the
17 ; input data is no longer written to memory, in order to increase the
18 ; available buffer size. the reverse data is played out back to the
19 ; beginning, plus a predetermined backtrack amount to catch the rising
20 ; edge of notes. at this point, the forward data saving is resumed, and
21 ; the reverse data is faded while the current data is faded in. this
22 ; crossfade size is determined via a constant at the beginning of the code.
23 ; there is also a holdoff time after the reverser function has finished,
24 ; before it can be retriggered, in order to reduce constant triggering and
25 ; glitches from not having enough forward data stored.
26
27 ; constant definitions
28 ;
29 .equ backtrack_000050 = $0800 ; past memory used as starting point
30 ; (must be even)
31 .equ holdoff_000050 = $0f00 ; holdoff before retriggering
32 ; must be larger than backtrack (must be even)
33 .equ stepsize_000050 = $0080 ; 65536/(stepsize * 44.1) = crossfade time (ms)
34 .equ threshold_000050 = $3900 ; threshold for turn on of reverser ($7fff max)
35 .equ minbuff_000050 = $02 ; minimum buffer time in multiples of 5.8ms
36 .equ maxbuff_000050 = ($03ff00 - (2 * ($010000 / stepsize_000050)) - holdoff_000050)
37 ; maximum buffer time to keep from overlapping
38 .equ mem_000050 = $0200 ; memory location for storage in internal sram
39
40 ; register usage - may be redefined in other sections
41 ;
42 ; r0 multiply result lsb
43 ; r1 multiply result msb
44 ; r2 left lsb out
45 ; r3 left msb out
46 ; r4 right lsb out
47 ; r5 right msb out
48 ; r6 left lsb in
49 ; r7 left msb in
50 ; r8 right lsb in
51 ; r9 right msb in
52 ; r10 adc accumulation lsb
53 ; r11 adc accumulation msb
54 ; r12 buffer bottom / crossfade lsb
55 ; r13 buffer bottom / crossfade msb
56 ; r14 adc accumulation fractional byte
57 ; r15 switch/adc sample counter
58 ; r16 temporary swap register
59 ; r17 temporary swap register
60 ; r18 null register
61 ; r19 reverse mode indicator
62 ; r20 temporary swap regiser
63 ; r21 buffer bottom third byte
64 ; r22 write address third byte
65 ; r23 read address third byte
66 ; r24 write address lsb
67 ; r25 write address msb
68 ; r26 desired buffer size lsb
69 ; r27 desired buffer size msb
70 ; r28 read address lsb
71 ; r29 read address msb
72 ; r30 jump location for interrupt lsb
73 ; r31 jump location for interrupt msb
74 ; t foward/reverse indicator
75
76 ; program starts here first time
77 ; initialze z pointer for correct jump
78 ; this assumes a less than 256 word jump
79 ldi r30,$23 ; set jump location to program start
80 clr r24 ; clear write register
81 clr r25
82 ldi r22,$00 ; setup write address high byte
83 clr r18 ; setup r18 as null register for carry addition and ddr setting
84 ldi r17,$ff ; setup r17 for ddr setting
85
86 clear_000050: ; clear delay buffer
87 ; eliminates static when first switching to the delay setting
88
89 adiw r25:r24,$01 ; increment write register
90 adc r22,r18 ; increment write third byte
91 cpi r22,$04 ; check if full memory space has been cleared
92 breq cleardone_000050 ; continue until end of buffer reached
93 out portd,r24 ; set address
94 sts porth,r25
95 out portg,r22 ; pull ce low,we low,and set high bits of address
96 out ddra,r17 ; set porta as output for data write
97 out ddrc,r17 ; set portc as output for data write
98 out porta,r18 ; set data
99 out portc,r18 ; r18 is cleared above
100 sbi portg,portg2 ; pull we high to write
101 out ddra,r18 ; set porta as input for data lines
102 out ddrc,r18 ; set portc as input for data lines
103 rjmp clear_000050 ; continue clearing
104
105 cleardone_000050: ; reset registers
106
107 ldi r24,$01 ; initialize write register
108 ldi r25,$00
109 ldi r22,$00 ; setup write address high byte
110 ldi r28,$01 ; set read address to minimum delay
111 ldi r29,$ff
112 ldi r23,$07 ; setup read address high byte
113 clr r19 ; initialize reverse mode register
114 clr r2 ; initialize data output registers
115 clr r3
116 clr r4
117 clr r5
118 clt ; clear t register to start with forward play
119 reti ; finish with initialization and wait for next interrupt
120
121 ; initiate data transfer to codec
122 ; this is the point the z-pointer is incremented to
123 ; program starts here all but first time
124 sbi portb,portb0 ; toggle slave select pin
125 out spdr,r3 ; send out left channel msb
126 cbi portb,portb0
127
128 ;increment write addresses
129 brts wait1_000050 ; dont write data to memory if reversing
130 adiw r25:r24,$01 ; increment write address
131 adc r22,r18 ; increment write third byte
132 andi r22,$03 ; mask off unsed bits
133
134 wait1_000050: ; check if byte has been sent
135
136 in r17,spsr
137 sbrs r17,spif
138 rjmp wait1_000050
139 in r7,spdr ; recieve in left channel msb
140 out spdr,r2 ; send out left channel lsb
141
142 wait2_000050: ; check if byte has been sent
143
144 in r17,spsr
145 sbrs r17,spif
146 rjmp wait2_000050
147 in r6,spdr ; recieve in left channel lsb
148 out spdr,r5 ; send out right channel msb
149
150 ;write left channel data to sram
151 brts wait3_000050 ; dont write data to memory if reversing
152 out portd,r24 ; set address
153 sts porth,r25
154 out portg,r22 ; pull ce low,we low,and set high bits of address
155 ldi r17,$ff
156 out ddra,r17 ; set porta as output for data write
157 out ddrc,r17 ; set portc as output for data write
158 out porta,r6 ; set data
159 out portc,r7
160 sbi portg,portg2 ; pull we high to write
161 out ddra,r18 ; set porta as input for data lines
162 out ddrc,r18 ; set portc as input for data lines
163
164 wait3_000050: ; check if byte has been sent
165
166 in r17,spsr
167 sbrs r17,spif
168 rjmp wait3_000050
169 in r9,spdr ; recieve in right channel msb
170 out spdr,r4 ; send out right channel lsb
171
172 ;increment write address
173 brts wait4_000050 ; dont write data to memory if reversing
174 adiw r25:r24,$01 ; increment write address
175 adc r22,r18 ; increment write third byte
176 andi r22,$03 ; mask off unsed bits
177
178 wait4_000050: ; check if byte has been sent
179
180 in r17,spsr
181 sbrs r17,spif
182 rjmp wait4_000050
183 in r8,spdr ; recieve in left channel lsb
184
185 ;write right channel data to sram
186 brts dataload_000050 ; dont write data to memory if reversing
187 out portd,r24 ; set address
188 sts porth,r25
189 out portg,r22 ; pull ce low,we low,and set high bits of address
190 ldi r17,$ff
191 out ddra,r17 ; set porta as output for data write
192 out ddrc,r17 ; set portc as output for data write
193 out porta,r8 ; set data
194 out portc,r9
195 sbi portg,portg2 ; pull we high to write
196 out ddra,r18 ; set porta as input for data lines
197 out ddrc,r18 ; set portc as input for data lines
198
199 ;check if input signal is above threshold
200 movw r3:r2,r7:r6 ; backup input values as they get modified
201 movw r5:r4,r9:r8 ; move input data to output
202 sbrc r19,$04 ; check if holding off after last trigger
203 rjmp holdtime_000050 ; countdown holdoff timer if waiting
204 sbrc r19,$07 ; check if already in reverse mode
205 rjmp reverse_000050 ; go to reverse function - else check threshold
206 ldi r16,low(threshold_000050) ; get threshold value
207 ldi r17,high(threshold_000050)
208 tst r7 ; check if negative
209 brpl compare_000050 ; compare if positive
210 com r6 ; invert if negative
211 com r7 ; ones complement used for simplicity
212
213 compare_000050: ; compare input value to threshold
214
215 cp r6,r16 ; compare to left channel input
216 cpc r7,r17
217 brsh start_000050 ; start reversing if above threshold
218 rjmp adcsample_000050 ; else finish off
219
220 holdtime_000050: ; decrement holdoff timer
221
222 ldi r17,$02 ; subtract 2 from holdoff timer
223 sub r12,r17 ; 2 is used to have holdoff and backup match scaling
224 sbc r13,r18 ; r18 is cleared above
225 brne finishoff_000050 ; finish off if it not done holding off
226 clr r19 ; set mode to forward and clear hold off bit
227
228 finishoff_000050: ; finish off if not done holding off
229
230 rjmp adcsample_000050 ; finish off - too long for a branch instruction
231
232 start_000050: ; intialize reversing
233
234 ldi r19,$80 ; indicate that reverser is active, waiting for delay
235 movw r17:r16,r25:r24 ; move write address to temporary register
236 mov r21,r22
237 subi r16,low(backtrack_000050) ; remove initial buffer size
238 sbci r17,high(backtrack_000050)
239 sbc r21,r18 ; r18 cleared above
240 andi r21,$03 ; mask off low bits
241 movw r13:r12,r17:r16 ; move buffer bottom to its register
242 rjmp adcsample_000050 ; finish off
243
244 reverse_000050: ; check for reverse function
245
246 sbrc r19,$06 ; check if delay time has been met
247 rjmp dataload_000050 ; get data from memory if delay time has been met
248 ; else check if delay time is up yet
249 movw r17:r16,r13:r12 ; move bottom of buffer to temporary register
250 mov r20,r21
251 add r17,r26 ; add in buffer size
252 adc r20,r27
253 andi r20,$03 ; mask off unused bits
254 cp r24,r16 ; check if write address is at top of buffer
255 cpc r25,r17
256 cpc r22,r20
257 breq bufferset_000050 ; set the read address to the top of the buffer
258 rjmp adcsample_000050 ; else finish off
259
260 bufferset_000050: ; set the read address to the top of the buffer
261
262 movw r29:r28,r25:r24 ; else set read address equal to write address
263 mov r23,r22
264 ori r19,$40 ; set delay time bit in function register
265 set ; set the t register to indicate reversing
266 rjmp dataload1_000050 ; get data from sram
267
268 dataload_000050: ; get data from sram
269
270 sbrc r19,$05 ; check if crossfading
271 rjmp dataload1_000050 ; skip buffer check if crossfading
272 andi r23,$03 ; mask off unused bits
273 cp r28,r12 ; check if at bottom of buffer
274 cpc r29,r13
275 cpc r23,r21
276 brne dataload1_000050 ; continue if not at bottom
277 ori r19,$20 ; set crossfade bit
278 ldi r16,$ff ; set crossfade distance to max value
279 mov r12,r16 ; buffer bottom value no longer needed
280 mov r13,r16
281 clt ; clear the t register to start recording forward again
282
283 dataload1_000050: ; continue getting data from sram
284
285 sbiw r29:r28,$03 ; decrement read address
286 sbc r23,r18 ; r18 is cleared above
287 andi r23,$03 ; mask off unused bits
288 ori r23,$04 ; set we/ bit in high byte register
289
290 ;get left channel data from sram
291 out portg,r23 ; pull ce low, we high, and set high bits of register
292 out portd,r28 ; set address
293 sts porth,r29
294 adiw r29:r28,$01 ; increment read address
295 adc r23,r18 ; increment write third byte
296 andi r23,$03 ; mask off unsed bits
297 ori r23,$04 ; set we/ bit in high byte register
298 in r2,pina ; get data
299 in r3,pinc ; get data
300
301 ;get right channel data from sram
302 out portg,r23 ; pull ce low, we high, and set high bits of register
303 out portd,r28 ; set address
304 sts porth,r29
305 nop ; wait 2 cycle setup time
306 nop
307 in r4,pina ; get data
308 in r5,pinc ; get data
309
310 ;check if crossfading
311 sbrs r19,$05 ; check if crossfading
312 rjmp adcsample_000050 ; finish off if not crossfading
313 ldi r16,low(stepsize_000050) ; get crossfade stepsize
314 ldi r17,high(stepsize_000050)
315 sub r12,r16 ; decrement crossfade distance counter
316 sbc r13,r17
317 breq crossfade_done_000050 ; stop crossfading if done
318 brcs crossfade_done_000050 ; stop crossfading if done
319 rjmp crossfade_000050
320
321 crossfade_done_000050: ; stop crossfading
322
323 movw r3:r2,r7:r6 ; move forward data to output
324 movw r5:r4,r9:r8
325 ldi r16,low(holdoff_000050) ; setup holdoff counter
326 ldi r17,high(holdoff_000050)
327 movw r13:r12,r17:r16 ; r13:r12 no longer needed for crossfading
328 ori r19,$10 ; set reverse mode to holdoff
329 rjmp adcsample_000050 ; finish off
330
331 crossfade_000050: ; crossfade between forward and reverse signals
332
333 sts mem_000050,r6 ; backup data to free a register
334 sts (mem_000050 + 1),r7
335
336 ;multiply left reverse sample by crossfade distance
337 movw r17:r16,r3:r2 ; move left reverse data to multiply register
338 movw r21:r20,r13:r12 ; move crossfade distance to multiply register
339 mulsu r17,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
340 movw r3:r2,r1:r0 ; store high bytes result for later
341 mul r16,r20 ; (unsigned)Al * (unsigned)Bl ; multiply low bytes
342 movw r7:r6,r1:r0 ; store low byets for later
343 mulsu r17,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
344 sbc r3,r18 ; r18 is cleared above - subtract sign bit
345 add r7,r0 ; accumulate result
346 adc r2,r1
347 adc r3,r18 ; r18 is cleared above
348 mul r21,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
349 add r7,r0 ; accumulate result
350 adc r2,r1
351 adc r3,r18 ; r18 is cleared above
352
353 ;multiply and accumulate left forward channel by crossfade distance
354 lds r16,mem_000050 ; fetch left forward channel from memory
355 lds r17,(mem_000050 + 1)
356 com r20 ; invert crossfade distance for forward channel
357 com r21
358 mulsu r17,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
359 add r2,r0 ; accumulate result
360 adc r3,r1
361 mul r16,r20 ; (unsigned)Al * (unsigned)Bl ; multiply low bytes
362 add r6,r0 ; accumulate result
363 adc r7,r1
364 adc r2,r18 ; r18 cleared above
365 adc r3,r18
366 mulsu r17,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
367 sbc r3,r18 ; r18 is cleared above - subtract sign bit
368 add r7,r0 ; accumulate result
369 adc r2,r1
370 adc r3,r18 ; r18 is cleared above
371 mul r21,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
372 add r7,r0 ; accumulate result
373 adc r2,r1
374 adc r3,r18 ; r18 is cleared above
375
376 ;multiply right reverse sample by crossfade distance
377 movw r17:r16,r5:r4 ; move right reverse data to multiply register
378 movw r21:r20,r13:r12 ; move crossfade distance to multiply register
379 mulsu r17,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
380 movw r5:r4,r1:r0 ; store high bytes result for later
381 mul r16,r20 ; (unsigned)Al * (unsigned)Bl ; multiply low bytes
382 movw r7:r6,r1:r0 ; store low byets for later
383 mulsu r17,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
384 sbc r5,r18 ; r18 is cleared above - subtract sign bit
385 add r7,r0 ; accumulate result
386 adc r4,r1
387 adc r5,r18 ; r18 is cleared above
388 mul r21,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
389 add r7,r0 ; accumulate result
390 adc r4,r1
391 adc r5,r18 ; r18 is cleared above
392
393 ;multiply and accumulate right forward channel by crossfade distance
394 movw r17:r16,r9:r8 ; move left forward data to multiply register
395 com r20 ; invert crossfade distance for forward channel
396 com r21
397 mulsu r17,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
398 add r4,r0 ; accumulate result
399 adc r5,r1
400 mul r16,r20 ; (unsigned)Al * (unsigned)Bl ; multiply low bytes
401 add r6,r0 ; accumulate result
402 adc r7,r1
403 adc r4,r18 ; r18 cleared above
404 adc r5,r18
405 mulsu r17,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
406 sbc r5,r18 ; r18 is cleared above - subtract sign bit
407 add r7,r0 ; accumulate result
408 adc r4,r1
409 adc r5,r18 ; r18 is cleared above
410 mul r21,r16 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
411 add r7,r0 ; accumulate result
412 adc r4,r1
413 adc r5,r18 ; r18 is cleared above
414
415 adcsample_000050: ; get buffer size from adc
416
417 lds r17,adcsra ; get adc control register
418 sbrs r17,adif ; check if adc conversion is complete
419 rjmp done_000050 ; skip adc sampling
420 lds r16,adcl ; get low byte adc value
421 lds r17,adch ; get high byte adc value
422 add r14,r16 ; accumulate adc samples
423 adc r10,r17
424 adc r11,r18 ; r18 is cleared above
425 ldi r17,$f7
426 sts adcsra,r17 ; clear interrupt flag
427 dec r15 ; countdown adc sample clock
428 brne done_000050 ; dont get buffer size till its been long enough
429 ldi r17,minbuff_000050 ; fetch minimum buffer size
430 cp r10,r17 ; check if adc value is less than minimum buffer size
431 cpc r11,r18 ; r18 is cleared above
432 brsh high_000050 ; check if above max buffer size if not below min
433 mov r10,r17 ; set to minimum buffer size
434 rjmp deadband_000050 ; check if adc value changed enough
435
436 high_000050: ; check max value of adc
437
438 ldi r16,low(maxbuff_000050) ; fetch max buffer size
439 ldi r17,high(maxbuff_000050)
440 cp r10,r16 ; check if adc value larger than max buffer size
441 cpc r11,r17
442 brlo deadband_000050 ; check for value chnage if lower than max size
443 mov r10,r16 ; set buffer size to max value
444 mov r11,r17
445
446 deadband_000050: ; check if adc value changed enough to warrant update
447
448 movw r17:r16,r11:r10 ; move adc sample to temporary register
449 sub r16,r26 ; find difference between adc sample and desired delay time
450 sbc r17,r27
451 brsh check_000050 ; check for deadband if positive
452 neg r16 ; invert if negative
453 adc r17,r18 ; r18 is cleared above
454 neg r17
455
456 check_000050: ; check if difference is greater than deadband
457
458 cpi r16,$02 ; check if difference is less than 2 lsb
459 cpc r17,r18 ; r18 cleared above
460 brlo empty_000050 ; do nothing if less than $02
461 movw r27:r26,r11:r10 ; move adc sample to delay time if large enough change
462
463 empty_000050: ; empty accumulation registers and finish off
464
465 clr r10 ; empty accumulation registers
466 clr r11
467 clr r14
468
469 switchsample_000050: ; check if at same function
470
471 lds r16,pinj ; get switch data
472 andi r16,$78 ; mask off rotary switch
473 lsr r16 ; adjust switch position to program memory location
474 lsr r16
475 ldi r17,$02
476 add r16,r17
477 cpse r16,r31 ; check if location has changed
478 clr r30 ; reset jump register to new value
479 mov r31,r16
480
481 done_000050:
482
483 reti ; return to waiting
484
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.