• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /*                                                                                  */
20 /*  Includes                                                                        */
21 /*                                                                                  */
22 /************************************************************************************/
23 
24 #include "LVCS.h"
25 #include "LVCS_Private.h"
26 #include "LVCS_BypassMix.h"
27 #include "VectorArithmetic.h"
28 #include "LVCS_Tables.h"
29 
30 /****************************************************************************************/
31 /*                                                                                      */
32 /*  Function Prototypes                                                                 */
33 /*                                                                                      */
34 /****************************************************************************************/
35 LVM_INT32 LVCS_MixerCallback(   LVCS_Handle_t   hInstance,
36                                 void            *pGeneralPurpose,
37                                 LVM_INT16       CallbackParam);
38 
39 /************************************************************************************/
40 /*                                                                                  */
41 /* FUNCTION:                LVCS_BypassMixInit                                      */
42 /*                                                                                  */
43 /* DESCRIPTION:                                                                     */
44 /*  Initialises the bypass mixer module                                             */
45 /*                                                                                  */
46 /*  The overall gain of the processed path is set by the gains in the individual    */
47 /*  processing blocks and by the effect level gain.                                 */
48 /*                                                                                  */
49 /*  The unprocessed path must have matching gain for the processed path to ensure   */
50 /*  as they are mixed together the correct effect is achieved, this is the value    */
51 /*  UnprocLoss.                                                                     */
52 /*                                                                                  */
53 /*  The overall gain is corrected by a combination of a shift with saturation and a */
54 /*  linear scaler, loss. The loss ensures the sum in the mixer does not saturate    */
55 /*  and also corrects for any excess gain in the shift.                             */
56 /*                                                                                  */
57 /* PARAMETERS:                                                                      */
58 /*  hInstance               Instance Handle                                         */
59 /*  pParams                 Initialisation parameters                               */
60 /*                                                                                  */
61 /* RETURNS:                                                                         */
62 /*  LVCS_Success            Always succeeds                                         */
63 /*                                                                                  */
64 /* NOTES:                                                                           */
65 /*                                                                                  */
66 /************************************************************************************/
67 
LVCS_BypassMixInit(LVCS_Handle_t hInstance,LVCS_Params_t * pParams)68 LVCS_ReturnStatus_en LVCS_BypassMixInit(LVCS_Handle_t       hInstance,
69                                         LVCS_Params_t       *pParams)
70 {
71 
72     LVM_UINT16          Offset;
73 #ifndef BUILD_FLOAT
74     LVM_UINT32          Gain;
75     LVM_INT32           Current;
76 #else
77     LVM_FLOAT           Gain;
78     LVM_FLOAT           Current;
79 #endif
80     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
81     LVCS_BypassMix_t    *pConfig   = (LVCS_BypassMix_t *)&pInstance->BypassMix;
82     const Gain_t        *pOutputGainTable;
83 
84 
85 
86     /*
87      * Set the transition gain
88      */
89     if ((pParams->OperatingMode == LVCS_ON) &&
90         (pInstance->bTimerDone == LVM_TRUE)
91         && (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transtion */
92         )
93     {
94 #ifndef BUILD_FLOAT
95         pInstance->TransitionGain = pParams->EffectLevel;
96 #else
97         pInstance->TransitionGain = ((LVM_FLOAT)pParams->EffectLevel / 32767);
98 #endif
99     }
100     else
101     {
102         /* Select no effect level */
103         pInstance->TransitionGain = 0;
104     }
105 
106     /*
107      * Calculate the output gain table offset
108      */
109     Offset = (LVM_UINT16)(pParams->SpeakerType + (pParams->SourceFormat*(1+LVCS_EX_HEADPHONES)));
110     pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
111 
112     /*
113      * Setup the mixer gain for the processed path
114      */
115 #ifndef BUILD_FLOAT
116     Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
117 #else
118     Gain =  (LVM_FLOAT)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
119 #endif
120 
121     pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0;
122     pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL;
123     pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL;
124     pConfig->Mixer_Instance.MixerStream[0].CallbackSet=1;
125 
126 #ifndef BUILD_FLOAT
127     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
128     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0],(LVM_INT32)(Gain >> 15),Current);
129     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
130 #else
131     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
132     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0], (LVM_FLOAT)(Gain), Current);
133     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
134                                        LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
135 #endif
136 
137     /*
138      * Setup the mixer gain for the unprocessed path
139      */
140 #ifndef BUILD_FLOAT
141     Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * (0x7FFF - pInstance->TransitionGain));
142     Gain = (LVM_UINT32)pOutputGainTable[Offset].UnprocLoss * (Gain >> 15);
143     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
144     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1],(LVM_INT32)(Gain >> 15),Current);
145     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
146 #else
147     Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * (1.0 - \
148                                     (LVM_FLOAT)pInstance->TransitionGain));
149     Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * Gain;
150     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
151     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1], (LVM_FLOAT)(Gain), Current);
152     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
153                                        LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
154 #endif
155     pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0;
156     pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance;
157     pConfig->Mixer_Instance.MixerStream[1].CallbackSet=1;
158     pConfig->Mixer_Instance.MixerStream[1].pCallBack = LVCS_MixerCallback;
159 
160     /*
161      * Setup the output gain shift
162      */
163     pConfig->Output_Shift = pOutputGainTable[Offset].Shift;
164 
165 
166     /*
167      * Correct gain for the effect level
168      */
169     {
170 #ifndef BUILD_FLOAT
171         LVM_INT16           GainCorrect;
172         LVM_INT32           Gain1;
173         LVM_INT32           Gain2;
174 
175         Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
176         Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
177         /*
178          * Calculate the gain correction
179          */
180         if (pInstance->Params.CompressorMode == LVM_MODE_ON)
181         {
182         GainCorrect = (LVM_INT16)(  pInstance->VolCorrect.GainMin
183                                     - (((LVM_INT32)pInstance->VolCorrect.GainMin * (LVM_INT32)pInstance->TransitionGain) >> 15)
184                                     + (((LVM_INT32)pInstance->VolCorrect.GainFull * (LVM_INT32)pInstance->TransitionGain) >> 15) );
185 
186         /*
187          * Apply the gain correction and shift, note the result is in Q3.13 format
188          */
189         Gain1 = (Gain1 * GainCorrect) << 4;
190         Gain2 = (Gain2 * GainCorrect) << 4;
191         }
192         else
193         {
194             Gain1 = Gain1 << 16;
195             Gain2 = Gain2 << 16;
196         }
197 
198 
199 
200         /*
201          * Set the gain values
202          */
203         pConfig->Output_Shift = pConfig->Output_Shift;
204         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1>>16);
205         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
206         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2>>16);
207         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
208 #else
209         LVM_FLOAT           GainCorrect;
210         LVM_FLOAT           Gain1;
211         LVM_FLOAT           Gain2;
212 
213         Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
214         Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
215         /*
216          * Calculate the gain correction
217          */
218         if (pInstance->Params.CompressorMode == LVM_MODE_ON)
219         {
220         GainCorrect = (LVM_FLOAT)(  pInstance->VolCorrect.GainMin
221                                     - (((LVM_FLOAT)pInstance->VolCorrect.GainMin * \
222                                                          ((LVM_FLOAT)pInstance->TransitionGain)))
223                                     + (((LVM_FLOAT)pInstance->VolCorrect.GainFull * \
224                                                         ((LVM_FLOAT)pInstance->TransitionGain))));
225 
226         /*
227          * Apply the gain correction
228          */
229         Gain1 = (Gain1 * GainCorrect);
230         Gain2 = (Gain2 * GainCorrect);
231 
232         }
233 
234         /*
235          * Set the gain values
236          */
237         pConfig->Output_Shift = pConfig->Output_Shift;
238         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1);
239         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
240                                            LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
241         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2);
242         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
243                                            LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
244 #endif
245     }
246 
247     return(LVCS_SUCCESS);
248 
249 }
250 
251 /************************************************************************************/
252 /*                                                                                  */
253 /* FUNCTION:                LVCS_BypassMixer                                        */
254 /*                                                                                  */
255 /* DESCRIPTION:                                                                     */
256 /*  Apply Bypass Mix.                                                               */
257 /*                                                                                  */
258 /*  This mixes the processed and unprocessed data streams together to correct the   */
259 /*  overall system gain and allow progressive control of the Concert Sound effect.  */
260 /*                                                                                  */
261 /*  When the bypass mixer is enabled the output is the processed signal only and    */
262 /*  without gain correction.                                                        */
263 /*                                                                                  */
264 /* PARAMETERS:                                                                      */
265 /*  hInstance               Instance Handle                                         */
266 /*  pProcessed              Pointer to the processed data                           */
267 /*  pUnprocessed            Pointer to the unprocessed data                         */
268 /*  pOutData                Pointer to the output data                              */
269 /*  NumSamples              Number of samples to process                            */
270 /*                                                                                  */
271 /* RETURNS:                                                                         */
272 /*  LVCS_Success            Always succeeds                                         */
273 /*                                                                                  */
274 /* NOTES:                                                                           */
275 /*                                                                                  */
276 /************************************************************************************/
277 
LVCS_BypassMixer(LVCS_Handle_t hInstance,const LVM_INT16 * pProcessed,const LVM_INT16 * pUnprocessed,LVM_INT16 * pOutData,LVM_UINT16 NumSamples)278 LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t         hInstance,
279 #ifndef BUILD_FLOAT
280                                       const LVM_INT16       *pProcessed,
281                                       const LVM_INT16       *pUnprocessed,
282                                       LVM_INT16             *pOutData,
283 #else
284                                       const LVM_FLOAT       *pProcessed,
285                                       const LVM_FLOAT       *pUnprocessed,
286                                       LVM_FLOAT             *pOutData,
287 #endif
288                                       LVM_UINT16            NumSamples)
289 {
290 
291     LVCS_Instance_t     *pInstance      = (LVCS_Instance_t  *)hInstance;
292     LVCS_BypassMix_t    *pConfig        = (LVCS_BypassMix_t *)&pInstance->BypassMix;
293 
294     /*
295      * Check if the bypass mixer is enabled
296      */
297     if ((pInstance->Params.OperatingMode & LVCS_BYPASSMIXSWITCH) != 0)
298     {
299         /*
300          * Apply the bypass mix
301          */
302 #ifndef BUILD_FLOAT
303         LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
304                                         pProcessed,
305                                         (LVM_INT16 *) pUnprocessed,
306                                         pOutData,
307                                         (LVM_INT16)(2*NumSamples));
308 
309         /*
310          * Apply output gain correction shift
311          */
312         Shift_Sat_v16xv16 ((LVM_INT16)pConfig->Output_Shift,
313                           (LVM_INT16*)pOutData,
314                           (LVM_INT16*)pOutData,
315                           (LVM_INT16)(2*NumSamples));          /* Left and right*/
316 #else
317         LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
318                                    pProcessed,
319                                    (LVM_FLOAT *) pUnprocessed,
320                                    pOutData,
321                                    (LVM_INT16)(2 * NumSamples));
322         /*
323          * Apply output gain correction shift
324          */
325         Shift_Sat_Float((LVM_INT16)pConfig->Output_Shift,
326                         (LVM_FLOAT*)pOutData,
327                         (LVM_FLOAT*)pOutData,
328                         (LVM_INT16)(2 * NumSamples));          /* Left and right*/
329 #endif
330     }
331 
332     return(LVCS_SUCCESS);
333 }
334 
335 
336 /************************************************************************************/
337 /*                                                                                  */
338 /* FUNCTION:                LVCS_MixerCallback                                      */
339 /*                                                                                  */
340 /************************************************************************************/
LVCS_MixerCallback(LVCS_Handle_t hInstance,void * pGeneralPurpose,LVM_INT16 CallbackParam)341 LVM_INT32 LVCS_MixerCallback(LVCS_Handle_t      hInstance,
342                             void                *pGeneralPurpose,
343                             LVM_INT16           CallbackParam)
344 {
345     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
346 
347    (void)pGeneralPurpose;
348 
349     /*
350      * Off transition has completed in Headphone mode
351      */
352     if ((pInstance->OutputDevice == LVCS_HEADPHONE) &&
353         (pInstance->bInOperatingModeTransition)     &&
354         (pInstance->MSTarget0 == 0x0000)&&  /* this indicates an on->off transition */
355         (CallbackParam == 0))
356     {
357         /* Set operating mode to OFF */
358         pInstance->Params.OperatingMode = LVCS_OFF;
359 
360         /* Exit transition state */
361         pInstance->bInOperatingModeTransition = LVM_FALSE;
362 
363         /* Signal to the bundle */
364         if((*pInstance->Capabilities.CallBack) != LVM_NULL){
365             (*pInstance->Capabilities.CallBack)(pInstance->Capabilities.pBundleInstance,
366                                                 LVM_NULL,
367                                                 (ALGORITHM_CS_ID | LVCS_EVENT_ALGOFF));
368         }
369     }
370 
371 
372     if ((pInstance->OutputDevice == LVCS_HEADPHONE)  &&
373         (pInstance->MSTarget0 == 1) &&
374         (pInstance->bTimerDone == LVM_TRUE)){
375 
376         /* Exit transition state */
377         pInstance->bInOperatingModeTransition = LVM_FALSE;
378     }
379 
380     return 1;
381 }
382 
383 
384 
385