• 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, void* pGeneralPurpose,
36                              LVM_INT16 CallbackParam);
37 
38 /************************************************************************************/
39 /*                                                                                  */
40 /* FUNCTION:                LVCS_BypassMixInit                                      */
41 /*                                                                                  */
42 /* DESCRIPTION:                                                                     */
43 /*  Initialises the bypass mixer module                                             */
44 /*                                                                                  */
45 /*  The overall gain of the processed path is set by the gains in the individual    */
46 /*  processing blocks and by the effect level gain.                                 */
47 /*                                                                                  */
48 /*  The unprocessed path must have matching gain for the processed path to ensure   */
49 /*  as they are mixed together the correct effect is achieved, this is the value    */
50 /*  UnprocLoss.                                                                     */
51 /*                                                                                  */
52 /*  The overall gain is corrected by a combination of a shift with saturation and a */
53 /*  linear scaler, loss. The loss ensures the sum in the mixer does not saturate    */
54 /*  and also corrects for any excess gain in the shift.                             */
55 /*                                                                                  */
56 /* PARAMETERS:                                                                      */
57 /*  hInstance               Instance Handle                                         */
58 /*  pParams                 Initialisation parameters                               */
59 /*                                                                                  */
60 /* RETURNS:                                                                         */
61 /*  LVCS_Success            Always succeeds                                         */
62 /*                                                                                  */
63 /* NOTES:                                                                           */
64 /*                                                                                  */
65 /************************************************************************************/
66 
LVCS_BypassMixInit(LVCS_Handle_t hInstance,LVCS_Params_t * pParams)67 LVCS_ReturnStatus_en LVCS_BypassMixInit(LVCS_Handle_t hInstance, LVCS_Params_t* pParams) {
68     LVM_UINT16 Offset;
69     LVM_FLOAT Gain;
70     LVM_FLOAT Current;
71     LVCS_Instance_t* pInstance = (LVCS_Instance_t*)hInstance;
72     LVCS_BypassMix_t* pConfig = (LVCS_BypassMix_t*)&pInstance->BypassMix;
73     const Gain_t* pOutputGainTable;
74 
75     /*
76      * Set the transition gain
77      */
78     if ((pParams->OperatingMode == LVCS_ON) && (pInstance->bTimerDone == LVM_TRUE) &&
79         (pInstance->MSTarget1 != 0x7FFF) /* this indicates an off->on transition */
80     ) {
81         pInstance->TransitionGain = ((LVM_FLOAT)pParams->EffectLevel / 32767);
82     } else {
83         /* Select no effect level */
84         pInstance->TransitionGain = 0;
85     }
86 
87     /*
88      * Calculate the output gain table offset
89      */
90     Offset =
91             (LVM_UINT16)(pParams->SpeakerType + (pParams->SourceFormat * (1 + LVCS_EX_HEADPHONES)));
92     pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
93 
94     /*
95      * Setup the mixer gain for the processed path
96      */
97     Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss * pInstance->TransitionGain);
98 
99     pConfig->Mixer_Instance.MixerStream[0].CallbackParam = 0;
100     pConfig->Mixer_Instance.MixerStream[0].pCallbackHandle = LVM_NULL;
101     pConfig->Mixer_Instance.MixerStream[0].pCallBack = LVM_NULL;
102     pConfig->Mixer_Instance.MixerStream[0].CallbackSet = 1;
103 
104     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[0]);
105     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[0], (LVM_FLOAT)(Gain), Current);
106     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
107                                        LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
108 
109     /*
110      * Setup the mixer gain for the unprocessed path
111      */
112     Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss *
113                        (1.0 - (LVM_FLOAT)pInstance->TransitionGain));
114     Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * Gain;
115     Current = LVC_Mixer_GetCurrent(&pConfig->Mixer_Instance.MixerStream[1]);
116     LVC_Mixer_Init(&pConfig->Mixer_Instance.MixerStream[1], (LVM_FLOAT)(Gain), Current);
117     LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
118                                        LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
119     pConfig->Mixer_Instance.MixerStream[1].CallbackParam = 0;
120     pConfig->Mixer_Instance.MixerStream[1].pCallbackHandle = hInstance;
121     pConfig->Mixer_Instance.MixerStream[1].CallbackSet = 1;
122     pConfig->Mixer_Instance.MixerStream[1].pCallBack = LVCS_MixerCallback;
123 
124     /*
125      * Setup the output gain shift
126      */
127     pConfig->Output_Shift = pOutputGainTable[Offset].Shift;
128 
129     /*
130      * Correct gain for the effect level
131      */
132     {
133         LVM_FLOAT GainCorrect;
134         LVM_FLOAT Gain1;
135         LVM_FLOAT Gain2;
136 
137         Gain1 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[0]);
138         Gain2 = LVC_Mixer_GetTarget(&pConfig->Mixer_Instance.MixerStream[1]);
139         /*
140          * Calculate the gain correction
141          */
142         if (pInstance->Params.CompressorMode == LVM_MODE_ON) {
143             GainCorrect = (LVM_FLOAT)(pInstance->VolCorrect.GainMin -
144                                       (((LVM_FLOAT)pInstance->VolCorrect.GainMin *
145                                         ((LVM_FLOAT)pInstance->TransitionGain))) +
146                                       (((LVM_FLOAT)pInstance->VolCorrect.GainFull *
147                                         ((LVM_FLOAT)pInstance->TransitionGain))));
148 
149             /*
150              * Apply the gain correction
151              */
152             Gain1 = (Gain1 * GainCorrect);
153             Gain2 = (Gain2 * GainCorrect);
154         }
155 
156         /*
157          * Set the gain values
158          */
159         pConfig->Output_Shift = pConfig->Output_Shift;
160         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[0], Gain1);
161         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[0],
162                                            LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
163         LVC_Mixer_SetTarget(&pConfig->Mixer_Instance.MixerStream[1], Gain2);
164         LVC_Mixer_VarSlope_SetTimeConstant(&pConfig->Mixer_Instance.MixerStream[1],
165                                            LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
166     }
167 
168     return (LVCS_SUCCESS);
169 }
170 
171 /************************************************************************************/
172 /*                                                                                  */
173 /* FUNCTION:                LVCS_BypassMixer                                        */
174 /*                                                                                  */
175 /* DESCRIPTION:                                                                     */
176 /*  Apply Bypass Mix.                                                               */
177 /*                                                                                  */
178 /*  This mixes the processed and unprocessed data streams together to correct the   */
179 /*  overall system gain and allow progressive control of the Concert Sound effect.  */
180 /*                                                                                  */
181 /*  When the bypass mixer is enabled the output is the processed signal only and    */
182 /*  without gain correction.                                                        */
183 /*                                                                                  */
184 /* PARAMETERS:                                                                      */
185 /*  hInstance               Instance Handle                                         */
186 /*  pProcessed              Pointer to the processed data                           */
187 /*  pUnprocessed            Pointer to the unprocessed data                         */
188 /*  pOutData                Pointer to the output data                              */
189 /*  NumSamples              Number of samples to process                            */
190 /*                                                                                  */
191 /* RETURNS:                                                                         */
192 /*  LVCS_Success            Always succeeds                                         */
193 /*                                                                                  */
194 /* NOTES:                                                                           */
195 /*                                                                                  */
196 /************************************************************************************/
197 
LVCS_BypassMixer(LVCS_Handle_t hInstance,const LVM_FLOAT * pProcessed,const LVM_FLOAT * pUnprocessed,LVM_FLOAT * pOutData,LVM_UINT16 NumSamples)198 LVCS_ReturnStatus_en LVCS_BypassMixer(LVCS_Handle_t hInstance, const LVM_FLOAT* pProcessed,
199                                       const LVM_FLOAT* pUnprocessed, LVM_FLOAT* pOutData,
200                                       LVM_UINT16 NumSamples) {
201     LVCS_Instance_t* pInstance = (LVCS_Instance_t*)hInstance;
202     LVCS_BypassMix_t* pConfig = (LVCS_BypassMix_t*)&pInstance->BypassMix;
203     LVM_UINT16 destNumSamples =
204             (pInstance->Params.NrChannels == FCC_1) ? NumSamples : FCC_2 * NumSamples;
205 
206     /*
207      * Check if the bypass mixer is enabled
208      */
209     if ((pInstance->Params.OperatingMode & LVCS_BYPASSMIXSWITCH) != 0) {
210         /*
211          * Apply the bypass mix
212          */
213         LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance, pProcessed, (LVM_FLOAT*)pUnprocessed,
214                                    pOutData, (LVM_INT16)destNumSamples);
215         /*
216          * Apply output gain correction shift
217          */
218         Shift_Sat_Float((LVM_INT16)pConfig->Output_Shift, (LVM_FLOAT*)pOutData,
219                         (LVM_FLOAT*)pOutData, (LVM_INT16)destNumSamples);
220     }
221 
222     return (LVCS_SUCCESS);
223 }
224 
225 /************************************************************************************/
226 /*                                                                                  */
227 /* FUNCTION:                LVCS_MixerCallback                                      */
228 /*                                                                                  */
229 /************************************************************************************/
LVCS_MixerCallback(LVCS_Handle_t hInstance,void * pGeneralPurpose,LVM_INT16 CallbackParam)230 LVM_INT32 LVCS_MixerCallback(LVCS_Handle_t hInstance, void* pGeneralPurpose,
231                              LVM_INT16 CallbackParam) {
232     LVCS_Instance_t* pInstance = (LVCS_Instance_t*)hInstance;
233 
234     (void)pGeneralPurpose;
235 
236     /*
237      * Off transition has completed in Headphone mode
238      */
239     if ((pInstance->OutputDevice == LVCS_HEADPHONE) && (pInstance->bInOperatingModeTransition) &&
240         (pInstance->MSTarget0 == 0x0000) && /* this indicates an on->off transition */
241         (CallbackParam == 0)) {
242         /* Set operating mode to OFF */
243         pInstance->Params.OperatingMode = LVCS_OFF;
244 
245         /* Exit transition state */
246         pInstance->bInOperatingModeTransition = LVM_FALSE;
247 
248         /* Signal to the bundle */
249         if ((*pInstance->Capabilities.CallBack) != LVM_NULL) {
250             (*pInstance->Capabilities.CallBack)(pInstance->Capabilities.pBundleInstance, LVM_NULL,
251                                                 (ALGORITHM_CS_ID | LVCS_EVENT_ALGOFF));
252         }
253     }
254 
255     if ((pInstance->OutputDevice == LVCS_HEADPHONE) && (pInstance->MSTarget0 == 1) &&
256         (pInstance->bTimerDone == LVM_TRUE)) {
257         /* Exit transition state */
258         pInstance->bInOperatingModeTransition = LVM_FALSE;
259     }
260 
261     return 1;
262 }
263