1 /*
2 * @file api68.c
3 * @brief audio mixer
4 * @author http://sourceforge.net/users/benjihan
5 *
6 * Copyright (c) 1998-2015 Benjamin Gerard
7 *
8 * This program is free software: you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation, either version 3 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program.
20 *
21 * If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28 #include "mixer68.h"
29
30 /* ARM compliant version */
31 /* #define SWAP_16BITWORD(V) ((V^=V<<16), (V^=V>>16), (V^=V<<16)) */
32
33 #define SWAP_16BITWORD(V) (((u32)(V)>>16)+(V<<16))
34
35 /* Mix 16-bit-stereo PCM into 16-bit-stereo with sign change.
36 *
37 * PCM' = PCM ^ sign
38 *
39 * sign=0 : Keep input sign,
40 * sign=0x00008000 : Change left channel sign
41 * sign=0x80000000 : Change right channel sign
42 * sign=0x80008000 : Change both channel
43 */
mixer68_stereo_16_LR(u32 * dst,u32 * src,int nb,const u32 sign)44 void mixer68_stereo_16_LR(u32 * dst, u32 * src, int nb, const u32 sign)
45 {
46 u32 *end;
47
48 /* Optimize trivial case : same buffer, no sign change */
49 if (!sign && dst == src) {
50 return;
51 }
52
53 end = dst+nb;
54 if (nb&1) {
55 *dst++ = (*src++) ^ sign;
56 }
57 if (nb&2) {
58 *dst++ = (*src++) ^ sign;
59 *dst++ = (*src++) ^ sign;
60 }
61 if (dst<end) {
62 do {
63 *dst++ = (*src++) ^ sign;
64 *dst++ = (*src++) ^ sign;
65 *dst++ = (*src++) ^ sign;
66 *dst++ = (*src++) ^ sign;
67 } while (dst < end);
68 }
69
70 }
71
72 /* Mix 16-bit-stereo PCM into 16-bit-stereo PCM with channel swapping.
73 */
mixer68_stereo_16_RL(u32 * dst,u32 * src,int nb,const u32 sign)74 void mixer68_stereo_16_RL(u32 * dst, u32 * src, int nb, const u32 sign)
75 {
76 u32 *end;
77
78 #undef MIX_ONE
79 #define MIX_ONE \
80 v = (*src++); \
81 *dst++ = SWAP_16BITWORD(v) ^ sign
82
83 end = dst+nb;
84 if (nb&1) {
85 u32 v;
86 MIX_ONE;
87 }
88 if (nb&2) {
89 u32 v;
90 MIX_ONE;
91 MIX_ONE;
92 }
93 if (dst<end) {
94 do {
95 u32 v;
96 MIX_ONE;
97 MIX_ONE;
98 MIX_ONE;
99 MIX_ONE;
100 } while (dst < end);
101 }
102
103 }
104
105 /* Mix 16-bit-stereo PCM into 32-bit-stereo-float (-norm..norm)
106 */
mixer68_stereo_FL_LR(float * dst,u32 * src,int nb,const u32 sign,const float norm)107 void mixer68_stereo_FL_LR (float * dst, u32 * src, int nb,
108 const u32 sign, const float norm)
109 {
110 const float mult = norm / 32768.0f;
111 int v;
112 float * const end = dst + (nb<<1);
113 if (dst < end) {
114 do {
115 v = (int)(s32)(*src++ ^ sign);
116 *dst++ = mult * (float)(s16)(v);
117 *dst++ = mult * (float)(v>>16);
118 } while (dst < end);
119 }
120 }
121
122 /* Duplicate left channel into right channel and change sign.
123 * PCM' = ( PCM-L | (PCM-L<<16) ) ^ sign
124 */
mixer68_dup_L_to_R(u32 * dst,u32 * src,int nb,const u32 sign)125 void mixer68_dup_L_to_R(u32 *dst, u32 *src, int nb,
126 const u32 sign)
127 {
128 u32 * const end = dst+nb;
129 if (nb&1) {
130 u32 v;
131 v = (u16)*src++; *dst++ = ((v<<16)|v) ^ sign;
132 }
133 if (nb&2) {
134 u32 v;
135 v = (u16)*src++; *dst++ = ((v<<16)|v) ^ sign;
136 v = (u16)*src++; *dst++ = ((v<<16)|v) ^ sign;
137 }
138 if (dst < end) {
139 do {
140 u32 v;
141 v = (u16)*src++; *dst++ = ((v<<16)|v) ^ sign;
142 v = (u16)*src++; *dst++ = ((v<<16)|v) ^ sign;
143 v = (u16)*src++; *dst++ = ((v<<16)|v) ^ sign;
144 v = (u16)*src++; *dst++ = ((v<<16)|v) ^ sign;
145 } while (dst < end);
146 }
147
148 }
149
150 /* Duplicate right channel into left channel and change sign.
151 * PCM = ( PCM-R | (PCM-R>>16) ) ^ sign
152 */
mixer68_dup_R_to_L(u32 * dst,u32 * src,int nb,const u32 sign)153 void mixer68_dup_R_to_L(u32 *dst, u32 *src, int nb, const u32 sign)
154 {
155 u32 * const end = dst+nb;
156
157 if (nb&1) {
158 u32 v;
159 v = *src++&0xFFFF0000; *dst++ = ((v>>16)|v) ^ sign;
160 }
161 if (nb&2) {
162 u32 v;
163 v = *src++&0xFFFF0000; *dst++ = ((v>>16)|v) ^ sign;
164 v = *src++&0xFFFF0000; *dst++ = ((v>>16)|v) ^ sign;
165 }
166 if (dst < end) {
167 do {
168 u32 v;
169 v = *src++&0xFFFF0000; *dst++ = ((v>>16)|v) ^ sign;
170 v = *src++&0xFFFF0000; *dst++ = ((v>>16)|v) ^ sign;
171 v = *src++&0xFFFF0000; *dst++ = ((v>>16)|v) ^ sign;
172 v = *src++&0xFFFF0000; *dst++ = ((v>>16)|v) ^ sign;
173 } while (dst < end);
174 }
175
176 }
177
178 /* Blend Left and right voice :
179 * factor [0..65536], 0:blend nothing, 65536:swap L/R
180 */
mixer68_blend_LR(u32 * dst,u32 * src,int nb,int factor,const u32 sign_r,const u32 sign_w)181 void mixer68_blend_LR(u32 * dst, u32 * src, int nb,
182 int factor,
183 const u32 sign_r, const u32 sign_w)
184 {
185 u32 *end;
186 int oof;
187
188 if (factor < 0) {
189 factor = 0;
190 } else if (factor > 65536) {
191 factor = 65536;
192 }
193
194 #undef MIX_ONE
195 #define MIX_ONE \
196 r = (int)(s32)(*src++ ^ sign_r); \
197 l = r >> 16; \
198 r = (int)(s16)r; \
199 *dst++ = ( \
200 ((l*oof+r*factor)&0xFFFF0000) \
201 | \
202 ((u32)(r*oof+l*factor) >> 16) \
203 ) ^ sign_w
204
205 oof = 65536-factor;
206 end = dst+nb;
207 if (nb&1) {
208 int l,r;
209 MIX_ONE;
210 }
211 if (nb&2) {
212 int l,r;
213 MIX_ONE;
214 MIX_ONE;
215 }
216 if (dst < end) {
217 do {
218 int l,r;
219
220 MIX_ONE;
221 MIX_ONE;
222 MIX_ONE;
223 MIX_ONE;
224 } while (dst < end);
225 }
226
227 }
228
229 /* Multiply left/right (signed) channel by ml/mr factor [-65536..65536]
230 */
mixer68_mult_LR(u32 * dst,u32 * src,int nb,const int ml,const int mr,const u32 sign_r,const u32 sign_w)231 void mixer68_mult_LR(u32 *dst, u32 *src, int nb,
232 const int ml, const int mr,
233 const u32 sign_r, const u32 sign_w)
234 {
235 u32 * end;
236
237 /* Optimize some trivial case. */
238
239 if (ml == 65536 && mr == 65536) {
240 mixer68_stereo_16_LR(dst, src, nb, sign_r ^ sign_w);
241 return;
242 }
243
244 if (ml==0 && mr==0) {
245 mixer68_fill(dst, nb, sign_w);
246 return;
247 }
248
249 #undef MIX_ONE
250 #define MIX_ONE \
251 r = (int)(s32)(*src++ ^ sign_r); \
252 l = (int)(s16)r; \
253 r = r >> 16; \
254 *dst++ = ((((u32)(l*ml))>>16) | ((r*mr)&0xFFFF0000)) ^ sign_w
255
256 end = dst+nb;
257
258 if (nb&1) {
259 int l,r;
260 MIX_ONE;
261 }
262
263 if (nb&2) {
264 int l,r;
265 MIX_ONE;
266 MIX_ONE;
267 }
268
269 if (dst < end) {
270 do {
271 int l,r;
272 MIX_ONE;
273 MIX_ONE;
274 MIX_ONE;
275 MIX_ONE;
276 } while (dst < end);
277 }
278
279 }
280
281 /* Fill buffer sign with value (RRRRLLLL)
282 */
mixer68_fill(u32 * dst,int nb,const u32 sign)283 void mixer68_fill(u32 * dst, int nb, const u32 sign)
284 {
285 u32 * const end = dst+nb;;
286
287 if (nb&1) {
288 *dst++ = sign;
289 }
290 if (nb&2) {
291 *dst++ = sign;
292 *dst++ = sign;
293 }
294 if (dst < end) {
295 do {
296 *dst++ = sign;
297 *dst++ = sign;
298 *dst++ = sign;
299 *dst++ = sign;
300 } while (dst < end);
301 }
302 }
303
mixer68_copy(u32 * dst,u32 * src,int nb)304 void mixer68_copy(u32 * dst, u32 * src, int nb)
305 {
306 /* Optimize trivial case : same buffer */
307 if (dst == src || nb <= 0) {
308 return;
309 } else {
310 u32 * const end = dst+nb;
311 if (nb&1) {
312 *dst++ = *src++;
313 }
314 if (nb&2) {
315 *dst++ = *src++;
316 *dst++ = *src++;
317 }
318 if (dst<end) {
319 do {
320 *dst++ = *src++;
321 *dst++ = *src++;
322 *dst++ = *src++;
323 *dst++ = *src++;
324 } while (dst < end);
325 }
326 }
327 }
328