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 <system/audio.h>
25 #include "LVEQNB.h"
26 #include "LVEQNB_Private.h"
27 #include "VectorArithmetic.h"
28 #include "BIQUAD.h"
29
30 /****************************************************************************************/
31 /* */
32 /* Defines */
33 /* */
34 /****************************************************************************************/
35
36 #define LOW_FREQ 298 /* 32768/110 for low test frequency */
37 #define HIGH_FREQ 386 /* 32768/85 for high test frequency */
38
39 /****************************************************************************************/
40 /* */
41 /* FUNCTION: LVEQNB_GetParameters */
42 /* */
43 /* DESCRIPTION: */
44 /* Request the N-Band equaliser parameters. The current parameter set is returned via */
45 /* the parameter pointer. */
46 /* */
47 /* PARAMETERS: */
48 /* hInstance Instance handle */
49 /* pParams Pointer to an empty parameter structure */
50 /* */
51 /* RETURNS: */
52 /* LVEQNB_SUCCESS Succeeds */
53 /* LVEQNB_NULLADDRESS Instance or pParams is NULL pointer */
54 /* */
55 /* NOTES: */
56 /* 1. This function may be interrupted by the LVEQNB_Process function */
57 /* */
58 /****************************************************************************************/
59
LVEQNB_GetParameters(LVEQNB_Handle_t hInstance,LVEQNB_Params_t * pParams)60 LVEQNB_ReturnStatus_en LVEQNB_GetParameters(LVEQNB_Handle_t hInstance, LVEQNB_Params_t* pParams) {
61 LVEQNB_Instance_t* pInstance = (LVEQNB_Instance_t*)hInstance;
62
63 /*
64 * Check for error conditions
65 */
66 if ((hInstance == LVM_NULL) || (pParams == LVM_NULL)) {
67 return LVEQNB_NULLADDRESS;
68 }
69
70 *pParams = pInstance->Params;
71
72 return (LVEQNB_SUCCESS);
73 }
74
75 /************************************************************************************/
76 /* */
77 /* FUNCTION: LVEQNB_GetCapabilities */
78 /* */
79 /* DESCRIPTION: */
80 /* Get the N-Band equaliser capabilities. The current capabilities are returned */
81 /* via the pointer. */
82 /* */
83 /* PARAMETERS: */
84 /* hInstance Instance handle */
85 /* pCapabilities Pointer to an empty capability structure */
86 /* */
87 /* RETURNS: */
88 /* LVEQNB_Success Succeeds */
89 /* LVEQNB_NULLADDRESS hInstance or pCapabilities is NULL */
90 /* */
91 /* NOTES: */
92 /* 1. This function may be interrupted by the LVEQNB_Process function */
93 /* */
94 /************************************************************************************/
95
LVEQNB_GetCapabilities(LVEQNB_Handle_t hInstance,LVEQNB_Capabilities_t * pCapabilities)96 LVEQNB_ReturnStatus_en LVEQNB_GetCapabilities(LVEQNB_Handle_t hInstance,
97 LVEQNB_Capabilities_t* pCapabilities) {
98 LVEQNB_Instance_t* pInstance = (LVEQNB_Instance_t*)hInstance;
99
100 if ((hInstance == LVM_NULL) || (pCapabilities == LVM_NULL)) {
101 return LVEQNB_NULLADDRESS;
102 }
103
104 *pCapabilities = pInstance->Capabilities;
105
106 return (LVEQNB_SUCCESS);
107 }
108
109 /************************************************************************************/
110 /* */
111 /* FUNCTION: LVEQNB_SetFilters */
112 /* */
113 /* DESCRIPTION: */
114 /* Sets the filter type based on the definition. */
115 /* */
116 /* PARAMETERS: */
117 /* pInstance Pointer to the instance */
118 /* pParams Initialisation parameters */
119 /* */
120 /* RETURNS: */
121 /* void Nothing */
122 /* */
123 /* NOTES: */
124 /* 1. To select the biquad type the follow rules are applied: */
125 /* Double precision if (fc <= fs/110) */
126 /* Double precision if (fs/110 < fc < fs/85) & (Q>3) */
127 /* Single precision otherwise */
128 /* */
129 /************************************************************************************/
130
LVEQNB_SetFilters(LVEQNB_Instance_t * pInstance,LVEQNB_Params_t * pParams)131 void LVEQNB_SetFilters(LVEQNB_Instance_t* pInstance, LVEQNB_Params_t* pParams) {
132 extern const LVM_UINT32 LVEQNB_SampleRateTab[]; /* Sample rate table */
133
134 LVM_UINT16 i; /* Filter band index */
135 LVM_UINT32 fs =
136 (LVM_UINT32)LVEQNB_SampleRateTab[(LVM_UINT16)pParams->SampleRate]; /* Sample rate */
137 LVM_UINT32 fc; /* Filter centre frequency */
138
139 pInstance->NBands = pParams->NBands;
140
141 for (i = 0; i < pParams->NBands; i++) {
142 /*
143 * Get the filter settings
144 */
145 fc = (LVM_UINT32)pParams->pBandDefinition[i].Frequency; /* Get the band centre frequency */
146
147 pInstance->pBiquadType[i] = LVEQNB_SinglePrecision_Float; /* Default to single precision */
148
149 /*
150 * Check for out of range frequencies
151 */
152 if (fc > (fs >> 1)) {
153 pInstance->pBiquadType[i] = LVEQNB_OutOfRange;
154 }
155
156 /*
157 * Copy the filter definition to persistant memory
158 */
159 pInstance->pBandDefinitions[i] = pParams->pBandDefinition[i];
160 }
161 }
162
163 /************************************************************************************/
164 /* */
165 /* FUNCTION: LVEQNB_SetCoefficients */
166 /* */
167 /* DESCRIPTION: */
168 /* Sets the filter coefficients. This uses the type to select single or double */
169 /* precision coefficients. */
170 /* */
171 /* PARAMETERS: */
172 /* pInstance Pointer to the instance */
173 /* pParams Initialisation parameters */
174 /* */
175 /************************************************************************************/
176
LVEQNB_SetCoefficients(LVEQNB_Instance_t * pInstance)177 void LVEQNB_SetCoefficients(LVEQNB_Instance_t* pInstance) {
178 LVM_UINT16 i; /* Filter band index */
179 LVEQNB_BiquadType_en BiquadType; /* Filter biquad type */
180
181 pInstance->gain.resize(pInstance->Params.NBands);
182 /*
183 * Set the coefficients for each band by the init function
184 */
185 for (i = 0; i < pInstance->Params.NBands; i++) {
186 /*
187 * Check band type for correct initialisation method and recalculate the coefficients
188 */
189 BiquadType = pInstance->pBiquadType[i];
190 switch (BiquadType) {
191 case LVEQNB_SinglePrecision_Float: {
192 PK_FLOAT_Coefs_t Coefficients;
193 /*
194 * Calculate the single precision coefficients
195 */
196 LVEQNB_SinglePrecCoefs((LVM_UINT16)pInstance->Params.SampleRate,
197 &pInstance->pBandDefinitions[i], &Coefficients);
198 /*
199 * Set the coefficients
200 */
201 pInstance->gain[i] = Coefficients.G;
202 std::array<LVM_FLOAT, android::audio_utils::kBiquadNumCoefs> coefs = {
203 Coefficients.A0, 0.0, -(Coefficients.A0), -(Coefficients.B1),
204 -(Coefficients.B2)};
205 pInstance->eqBiquad[i]
206 .setCoefficients<
207 std::array<LVM_FLOAT, android::audio_utils::kBiquadNumCoefs>>(
208 coefs);
209 break;
210 }
211 default:
212 break;
213 }
214 }
215 }
216
217 /************************************************************************************/
218 /* */
219 /* FUNCTION: LVEQNB_ClearFilterHistory */
220 /* */
221 /* DESCRIPTION: */
222 /* Clears the filter data history */
223 /* */
224 /* PARAMETERS: */
225 /* pInstance Pointer to the instance */
226 /* */
227 /************************************************************************************/
LVEQNB_ClearFilterHistory(LVEQNB_Instance_t * pInstance)228 void LVEQNB_ClearFilterHistory(LVEQNB_Instance_t* pInstance) {
229 for (size_t i = 0; i < pInstance->eqBiquad.size(); i++) {
230 pInstance->eqBiquad[i].clear();
231 }
232 }
233 /****************************************************************************************/
234 /* */
235 /* FUNCTION: LVEQNB_Control */
236 /* */
237 /* DESCRIPTION: */
238 /* Sets or changes the LifeVibes module parameters. */
239 /* */
240 /* PARAMETERS: */
241 /* hInstance Instance handle */
242 /* pParams Pointer to a parameter structure */
243 /* */
244 /* RETURNS: */
245 /* LVEQNB_Success Always succeeds */
246 /* LVEQNB_NULLADDRESS Instance or pParams is NULL pointer */
247 /* LVEQNB_NULLADDRESS NULL address for the equaliser filter definitions and the */
248 /* number of bands is non-zero */
249 /* */
250 /* NOTES: */
251 /* 1. This function may be interrupted by the LVEQNB_Process function */
252 /* */
253 /****************************************************************************************/
254
LVEQNB_Control(LVEQNB_Handle_t hInstance,LVEQNB_Params_t * pParams)255 LVEQNB_ReturnStatus_en LVEQNB_Control(LVEQNB_Handle_t hInstance, LVEQNB_Params_t* pParams) {
256 LVEQNB_Instance_t* pInstance = (LVEQNB_Instance_t*)hInstance;
257 LVM_INT16 bChange = LVM_FALSE;
258 LVM_INT16 i = 0;
259 LVEQNB_Mode_en OperatingModeSave;
260
261 /*
262 * Check for error conditions
263 */
264 if ((hInstance == LVM_NULL) || (pParams == LVM_NULL)) {
265 return LVEQNB_NULLADDRESS;
266 }
267
268 if ((pParams->NBands != 0) && (pParams->pBandDefinition == LVM_NULL)) {
269 return LVEQNB_NULLADDRESS;
270 }
271
272 OperatingModeSave = pInstance->Params.OperatingMode;
273
274 /* Set the alpha factor of the mixer */
275 if (pParams->SampleRate != pInstance->Params.SampleRate) {
276 LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],
277 LVEQNB_BYPASS_MIXER_TC, (LVM_Fs_en)pParams->SampleRate,
278 2);
279 LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],
280 LVEQNB_BYPASS_MIXER_TC, (LVM_Fs_en)pParams->SampleRate,
281 2);
282 }
283
284 if ((pInstance->Params.NBands != pParams->NBands) ||
285 (pInstance->Params.OperatingMode != pParams->OperatingMode) ||
286 (pInstance->Params.pBandDefinition != pParams->pBandDefinition) ||
287 (pInstance->Params.SampleRate != pParams->SampleRate) ||
288 (pInstance->Params.SourceFormat != pParams->SourceFormat)) {
289 bChange = LVM_TRUE;
290 } else {
291 for (i = 0; i < pParams->NBands; i++) {
292 if ((pInstance->pBandDefinitions[i].Frequency !=
293 pParams->pBandDefinition[i].Frequency) ||
294 (pInstance->pBandDefinitions[i].Gain != pParams->pBandDefinition[i].Gain) ||
295 (pInstance->pBandDefinitions[i].QFactor != pParams->pBandDefinition[i].QFactor)) {
296 bChange = LVM_TRUE;
297 }
298 }
299 }
300
301 // During operating mode transition, there is a race condition where the mode
302 // is still LVEQNB_ON, but the effect is considered disabled in the upper layers.
303 // modeChange handles this special race condition.
304 const int /* bool */ modeChange =
305 pParams->OperatingMode != OperatingModeSave ||
306 (OperatingModeSave == LVEQNB_ON && pInstance->bInOperatingModeTransition &&
307 LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0);
308
309 /*
310 * Create biquad instance
311 */
312 pInstance->eqBiquad.resize(pParams->NBands,
313 android::audio_utils::BiquadFilter<LVM_FLOAT>(pParams->NrChannels));
314
315 if (bChange || modeChange) {
316 LVEQNB_ClearFilterHistory(pInstance);
317 /*
318 * If the sample rate has changed clear the history
319 */
320 if (pInstance->Params.SampleRate != pParams->SampleRate) {
321 LVEQNB_ClearFilterHistory(pInstance); /* Clear the history */
322 }
323
324 /*
325 * Update the instance parameters
326 */
327 pInstance->Params = *pParams;
328
329 /*
330 * Reset the filters except if the algo is switched off
331 */
332 if (pParams->OperatingMode != LVEQNB_BYPASS) {
333 /*
334 * Reset the filters as all parameters could have changed
335 */
336 LVEQNB_SetFilters(pInstance, /* Instance pointer */
337 pParams); /* New parameters */
338
339 /*
340 * Update the filters
341 */
342 LVEQNB_SetCoefficients(pInstance); /* Instance pointer */
343 }
344
345 if (modeChange) {
346 if (pParams->OperatingMode == LVEQNB_ON) {
347 LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0], 1.0f);
348 LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1], 0.0f);
349 pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
350 pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
351 } else {
352 /* Stay on the ON operating mode until the transition is done */
353 // This may introduce a state race condition if the effect is enabled again
354 // while in transition. This is fixed in the modeChange logic.
355 pInstance->Params.OperatingMode = LVEQNB_ON;
356 LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0], 0.0f);
357 LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1], 1.0f);
358 pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
359 pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
360 }
361 LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],
362 LVEQNB_BYPASS_MIXER_TC,
363 (LVM_Fs_en)pParams->SampleRate, 2);
364 LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],
365 LVEQNB_BYPASS_MIXER_TC,
366 (LVM_Fs_en)pParams->SampleRate, 2);
367 pInstance->bInOperatingModeTransition = LVM_TRUE;
368 }
369 }
370 return (LVEQNB_SUCCESS);
371 }
372
373 /****************************************************************************************/
374 /* */
375 /* FUNCTION: LVEQNB_BypassMixerCallBack */
376 /* */
377 /* DESCRIPTION: */
378 /* CallBack function of the mixer */
379 /* transition */
380 /* */
381 /****************************************************************************************/
LVEQNB_BypassMixerCallBack(void * hInstance,void * pGeneralPurpose,LVM_INT16 CallbackParam)382 LVM_INT32 LVEQNB_BypassMixerCallBack(void* hInstance, void* pGeneralPurpose,
383 LVM_INT16 CallbackParam) {
384 LVEQNB_Instance_t* pInstance = (LVEQNB_Instance_t*)hInstance;
385 LVM_Callback CallBack = pInstance->Capabilities.CallBack;
386
387 (void)pGeneralPurpose;
388
389 /*
390 * Send an ALGOFF event if the ON->OFF switch transition is finished
391 */
392 if ((LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0) &&
393 (CallbackParam == 0)) {
394 pInstance->Params.OperatingMode = LVEQNB_BYPASS;
395 if (CallBack != LVM_NULL) {
396 CallBack(pInstance->Capabilities.pBundleInstance, LVM_NULL,
397 ALGORITHM_EQNB_ID | LVEQNB_EVENT_ALGOFF);
398 }
399 }
400
401 /*
402 * Exit transition state
403 */
404 pInstance->bInOperatingModeTransition = LVM_FALSE;
405
406 return 1;
407 }
408