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