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