1.32 release
[picodrive.git] / Pico / sound / mix.s
1 @ vim:filetype=armasm
2
3 @ Generic routines for mixing audio samples
4 @ (c) Copyright 2007, Grazvydas "notaz" Ignotas
5
6
7 @ this assumes src is word aligned
8 .global mix_16h_to_32 @ int *dest, short *src, int count
9
10 mix_16h_to_32:
11     stmfd   sp!, {r4-r6,lr}
12 /*
13     tst     r1, #2
14     beq     m16_32_mo_unalw
15     ldrsh   r4, [r1], #2
16     ldr     r3, [r0]
17     sub     r2, r2, #1
18     add     r3, r3, r4, asr #1
19     str     r3, [r0], #4
20 */
21 m16_32_mo_unalw:
22     subs    r2, r2, #4
23     bmi     m16_32_end
24
25 m16_32_loop:
26     ldmia   r0, {r3-r6}
27     ldmia   r1!,{r12,lr}
28     subs    r2, r2, #4
29     add     r4, r4, r12,asr #17 @ we use half volume
30     mov     r12,r12,lsl #16
31     add     r3, r3, r12,asr #17
32     add     r6, r6, lr, asr #17
33     mov     lr, lr, lsl #16
34     add     r5, r5, lr, asr #17
35     stmia   r0!,{r3-r6}
36     bpl     m16_32_loop
37
38 m16_32_end:
39     tst     r2, #2
40     beq     m16_32_no_unal2
41     ldr     r5, [r1], #4
42     ldmia   r0, {r3,r4}
43     mov     r12,r5, lsl #16
44     add     r3, r3, r12,asr #17
45     add     r4, r4, r5, asr #17
46     stmia   r0!,{r3,r4}
47
48 m16_32_no_unal2:
49     tst     r2, #1
50     ldmeqfd sp!, {r4-r6,pc}
51     ldrsh   r4, [r1], #2
52     ldr     r3, [r0]
53     add     r3, r3, r4, asr #1
54     str     r3, [r0], #4
55
56     ldmfd   sp!, {r4-r6,lr}
57     bx      lr
58
59
60
61 .global mix_16h_to_32_s1 @ int *dest, short *src, int count
62
63 mix_16h_to_32_s1:
64     stmfd   sp!, {r4-r6,lr}
65
66     subs    r2, r2, #4
67     bmi     m16_32_s1_end
68
69 m16_32_s1_loop:
70     ldmia   r0, {r3-r6}
71     ldr     r12,[r1], #8
72     ldr     lr, [r1], #8
73     subs    r2, r2, #4
74     add     r4, r4, r12,asr #17
75     mov     r12,r12,lsl #16
76     add     r3, r3, r12,asr #17 @ we use half volume
77     add     r6, r6, lr, asr #17
78     mov     lr, lr, lsl #16
79     add     r5, r5, lr, asr #17
80     stmia   r0!,{r3-r6}
81     bpl     m16_32_s1_loop
82
83 m16_32_s1_end:
84     tst     r2, #2
85     beq     m16_32_s1_no_unal2
86     ldr     r5, [r1], #8
87     ldmia   r0, {r3,r4}
88     mov     r12,r5, lsl #16
89     add     r3, r3, r12,asr #17
90     add     r4, r4, r5, asr #17
91     stmia   r0!,{r3,r4}
92
93 m16_32_s1_no_unal2:
94     tst     r2, #1
95     ldmeqfd sp!, {r4-r6,pc}
96     ldrsh   r4, [r1], #2
97     ldr     r3, [r0]
98     add     r3, r3, r4, asr #1
99     str     r3, [r0], #4
100
101     ldmfd   sp!, {r4-r6,lr}
102     bx      lr
103
104
105
106 .global mix_16h_to_32_s2 @ int *dest, short *src, int count
107
108 mix_16h_to_32_s2:
109     stmfd   sp!, {r4-r6,lr}
110
111     subs    r2, r2, #4
112     bmi     m16_32_s2_end
113
114 m16_32_s2_loop:
115     ldmia   r0, {r3-r6}
116     ldr     r12,[r1], #16
117     ldr     lr, [r1], #16
118     subs    r2, r2, #4
119     add     r4, r4, r12,asr #17
120     mov     r12,r12,lsl #16
121     add     r3, r3, r12,asr #17 @ we use half volume
122     add     r6, r6, lr, asr #17
123     mov     lr, lr, lsl #16
124     add     r5, r5, lr, asr #17
125     stmia   r0!,{r3-r6}
126     bpl     m16_32_s2_loop
127
128 m16_32_s2_end:
129     tst     r2, #2
130     beq     m16_32_s2_no_unal2
131     ldr     r5, [r1], #16
132     ldmia   r0, {r3,r4}
133     mov     r12,r5, lsl #16
134     add     r3, r3, r12,asr #17
135     add     r4, r4, r5, asr #17
136     stmia   r0!,{r3,r4}
137
138 m16_32_s2_no_unal2:
139     tst     r2, #1
140     ldmeqfd sp!, {r4-r6,pc}
141     ldrsh   r4, [r1], #2
142     ldr     r3, [r0]
143     add     r3, r3, r4, asr #1
144     str     r3, [r0], #4
145
146     ldmfd   sp!, {r4-r6,lr}
147     bx      lr
148
149
150
151 @ limit
152 @ reg=int_sample, lr=1, r3=tmp, kills flags
153 .macro Limit reg
154     add     r3, lr, \reg, asr #15
155     bics    r3, r3, #1                  @ in non-overflow conditions r3 is 0 or 1
156     movne   \reg, #0x8000
157     subpl   \reg, \reg, #1
158 .endm
159
160
161 @ limit and shift up by 16
162 @ reg=int_sample, lr=1, r3=tmp, kills flags
163 .macro Limitsh reg
164 @    movs    r4, r3, asr #16
165 @    cmnne   r4, #1
166 @    beq     c32_16_no_overflow
167 @    tst     r4, r4
168 @    mov     r3, #0x8000
169 @    subpl   r3, r3, #1
170
171     add     r3, lr, \reg, asr #15
172     bics    r3, r3, #1                  @ in non-overflow conditions r3 is 0 or 1
173     moveq   \reg, \reg, lsl #16
174     movne   \reg, #0x80000000
175     subpl   \reg, \reg, #0x00010000
176 .endm
177
178
179 @ mix 32bit audio (with 16bits really used, upper bits indicate overflow) with normal 16 bit audio with left channel only
180 @ warning: this function assumes dest is word aligned
181 .global mix_32_to_16l_stereo @ short *dest, int *src, int count
182
183 mix_32_to_16l_stereo:
184     stmfd   sp!, {r4-r8,lr}
185
186     mov     lr, #1
187
188     mov     r2, r2, lsl #1
189     subs    r2, r2, #4
190     bmi     m32_16l_st_end
191
192 m32_16l_st_loop:
193     ldmia   r0,  {r8,r12}
194     ldmia   r1!, {r4-r7}
195     mov     r8, r8, lsl #16
196     mov     r12,r12,lsl #16
197     add     r4, r4, r8, asr #16
198     add     r5, r5, r8, asr #16
199     add     r6, r6, r12,asr #16
200     add     r7, r7, r12,asr #16
201     Limitsh r4
202     Limitsh r5
203     Limitsh r6
204     Limitsh r7
205     subs    r2, r2, #4
206     orr     r4, r5, r4, lsr #16
207     orr     r5, r7, r6, lsr #16
208     stmia   r0!, {r4,r5}
209     bpl     m32_16l_st_loop
210
211 m32_16l_st_end:
212     @ check for remaining bytes to convert
213     tst     r2, #2
214     beq     m32_16l_st_no_unal2
215     ldrsh   r6, [r0]
216     ldmia   r1!,{r4,r5}
217     add     r4, r4, r6
218     add     r5, r5, r6
219     Limitsh r4
220     Limitsh r5
221     orr     r4, r5, r4, lsr #16
222     str     r4, [r0], #4
223
224 m32_16l_st_no_unal2:
225     ldmfd   sp!, {r4-r8,lr}
226     bx      lr
227
228
229 @ mix 32bit audio (with 16bits really used, upper bits indicate overflow) with normal 16 bit audio (for mono sound)
230 .global mix_32_to_16_mono @ short *dest, int *src, int count
231
232 mix_32_to_16_mono:
233     stmfd   sp!, {r4-r8,lr}
234
235     mov     lr, #1
236
237     @ check if dest is word aligned
238     tst     r0, #2
239     beq     m32_16_mo_no_unalw
240     ldrsh   r5, [r0]
241     ldr     r4, [r1], #4
242     sub     r2, r2, #1
243     add     r4, r4, r5
244     Limit   r4
245     strh    r4, [r0], #2
246
247 m32_16_mo_no_unalw:
248     subs    r2, r2, #4
249     bmi     m32_16_mo_end
250
251 m32_16_mo_loop:
252     ldmia   r0,  {r8,r12}
253     ldmia   r1!, {r4-r7}
254     add     r5, r5, r8, asr #16
255     mov     r8, r8, lsl #16
256     add     r4, r4, r8, asr #16
257     add     r7, r7, r12,asr #16
258     mov     r12,r12,lsl #16
259     add     r6, r6, r12,asr #16
260     Limitsh r4
261     Limitsh r5
262     Limitsh r6
263     Limitsh r7
264     subs    r2, r2, #4
265     orr     r4, r5, r4, lsr #16
266     orr     r5, r7, r6, lsr #16
267     stmia   r0!, {r4,r5}
268     bpl     m32_16_mo_loop
269
270 m32_16_mo_end:
271     @ check for remaining bytes to convert
272     tst     r2, #2
273     beq     m32_16_mo_no_unal2
274     ldr     r6, [r0]
275     ldmia   r1!,{r4,r5}
276     add     r5, r5, r6, asr #16
277     mov     r6, r6, lsl #16
278     add     r4, r4, r6, asr #16
279     Limitsh r4
280     Limitsh r5
281     orr     r4, r5, r4, lsr #16
282     str     r4, [r0], #4
283
284 m32_16_mo_no_unal2:
285     tst     r2, #1
286     ldmeqfd sp!, {r4-r8,pc}
287     ldrsh   r5, [r0]
288     ldr     r4, [r1], #4
289     add     r4, r4, r5
290     Limit   r4
291     strh    r4, [r0], #2
292
293     ldmfd   sp!, {r4-r8,lr}
294     bx      lr
295