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