blob: fddedb9947d68e4b13a97f20874324ac773d4832 [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_Private.h"
/****************************************************************************************/
/* */
/* Defines */
/* */
/****************************************************************************************/
#define PI 3.14159265358979
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_DoublePrecCoefs */
/* */
/* DESCRIPTION: */
/* Calculate double precision coefficients for a peaking filter */
/* */
/* PARAMETERS: */
/* Fs Sampling frequency index */
/* pFilterDefinition Pointer to the filter definition */
/* pCoefficients Pointer to the coefficients */
/* */
/* RETURNS: */
/* LVEQNB_SUCCESS Always succeeds */
/* */
/* NOTES: */
/* 1. The equations used are as follows: */
/* */
/* G = 10^(GaindB/20) - 1 */
/* t0 = 2 * Pi * Fc / Fs */
/* D = 1 if GaindB >= 0 */
/* D = 1 / (1 + G) if GaindB < 0 */
/* */
/* b2 = -0.5 * (2Q - D * t0) / (2Q + D * t0) */
/* b1 = (0.5 - b2) * (1 - coserr(t0)) */
/* a0 = (0.5 + b2) / 2 */
/* */
/* Where: */
/* GaindB is the gain in dBs, range -15dB to +15dB */
/* Fc is the centre frequency, DC to Fs/50 */
/* Fs is the sample frequency, 8000 to 48000 in descrete steps */
/* Q is the Q factor, 0.25 to 12 (represented by 25 to 1200) */
/* */
/* 2. The double precision coefficients are only used when fc is less than fs/85, so */
/* the cosine of t0 is always close to 1.0. Instead of calculating the cosine */
/* itself the difference from the value 1.0 is calculated, this can be done with */
/* lower precision maths. */
/* */
/* 3. The value of the B2 coefficient is only calculated as a single precision value, */
/* small errors in this value have a combined effect on the Q and Gain but not the */
/* the frequency of the filter. */
/* */
/****************************************************************************************/
LVEQNB_ReturnStatus_en LVEQNB_DoublePrecCoefs(LVM_UINT16 Fs,
LVEQNB_BandDef_t *pFilterDefinition,
PK_C32_Coefs_t *pCoefficients)
{
extern LVM_INT16 LVEQNB_GainTable[];
extern LVM_INT16 LVEQNB_TwoPiOnFsTable[];
extern LVM_INT16 LVEQNB_DTable[];
extern LVM_INT16 LVEQNB_DPCosCoef[];
/*
* Get the filter definition
*/
LVM_INT16 Gain = pFilterDefinition->Gain;
LVM_UINT16 Frequency = pFilterDefinition->Frequency;
LVM_UINT16 QFactor = pFilterDefinition->QFactor;
/*
* Intermediate variables and temporary values
*/
LVM_INT32 T0;
LVM_INT16 D;
LVM_INT32 A0;
LVM_INT32 B1;
LVM_INT32 B2;
LVM_INT32 Dt0;
LVM_INT32 B2_Den;
LVM_INT32 B2_Num;
LVM_INT32 CosErr;
LVM_INT16 coef;
LVM_INT32 factor;
LVM_INT16 t0;
LVM_INT16 i;
/*
* Calculating the intermediate values
*/
T0 = (LVM_INT32)Frequency * LVEQNB_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
if (Gain >= 0)
{
D = LVEQNB_DTable[15]; /* D = 1 if GaindB >= 0 */
}
else
{
D = LVEQNB_DTable[Gain+15]; /* D = 1 / (1 + G) if GaindB < 0 */
}
/*
* Calculate the B2 coefficient
*/
Dt0 = D * (T0 >> 10);
B2_Den = ((LVM_INT32)QFactor << 19) + (Dt0 >> 2);
B2_Num = (Dt0 >> 3) - ((LVM_INT32)QFactor << 18);
B2 = (B2_Num / (B2_Den >> 16)) << 15;
/*
* Calculate the cosine error by a polynomial expansion using the equation:
*
* CosErr += coef(n) * t0^n For n = 0 to 4
*/
T0 = (T0 >> 6) * 0x7f53; /* Scale to 1.0 in 16-bit for range 0 to fs/50 */
t0 = (LVM_INT16)(T0 >> 16);
factor = 0x7fff; /* Initialise to 1.0 for the a0 coefficient */
CosErr = 0; /* Initialise the error to zero */
for (i=1; i<5; i++)
{
coef = LVEQNB_DPCosCoef[i]; /* Get the nth coefficient */
CosErr += (factor * coef) >> 5; /* The nth partial sum */
factor = (factor * t0) >> 15; /* Calculate t0^n */
}
CosErr = CosErr << (LVEQNB_DPCosCoef[0]); /* Correct the scaling */
/*
* Calculate the B1 and A0 coefficients
*/
B1 = (0x40000000 - B2); /* B1 = (0.5 - b2/2) */
A0 = ((B1 >> 16) * (CosErr >> 10)) >> 6; /* Temporary storage for (0.5 - b2/2) * coserr(t0) */
B1 -= A0; /* B1 = (0.5 - b2/2) * (1 - coserr(t0)) */
A0 = (0x40000000 + B2) >> 1; /* A0 = (0.5 + b2) */
/*
* Write coeff into the data structure
*/
pCoefficients->A0 = A0;
pCoefficients->B1 = B1;
pCoefficients->B2 = B2;
pCoefficients->G = LVEQNB_GainTable[Gain+15];
return(LVEQNB_SUCCESS);
}
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_SinglePrecCoefs */
/* */
/* DESCRIPTION: */
/* Calculate single precision coefficients for a peaking filter */
/* */
/* PARAMETERS: */
/* Fs Sampling frequency index */
/* pFilterDefinition Pointer to the filter definition */
/* pCoefficients Pointer to the coefficients */
/* */
/* RETURNS: */
/* LVEQNB_SUCCESS Always succeeds */
/* */
/* NOTES: */
/* 1. The equations used are as follows: */
/* */
/* G = 10^(GaindB/20) - 1 */
/* t0 = 2 * Pi * Fc / Fs */
/* D = 1 if GaindB >= 0 */
/* D = 1 / (1 + G) if GaindB < 0 */
/* */
/* b2 = -0.5 * (2Q - D * t0) / (2Q + D * t0) */
/* b1 = (0.5 - b2) * cos(t0) */
/* a0 = (0.5 + b2) / 2 */
/* */
/* Where: */
/* GaindB is the gain in dBs, range -15dB to +15dB */
/* Fc is the centre frequency, DC to Nyquist */
/* Fs is the sample frequency, 8000 to 48000 in descrete steps */
/* Q is the Q factor, 0.25 to 12 */
/* */
/****************************************************************************************/
LVEQNB_ReturnStatus_en LVEQNB_SinglePrecCoefs(LVM_UINT16 Fs,
LVEQNB_BandDef_t *pFilterDefinition,
PK_C16_Coefs_t *pCoefficients)
{
extern LVM_INT16 LVEQNB_GainTable[];
extern LVM_INT16 LVEQNB_TwoPiOnFsTable[];
extern LVM_INT16 LVEQNB_DTable[];
extern LVM_INT16 LVEQNB_CosCoef[];
/*
* Get the filter definition
*/
LVM_INT16 Gain = pFilterDefinition->Gain;
LVM_UINT16 Frequency = pFilterDefinition->Frequency;
LVM_UINT16 QFactor = pFilterDefinition->QFactor;
/*
* Intermediate variables and temporary values
*/
LVM_INT32 T0;
LVM_INT16 D;
LVM_INT32 A0;
LVM_INT32 B1;
LVM_INT32 B2;
LVM_INT32 Dt0;
LVM_INT32 B2_Den;
LVM_INT32 B2_Num;
LVM_INT32 COS_T0;
LVM_INT16 coef;
LVM_INT32 factor;
LVM_INT16 t0;
LVM_INT16 i;
/*
* Calculating the intermediate values
*/
T0 = (LVM_INT32)Frequency * LVEQNB_TwoPiOnFsTable[Fs]; /* T0 = 2 * Pi * Fc / Fs */
if (Gain >= 0)
{
D = LVEQNB_DTable[15]; /* D = 1 if GaindB >= 0 */
}
else
{
D = LVEQNB_DTable[Gain+15]; /* D = 1 / (1 + G) if GaindB < 0 */
}
/*
* Calculate the B2 coefficient
*/
Dt0 = D * (T0 >> 10);
B2_Den = ((LVM_INT32)QFactor << 19) + (Dt0 >> 2);
B2_Num = (Dt0 >> 3) - ((LVM_INT32)QFactor << 18);
B2 = (B2_Num / (B2_Den >> 16)) << 15;
/*
* Calculate the cosine by a polynomial expansion using the equation:
*
* Cos += coef(n) * t0^n For n = 0 to 6
*/
T0 = (T0 >> 10) * 20859; /* Scale to 1.0 in 16-bit for range 0 to fs/2 */
t0 = (LVM_INT16)(T0 >> 16);
factor = 0x7fff; /* Initialise to 1.0 for the a0 coefficient */
COS_T0 = 0; /* Initialise the error to zero */
for (i=1; i<7; i++)
{
coef = LVEQNB_CosCoef[i]; /* Get the nth coefficient */
COS_T0 += (factor * coef) >> 5; /* The nth partial sum */
factor = (factor * t0) >> 15; /* Calculate t0^n */
}
COS_T0 = COS_T0 << (LVEQNB_CosCoef[0]+6); /* Correct the scaling */
B1 = ((0x40000000 - B2) >> 16) * (COS_T0 >> 16); /* B1 = (0.5 - b2/2) * cos(t0) */
A0 = (0x40000000 + B2) >> 1; /* A0 = (0.5 + b2/2) */
/*
* Write coeff into the data structure
*/
pCoefficients->A0 = (LVM_INT16)(A0>>16);
pCoefficients->B1 = (LVM_INT16)(B1>>15);
pCoefficients->B2 = (LVM_INT16)(B2>>16);
pCoefficients->G = LVEQNB_GainTable[Gain+15];
return(LVEQNB_SUCCESS);
}