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     LVM_FLOAT           Gain;
74     LVM_FLOAT           Current;
75     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
76     LVCS_BypassMix_t    *pConfig   = (LVCS_BypassMix_t *)&pInstance->BypassMix;
77     const Gain_t        *pOutputGainTable;
78 
79     /*
80      * Set the transition gain
81      */
82     if ((pParams->OperatingMode == LVCS_ON) &&
83         (pInstance->bTimerDone == LVM_TRUE)
84         && (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transtion */
85         )
86     {
87         pInstance->TransitionGain = ((LVM_FLOAT)pParams->EffectLevel / 32767);
88     }
89     else
90     {
91         /* Select no effect level */
92         pInstance->TransitionGain = 0;
93     }
94 
95     /*
96      * Calculate the output gain table offset
97      */
98     Offset = (LVM_UINT16)(pParams->SpeakerType + (pParams->SourceFormat*(1+LVCS_EX_HEADPHONES)));
99     pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
100 
101     /*
102      * Setup the mixer gain for the processed path
103      */
104     Gain =  (LVM_FLOAT)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
105 
106     pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0;
107     pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL;
108     pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL;
109     pConfig->Mixer_Instance.MixerStream[0].CallbackSet=1;
110 
111     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
112     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0], (LVM_FLOAT)(Gain), Current);
113     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
114                                        LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
115 
116     /*
117      * Setup the mixer gain for the unprocessed path
118      */
119     Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * (1.0 - \
120                                     (LVM_FLOAT)pInstance->TransitionGain));
121     Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * Gain;
122     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
123     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1], (LVM_FLOAT)(Gain), Current);
124     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
125                                        LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
126     pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0;
127     pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance;
128     pConfig->Mixer_Instance.MixerStream[1].CallbackSet=1;
129     pConfig->Mixer_Instance.MixerStream[1].pCallBack = LVCS_MixerCallback;
130 
131     /*
132      * Setup the output gain shift
133      */
134     pConfig->Output_Shift = pOutputGainTable[Offset].Shift;
135 
136     /*
137      * Correct gain for the effect level
138      */
139     {
140         LVM_FLOAT           GainCorrect;
141         LVM_FLOAT           Gain1;
142         LVM_FLOAT           Gain2;
143 
144         Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
145         Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
146         /*
147          * Calculate the gain correction
148          */
149         if (pInstance->Params.CompressorMode == LVM_MODE_ON)
150         {
151         GainCorrect = (LVM_FLOAT)(  pInstance->VolCorrect.GainMin
152                                     - (((LVM_FLOAT)pInstance->VolCorrect.GainMin * \
153                                                          ((LVM_FLOAT)pInstance->TransitionGain)))
154                                     + (((LVM_FLOAT)pInstance->VolCorrect.GainFull * \
155                                                         ((LVM_FLOAT)pInstance->TransitionGain))));
156 
157         /*
158          * Apply the gain correction
159          */
160         Gain1 = (Gain1 * GainCorrect);
161         Gain2 = (Gain2 * GainCorrect);
162 
163         }
164 
165         /*
166          * Set the gain values
167          */
168         pConfig->Output_Shift = pConfig->Output_Shift;
169         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1);
170         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
171                                            LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
172         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2);
173         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
174                                            LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
175     }
176 
177     return(LVCS_SUCCESS);
178 
179 }
180 
181 /************************************************************************************/
182 /*                                                                                  */
183 /* FUNCTION:                LVCS_BypassMixer                                        */
184 /*                                                                                  */
185 /* DESCRIPTION:                                                                     */
186 /*  Apply Bypass Mix.                                                               */
187 /*                                                                                  */
188 /*  This mixes the processed and unprocessed data streams together to correct the   */
189 /*  overall system gain and allow progressive control of the Concert Sound effect.  */
190 /*                                                                                  */
191 /*  When the bypass mixer is enabled the output is the processed signal only and    */
192 /*  without gain correction.                                                        */
193 /*                                                                                  */
194 /* PARAMETERS:                                                                      */
195 /*  hInstance               Instance Handle                                         */
196 /*  pProcessed              Pointer to the processed data                           */
197 /*  pUnprocessed            Pointer to the unprocessed data                         */
198 /*  pOutData                Pointer to the output data                              */
199 /*  NumSamples              Number of samples to process                            */
200 /*                                                                                  */
201 /* RETURNS:                                                                         */
202 /*  LVCS_Success            Always succeeds                                         */
203 /*                                                                                  */
204 /* NOTES:                                                                           */
205 /*                                                                                  */
206 /************************************************************************************/
207 
LVCS_BypassMixer(LVCS_Handle_t hInstance,const LVM_FLOAT * pProcessed,const LVM_FLOAT * pUnprocessed,LVM_FLOAT * pOutData,LVM_UINT16 NumSamples)208 LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t         hInstance,
209                                       const LVM_FLOAT       *pProcessed,
210                                       const LVM_FLOAT       *pUnprocessed,
211                                       LVM_FLOAT             *pOutData,
212                                       LVM_UINT16            NumSamples)
213 {
214 
215     LVCS_Instance_t     *pInstance      = (LVCS_Instance_t  *)hInstance;
216     LVCS_BypassMix_t    *pConfig        = (LVCS_BypassMix_t *)&pInstance->BypassMix;
217 
218     /*
219      * Check if the bypass mixer is enabled
220      */
221     if ((pInstance->Params.OperatingMode & LVCS_BYPASSMIXSWITCH) != 0)
222     {
223         /*
224          * Apply the bypass mix
225          */
226         LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance,
227                                    pProcessed,
228                                    (LVM_FLOAT *) pUnprocessed,
229                                    pOutData,
230                                    (LVM_INT16)(2 * NumSamples));
231         /*
232          * Apply output gain correction shift
233          */
234         Shift_Sat_Float((LVM_INT16)pConfig->Output_Shift,
235                         (LVM_FLOAT*)pOutData,
236                         (LVM_FLOAT*)pOutData,
237                         (LVM_INT16)(2 * NumSamples));          /* Left and right*/
238     }
239 
240     return(LVCS_SUCCESS);
241 }
242 
243 /************************************************************************************/
244 /*                                                                                  */
245 /* FUNCTION:                LVCS_MixerCallback                                      */
246 /*                                                                                  */
247 /************************************************************************************/
LVCS_MixerCallback(LVCS_Handle_t hInstance,void * pGeneralPurpose,LVM_INT16 CallbackParam)248 LVM_INT32 LVCS_MixerCallback(LVCS_Handle_t      hInstance,
249                             void                *pGeneralPurpose,
250                             LVM_INT16           CallbackParam)
251 {
252     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
253 
254    (void)pGeneralPurpose;
255 
256     /*
257      * Off transition has completed in Headphone mode
258      */
259     if ((pInstance->OutputDevice == LVCS_HEADPHONE) &&
260         (pInstance->bInOperatingModeTransition)     &&
261         (pInstance->MSTarget0 == 0x0000)&&  /* this indicates an on->off transition */
262         (CallbackParam == 0))
263     {
264         /* Set operating mode to OFF */
265         pInstance->Params.OperatingMode = LVCS_OFF;
266 
267         /* Exit transition state */
268         pInstance->bInOperatingModeTransition = LVM_FALSE;
269 
270         /* Signal to the bundle */
271         if((*pInstance->Capabilities.CallBack) != LVM_NULL){
272             (*pInstance->Capabilities.CallBack)(pInstance->Capabilities.pBundleInstance,
273                                                 LVM_NULL,
274                                                 (ALGORITHM_CS_ID | LVCS_EVENT_ALGOFF));
275         }
276     }
277 
278     if ((pInstance->OutputDevice == LVCS_HEADPHONE)  &&
279         (pInstance->MSTarget0 == 1) &&
280         (pInstance->bTimerDone == LVM_TRUE)){
281 
282         /* Exit transition state */
283         pInstance->bInOperatingModeTransition = LVM_FALSE;
284     }
285 
286     return 1;
287 }
288 
289