1 /*
2 * Copyright (C) 2004-2010 NXP Software
3 * Copyright (C) 2010 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /**********************************************************************************
19 INCLUDE FILES
20 ***********************************************************************************/
21
22 #include <system/audio.h>
23
24 #include "LVC_Mixer_Private.h"
25 #include "VectorArithmetic.h"
26 #include "ScalarArithmetic.h"
27
28 /**********************************************************************************
29 DEFINITIONS
30 ***********************************************************************************/
31
32 #define TRUE 1
33 #define FALSE 0
34
35 #define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof(*(a))))
36
37 /**********************************************************************************
38 FUNCTION LVC_MixSoft_1St_2i_D16C31_SAT
39 ***********************************************************************************/
40 #ifdef BUILD_FLOAT
41 #ifdef SUPPORT_MC
42 /* This threshold is used to decide on the processing to be applied on
43 * front center and back center channels
44 */
45 #define LVM_VOL_BAL_THR (0.000016f)
LVC_MixSoft_1St_MC_float_SAT(LVMixer3_2St_FLOAT_st * ptrInstance,const LVM_FLOAT * src,LVM_FLOAT * dst,LVM_INT16 NrFrames,LVM_INT32 NrChannels,LVM_INT32 ChMask)46 void LVC_MixSoft_1St_MC_float_SAT (LVMixer3_2St_FLOAT_st *ptrInstance,
47 const LVM_FLOAT *src,
48 LVM_FLOAT *dst,
49 LVM_INT16 NrFrames,
50 LVM_INT32 NrChannels,
51 LVM_INT32 ChMask)
52 {
53 char HardMixing = TRUE;
54 LVM_FLOAT TargetGain;
55 Mix_Private_FLOAT_st Target_lfe = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
56 Mix_Private_FLOAT_st Target_ctr = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
57 Mix_Private_FLOAT_st *pInstance1 = \
58 (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
59 Mix_Private_FLOAT_st *pInstance2 = \
60 (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
61 Mix_Private_FLOAT_st *pMixPrivInst[4] = {pInstance1, pInstance2, &Target_ctr, &Target_lfe};
62 Mix_Private_FLOAT_st *pInstance[NrChannels];
63
64 if (audio_channel_mask_get_representation(ChMask)
65 == AUDIO_CHANNEL_REPRESENTATION_INDEX)
66 {
67 for (int i = 0; i < 2; i++)
68 {
69 pInstance[i] = pMixPrivInst[i];
70 }
71 for (int i = 2; i < NrChannels; i++)
72 {
73 pInstance[i] = pMixPrivInst[2];
74 }
75 }
76 else
77 {
78 // TODO: Combine with system/media/audio_utils/Balance.cpp
79 // Constants in system/media/audio/include/system/audio-base.h
80 // 'mixInstIdx' is used to map the appropriate mixer instance for each channel.
81 const int mixInstIdx[] = {
82 0, // AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1u,
83 1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2u,
84 2, // AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4u,
85 3, // AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8u,
86 0, // AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10u,
87 1, // AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20u,
88 0, // AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40u,
89 1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80u,
90 2, // AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100u,
91 0, // AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200u,
92 1, // AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400u,
93 2, // AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800u,
94 0, // AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000u,
95 2, // AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000u,
96 1, // AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000u,
97 0, // AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000u,
98 2, // AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000u,
99 1, // AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000u,
100 0, // AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT = 0x40000u,
101 1, // AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT = 0x80000u
102 };
103 if (pInstance1->Target <= LVM_VOL_BAL_THR ||
104 pInstance2->Target <= LVM_VOL_BAL_THR)
105 {
106 Target_ctr.Target = 0.0f;
107 Target_ctr.Current = 0.0f;
108 Target_ctr.Delta = 0.0f;
109 }
110 const unsigned int idxArrSize = ARRAY_SIZE(mixInstIdx);
111 for (unsigned int i = 0, channel = ChMask; channel !=0 ; ++i)
112 {
113 const unsigned int idx = __builtin_ctz(channel);
114 if (idx < idxArrSize)
115 {
116 pInstance[i] = pMixPrivInst[mixInstIdx[idx]];
117 }
118 else
119 {
120 pInstance[i] = pMixPrivInst[2];
121 }
122 channel &= ~(1 << idx);
123 }
124 }
125
126 if (NrFrames <= 0) return;
127
128 /******************************************************************************
129 SOFT MIXING
130 *******************************************************************************/
131
132 if ((pInstance1->Current != pInstance1->Target) ||
133 (pInstance2->Current != pInstance2->Target))
134 {
135 // TODO: combine similar checks below.
136 if (pInstance1->Delta == LVM_MAXFLOAT
137 || Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
138 {
139 /* Difference is not significant anymore. Make them equal. */
140 pInstance1->Current = pInstance1->Target;
141 TargetGain = pInstance1->Target;
142 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
143 }
144 else
145 {
146 /* Soft mixing has to be applied */
147 HardMixing = FALSE;
148 }
149
150 if (HardMixing == TRUE)
151 {
152 if (pInstance2->Delta == LVM_MAXFLOAT
153 || Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
154 {
155 /* Difference is not significant anymore. Make them equal. */
156 pInstance2->Current = pInstance2->Target;
157 TargetGain = pInstance2->Target;
158 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
159 }
160 else
161 {
162 /* Soft mixing has to be applied */
163 HardMixing = FALSE;
164 }
165 }
166
167 if (HardMixing == FALSE)
168 {
169 LVC_Core_MixSoft_1St_MC_float_WRA (&pInstance[0],
170 src, dst, NrFrames, NrChannels);
171 }
172 }
173
174 /******************************************************************************
175 HARD MIXING
176 *******************************************************************************/
177
178 if (HardMixing == TRUE)
179 {
180 if ((pInstance1->Target == LVM_MAXFLOAT) && (pInstance2->Target == LVM_MAXFLOAT))
181 {
182 if (src != dst)
183 {
184 Copy_Float(src, dst, NrFrames*NrChannels);
185 }
186 }
187 else
188 {
189 LVC_Core_MixHard_1St_MC_float_SAT(&(pInstance[0]),
190 src, dst, NrFrames, NrChannels);
191 }
192 }
193
194 /******************************************************************************
195 CALL BACK
196 *******************************************************************************/
197
198 if (ptrInstance->MixerStream[0].CallbackSet)
199 {
200 if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
201 {
202 pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
203 Make them equal. */
204 TargetGain = pInstance1->Target;
205 LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0], TargetGain);
206 ptrInstance->MixerStream[0].CallbackSet = FALSE;
207 if (ptrInstance->MixerStream[0].pCallBack != 0)
208 {
209 (*ptrInstance->MixerStream[0].pCallBack) (\
210 ptrInstance->MixerStream[0].pCallbackHandle,
211 ptrInstance->MixerStream[0].pGeneralPurpose,
212 ptrInstance->MixerStream[0].CallbackParam);
213 }
214 }
215 }
216 if (ptrInstance->MixerStream[1].CallbackSet)
217 {
218 if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
219 {
220 pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore.
221 Make them equal. */
222 TargetGain = pInstance2->Target;
223 LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1], TargetGain);
224 ptrInstance->MixerStream[1].CallbackSet = FALSE;
225 if (ptrInstance->MixerStream[1].pCallBack != 0)
226 {
227 (*ptrInstance->MixerStream[1].pCallBack) (\
228 ptrInstance->MixerStream[1].pCallbackHandle,
229 ptrInstance->MixerStream[1].pGeneralPurpose,
230 ptrInstance->MixerStream[1].CallbackParam);
231 }
232 }
233 }
234 }
235 #endif
LVC_MixSoft_1St_2i_D16C31_SAT(LVMixer3_2St_FLOAT_st * ptrInstance,const LVM_FLOAT * src,LVM_FLOAT * dst,LVM_INT16 n)236 void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_FLOAT_st *ptrInstance,
237 const LVM_FLOAT *src,
238 LVM_FLOAT *dst,
239 LVM_INT16 n)
240 {
241 char HardMixing = TRUE;
242 LVM_FLOAT TargetGain;
243 Mix_Private_FLOAT_st *pInstance1 = \
244 (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
245 Mix_Private_FLOAT_st *pInstance2 = \
246 (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
247
248 if(n <= 0) return;
249
250 /******************************************************************************
251 SOFT MIXING
252 *******************************************************************************/
253 if ((pInstance1->Current != pInstance1->Target) || (pInstance2->Current != pInstance2->Target))
254 {
255 if(pInstance1->Delta == 1.0f)
256 {
257 pInstance1->Current = pInstance1->Target;
258 TargetGain = pInstance1->Target;
259 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
260 }
261 else if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
262 {
263 pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
264 Make them equal. */
265 TargetGain = pInstance1->Target;
266 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
267 }
268 else
269 {
270 /* Soft mixing has to be applied */
271 HardMixing = FALSE;
272 }
273
274 if(HardMixing == TRUE)
275 {
276 if(pInstance2->Delta == 1.0f)
277 {
278 pInstance2->Current = pInstance2->Target;
279 TargetGain = pInstance2->Target;
280 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
281 }
282 else if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
283 {
284 pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore. \
285 Make them equal. */
286 TargetGain = pInstance2->Target;
287 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
288 }
289 else
290 {
291 /* Soft mixing has to be applied */
292 HardMixing = FALSE;
293 }
294 }
295
296 if(HardMixing == FALSE)
297 {
298 LVC_Core_MixSoft_1St_2i_D16C31_WRA( &(ptrInstance->MixerStream[0]),
299 &(ptrInstance->MixerStream[1]),
300 src, dst, n);
301 }
302 }
303
304 /******************************************************************************
305 HARD MIXING
306 *******************************************************************************/
307
308 if (HardMixing)
309 {
310 if ((pInstance1->Target == 1.0f) && (pInstance2->Target == 1.0f))
311 {
312 if(src != dst)
313 {
314 Copy_Float(src, dst, n);
315 }
316 }
317 else
318 {
319 LVC_Core_MixHard_1St_2i_D16C31_SAT(&(ptrInstance->MixerStream[0]),
320 &(ptrInstance->MixerStream[1]),
321 src, dst, n);
322 }
323 }
324
325 /******************************************************************************
326 CALL BACK
327 *******************************************************************************/
328
329 if (ptrInstance->MixerStream[0].CallbackSet)
330 {
331 if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
332 {
333 pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
334 Make them equal. */
335 TargetGain = pInstance1->Target;
336 LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0], TargetGain);
337 ptrInstance->MixerStream[0].CallbackSet = FALSE;
338 if (ptrInstance->MixerStream[0].pCallBack != 0)
339 {
340 (*ptrInstance->MixerStream[0].pCallBack) ( \
341 ptrInstance->MixerStream[0].pCallbackHandle,
342 ptrInstance->MixerStream[0].pGeneralPurpose,
343 ptrInstance->MixerStream[0].CallbackParam );
344 }
345 }
346 }
347 if (ptrInstance->MixerStream[1].CallbackSet)
348 {
349 if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
350 {
351 pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore.
352 Make them equal. */
353 TargetGain = pInstance2->Target;
354 LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1], TargetGain);
355 ptrInstance->MixerStream[1].CallbackSet = FALSE;
356 if (ptrInstance->MixerStream[1].pCallBack != 0)
357 {
358 (*ptrInstance->MixerStream[1].pCallBack) (
359 ptrInstance->MixerStream[1].pCallbackHandle,
360 ptrInstance->MixerStream[1].pGeneralPurpose,
361 ptrInstance->MixerStream[1].CallbackParam );
362 }
363 }
364 }
365 }
366 #else
LVC_MixSoft_1St_2i_D16C31_SAT(LVMixer3_2St_st * ptrInstance,const LVM_INT16 * src,LVM_INT16 * dst,LVM_INT16 n)367 void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_st *ptrInstance,
368 const LVM_INT16 *src,
369 LVM_INT16 *dst,
370 LVM_INT16 n)
371 {
372 char HardMixing = TRUE;
373 LVM_INT32 TargetGain;
374 Mix_Private_st *pInstance1=(Mix_Private_st *)(ptrInstance->MixerStream[0].PrivateParams);
375 Mix_Private_st *pInstance2=(Mix_Private_st *)(ptrInstance->MixerStream[1].PrivateParams);
376
377 if(n<=0) return;
378
379 /******************************************************************************
380 SOFT MIXING
381 *******************************************************************************/
382 if ((pInstance1->Current != pInstance1->Target)||(pInstance2->Current != pInstance2->Target))
383 {
384 if(pInstance1->Delta == 0x7FFFFFFF)
385 {
386 pInstance1->Current = pInstance1->Target;
387 TargetGain=pInstance1->Target>>16; // TargetGain in Q16.15 format, no integer part
388 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]),TargetGain);
389 }
390 else if (Abs_32(pInstance1->Current-pInstance1->Target) < pInstance1->Delta)
391 {
392 pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. Make them equal. */
393 TargetGain=pInstance1->Target>>16; // TargetGain in Q16.15 format, no integer part
394 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]),TargetGain);
395 }
396 else
397 {
398 /* Soft mixing has to be applied */
399 HardMixing = FALSE;
400 }
401
402 if(HardMixing == TRUE)
403 {
404 if(pInstance2->Delta == 0x7FFFFFFF)
405 {
406 pInstance2->Current = pInstance2->Target;
407 TargetGain=pInstance2->Target>>16; // TargetGain in Q16.15 format, no integer part
408 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]),TargetGain);
409 }
410 else if (Abs_32(pInstance2->Current-pInstance2->Target) < pInstance2->Delta)
411 {
412 pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore. Make them equal. */
413 TargetGain=pInstance2->Target>>16; // TargetGain in Q16.15 format, no integer part
414 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]),TargetGain);
415 }
416 else
417 {
418 /* Soft mixing has to be applied */
419 HardMixing = FALSE;
420 }
421 }
422
423 if(HardMixing == FALSE)
424 {
425 LVC_Core_MixSoft_1St_2i_D16C31_WRA( &(ptrInstance->MixerStream[0]),&(ptrInstance->MixerStream[1]), src, dst, n);
426 }
427 }
428
429 /******************************************************************************
430 HARD MIXING
431 *******************************************************************************/
432
433 if (HardMixing)
434 {
435 if (((pInstance1->Target>>16) == 0x7FFF)&&((pInstance2->Target>>16) == 0x7FFF))
436 {
437 if(src!=dst)
438 {
439 Copy_16(src, dst, n);
440 }
441 }
442 else
443 {
444 LVC_Core_MixHard_1St_2i_D16C31_SAT(&(ptrInstance->MixerStream[0]),&(ptrInstance->MixerStream[1]), src, dst, n);
445 }
446 }
447
448 /******************************************************************************
449 CALL BACK
450 *******************************************************************************/
451
452 if (ptrInstance->MixerStream[0].CallbackSet)
453 {
454 if (Abs_32(pInstance1->Current-pInstance1->Target) < pInstance1->Delta)
455 {
456 pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. Make them equal. */
457 TargetGain=pInstance1->Target>>(16-pInstance1->Shift); // TargetGain in Q16.15 format
458 LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0],TargetGain);
459 ptrInstance->MixerStream[0].CallbackSet = FALSE;
460 if (ptrInstance->MixerStream[0].pCallBack != 0)
461 {
462 (*ptrInstance->MixerStream[0].pCallBack) ( ptrInstance->MixerStream[0].pCallbackHandle, ptrInstance->MixerStream[0].pGeneralPurpose,ptrInstance->MixerStream[0].CallbackParam );
463 }
464 }
465 }
466 if (ptrInstance->MixerStream[1].CallbackSet)
467 {
468 if (Abs_32(pInstance2->Current-pInstance2->Target) < pInstance2->Delta)
469 {
470 pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore. Make them equal. */
471 TargetGain=pInstance2->Target>>(16-pInstance2->Shift); // TargetGain in Q16.15 format
472 LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1],TargetGain);
473 ptrInstance->MixerStream[1].CallbackSet = FALSE;
474 if (ptrInstance->MixerStream[1].pCallBack != 0)
475 {
476 (*ptrInstance->MixerStream[1].pCallBack) ( ptrInstance->MixerStream[1].pCallbackHandle, ptrInstance->MixerStream[1].pGeneralPurpose,ptrInstance->MixerStream[1].CallbackParam );
477 }
478 }
479 }
480 }
481 #endif
482 /**********************************************************************************/
483