1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006-2007 Thom Johansen
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 /****************************************************************************
24 * void channels_process_sound_chan_mono(int count, int32_t *buf[])
26 .section .icode, "ax", %progbits
28 .global channels_process_sound_chan_mono
29 .type channels_process_sound_chan_mono, %function
30 channels_process_sound_chan_mono:
31 @ input: r0 = count, r1 = buf
32 stmfd sp!, { r4, lr } @
34 ldmia r1, { r1, r2 } @ r1 = buf[0], r2 = buf[1]
35 subs r0, r0, #1 @ odd: end at 0; even: end at -1
36 beq .mono_singlesample @ Zero? Only one sample!
39 ldmia r1, { r3, r4 } @ r3, r4 = Li0, Li1
40 ldmia r2, { r12, r14 } @ r12, r14 = Ri0, Ri1
41 mov r3, r3, asr #1 @ Mo0 = Li0 / 2 + Ri0 / 2
42 mov r4, r4, asr #1 @ Mo1 = Li1 / 2 + Ri1 / 2
43 add r12, r3, r12, asr #1 @
44 add r14, r4, r14, asr #1 @
46 stmia r1!, { r12, r14 } @ store Mo0, Mo1
47 stmia r2!, { r12, r14 } @ store Mo0, Mo1
50 ldmltfd sp!, { r4, pc } @ if count was even, we're done
53 ldr r3, [r1] @ r3 = Ls
54 ldr r12, [r2] @ r12 = Rs
55 mov r3, r3, asr #1 @ Mo = Ls / 2 + Rs / 2
56 add r12, r3, r12, asr #1 @
57 str r12, [r1] @ store Mo
58 str r12, [r2] @ store Mo
60 ldmfd sp!, { r4, pc } @
61 .size channels_process_sound_chan_mono, \
62 .-channels_process_sound_chan_mono
64 /****************************************************************************
65 * void channels_process_sound_chan_custom(int count, int32_t *buf[])
67 .section .icode, "ax", %progbits
69 .global channels_process_sound_chan_custom
70 .type channels_process_sound_chan_custom, %function
71 channels_process_sound_chan_custom:
72 stmfd sp!, { r4-r10, lr }
77 ldmia r1, { r1, r2 } @ r1 = buf[0], r2 = buf[1]
78 ldr r3, [r3] @ r3 = dsp_sw_gain
79 ldr r4, [r4] @ r4 = dsp_sw_cross
82 beq .custom_single_sample @ Zero? Only one sample!
85 ldmia r1, { r5, r6 } @ r5 = Li0, r6 = Li1
86 ldmia r2, { r7, r8 } @ r7 = Ri0, r8 = Ri1
90 smull r9, r10, r5, r3 @ Lc0 = Li0*gain
91 smull r12, r14, r7, r3 @ Rc0 = Ri0*gain
92 smlal r9, r10, r7, r4 @ Lc0 += Ri0*cross
93 smlal r12, r14, r5, r4 @ Rc0 += Li0*cross
95 mov r9, r9, lsr #31 @ Convert to s0.31
97 orr r5, r9, r10, asl #1
98 orr r7, r12, r14, asl #1
100 smull r9, r10, r6, r3 @ Lc1 = Li1*gain
101 smull r12, r14, r8, r3 @ Rc1 = Ri1*gain
102 smlal r9, r10, r8, r4 @ Lc1 += Ri1*cross
103 smlal r12, r14, r6, r4 @ Rc1 += Li1*cross
105 mov r9, r9, lsr #31 @ Convert to s0.31
106 mov r12, r12, lsr #31
107 orr r6, r9, r10, asl #1
108 orr r8, r12, r14, asl #1
110 stmia r1!, { r5, r6 } @ Store Lc0, Lc1
111 stmia r2!, { r7, r8 } @ Store Rc0, Rc1
115 ldmltfd sp!, { r4-r10, pc } @ < 0? even count
117 .custom_single_sample:
118 ldr r5, [r1] @ handle odd sample
121 smull r9, r10, r5, r3 @ Lc0 = Li0*gain
122 smull r12, r14, r7, r3 @ Rc0 = Ri0*gain
123 smlal r9, r10, r7, r4 @ Lc0 += Ri0*cross
124 smlal r12, r14, r5, r4 @ Rc0 += Li0*cross
126 mov r9, r9, lsr #31 @ Convert to s0.31
127 mov r12, r12, lsr #31
128 orr r5, r9, r10, asl #1
129 orr r7, r12, r14, asl #1
131 str r5, [r1] @ Store Lc0
132 str r7, [r2] @ Store Rc0
134 ldmfd sp!, { r4-r10, pc }
135 .size channels_process_sound_chan_custom, \
136 .-channels_process_sound_chan_custom
138 /****************************************************************************
139 * void channels_process_sound_chan_karaoke(int count, int32_t *buf[])
141 .section .icode, "ax", %progbits
143 .global channels_process_sound_chan_karaoke
144 .type channels_process_sound_chan_karaoke, %function
145 channels_process_sound_chan_karaoke:
146 @ input: r0 = count, r1 = buf
147 stmfd sp!, { r4, lr } @
149 ldmia r1, { r1, r2 } @ r1 = buf[0], r2 = buf[1]
150 subs r0, r0, #1 @ odd: end at 0; even: end at -1
151 beq .karaoke_singlesample @ Zero? Only one sample!
154 ldmia r1, { r3, r4 } @ r3, r4 = Li0, Li1
155 ldmia r2, { r12, r14 } @ r12, r14 = Ri0, Ri1
156 mov r3, r3, asr #1 @ Lo0 = Li0 / 2 - Ri0 / 2
157 mov r4, r4, asr #1 @ Lo1 = Li1 / 2 - Ri1 / 2
158 sub r3, r3, r12, asr #1 @
159 sub r4, r4, r14, asr #1 @
160 rsb r12, r3, #0 @ Ro0 = -Lk0 = Rs0 / 2 - Ls0 / 2
161 rsb r14, r4, #0 @ Ro1 = -Lk1 = Ri1 / 2 - Li1 / 2
163 stmia r1!, { r3, r4 } @ store Lo0, Lo1
164 stmia r2!, { r12, r14 } @ store Ro0, Ro1
167 ldmltfd sp!, { r4, pc } @ if count was even, we're done
169 .karaoke_singlesample: @
170 ldr r3, [r1] @ r3 = Li
171 ldr r12, [r2] @ r12 = Ri
172 mov r3, r3, asr #1 @ Lk = Li / 2 - Ri /2
173 sub r3, r3, r12, asr #1 @
174 rsb r12, r3, #0 @ Rk = -Lo = Ri / 2 - Li / 2
175 str r3, [r1] @ store Lo
176 str r12, [r2] @ store Ro
178 ldmfd sp!, { r4, pc } @
179 .size channels_process_sound_chan_karaoke, \
180 .-channels_process_sound_chan_karaoke
183 /****************************************************************************
184 * void sample_output_mono(int count, struct dsp_data *data,
185 * const int32_t *src[], int16_t *dst)
187 .section .icode, "ax", %progbits
189 .global sample_output_mono
190 .type sample_output_mono, %function
192 @ input: r0 = count, r1 = data, r2 = src, r3 = dst
193 stmfd sp!, { r4-r6, lr }
195 ldr r1, [r1] @ lr = data->output_scale
196 ldr r2, [r2] @ r2 = src[0]
199 mov r4, r4, lsl r1 @ r4 = 1 << (scale-1)
201 mvn r14, #0x8000 @ r14 = 0xffff7fff, needed for
202 @ clipping and masking
204 beq .som_singlesample @ Zero? Only one sample!
207 ldmia r2!, { r5, r6 }
208 add r5, r5, r4 @ r6 = (r6 + 1<<(scale-1)) >> scale
211 teq r12, r12, asr #31
212 eorne r5, r14, r5, asr #31 @ Clip (-32768...+32767)
214 mov r6, r6, asr r1 @ r7 = (r7 + 1<<(scale-1)) >> scale
216 teq r12, r12, asr #31
217 eorne r6, r14, r6, asr #31 @ Clip (-32768...+32767)
219 and r5, r5, r14, lsr #16
220 and r6, r6, r14, lsr #16
221 orr r5, r5, r5, lsl #16 @ pack first 2 halfwords into 1 word
222 orr r6, r6, r6, lsl #16 @ pack last 2 halfwords into 1 word
223 stmia r3!, { r5, r6 }
228 ldmltfd sp!, { r4-r6, pc } @ even 'count'? return
231 ldr r5, [r2] @ do odd sample
235 teq r12, r12, asr #31
236 eorne r5, r14, r5, asr #31
238 and r5, r5, r14, lsr #16 @ pack 2 halfwords into 1 word
239 orr r5, r5, r5, lsl #16
242 ldmfd sp!, { r4-r6, pc }
243 .size sample_output_mono, .-sample_output_mono
245 /****************************************************************************
246 * void sample_output_stereo(int count, struct dsp_data *data,
247 * const int32_t *src[], int16_t *dst)
249 .section .icode, "ax", %progbits
251 .global sample_output_stereo
252 .type sample_output_stereo, %function
253 sample_output_stereo:
254 @ input: r0 = count, r1 = data, r2 = src, r3 = dst
255 stmfd sp!, { r4-r9, lr }
257 ldr r1, [r1] @ r1 = data->output_scale
258 ldmia r2, { r2, r5 } @ r2 = src[0], r5 = src[1]
261 mov r4, r4, lsl r1 @ r4 = 1 << (scale-1)
264 mvn r14, #0x8000 @ r14 = 0xffff7fff, needed for
265 @ clipping and masking
267 beq .sos_singlesample @ Zero? Only one sample!
270 ldmia r2!, { r6, r7 } @ 2 left
271 ldmia r5!, { r8, r9 } @ 2 right
273 add r6, r6, r4 @ r6 = (r6 + 1<<(scale-1)) >> scale
276 teq r12, r12, asr #31
277 eorne r6, r14, r6, asr #31 @ Clip (-32768...+32767)
279 mov r7, r7, asr r1 @ r7 = (r7 + 1<<(scale-1)) >> scale
281 teq r12, r12, asr #31
282 eorne r7, r14, r7, asr #31 @ Clip (-32768...+32767)
284 add r8, r8, r4 @ r8 = (r8 + 1<<(scale-1)) >> scale
287 teq r12, r12, asr #31
288 eorne r8, r14, r8, asr #31 @ Clip (-32768...+32767)
289 add r9, r9, r4 @ r9 = (r9 + 1<<(scale-1)) >> scale
292 teq r12, r12, asr #31
293 eorne r9, r14, r9, asr #31 @ Clip (-32768...+32767)
295 and r6, r6, r14, lsr #16 @ pack first 2 halfwords into 1 word
296 orr r8, r6, r8, asl #16
297 and r7, r7, r14, lsr #16 @ pack last 2 halfwords into 1 word
298 orr r9, r7, r9, asl #16
300 stmia r3!, { r8, r9 }
305 ldmltfd sp!, { r4-r9, pc } @ even 'count'? return
308 ldr r6, [r2] @ left odd sample
309 ldr r8, [r5] @ right odd sample
311 add r6, r6, r4 @ r6 = (r7 + 1<<(scale-1)) >> scale
314 teq r12, r12, asr #31
315 eorne r6, r14, r6, asr #31 @ Clip (-32768...+32767)
316 add r8, r8, r4 @ r8 = (r8 + 1<<(scale-1)) >> scale
319 teq r12, r12, asr #31
320 eorne r8, r14, r8, asr #31 @ Clip (-32768...+32767)
322 and r6, r6, r14, lsr #16 @ pack 2 halfwords into 1 word
323 orr r8, r6, r8, asl #16
327 ldmfd sp!, { r4-r9, pc }
328 .size sample_output_stereo, .-sample_output_stereo
329 #endif /* ARM_ARCH < 6 */
331 /****************************************************************************
332 * void apply_crossfeed(int count, int32_t* src[])
335 .global apply_crossfeed
337 @ unfortunately, we ended up in a bit of a register squeeze here, and need
338 @ to keep the count on the stack :/
339 stmdb sp!, { r4-r11, lr } @ stack modified regs
340 ldmia r1, { r2-r3 } @ r2 = src[0], r3 = src[1]
342 ldr r1, =crossfeed_data
343 ldmia r1!, { r4-r11 } @ load direct gain and filter data
344 mov r12, r0 @ better to ldm delay + count later
345 add r0, r1, #13*4*2 @ calculate end of delay
346 stmdb sp!, { r0, r12 } @ stack end of delay adr and count
347 ldr r0, [r1, #13*4*2] @ fetch current delay line address
349 /* Register usage in loop:
350 * r0 = &delay[index][0], r1 = accumulator high, r2 = src[0], r3 = src[1],
351 * r4 = direct gain, r5-r7 = b0, b1, a1 (filter coefs),
352 * r8-r11 = filter history, r12 = temp, r14 = accumulator low
355 smull r14, r1, r6, r8 @ acc = b1*dr[n - 1]
356 smlal r14, r1, r7, r9 @ acc += a1*y_l[n - 1]
357 ldr r8, [r0, #4] @ r8 = dr[n]
358 smlal r14, r1, r5, r8 @ acc += b0*dr[n]
359 mov r9, r1, lsl #1 @ fix format for filter history
360 ldr r12, [r2] @ load left input
361 smlal r14, r1, r4, r12 @ acc += gain*x_l[n]
362 mov r1, r1, lsl #1 @ fix format
363 str r1, [r2], #4 @ save result
365 smull r14, r1, r6, r10 @ acc = b1*dl[n - 1]
366 smlal r14, r1, r7, r11 @ acc += a1*y_r[n - 1]
367 ldr r10, [r0] @ r10 = dl[n]
368 str r12, [r0], #4 @ save left input to delay line
369 smlal r14, r1, r5, r10 @ acc += b0*dl[n]
370 mov r11, r1, lsl #1 @ fix format for filter history
371 ldr r12, [r3] @ load right input
372 smlal r14, r1, r4, r12 @ acc += gain*x_r[n]
373 str r12, [r0], #4 @ save right input to delay line
374 mov r1, r1, lsl #1 @ fix format
375 ldmia sp, { r12, r14 } @ fetch delay line end addr and count from stack
376 str r1, [r3], #4 @ save result
378 cmp r0, r12 @ need to wrap to start of delay?
379 subeq r0, r0, #13*4*2 @ wrap back delay line ptr to start
381 subs r14, r14, #1 @ are we finished?
382 strne r14, [sp, #4] @ nope, save count back to stack
385 @ save data back to struct
386 ldr r12, =crossfeed_data + 4*4
387 stmia r12, { r8-r11 } @ save filter history
388 str r0, [r12, #30*4] @ save delay line index
389 add sp, sp, #8 @ remove temp variables from stack
390 ldmia sp!, { r4-r11, pc }
391 .size apply_crossfeed, .-apply_crossfeed
393 /****************************************************************************
394 * int dsp_downsample(int count, struct dsp_data *data,
395 * in32_t *src[], int32_t *dst[])
398 .global dsp_downsample
400 stmdb sp!, { r4-r11, lr } @ stack modified regs
401 ldmib r1, { r5-r6 } @ r5 = num_channels,r6 = resample_data.delta
402 sub r5, r5, #1 @ pre-decrement num_channels for use
403 add r4, r1, #12 @ r4 = &resample_data.phase
405 orr r12, r12, #0xff00 @ r12 = 0xffff
407 ldr r1, [r4] @ r1 = resample_data.phase
408 ldr r7, [r2, r5, lsl #2] @ r7 = s = src[ch - 1]
409 ldr r8, [r3, r5, lsl #2] @ r8 = d = dst[ch - 1]
410 add r9, r4, #4 @ r9 = &last_sample[0]
411 ldr r10, [r9, r5, lsl #2] @ r10 = last_sample[ch - 1]
413 ldr r14, [r7, r11, lsl #2] @ load last sample in s[] ...
414 str r14, [r9, r5, lsl #2] @ and write as next frame's last_sample
415 movs r9, r1, lsr #16 @ r9 = pos = phase >> 16
416 ldreq r11, [r7] @ if pos = 0, load src[0] and jump into loop
417 beq .dsuse_last_start
418 cmp r9, r0 @ if pos >= count, we're already done
421 @ Register usage in loop:
422 @ r0 = count, r1 = phase, r4 = &resample_data.phase, r5 = cur_channel,
423 @ r6 = delta, r7 = s, r8 = d, r9 = pos, r10 = s[pos - 1], r11 = s[pos]
425 add r9, r7, r9, lsl #2 @ r9 = &s[pos]
426 ldmda r9, { r10, r11 } @ r10 = s[pos - 1], r11 = s[pos]
428 sub r11, r11, r10 @ r11 = diff = s[pos] - s[pos - 1]
429 @ keep frac in lower bits to take advantage of multiplier early termination
430 and r9, r1, r12 @ frac = phase & 0xffff
431 smull r9, r14, r11, r9
432 add r1, r1, r6 @ phase += delta
433 add r10, r10, r9, lsr #16 @ r10 = out = s[pos - 1] + frac*diff
434 add r10, r10, r14, lsl #16
435 str r10, [r8], #4 @ *d++ = out
436 mov r9, r1, lsr #16 @ pos = phase >> 16
437 cmp r9, r0 @ pos < count?
438 blt .dsloop @ yup, do more samples
441 bpl .dschannel_loop @ if (--ch) >= 0, do another channel
442 sub r1, r1, r0, lsl #16 @ wrap phase back to start
443 str r1, [r4] @ store back
444 ldr r1, [r3] @ r1 = &dst[0]
445 sub r8, r8, r1 @ dst - &dst[0]
446 mov r0, r8, lsr #2 @ convert bytes->samples
447 ldmia sp!, { r4-r11, pc } @ ... and we're out
448 .size dsp_downsample, .-dsp_downsample
450 /****************************************************************************
451 * int dsp_upsample(int count, struct dsp_data *dsp,
452 * in32_t *src[], int32_t *dst[])
457 stmfd sp!, { r4-r11, lr } @ stack modified regs
458 ldmib r1, { r5-r6 } @ r5 = num_channels,r6 = resample_data.delta
459 sub r5, r5, #1 @ pre-decrement num_channels for use
460 add r4, r1, #12 @ r4 = &resample_data.phase
461 mov r6, r6, lsl #16 @ we'll use carry to detect pos increments
462 stmfd sp!, { r0, r4 } @ stack count and &resample_data.phase
464 ldr r12, [r4] @ r12 = resample_data.phase
465 ldr r7, [r2, r5, lsl #2] @ r7 = s = src[ch - 1]
466 ldr r8, [r3, r5, lsl #2] @ r8 = d = dst[ch - 1]
467 add r9, r4, #4 @ r9 = &last_sample[0]
468 mov r1, r12, lsl #16 @ we'll use carry to detect pos increments
470 ldr r14, [r7, r11, lsl #2] @ load last sample in s[] ...
471 ldr r10, [r9, r5, lsl #2] @ r10 = last_sample[ch - 1]
472 str r14, [r9, r5, lsl #2] @ and write as next frame's last_sample
473 movs r14, r12, lsr #16 @ pos = resample_data.phase >> 16
474 beq .usstart_0 @ pos = 0
475 cmp r14, r0 @ if pos >= count, we're already done
477 add r7, r7, r14, lsl #2 @ r7 = &s[pos]
478 ldr r10, [r7, #-4] @ r11 = s[pos - 1]
481 @ Register usage in loop:
482 @ r0 = count, r1 = phase, r4 = &resample_data.phase, r5 = cur_channel,
483 @ r6 = delta, r7 = s, r8 = d, r9 = diff, r10 = s[pos - 1], r11 = s[pos]
485 mov r10, r11 @ r10 = previous sample
487 ldr r11, [r7], #4 @ r11 = next sample
488 mov r4, r1, lsr #16 @ r4 = frac = phase >> 16
489 sub r9, r11, r10 @ r9 = diff = s[pos] - s[pos - 1]
491 smull r12, r14, r4, r9
492 adds r1, r1, r6 @ phase += delta << 16
493 mov r4, r1, lsr #16 @ r4 = frac = phase >> 16
494 add r14, r10, r14, lsl #16
495 add r14, r14, r12, lsr #16 @ r14 = out = s[pos - 1] + frac*diff
496 str r14, [r8], #4 @ *d++ = out
497 bcc .usloop_0 @ if carry is set, pos is incremented
498 subs r0, r0, #1 @ if count > 0, do another sample
502 ldmfd sp, { r0, r4 } @ reload count and &resample_data.phase
503 bpl .uschannel_loop @ if (--ch) >= 0, do another channel
504 mov r1, r1, lsr #16 @ wrap phase back to start of next frame
505 ldr r2, [r3] @ r1 = &dst[0]
506 str r1, [r4] @ store phase
507 sub r8, r8, r2 @ dst - &dst[0]
508 mov r0, r8, lsr #2 @ convert bytes->samples
509 add sp, sp, #8 @ adjust stack for temp variables
510 ldmfd sp!, { r4-r11, pc } @ ... and we're out
511 .size dsp_upsample, .-dsp_upsample
513 /****************************************************************************
514 * void dsp_apply_gain(int count, struct dsp_data *data, int32_t *buf[])
516 .section .icode, "ax", %progbits
518 .global dsp_apply_gain
519 .type dsp_apply_gain, %function
521 @ input: r0 = count, r1 = data, r2 = buf[]
522 stmfd sp!, { r4-r8, lr }
524 ldr r3, [r1, #4] @ r3 = data->num_channels
525 ldr r4, [r1, #32] @ r5 = data->gain
528 ldr r1, [r2], #4 @ r1 = buf[0] and increment index of buf[]
529 subs r12, r0, #1 @ r12 = r0 = count - 1
530 beq .dag_singlesample @ Zero? Only one sample!
533 ldmia r1, { r5, r6 } @ load r5, r6 from r1
534 smull r7, r8, r5, r4 @ r7 = FRACMUL_SHL(r5, r4, 8)
535 smull r14, r5, r6, r4 @ r14 = FRACMUL_SHL(r6, r4, 8)
538 mov r14, r14, lsr #23
539 orr r7, r7, r8, asl #9
540 orr r14, r14, r5, asl #9
541 stmia r1!, { r7, r14 } @ save r7, r14 to [r1] and increment r1
542 bgt .dag_innerloop @ end of inner loop
544 blt .dag_evencount @ < 0? even count
547 ldr r5, [r1] @ handle odd sample
548 smull r7, r8, r5, r4 @ r7 = FRACMUL_SHL(r5, r4, 8)
550 orr r7, r7, r8, asl #9
555 bgt .dag_outerloop @ end of outer loop
557 ldmfd sp!, { r4-r8, pc }
558 .size dsp_apply_gain, .-dsp_apply_gain