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