• 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 <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