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