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_UINT32          Gain;
74     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
75     LVCS_BypassMix_t    *pConfig   = (LVCS_BypassMix_t *)&pInstance->BypassMix;
76     const Gain_t        *pOutputGainTable;
77     LVM_INT32           Current;
78 
79 
80     /*
81      * Set the transition gain
82      */
83     if ((pParams->OperatingMode == LVCS_ON) &&
84         (pInstance->bTimerDone == LVM_TRUE)
85         && (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transtion */
86         )
87     {
88         pInstance->TransitionGain = pParams->EffectLevel;
89     }
90     else
91     {
92         /* Select no effect level */
93         pInstance->TransitionGain = 0;
94     }
95 
96     /*
97      * Calculate the output gain table offset
98      */
99     Offset = (LVM_UINT16)(pParams->SpeakerType + (pParams->SourceFormat*(1+LVCS_EX_HEADPHONES)));
100     pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
101 
102     /*
103      * Setup the mixer gain for the processed path
104      */
105     Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
106 
107     pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0;
108     pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL;
109     pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL;
110     pConfig->Mixer_Instance.MixerStream[0].CallbackSet=1;
111     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
112     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0],(LVM_INT32)(Gain >> 15),Current);
113     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
114     /*
115      * Setup the mixer gain for the unprocessed path
116      */
117     Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * (0x7FFF - pInstance->TransitionGain));
118     Gain = (LVM_UINT32)pOutputGainTable[Offset].UnprocLoss * (Gain >> 15);
119     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
120     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1],(LVM_INT32)(Gain >> 15),Current);
121     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
122     pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0;
123     pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance;
124     pConfig->Mixer_Instance.MixerStream[1].CallbackSet=1;
125     pConfig->Mixer_Instance.MixerStream[1].pCallBack = LVCS_MixerCallback;
126 
127     /*
128      * Setup the output gain shift
129      */
130     pConfig->Output_Shift = pOutputGainTable[Offset].Shift;
131 
132 
133     /*
134      * Correct gain for the effect level
135      */
136     {
137 
138         LVM_INT16           GainCorrect;
139         LVM_INT32           Gain1;
140         LVM_INT32           Gain2;
141 
142         Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
143         Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
144         /*
145          * Calculate the gain correction
146          */
147         if (pInstance->Params.CompressorMode == LVM_MODE_ON)
148         {
149         GainCorrect = (LVM_INT16)(  pInstance->VolCorrect.GainMin
150                                     - (((LVM_INT32)pInstance->VolCorrect.GainMin * (LVM_INT32)pInstance->TransitionGain) >> 15)
151                                     + (((LVM_INT32)pInstance->VolCorrect.GainFull * (LVM_INT32)pInstance->TransitionGain) >> 15) );
152 
153         /*
154          * Apply the gain correction and shift, note the result is in Q3.13 format
155          */
156         Gain1 = (Gain1 * GainCorrect) << 4;
157         Gain2 = (Gain2 * GainCorrect) << 4;
158         }
159         else
160         {
161             Gain1 = Gain1 << 16;
162             Gain2 = Gain2 << 16;
163         }
164 
165 
166 
167         /*
168          * Set the gain values
169          */
170         pConfig->Output_Shift = pConfig->Output_Shift;
171         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0],Gain1>>16);
172         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
173         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1],Gain2>>16);
174         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],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_INT16 * pProcessed,const LVM_INT16 * pUnprocessed,LVM_INT16 * pOutData,LVM_UINT16 NumSamples)208 LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t         hInstance,
209                                       const LVM_INT16       *pProcessed,
210                                       const LVM_INT16       *pUnprocessed,
211                                       LVM_INT16             *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_INT16 *) pUnprocessed,
229                                         pOutData,
230                                         (LVM_INT16)(2*NumSamples));
231 
232         /*
233          * Apply output gain correction shift
234          */
235         Shift_Sat_v16xv16 ((LVM_INT16)pConfig->Output_Shift,
236                           (LVM_INT16*)pOutData,
237                           (LVM_INT16*)pOutData,
238                           (LVM_INT16)(2*NumSamples));          /* Left and right*/
239     }
240 
241     return(LVCS_SUCCESS);
242 }
243 
244 
245 /************************************************************************************/
246 /*                                                                                  */
247 /* FUNCTION:                LVCS_MixerCallback                                      */
248 /*                                                                                  */
249 /************************************************************************************/
LVCS_MixerCallback(LVCS_Handle_t hInstance,void * pGeneralPurpose,LVM_INT16 CallbackParam)250 LVM_INT32 LVCS_MixerCallback(LVCS_Handle_t      hInstance,
251                             void                *pGeneralPurpose,
252                             LVM_INT16           CallbackParam)
253 {
254     LVCS_Instance_t     *pInstance = (LVCS_Instance_t  *)hInstance;
255 
256    (void)pGeneralPurpose;
257 
258     /*
259      * Off transition has completed in Headphone mode
260      */
261     if ((pInstance->OutputDevice == LVCS_HEADPHONE) &&
262         (pInstance->bInOperatingModeTransition)     &&
263         (pInstance->MSTarget0 == 0x0000)&&  /* this indicates an on->off transition */
264         (CallbackParam == 0))
265     {
266         /* Set operating mode to OFF */
267         pInstance->Params.OperatingMode = LVCS_OFF;
268 
269         /* Exit transition state */
270         pInstance->bInOperatingModeTransition = LVM_FALSE;
271 
272         /* Signal to the bundle */
273         if((*pInstance->Capabilities.CallBack) != LVM_NULL){
274             (*pInstance->Capabilities.CallBack)(pInstance->Capabilities.pBundleInstance,
275                                                 LVM_NULL,
276                                                 (ALGORITHM_CS_ID | LVCS_EVENT_ALGOFF));
277         }
278     }
279 
280 
281     if ((pInstance->OutputDevice == LVCS_HEADPHONE)  &&
282         (pInstance->MSTarget0 == 1) &&
283         (pInstance->bTimerDone == LVM_TRUE)){
284 
285         /* Exit transition state */
286         pInstance->bInOperatingModeTransition = LVM_FALSE;
287     }
288 
289     return 1;
290 }
291 
292 
293 
294