blob: 10e7d74d25d100d0884ffcbfad48ff8efa455aaf [file] [log] [blame]
/*
* Copyright (C) 2004-2010 NXP Software
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/****************************************************************************************/
/* */
/* Includes */
/* */
/****************************************************************************************/
#include "LVEQNB.h"
#include "LVEQNB_Private.h"
#include "VectorArithmetic.h"
#include "BIQUAD.h"
/****************************************************************************************/
/* */
/* Defines */
/* */
/****************************************************************************************/
#define LOW_FREQ 298 /* 32768/110 for low test frequency */
#define HIGH_FREQ 386 /* 32768/85 for high test frequency */
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_GetParameters */
/* */
/* DESCRIPTION: */
/* Request the N-Band equaliser parameters. The current parameter set is returned via */
/* the parameter pointer. */
/* */
/* PARAMETERS: */
/* hInstance Instance handle */
/* pParams Pointer to an empty parameter structure */
/* */
/* RETURNS: */
/* LVEQNB_SUCCESS Succeeds */
/* LVEQNB_NULLADDRESS Instance or pParams is NULL pointer */
/* */
/* NOTES: */
/* 1. This function may be interrupted by the LVEQNB_Process function */
/* */
/****************************************************************************************/
LVEQNB_ReturnStatus_en LVEQNB_GetParameters(LVEQNB_Handle_t hInstance,
LVEQNB_Params_t *pParams)
{
LVEQNB_Instance_t *pInstance =(LVEQNB_Instance_t *)hInstance;
/*
* Check for error conditions
*/
if((hInstance == LVM_NULL) || (pParams == LVM_NULL))
{
return LVEQNB_NULLADDRESS;
}
*pParams = pInstance->Params;
return(LVEQNB_SUCCESS);
}
/************************************************************************************/
/* */
/* FUNCTION: LVEQNB_GetCapabilities */
/* */
/* DESCRIPTION: */
/* Get the N-Band equaliser capabilities. The current capabilities are returned */
/* via the pointer. */
/* */
/* PARAMETERS: */
/* hInstance Instance handle */
/* pCapabilities Pointer to an empty capability structure */
/* */
/* RETURNS: */
/* LVEQNB_Success Succeeds */
/* LVEQNB_NULLADDRESS hInstance or pCapabilities is NULL */
/* */
/* NOTES: */
/* 1. This function may be interrupted by the LVEQNB_Process function */
/* */
/************************************************************************************/
LVEQNB_ReturnStatus_en LVEQNB_GetCapabilities(LVEQNB_Handle_t hInstance,
LVEQNB_Capabilities_t *pCapabilities)
{
LVEQNB_Instance_t *pInstance =(LVEQNB_Instance_t *)hInstance;
if((hInstance == LVM_NULL) || (pCapabilities == LVM_NULL))
{
return LVEQNB_NULLADDRESS;
}
*pCapabilities = pInstance->Capabilities;
return(LVEQNB_SUCCESS);
}
/************************************************************************************/
/* */
/* FUNCTION: LVEQNB_SetFilters */
/* */
/* DESCRIPTION: */
/* Sets the filter type based on the definition. */
/* */
/* PARAMETERS: */
/* pInstance Pointer to the instance */
/* pParams Initialisation parameters */
/* */
/* RETURNS: */
/* void Nothing */
/* */
/* NOTES: */
/* 1. To select the biquad type the follow rules are applied: */
/* Double precision if (fc <= fs/110) */
/* Double precision if (fs/110 < fc < fs/85) & (Q>3) */
/* Single precision otherwise */
/* */
/************************************************************************************/
void LVEQNB_SetFilters(LVEQNB_Instance_t *pInstance,
LVEQNB_Params_t *pParams)
{
extern const LVM_UINT16 LVEQNB_SampleRateTab[]; /* Sample rate table */
LVM_UINT16 i; /* Filter band index */
LVM_UINT32 fs = (LVM_UINT32)LVEQNB_SampleRateTab[(LVM_UINT16)pParams->SampleRate]; /* Sample rate */
LVM_UINT32 fc; /* Filter centre frequency */
LVM_INT16 QFactor; /* Filter Q factor */
pInstance->NBands = pParams->NBands;
for (i=0; i<pParams->NBands; i++)
{
/*
* Get the filter settings
*/
fc = (LVM_UINT32)pParams->pBandDefinition[i].Frequency; /* Get the band centre frequency */
QFactor = (LVM_INT16)pParams->pBandDefinition[i].QFactor; /* Get the band Q factor */
/*
* For each filter set the type of biquad required
*/
pInstance->pBiquadType[i] = LVEQNB_SinglePrecision; /* Default to single precision */
if ((fc << 15) <= (LOW_FREQ * fs))
{
/*
* fc <= fs/110
*/
pInstance->pBiquadType[i] = LVEQNB_DoublePrecision;
}
else if (((fc << 15) <= (HIGH_FREQ * fs)) && (QFactor > 300))
{
/*
* (fs/110 < fc < fs/85) & (Q>3)
*/
pInstance->pBiquadType[i] = LVEQNB_DoublePrecision;
}
/*
* Check for out of range frequencies
*/
if (fc > (fs >> 1))
{
pInstance->pBiquadType[i] = LVEQNB_OutOfRange;
}
/*
* Copy the filter definition to persistant memory
*/
pInstance->pBandDefinitions[i] = pParams->pBandDefinition[i];
}
}
/************************************************************************************/
/* */
/* FUNCTION: LVEQNB_SetCoefficients */
/* */
/* DESCRIPTION: */
/* Sets the filter coefficients. This uses the type to select single or double */
/* precision coefficients. */
/* */
/* PARAMETERS: */
/* pInstance Pointer to the instance */
/* pParams Initialisation parameters */
/* */
/************************************************************************************/
void LVEQNB_SetCoefficients(LVEQNB_Instance_t *pInstance)
{
LVM_UINT16 i; /* Filter band index */
LVEQNB_BiquadType_en BiquadType; /* Filter biquad type */
/*
* Set the coefficients for each band by the init function
*/
for (i=0; i<pInstance->Params.NBands; i++)
{
/*
* Check band type for correct initialisation method and recalculate the coefficients
*/
BiquadType = pInstance->pBiquadType[i];
switch (BiquadType)
{
case LVEQNB_DoublePrecision:
{
PK_C32_Coefs_t Coefficients;
/*
* Calculate the double precision coefficients
*/
LVEQNB_DoublePrecCoefs((LVM_UINT16)pInstance->Params.SampleRate,
&pInstance->pBandDefinitions[i],
&Coefficients);
/*
* Set the coefficients
*/
PK_2I_D32F32CllGss_TRC_WRA_01_Init(&pInstance->pEQNB_FilterState[i],
&pInstance->pEQNB_Taps[i],
&Coefficients);
break;
}
case LVEQNB_SinglePrecision:
{
PK_C16_Coefs_t Coefficients;
/*
* Calculate the single precision coefficients
*/
LVEQNB_SinglePrecCoefs((LVM_UINT16)pInstance->Params.SampleRate,
&pInstance->pBandDefinitions[i],
&Coefficients);
/*
* Set the coefficients
*/
PK_2I_D32F32CssGss_TRC_WRA_01_Init(&pInstance->pEQNB_FilterState[i],
&pInstance->pEQNB_Taps[i],
&Coefficients);
break;
}
default:
break;
}
}
}
/************************************************************************************/
/* */
/* FUNCTION: LVEQNB_ClearFilterHistory */
/* */
/* DESCRIPTION: */
/* Clears the filter data history */
/* */
/* PARAMETERS: */
/* pInstance Pointer to the instance */
/* */
/************************************************************************************/
void LVEQNB_ClearFilterHistory(LVEQNB_Instance_t *pInstance)
{
LVM_INT16 *pTapAddress;
LVM_INT16 NumTaps;
pTapAddress = (LVM_INT16 *)pInstance->pEQNB_Taps;
NumTaps = (LVM_INT16)((pInstance->Capabilities.MaxBands * sizeof(Biquad_2I_Order2_Taps_t))/sizeof(LVM_INT16));
if (NumTaps != 0)
{
LoadConst_16(0, /* Clear the history, value 0 */
pTapAddress, /* Destination */
NumTaps); /* Number of words */
}
}
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_Control */
/* */
/* DESCRIPTION: */
/* Sets or changes the LifeVibes module parameters. */
/* */
/* PARAMETERS: */
/* hInstance Instance handle */
/* pParams Pointer to a parameter structure */
/* */
/* RETURNS: */
/* LVEQNB_Success Always succeeds */
/* LVEQNB_NULLADDRESS Instance or pParams is NULL pointer */
/* LVEQNB_NULLADDRESS NULL address for the equaliser filter definitions and the */
/* number of bands is non-zero */
/* */
/* NOTES: */
/* 1. This function may be interrupted by the LVEQNB_Process function */
/* */
/****************************************************************************************/
LVEQNB_ReturnStatus_en LVEQNB_Control(LVEQNB_Handle_t hInstance,
LVEQNB_Params_t *pParams)
{
LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
LVM_INT16 bChange = LVM_FALSE;
LVM_INT16 i = 0;
LVEQNB_Mode_en OperatingModeSave ;
/*
* Check for error conditions
*/
if((hInstance == LVM_NULL) || (pParams == LVM_NULL))
{
return LVEQNB_NULLADDRESS;
}
if((pParams->NBands !=0) && (pParams->pBandDefinition==LVM_NULL))
{
return LVEQNB_NULLADDRESS;
}
OperatingModeSave = pInstance->Params.OperatingMode;
/* Set the alpha factor of the mixer */
if (pParams->SampleRate != pInstance->Params.SampleRate)
{
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
}
if( (pInstance->Params.NBands != pParams->NBands ) ||
(pInstance->Params.OperatingMode != pParams->OperatingMode ) ||
(pInstance->Params.pBandDefinition != pParams->pBandDefinition ) ||
(pInstance->Params.SampleRate != pParams->SampleRate ) ||
(pInstance->Params.SourceFormat != pParams->SourceFormat ))
{
bChange = LVM_TRUE;
}
else
{
for(i = 0; i < pParams->NBands; i++)
{
if((pInstance->pBandDefinitions[i].Frequency != pParams->pBandDefinition[i].Frequency )||
(pInstance->pBandDefinitions[i].Gain != pParams->pBandDefinition[i].Gain )||
(pInstance->pBandDefinitions[i].QFactor != pParams->pBandDefinition[i].QFactor ))
{
bChange = LVM_TRUE;
}
}
}
if(bChange){
/*
* If the sample rate has changed clear the history
*/
if (pInstance->Params.SampleRate != pParams->SampleRate)
{
LVEQNB_ClearFilterHistory(pInstance); /* Clear the history */
}
/*
* Update the instance parameters
*/
pInstance->Params = *pParams;
/*
* Reset the filters except if the algo is switched off
*/
if(pParams->OperatingMode != LVEQNB_BYPASS){
/*
* Reset the filters as all parameters could have changed
*/
LVEQNB_SetFilters(pInstance, /* Instance pointer */
pParams); /* New parameters */
/*
* Update the filters
*/
LVEQNB_SetCoefficients(pInstance); /* Instance pointer */
}
if(pParams->OperatingMode != OperatingModeSave)
{
if(pParams->OperatingMode == LVEQNB_ON)
{
LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0],LVM_MAXINT_16);
LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1],0);
pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
}
else
{
/* Stay on the ON operating mode until the transition is done */
pInstance->Params.OperatingMode = LVEQNB_ON;
LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[0],0);
LVC_Mixer_SetTarget(&pInstance->BypassMixer.MixerStream[1],LVM_MAXINT_16);
pInstance->BypassMixer.MixerStream[0].CallbackSet = 1;
pInstance->BypassMixer.MixerStream[1].CallbackSet = 1;
}
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[0],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMixer.MixerStream[1],LVEQNB_BYPASS_MIXER_TC,(LVM_Fs_en)pParams->SampleRate,2);
pInstance->bInOperatingModeTransition = LVM_TRUE;
}
}
return(LVEQNB_SUCCESS);
}
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_BypassMixerCallBack */
/* */
/* DESCRIPTION: */
/* CallBack function of the mixer */
/* transition */
/* */
/****************************************************************************************/
LVM_INT32 LVEQNB_BypassMixerCallBack (void* hInstance,
void *pGeneralPurpose,
LVM_INT16 CallbackParam)
{
LVEQNB_Instance_t *pInstance =(LVEQNB_Instance_t *)hInstance;
LVM_Callback CallBack = pInstance->Capabilities.CallBack;
(void) pGeneralPurpose;
/*
* Send an ALGOFF event if the ON->OFF switch transition is finished
*/
if((LVC_Mixer_GetTarget(&pInstance->BypassMixer.MixerStream[0]) == 0x00000000) &&
(CallbackParam == 0)){
pInstance->Params.OperatingMode = LVEQNB_BYPASS;
if (CallBack != LVM_NULL){
CallBack(pInstance->Capabilities.pBundleInstance, LVM_NULL, ALGORITHM_EQNB_ID|LVEQNB_EVENT_ALGOFF);
}
}
/*
* Exit transition state
*/
pInstance->bInOperatingModeTransition = LVM_FALSE;
return 1;
}