diff options
Diffstat (limited to 'apps/plugins/sdl/progs/quake/snd_mix_arm.S')
-rw-r--r-- | apps/plugins/sdl/progs/quake/snd_mix_arm.S | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/snd_mix_arm.S b/apps/plugins/sdl/progs/quake/snd_mix_arm.S new file mode 100644 index 0000000000..15733d8912 --- /dev/null +++ b/apps/plugins/sdl/progs/quake/snd_mix_arm.S | |||
@@ -0,0 +1,129 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2019 Franklin Wei | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | /** Sound mixing code for ARM. **/ | ||
23 | /* Takes 8-bit mono audio and outputs stereo 16-bit samples. | ||
24 | * stereo volumes are passed as arguments. | ||
25 | * | ||
26 | * Bear with me. This is my first ARM assembly, ever. | ||
27 | */ | ||
28 | |||
29 | .text | ||
30 | .align 2 | ||
31 | .global SND_PaintChannelFrom8 | ||
32 | .type SND_PaintChannelFrom8, %function | ||
33 | |||
34 | #if defined(__ARM_ARCH_5TEJ__) | ||
35 | SND_PaintChannelFrom8: | ||
36 | // r0: int true_lvol | ||
37 | // r1: int true_rvol | ||
38 | // r2: char *sfx | ||
39 | // r3: int count | ||
40 | |||
41 | stmfd sp!, {r4, r5, r6, r7, r8, sl} | ||
42 | |||
43 | ldr ip, =paintbuffer | ||
44 | ldr ip, [ip] | ||
45 | |||
46 | mov r0, r0, asl #16 // pre-scale both volumes by 2^16 | ||
47 | mov r1, r1, asl #16 | ||
48 | |||
49 | sub r3, r3, #1 // we'll count backwards | ||
50 | // sl = 0xffff0000 | ||
51 | ldrh sl, =0xffff | ||
52 | |||
53 | .loop: | ||
54 | ldrsb r4, [r2, r3] // load *sfx[i] -> r4 | ||
55 | |||
56 | // keep endianness in mind here | ||
57 | // buffer looks like [left_0, left_1, right_0, right_1] in memory | ||
58 | // but it is loaded as [right1, right0, left1, left0] to registers | ||
59 | ldr r8, [ip, r3, lsl #2] // load paintbuffer[0:1] = RIGHTCHANNEL:LEFTCHANNEL | ||
60 | |||
61 | // handle high half (right channel) first | ||
62 | mul r5, r4, r1 // SCALEDRIGHT = SFXI * (true_rvol << 16) -- bottom half is zero | ||
63 | |||
64 | // r7 holds right channel in high half (dirty bottom half) | ||
65 | qadd r7, r5, r8 // RIGHTCHANORIG = SCALEDRIGHT + RIGHTCHANORIG (high half) | ||
66 | |||
67 | bic r7, r7, sl // zero bottom bits of r7 | ||
68 | |||
69 | // trash r5, r6 and handle left channel | ||
70 | mul r5, r4, r0 // SCALEDLEFT = SFXI * (true_rvol << 16) | ||
71 | |||
72 | mov r8, r8, lsl #16 // extract original left channel from paintbuffer | ||
73 | |||
74 | // r8 holds left channel in high half with zero bottom half | ||
75 | qadd r8, r5, r8 | ||
76 | |||
77 | // combine the two 16-bit samples in r7 as 32-bit [left:right] | ||
78 | // (use lsr to not sign-extend the lower half) | ||
79 | orr r7, r7, r8, lsr #16 | ||
80 | |||
81 | str r7, [ip, r3, lsl #2] // write 32-bit to paintbuffer | ||
82 | subs r3, r3, #1 | ||
83 | bgt .loop // must use instead of bne because of the corner case count=1 | ||
84 | |||
85 | |||
86 | |||
87 | ldmfd sp!, {r4, r5, r6, r7, r8, sl} | ||
88 | |||
89 | bx lr | ||
90 | |||
91 | #elif defined(__ARM_ARCH_6__) // ARMv6 with QADD16 (disabled) | ||
92 | SND_PaintChannelFrom8: | ||
93 | // r0: int true_lvol | ||
94 | // r1: int true_rvol | ||
95 | // r2: char *sfx | ||
96 | // r3: int count | ||
97 | |||
98 | stmfd sp!, {r4, r5, r6, r7} | ||
99 | |||
100 | ldr ip, =paintbuffer | ||
101 | ldr ip, [ip] | ||
102 | sub r3, r3, #1 // we'll count backwards | ||
103 | .loop: | ||
104 | ldrsb r4, [r2, r3] // load *sfx[i] -> r4 | ||
105 | |||
106 | // keep endianness in mind here | ||
107 | // buffer looks like [left_0, left_1, right_0, right_1] in memory | ||
108 | // but it is loaded as [right1, right0, left1, left0] to registers | ||
109 | ldr r7, [ip, r3, lsl #2] // load paintbuffer[0:1] = RIGHTCHANNEL:LEFTCHANNEL | ||
110 | |||
111 | // handle high half (right channel) first | ||
112 | mul r5, r4, r1 // SCALEDRIGHT = SFXI * true_rvol | ||
113 | mul r6, r4, r0 // SCALEDLEFT = SFXI * true_rvol | ||
114 | |||
115 | orr r6, r6, r5, lsl #16 | ||
116 | |||
117 | qadd16 r6, r6, r7 | ||
118 | |||
119 | str r6, [ip, r3, lsl #2] // write 32-bit to paintbuffer | ||
120 | |||
121 | subs r3, r3, #1 | ||
122 | bne .loop | ||
123 | |||
124 | ldmfd sp!, {r4, r5, r6, r7} | ||
125 | |||
126 | bx lr | ||
127 | #else | ||
128 | #error ARMv5/6 only | ||
129 | #endif | ||