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.