platform ps2, handle audio similar to psp
[picodrive.git] / pico / sound / mix_arm.S
... / ...
CommitLineData
1/*
2 * Generic routines for mixing audio samples
3 * (C) notaz, 2007,2008
4 * (C) irixxxx, 2019,2020 added filtering
5 *
6 * This work is licensed under the terms of MAME license.
7 * See COPYING file in the top-level directory.
8 */
9
10.text
11.align 4
12
13@ this assumes src is word aligned
14.global mix_16h_to_32 @ int *dest, short *src, int count
15
16mix_16h_to_32:
17 stmfd sp!, {r4-r6,lr}
18/*
19 tst r1, #2
20 beq m16_32_mo_unalw
21 ldrsh r4, [r1], #2
22 ldr r3, [r0]
23 sub r2, r2, #1
24 add r3, r3, r4, asr #1
25 str r3, [r0], #4
26*/
27m16_32_mo_unalw:
28 subs r2, r2, #4
29 bmi m16_32_end
30
31m16_32_loop:
32 ldmia r0, {r3-r6}
33 ldmia r1!,{r12,lr}
34 subs r2, r2, #4
35 add r4, r4, r12,asr #17 @ we use 5/8 volume
36 add r4, r4, r12,asr #19
37 mov r12,r12,lsl #16
38 add r3, r3, r12,asr #17
39 add r3, r3, r12,asr #19
40 add r6, r6, lr, asr #17
41 add r6, r6, lr, asr #19
42 mov lr, lr, lsl #16
43 add r5, r5, lr, asr #17
44 add r5, r5, lr, asr #19
45 stmia r0!,{r3-r6}
46 bpl m16_32_loop
47
48m16_32_end:
49 tst r2, #2
50 beq m16_32_no_unal2
51 ldr r5, [r1], #4
52 ldmia r0, {r3,r4}
53 mov r12,r5, lsl #16
54 add r3, r3, r12,asr #17
55 add r3, r3, r12,asr #19
56 add r4, r4, r5, asr #17
57 add r4, r4, r5, asr #19
58 stmia r0!,{r3,r4}
59
60m16_32_no_unal2:
61 tst r2, #1
62 ldmeqfd sp!, {r4-r6,pc}
63 ldrsh r4, [r1], #2
64 ldr r3, [r0]
65 add r3, r3, r4, asr #1
66 add r3, r3, r4, asr #3
67 str r3, [r0], #4
68
69 ldmfd sp!, {r4-r6,lr}
70 bx lr
71
72
73
74.global mix_16h_to_32_s1 @ int *dest, short *src, int count
75
76mix_16h_to_32_s1:
77 stmfd sp!, {r4-r6,lr}
78
79 subs r2, r2, #4
80 bmi m16_32_s1_end
81
82m16_32_s1_loop:
83 ldmia r0, {r3-r6}
84 ldr r12,[r1], #8
85 ldr lr, [r1], #8
86 subs r2, r2, #4
87 add r4, r4, r12,asr #17 @ we use 5/8 volume
88 add r4, r4, r12,asr #19
89 mov r12,r12,lsl #16
90 add r3, r3, r12,asr #17
91 add r3, r3, r12,asr #19
92 add r6, r6, lr, asr #17
93 add r6, r6, lr, asr #19
94 mov lr, lr, lsl #16
95 add r5, r5, lr, asr #17
96 add r5, r5, lr, asr #19
97 stmia r0!,{r3-r6}
98 bpl m16_32_s1_loop
99
100m16_32_s1_end:
101 tst r2, #2
102 beq m16_32_s1_no_unal2
103 ldr r5, [r1], #8
104 ldmia r0, {r3,r4}
105 mov r12,r5, lsl #16
106 add r3, r3, r12,asr #17
107 add r3, r3, r12,asr #19
108 add r4, r4, r5, asr #17
109 add r4, r4, r5, asr #19
110 stmia r0!,{r3,r4}
111
112m16_32_s1_no_unal2:
113 tst r2, #1
114 ldmeqfd sp!, {r4-r6,pc}
115 ldrsh r4, [r1], #2
116 ldr r3, [r0]
117 add r3, r3, r4, asr #1
118 add r3, r3, r4, asr #3
119 str r3, [r0], #4
120
121 ldmfd sp!, {r4-r6,lr}
122 bx lr
123
124
125
126.global mix_16h_to_32_s2 @ int *dest, short *src, int count
127
128mix_16h_to_32_s2:
129 stmfd sp!, {r4-r6,lr}
130
131 subs r2, r2, #4
132 bmi m16_32_s2_end
133
134m16_32_s2_loop:
135 ldmia r0, {r3-r6}
136 ldr r12,[r1], #16
137 ldr lr, [r1], #16
138 subs r2, r2, #4
139 add r4, r4, r12,asr #17 @ we use 5/8 volume
140 add r4, r4, r12,asr #19
141 mov r12,r12,lsl #16
142 add r3, r3, r12,asr #17
143 add r3, r3, r12,asr #19
144 add r6, r6, lr, asr #17
145 add r6, r6, lr, asr #19
146 mov lr, lr, lsl #16
147 add r5, r5, lr, asr #17
148 add r5, r5, lr, asr #19
149 stmia r0!,{r3-r6}
150 bpl m16_32_s2_loop
151
152m16_32_s2_end:
153 tst r2, #2
154 beq m16_32_s2_no_unal2
155 ldr r5, [r1], #16
156 ldmia r0, {r3,r4}
157 mov r12,r5, lsl #16
158 add r3, r3, r12,asr #17
159 add r3, r3, r12,asr #19
160 add r4, r4, r5, asr #17
161 add r4, r4, r5, asr #19
162 stmia r0!,{r3,r4}
163
164m16_32_s2_no_unal2:
165 tst r2, #1
166 ldmeqfd sp!, {r4-r6,pc}
167 ldrsh r4, [r1], #2
168 ldr r3, [r0]
169 add r3, r3, r4, asr #1
170 add r3, r3, r4, asr #3
171 str r3, [r0], #4
172
173 ldmfd sp!, {r4-r6,lr}
174 bx lr
175
176
177
178.global mix_16h_to_32_resample_stereo @ int *dest, short *src, int count, int fac16
179
180mix_16h_to_32_resample_stereo:
181 stmfd sp!, {r4-r9,lr}
182
183 subs r2, r2, #2
184 mov r4, #0
185 bmi m16_32_rss_end
186
187m16_32_rss_loop:
188 ldmia r0, {r5-r8}
189 mov r9, r4, lsr #16
190 ldr r12,[r1, r9, lsl #2]
191 add r4, r4, r3
192 mov r9, r4, lsr #16
193 ldr lr ,[r1, r9, lsl #2]
194 add r4, r4, r3
195 subs r2, r2, #2
196 add r6, r6, r12,asr #17 @ we use 5/8 volume
197 add r6, r6, r12,asr #19
198 mov r12,r12,lsl #16
199 add r5, r5, r12,asr #17
200 add r5, r5, r12,asr #19
201 add r8, r8, lr, asr #17
202 add r8, r8, lr, asr #19
203 mov lr, lr, lsl #16
204 add r7, r7, lr, asr #17
205 add r7, r7, lr, asr #19
206 stmia r0!,{r5-r8}
207 bpl m16_32_rss_loop
208
209m16_32_rss_end:
210 tst r2, #1
211 ldmeqfd sp!, {r4-r9,pc}
212 mov r9, r4, lsr #16
213 ldr lr ,[r1, r9, lsl #2]
214 ldmia r0, {r5,r6}
215 mov r12,lr, lsl #16
216 add r5, r5, r12,asr #17
217 add r5, r5, r12,asr #19
218 add r6, r6, lr, asr #17
219 add r6, r6, lr, asr #19
220 stmia r0!,{r5,r6}
221
222 ldmfd sp!, {r4-r9,lr}
223 bx lr
224
225
226
227.global mix_16h_to_32_resample_mono @ int *dest, short *src, int count, int fac16
228
229mix_16h_to_32_resample_mono:
230 stmfd sp!, {r4-r6,r9,lr}
231
232 subs r2, r2, #2
233 mov r4, #0
234 bmi m16_32_rsm_end
235
236m16_32_rsm_loop:
237 ldmia r0, {r5-r6}
238 mov r9, r4, lsr #16
239 ldr r12,[r1, r9, lsl #2]
240 add r4, r4, r3
241 mov r9, r4, lsr #16
242 ldr lr ,[r1, r9, lsl #2]
243 add r4, r4, r3
244 subs r2, r2, #2
245 add r5, r5, r12,asr #18 @ we use 5/8 volume (= 5/16 vol per channel)
246 add r5, r5, r12,asr #20
247 mov r12,r12,lsl #16
248 add r5, r5, r12,asr #18
249 add r5, r5, r12,asr #20
250 add r6, r6, lr, asr #18
251 add r6, r6, lr, asr #20
252 mov lr, lr, lsl #16
253 add r6, r6, lr, asr #18
254 add r6, r6, lr, asr #20
255 stmia r0!,{r5-r6}
256 bpl m16_32_rsm_loop
257
258m16_32_rsm_end:
259 tst r2, #1
260 ldmeqfd sp!, {r4-r6,r9,pc}
261 mov r9, r4, lsr #16
262 ldr lr ,[r1, r9, lsl #2]
263 ldr r5, [r0]
264 mov r12,lr, lsl #16
265 add r5, r5, r12,asr #18
266 add r5, r5, r12,asr #20
267 add r5, r5, lr, asr #18
268 add r5, r5, lr, asr #20
269 str r5, [r0]
270
271 ldmfd sp!, {r4-r6,r9,lr}
272 bx lr
273
274
275
276@ limit
277@ reg=int_sample, r12=1, r8=tmp, kills flags
278.macro Limit reg
279 sub \reg, \reg, \reg, asr #3 @ reduce audio lvl some to avoid clipping
280 add r8, r12, \reg, asr #15
281 bics r8, r8, #1 @ in non-overflow conditions r8 is 0 or 1
282 movne \reg, #0x8000
283 subpl \reg, \reg, #1
284.endm
285
286@ limit and shift up by 16
287@ reg=int_sample, r12=1, r8=tmp, kills flags
288.macro Limitsh reg
289 sub \reg, \reg, \reg, asr #3 @ reduce audio lvl some to avoid clipping
290 add r8, r12,\reg, asr #15
291 bics r8, r8, #1 @ in non-overflow conditions r8 is 0 or 1
292 moveq \reg, \reg, lsl #16
293 movne \reg, #0x80000000
294 subpl \reg, \reg, #0x00010000
295.endm
296
297
298@ filter out DC offset
299@ in=int_sample (max 20 bit), y=filter memory, r8=tmp
300.macro DCfilt in y
301 rsb r8, \y, \in, lsl #12 @ fixpoint 20.12
302 add \y, \y, r8, asr #12 @ alpha = 1-1/4094
303 sub \in, \in, \y, asr #12
304.endm
305
306@ lowpass filter
307@ in=int_sample (max 20 bit), y=filter memory, r12=alpha(Q8), r8=tmp
308.macro LPfilt in y
309@ mov r8, \y, asr #8
310@ rsb r8, r8, \in, lsl #4 @ fixpoint 20.12
311 sub r8, \in, \y, asr #12 @ fixpoint 20.12
312 mla \y, r8, r12, \y
313 mov \in, \y, asr #12
314.endm
315
316
317@ mix 32bit audio (with 16bits really used, upper bits indicate overflow) with normal 16 bit audio with left channel only
318@ warning: this function assumes dest is word aligned
319.global mix_32_to_16_stereo @ short *dest, int *src, int count
320
321mix_32_to_16_stereo:
322 stmfd sp!, {r4-r8,r10-r11,lr}
323
324 mov r2, r2, lsl #1
325 subs r2, r2, #4
326 bmi m32_16_st_end
327
328 ldr r12, =filter
329 ldr r8, [r12], #4
330 ldmia r12, {r3,r10-r11,lr}
331 str r8, [sp, #-4]!
332
333m32_16_st_loop:
334 ldmia r0, {r8,r12}
335 ldmia r1!, {r4-r7}
336 add r5, r5, r8, asr #16
337 add r7, r7, r12,asr #16
338 mov r8, r8, lsl #16
339 mov r12,r12,lsl #16
340 add r4, r4, r8, asr #16
341 add r6, r6, r12,asr #16
342 ldr r12,[sp]
343 LPfilt r4, r3
344 LPfilt r5, lr
345 LPfilt r6, r3
346 LPfilt r7, lr
347 DCfilt r4, r10
348 DCfilt r5, r11
349 DCfilt r6, r10
350 DCfilt r7, r11
351 mov r12,#1
352 Limitsh r4
353 Limitsh r5
354 Limitsh r6
355 Limitsh r7
356 subs r2, r2, #4
357 orr r4, r5, r4, lsr #16
358 orr r5, r7, r6, lsr #16
359 stmia r0!, {r4,r5}
360 bpl m32_16_st_loop
361
362m32_16_st_end:
363 @ check for remaining bytes to convert
364 tst r2, #2
365 beq m32_16_st_no_unal2
366 ldr r6, [r0]
367 ldmia r1!,{r4,r5}
368 add r5, r5, r6, asr #16
369 mov r6, r6, lsl #16
370 add r4, r4, r6, asr #16
371 ldr r12,[sp]
372 LPfilt r4, r3
373 LPfilt r5, lr
374 DCfilt r4, r10
375 DCfilt r5, r11
376 mov r12,#1
377 Limitsh r4
378 Limitsh r5
379 orr r4, r5, r4, lsr #16
380 str r4, [r0], #4
381
382m32_16_st_no_unal2:
383 ldr r12, =filter
384 add r12,r12, #4
385 stmia r12, {r3,r10-r11,lr}
386 add sp, sp, #4
387 ldmfd sp!, {r4-r8,r10-r11,lr}
388 bx lr
389
390
391@ mix 32bit audio (with 16bits really used, upper bits indicate overflow) with normal 16 bit audio (for mono sound)
392.global mix_32_to_16_mono @ short *dest, int *src, int count
393
394mix_32_to_16_mono:
395 stmfd sp!, {r4-r8,r10-r11,lr}
396
397 ldr r12, =filter
398 ldr r8, [r12], #4
399 ldmia r12, {r10-r11}
400 str r8, [sp, #-4]!
401
402 @ check if dest is word aligned
403 tst r0, #2
404 beq m32_16_mo_no_unalw
405 ldrsh r5, [r0]
406 ldr r4, [r1], #4
407 sub r2, r2, #1
408 add r4, r4, r5
409 ldr r12,[sp]
410 LPfilt r4, r11
411 DCfilt r4, r10
412 mov r12,#1
413 Limit r4
414 strh r4, [r0], #2
415
416m32_16_mo_no_unalw:
417 subs r2, r2, #4
418 bmi m32_16_mo_end
419
420m32_16_mo_loop:
421 ldmia r0, {r8,r12}
422 ldmia r1!, {r4-r7}
423 add r5, r5, r8, asr #16
424 add r7, r7, r12,asr #16
425 mov r8, r8, lsl #16
426 mov r12,r12,lsl #16
427 add r4, r4, r8, asr #16
428 add r6, r6, r12,asr #16
429 ldr r12,[sp]
430 LPfilt r4, r11
431 LPfilt r5, r11
432 LPfilt r6, r11
433 LPfilt r7, r11
434 DCfilt r4, r10
435 DCfilt r5, r10
436 DCfilt r6, r10
437 DCfilt r7, r10
438 mov r12,#1
439 Limitsh r4
440 Limitsh r5
441 Limitsh r6
442 Limitsh r7
443 subs r2, r2, #4
444 orr r4, r5, r4, lsr #16
445 orr r5, r7, r6, lsr #16
446 stmia r0!, {r4,r5}
447 bpl m32_16_mo_loop
448
449m32_16_mo_end:
450 @ check for remaining bytes to convert
451 tst r2, #2
452 beq m32_16_mo_no_unal2
453 ldr r6, [r0]
454 ldmia r1!,{r4,r5}
455 add r5, r5, r6, asr #16
456 mov r6, r6, lsl #16
457 add r4, r4, r6, asr #16
458 ldr r12,[sp]
459 LPfilt r4, r11
460 LPfilt r5, r11
461 DCfilt r4, r10
462 DCfilt r5, r10
463 mov r12,#1
464 Limitsh r4
465 Limitsh r5
466 orr r4, r5, r4, lsr #16
467 str r4, [r0], #4
468
469m32_16_mo_no_unal2:
470 tst r2, #1
471 beq m32_16_mo_no_unal
472 ldrsh r5, [r0]
473 ldr r4, [r1], #4
474 add r4, r4, r5
475 ldr r12,[sp]
476 LPfilt r4, r11
477 DCfilt r4, r10
478 mov r12,#1
479 Limit r4
480 strh r4, [r0], #2
481
482m32_16_mo_no_unal:
483 ldr r12, =filter
484 add r12,r12, #4
485 stmia r12, {r10-r11}
486 add sp, sp, #4
487 ldmfd sp!, {r4-r8,r10-r11,lr}
488 bx lr
489
490
491#ifdef __GP2X__
492
493.data
494.align 4
495
496.global mix_32_to_16_level
497mix_32_to_16_level:
498 .word 0
499
500.text
501.align 4
502
503@ same as mix_32_to_16_stereo, but with additional shift
504.global mix_32_to_16_stereo_lvl @ short *dest, int *src, int count
505
506mix_32_to_16_stereo_lvl:
507 stmfd sp!, {r4-r11,lr}
508
509 ldr r9, =mix_32_to_16_level
510 mov lr, #1
511 ldr r9, [r9]
512 ldr r12, =filter
513 ldr r8, [r12], #4
514 ldmia r12, {r3,r10-r11,lr}
515 str r8, [sp, #-4]!
516
517 mov r2, r2, lsl #1
518 subs r2, r2, #4
519 bmi m32_16_st_l_end
520
521m32_16_st_l_loop:
522 ldmia r0, {r8,r12}
523 ldmia r1!, {r4-r7}
524 add r5, r5, r8, asr #16
525 add r7, r7, r12,asr #16
526 mov r8, r8, lsl #16
527 mov r12,r12,lsl #16
528 add r4, r4, r8, asr #16
529 add r6, r6, r12,asr #16
530 mov r4, r4, asr r9
531 mov r5, r5, asr r9
532 mov r6, r6, asr r9
533 mov r7, r7, asr r9
534 ldr r12,[sp]
535 LPfilt r4, r3
536 LPfilt r5, lr
537 LPfilt r6, r3
538 LPfilt r7, lr
539 DCfilt r4, r10
540 DCfilt r5, r11
541 DCfilt r6, r10
542 DCfilt r7, r11
543 mov r12,#1
544 Limitsh r4
545 Limitsh r5
546 Limitsh r6
547 Limitsh r7
548 subs r2, r2, #4
549 orr r4, r5, r4, lsr #16
550 orr r5, r7, r6, lsr #16
551 stmia r0!, {r4,r5}
552 bpl m32_16_st_l_loop
553
554m32_16_st_l_end:
555 @ check for remaining bytes to convert
556 tst r2, #2
557 beq m32_16_st_l_no_unal2
558 ldr r6, [r0]
559 ldmia r1!,{r4,r5}
560 add r5, r5, r6, asr #16
561 mov r6, r6, lsl #16
562 add r4, r4, r6, asr #16
563 mov r4, r4, asr r9
564 mov r5, r5, asr r9
565 ldr r12,[sp]
566 LPfilt r4, r3
567 LPfilt r5, lr
568 DCfilt r4, r10
569 DCfilt r5, r11
570 mov r12,#1
571 Limitsh r4
572 Limitsh r5
573 orr r4, r5, r4, lsr #16
574 str r4, [r0], #4
575
576m32_16_st_l_no_unal2:
577 ldr r12, =filter
578 add r12,r12, #4
579 stmia r12, {r3,r10-r11,lr}
580 add sp, sp, #4
581 ldmfd sp!, {r4-r11,lr}
582 bx lr
583
584#endif /* __GP2X__ */
585
586.global mix_reset @ int alpha_q16
587mix_reset:
588 ldr r2, =filter
589 rsb r0, r0, #0x10000
590@ mov r0, r0, asr #8
591 mov r0, r0, asr #4
592 str r0, [r2], #4
593 mov r1, #0
594 str r1, [r2], #4
595 str r1, [r2], #4
596 str r1, [r2], #4
597 str r1, [r2], #4
598 bx lr
599
600.data
601filter:
602 .ds 4 @ alpha_q8
603 .ds 8 @ filter history for left channel
604 .ds 8 @ filter history for right channel
605
606@ vim:filetype=armasm