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 LVM_INT16 QFactor; /* Filter Q factor */
139
140 pInstance->NBands = pParams->NBands;
141
142 for (i = 0; i < pParams->NBands; i++) {
143 /*
144 * Get the filter settings
145 */
146 fc = (LVM_UINT32)pParams->pBandDefinition[i].Frequency; /* Get the band centre frequency */
147 QFactor = (LVM_INT16)pParams->pBandDefinition[i].QFactor; /* Get the band Q factor */
148
149 pInstance->pBiquadType[i] = LVEQNB_SinglePrecision_Float; /* Default to single precision */
150
151 /*
152 * Check for out of range frequencies
153 */
154 if (fc > (fs >> 1)) {
155 pInstance->pBiquadType[i] = LVEQNB_OutOfRange;
156 }
157
158 /*
159 * Copy the filter definition to persistant memory
160 */
161 pInstance->pBandDefinitions[i] = pParams->pBandDefinition[i];
162 }
163 }
164
165 /************************************************************************************/
166 /* */
167 /* FUNCTION: LVEQNB_SetCoefficients */
168 /* */
169 /* DESCRIPTION: */
170 /* Sets the filter coefficients. This uses the type to select single or double */
171 /* precision coefficients. */
172 /* */
173 /* PARAMETERS: */
174 /* pInstance Pointer to the instance */
175 /* pParams Initialisation parameters */
176 /* */
177 /************************************************************************************/
178
LVEQNB_SetCoefficients(LVEQNB_Instance_t * pInstance)179 void LVEQNB_SetCoefficients(LVEQNB_Instance_t* pInstance) {
180 LVM_UINT16 i; /* Filter band index */
181 LVEQNB_BiquadType_en BiquadType; /* Filter biquad type */
182
183 pInstance->gain.resize(pInstance->Params.NBands);
184 /*
185 * Set the coefficients for each band by the init function
186 */
187 for (i = 0; i < pInstance->Params.NBands; i++) {
188 /*
189 * Check band type for correct initialisation method and recalculate the coefficients
190 */
191 BiquadType = pInstance->pBiquadType[i];
192 switch (BiquadType) {
193 case LVEQNB_SinglePrecision_Float: {
194 PK_FLOAT_Coefs_t Coefficients;
195 /*
196 * Calculate the single precision coefficients
197 */
198 LVEQNB_SinglePrecCoefs((LVM_UINT16)pInstance->Params.SampleRate,
199 &pInstance->pBandDefinitions[i], &Coefficients);
200 /*
201 * Set the coefficients
202 */
203 pInstance->gain[i] = Coefficients.G;
204 std::array<LVM_FLOAT, android::audio_utils::kBiquadNumCoefs> coefs = {
205 Coefficients.A0, 0.0, -(Coefficients.A0), -(Coefficients.B1),
206 -(Coefficients.B2)};
207 pInstance->eqBiquad[i]
208 .setCoefficients<
209 std::array<LVM_FLOAT, android::audio_utils::kBiquadNumCoefs>>(
210 coefs);
211 break;
212 }
213 default:
214 break;
215 }
216 }
217 }
218
219 /************************************************************************************/
220 /* */
221 /* FUNCTION: LVEQNB_ClearFilterHistory */
222 /* */
223 /* DESCRIPTION: */
224 /* Clears the filter data history */
225 /* */
226 /* PARAMETERS: */
227 /* pInstance Pointer to the instance */
228 /* */
229 /************************************************************************************/
LVEQNB_ClearFilterHistory(LVEQNB_Instance_t * pInstance)230 void LVEQNB_ClearFilterHistory(LVEQNB_Instance_t* pInstance) {
231 for (size_t i = 0; i < pInstance->eqBiquad.size(); i++) {
232 pInstance->eqBiquad[i].clear();
233 }
234 }
235 /****************************************************************************************/
236 /* */
237 /* FUNCTION: LVEQNB_Control */
238 /* */
239 /* DESCRIPTION: */
240 /* Sets or changes the LifeVibes module parameters. */
241 /* */
242 /* PARAMETERS: */
243 /* hInstance Instance handle */
244 /* pParams Pointer to a parameter structure */
245 /* */
246 /* RETURNS: */
247 /* LVEQNB_Success Always succeeds */
248 /* LVEQNB_NULLADDRESS Instance or pParams is NULL pointer */
249 /* LVEQNB_NULLADDRESS NULL address for the equaliser filter definitions and the */
250 /* number of bands is non-zero */
251 /* */
252 /* NOTES: */
253 /* 1. This function may be interrupted by the LVEQNB_Process function */
254 /* */
255 /****************************************************************************************/
256
LVEQNB_Control(LVEQNB_Handle_t hInstance,LVEQNB_Params_t * pParams)257 LVEQNB_ReturnStatus_en LVEQNB_Control(LVEQNB_Handle_t hInstance, LVEQNB_Params_t* pParams) {
258 LVEQNB_Instance_t* pInstance = (LVEQNB_Instance_t*)hInstance;
259 LVM_INT16 bChange = LVM_FALSE;
260 LVM_INT16 i = 0;
261 LVEQNB_Mode_en OperatingModeSave;
262
263 /*
264 * Check for error conditions
265 */
266 if ((hInstance == LVM_NULL) || (pParams == LVM_NULL)) {
267 return LVEQNB_NULLADDRESS;
268 }
269
270 if ((pParams->NBands != 0) && (pParams->pBandDefinition == LVM_NULL)) {
271 return LVEQNB_NULLADDRESS;
272 }
273
274 OperatingModeSave = pInstance->Params.OperatingMode;
275
276 /* Set the alpha factor of the mixer */
277 if (pParams->SampleRate != pInstance->Params.SampleRate) {
278 LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],
279 LVEQNB_BYPASS_MIXER_TC, (LVM_Fs_en)pParams->SampleRate,
280 2);
281 LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],
282 LVEQNB_BYPASS_MIXER_TC, (LVM_Fs_en)pParams->SampleRate,
283 2);
284 }
285
286 if ((pInstance->Params.NBands != pParams->NBands) ||
287 (pInstance->Params.OperatingMode != pParams->OperatingMode) ||
288 (pInstance->Params.pBandDefinition != pParams->pBandDefinition) ||
289 (pInstance->Params.SampleRate != pParams->SampleRate) ||
290 (pInstance->Params.SourceFormat != pParams->SourceFormat)) {
291 bChange = LVM_TRUE;
292 } else {
293 for (i = 0; i < pParams->NBands; i++) {
294 if ((pInstance->pBandDefinitions[i].Frequency !=
295 pParams->pBandDefinition[i].Frequency) ||
296 (pInstance->pBandDefinitions[i].Gain != pParams->pBandDefinition[i].Gain) ||
297 (pInstance->pBandDefinitions[i].QFactor != pParams->pBandDefinition[i].QFactor)) {
298 bChange = LVM_TRUE;
299 }
300 }
301 }
302
303 // During operating mode transition, there is a race condition where the mode
304 // is still LVEQNB_ON, but the effect is considered disabled in the upper layers.
305 // modeChange handles this special race condition.
306 const int /* bool */ modeChange =
307 pParams->OperatingMode != OperatingModeSave ||
308 (OperatingModeSave == LVEQNB_ON && pInstance->bInOperatingModeTransition &&
309 LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0);
310
311 /*
312 * Create biquad instance
313 */
314 pInstance->eqBiquad.resize(pParams->NBands,
315 android::audio_utils::BiquadFilter<LVM_FLOAT>(pParams->NrChannels));
316 LVEQNB_ClearFilterHistory(pInstance);
317
318 if (bChange || modeChange) {
319 /*
320 * If the sample rate has changed clear the history
321 */
322 if (pInstance->Params.SampleRate != pParams->SampleRate) {
323 LVEQNB_ClearFilterHistory(pInstance); /* Clear the history */
324 }
325
326 /*
327 * Update the instance parameters
328 */
329 pInstance->Params = *pParams;
330
331 /*
332 * Reset the filters except if the algo is switched off
333 */
334 if (pParams->OperatingMode != LVEQNB_BYPASS) {
335 /*
336 * Reset the filters as all parameters could have changed
337 */
338 LVEQNB_SetFilters(pInstance, /* Instance pointer */
339 pParams); /* New parameters */
340
341 /*
342 * Update the filters
343 */
344 LVEQNB_SetCoefficients(pInstance); /* Instance pointer */
345 }
346
347 if (modeChange) {
348 if (pParams->OperatingMode == LVEQNB_ON) {
349 LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0], 1.0f);
350 LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1], 0.0f);
351 pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
352 pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
353 } else {
354 /* Stay on the ON operating mode until the transition is done */
355 // This may introduce a state race condition if the effect is enabled again
356 // while in transition. This is fixed in the modeChange logic.
357 pInstance->Params.OperatingMode = LVEQNB_ON;
358 LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0], 0.0f);
359 LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1], 1.0f);
360 pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
361 pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
362 }
363 LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],
364 LVEQNB_BYPASS_MIXER_TC,
365 (LVM_Fs_en)pParams->SampleRate, 2);
366 LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],
367 LVEQNB_BYPASS_MIXER_TC,
368 (LVM_Fs_en)pParams->SampleRate, 2);
369 pInstance->bInOperatingModeTransition = LVM_TRUE;
370 }
371 }
372 return (LVEQNB_SUCCESS);
373 }
374
375 /****************************************************************************************/
376 /* */
377 /* FUNCTION: LVEQNB_BypassMixerCallBack */
378 /* */
379 /* DESCRIPTION: */
380 /* CallBack function of the mixer */
381 /* transition */
382 /* */
383 /****************************************************************************************/
LVEQNB_BypassMixerCallBack(void * hInstance,void * pGeneralPurpose,LVM_INT16 CallbackParam)384 LVM_INT32 LVEQNB_BypassMixerCallBack(void* hInstance, void* pGeneralPurpose,
385 LVM_INT16 CallbackParam) {
386 LVEQNB_Instance_t* pInstance = (LVEQNB_Instance_t*)hInstance;
387 LVM_Callback CallBack = pInstance->Capabilities.CallBack;
388
389 (void)pGeneralPurpose;
390
391 /*
392 * Send an ALGOFF event if the ON->OFF switch transition is finished
393 */
394 if ((LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0) &&
395 (CallbackParam == 0)) {
396 pInstance->Params.OperatingMode = LVEQNB_BYPASS;
397 if (CallBack != LVM_NULL) {
398 CallBack(pInstance->Capabilities.pBundleInstance, LVM_NULL,
399 ALGORITHM_EQNB_ID | LVEQNB_EVENT_ALGOFF);
400 }
401 }
402
403 /*
404 * Exit transition state
405 */
406 pInstance->bInOperatingModeTransition = LVM_FALSE;
407
408 return 1;
409 }
410