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 SUPPORT_MC
41 /* This threshold is used to decide on the processing to be applied on
42 * front center and back center channels
43 */
44 #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)45 void LVC_MixSoft_1St_MC_float_SAT (LVMixer3_2St_FLOAT_st *ptrInstance,
46 const LVM_FLOAT *src,
47 LVM_FLOAT *dst,
48 LVM_INT16 NrFrames,
49 LVM_INT32 NrChannels,
50 LVM_INT32 ChMask)
51 {
52 char HardMixing = TRUE;
53 LVM_FLOAT TargetGain;
54 Mix_Private_FLOAT_st Target_lfe = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
55 Mix_Private_FLOAT_st Target_ctr = {LVM_MAXFLOAT, LVM_MAXFLOAT, LVM_MAXFLOAT};
56 Mix_Private_FLOAT_st *pInstance1 = \
57 (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
58 Mix_Private_FLOAT_st *pInstance2 = \
59 (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
60 Mix_Private_FLOAT_st *pMixPrivInst[4] = {pInstance1, pInstance2, &Target_ctr, &Target_lfe};
61 Mix_Private_FLOAT_st *pInstance[NrChannels];
62
63 if (audio_channel_mask_get_representation(ChMask)
64 == AUDIO_CHANNEL_REPRESENTATION_INDEX)
65 {
66 for (int i = 0; i < 2; i++)
67 {
68 pInstance[i] = pMixPrivInst[i];
69 }
70 for (int i = 2; i < NrChannels; i++)
71 {
72 pInstance[i] = pMixPrivInst[2];
73 }
74 }
75 else
76 {
77 // TODO: Combine with system/media/audio_utils/Balance.cpp
78 // Constants in system/media/audio/include/system/audio-base.h
79 // 'mixInstIdx' is used to map the appropriate mixer instance for each channel.
80 const int mixInstIdx[] = {
81 0, // AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1u,
82 1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2u,
83 2, // AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4u,
84 3, // AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8u,
85 0, // AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10u,
86 1, // AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20u,
87 0, // AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40u,
88 1, // AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80u,
89 2, // AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100u,
90 0, // AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200u,
91 1, // AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400u,
92 2, // AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800u,
93 0, // AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000u,
94 2, // AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000u,
95 1, // AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000u,
96 0, // AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000u,
97 2, // AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000u,
98 1, // AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000u,
99 0, // AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT = 0x40000u,
100 1, // AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT = 0x80000u
101 };
102 if (pInstance1->Target <= LVM_VOL_BAL_THR ||
103 pInstance2->Target <= LVM_VOL_BAL_THR)
104 {
105 Target_ctr.Target = 0.0f;
106 Target_ctr.Current = 0.0f;
107 Target_ctr.Delta = 0.0f;
108 }
109 const unsigned int idxArrSize = ARRAY_SIZE(mixInstIdx);
110 for (unsigned int i = 0, channel = ChMask; channel !=0 ; ++i)
111 {
112 const unsigned int idx = __builtin_ctz(channel);
113 if (idx < idxArrSize)
114 {
115 pInstance[i] = pMixPrivInst[mixInstIdx[idx]];
116 }
117 else
118 {
119 pInstance[i] = pMixPrivInst[2];
120 }
121 channel &= ~(1 << idx);
122 }
123 }
124
125 if (NrFrames <= 0) return;
126
127 /******************************************************************************
128 SOFT MIXING
129 *******************************************************************************/
130
131 if ((pInstance1->Current != pInstance1->Target) ||
132 (pInstance2->Current != pInstance2->Target))
133 {
134 // TODO: combine similar checks below.
135 if (pInstance1->Delta == LVM_MAXFLOAT
136 || Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
137 {
138 /* Difference is not significant anymore. Make them equal. */
139 pInstance1->Current = pInstance1->Target;
140 TargetGain = pInstance1->Target;
141 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
142 }
143 else
144 {
145 /* Soft mixing has to be applied */
146 HardMixing = FALSE;
147 }
148
149 if (HardMixing == TRUE)
150 {
151 if (pInstance2->Delta == LVM_MAXFLOAT
152 || Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
153 {
154 /* Difference is not significant anymore. Make them equal. */
155 pInstance2->Current = pInstance2->Target;
156 TargetGain = pInstance2->Target;
157 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
158 }
159 else
160 {
161 /* Soft mixing has to be applied */
162 HardMixing = FALSE;
163 }
164 }
165
166 if (HardMixing == FALSE)
167 {
168 LVC_Core_MixSoft_1St_MC_float_WRA (&pInstance[0],
169 src, dst, NrFrames, NrChannels);
170 }
171 }
172
173 /******************************************************************************
174 HARD MIXING
175 *******************************************************************************/
176
177 if (HardMixing == TRUE)
178 {
179 if ((pInstance1->Target == LVM_MAXFLOAT) && (pInstance2->Target == LVM_MAXFLOAT))
180 {
181 if (src != dst)
182 {
183 Copy_Float(src, dst, NrFrames*NrChannels);
184 }
185 }
186 else
187 {
188 LVC_Core_MixHard_1St_MC_float_SAT(&(pInstance[0]),
189 src, dst, NrFrames, NrChannels);
190 }
191 }
192
193 /******************************************************************************
194 CALL BACK
195 *******************************************************************************/
196
197 if (ptrInstance->MixerStream[0].CallbackSet)
198 {
199 if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
200 {
201 pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
202 Make them equal. */
203 TargetGain = pInstance1->Target;
204 LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0], TargetGain);
205 ptrInstance->MixerStream[0].CallbackSet = FALSE;
206 if (ptrInstance->MixerStream[0].pCallBack != 0)
207 {
208 (*ptrInstance->MixerStream[0].pCallBack) (\
209 ptrInstance->MixerStream[0].pCallbackHandle,
210 ptrInstance->MixerStream[0].pGeneralPurpose,
211 ptrInstance->MixerStream[0].CallbackParam);
212 }
213 }
214 }
215 if (ptrInstance->MixerStream[1].CallbackSet)
216 {
217 if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
218 {
219 pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore.
220 Make them equal. */
221 TargetGain = pInstance2->Target;
222 LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1], TargetGain);
223 ptrInstance->MixerStream[1].CallbackSet = FALSE;
224 if (ptrInstance->MixerStream[1].pCallBack != 0)
225 {
226 (*ptrInstance->MixerStream[1].pCallBack) (\
227 ptrInstance->MixerStream[1].pCallbackHandle,
228 ptrInstance->MixerStream[1].pGeneralPurpose,
229 ptrInstance->MixerStream[1].CallbackParam);
230 }
231 }
232 }
233 }
234 #endif
LVC_MixSoft_1St_2i_D16C31_SAT(LVMixer3_2St_FLOAT_st * ptrInstance,const LVM_FLOAT * src,LVM_FLOAT * dst,LVM_INT16 n)235 void LVC_MixSoft_1St_2i_D16C31_SAT( LVMixer3_2St_FLOAT_st *ptrInstance,
236 const LVM_FLOAT *src,
237 LVM_FLOAT *dst,
238 LVM_INT16 n)
239 {
240 char HardMixing = TRUE;
241 LVM_FLOAT TargetGain;
242 Mix_Private_FLOAT_st *pInstance1 = \
243 (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[0].PrivateParams);
244 Mix_Private_FLOAT_st *pInstance2 = \
245 (Mix_Private_FLOAT_st *)(ptrInstance->MixerStream[1].PrivateParams);
246
247 if(n <= 0) return;
248
249 /******************************************************************************
250 SOFT MIXING
251 *******************************************************************************/
252 if ((pInstance1->Current != pInstance1->Target) || (pInstance2->Current != pInstance2->Target))
253 {
254 if(pInstance1->Delta == 1.0f)
255 {
256 pInstance1->Current = pInstance1->Target;
257 TargetGain = pInstance1->Target;
258 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
259 }
260 else if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
261 {
262 pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
263 Make them equal. */
264 TargetGain = pInstance1->Target;
265 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[0]), TargetGain);
266 }
267 else
268 {
269 /* Soft mixing has to be applied */
270 HardMixing = FALSE;
271 }
272
273 if(HardMixing == TRUE)
274 {
275 if(pInstance2->Delta == 1.0f)
276 {
277 pInstance2->Current = pInstance2->Target;
278 TargetGain = pInstance2->Target;
279 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
280 }
281 else if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
282 {
283 pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore. \
284 Make them equal. */
285 TargetGain = pInstance2->Target;
286 LVC_Mixer_SetTarget(&(ptrInstance->MixerStream[1]), TargetGain);
287 }
288 else
289 {
290 /* Soft mixing has to be applied */
291 HardMixing = FALSE;
292 }
293 }
294
295 if(HardMixing == FALSE)
296 {
297 LVC_Core_MixSoft_1St_2i_D16C31_WRA( &(ptrInstance->MixerStream[0]),
298 &(ptrInstance->MixerStream[1]),
299 src, dst, n);
300 }
301 }
302
303 /******************************************************************************
304 HARD MIXING
305 *******************************************************************************/
306
307 if (HardMixing)
308 {
309 if ((pInstance1->Target == 1.0f) && (pInstance2->Target == 1.0f))
310 {
311 if(src != dst)
312 {
313 Copy_Float(src, dst, n);
314 }
315 }
316 else
317 {
318 LVC_Core_MixHard_1St_2i_D16C31_SAT(&(ptrInstance->MixerStream[0]),
319 &(ptrInstance->MixerStream[1]),
320 src, dst, n);
321 }
322 }
323
324 /******************************************************************************
325 CALL BACK
326 *******************************************************************************/
327
328 if (ptrInstance->MixerStream[0].CallbackSet)
329 {
330 if (Abs_Float(pInstance1->Current - pInstance1->Target) < pInstance1->Delta)
331 {
332 pInstance1->Current = pInstance1->Target; /* Difference is not significant anymore. \
333 Make them equal. */
334 TargetGain = pInstance1->Target;
335 LVC_Mixer_SetTarget(&ptrInstance->MixerStream[0], TargetGain);
336 ptrInstance->MixerStream[0].CallbackSet = FALSE;
337 if (ptrInstance->MixerStream[0].pCallBack != 0)
338 {
339 (*ptrInstance->MixerStream[0].pCallBack) ( \
340 ptrInstance->MixerStream[0].pCallbackHandle,
341 ptrInstance->MixerStream[0].pGeneralPurpose,
342 ptrInstance->MixerStream[0].CallbackParam );
343 }
344 }
345 }
346 if (ptrInstance->MixerStream[1].CallbackSet)
347 {
348 if (Abs_Float(pInstance2->Current - pInstance2->Target) < pInstance2->Delta)
349 {
350 pInstance2->Current = pInstance2->Target; /* Difference is not significant anymore.
351 Make them equal. */
352 TargetGain = pInstance2->Target;
353 LVC_Mixer_SetTarget(&ptrInstance->MixerStream[1], TargetGain);
354 ptrInstance->MixerStream[1].CallbackSet = FALSE;
355 if (ptrInstance->MixerStream[1].pCallBack != 0)
356 {
357 (*ptrInstance->MixerStream[1].pCallBack) (
358 ptrInstance->MixerStream[1].pCallbackHandle,
359 ptrInstance->MixerStream[1].pGeneralPurpose,
360 ptrInstance->MixerStream[1].CallbackParam );
361 }
362 }
363 }
364 }
365 /**********************************************************************************/
366