blob: d188c0e1ae212a50000eda7d83fcd8ee2d6e5a0b [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"
#include <log/log.h>
/****************************************************************************************/
/* */
/* Defines */
/* */
/****************************************************************************************/
#define SHIFT 13
/****************************************************************************************/
/* */
/* FUNCTION: LVEQNB_Process */
/* */
/* DESCRIPTION: */
/* Process function for the N-Band Equaliser module. */
/* */
/* PARAMETERS: */
/* hInstance Instance handle */
/* pInData Pointer to the input data */
/* pOutData Pointer to the output data */
/* NumSamples Number of samples in the input buffer */
/* */
/* RETURNS: */
/* LVEQNB_SUCCESS Succeeded */
/* LVEQNB_NULLADDRESS When hInstance, pInData or pOutData are NULL */
/* LVEQNB_ALIGNMENTERROR When pInData or pOutData are not 32-bit aligned */
/* LVEQNB_TOOMANYSAMPLES NumSamples was larger than the maximum block size */
/* */
/* NOTES: */
/* */
/****************************************************************************************/
#ifdef BUILD_FLOAT
LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance,
const LVM_FLOAT *pInData,
LVM_FLOAT *pOutData,
const LVM_UINT16 NrFrames)
{ // updated to use samples = frames * channels.
LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
#ifdef SUPPORT_MC
// Mono passed in as stereo
const LVM_INT32 NrChannels = pInstance->Params.NrChannels == 1
? 2 : pInstance->Params.NrChannels;
#else
const LVM_INT32 NrChannels = 2; // FCC_2
#endif
const LVM_INT32 NrSamples = NrChannels * NrFrames;
/* Check for NULL pointers */
if((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
{
return LVEQNB_NULLADDRESS;
}
/* Check if the input and output data buffers are 32-bit aligned */
if ((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0))
{
return LVEQNB_ALIGNMENTERROR;
}
LVM_FLOAT * const pScratch = (LVM_FLOAT *)pInstance->pFastTemporary;
/*
* Check the number of frames is not too large
*/
if (NrFrames > pInstance->Capabilities.MaxBlockSize)
{
return LVEQNB_TOOMANYSAMPLES;
}
if (pInstance->Params.OperatingMode == LVEQNB_ON)
{
/*
* Copy input data in to scratch buffer
*/
Copy_Float(pInData, /* Source */
pScratch, /* Destination */
(LVM_INT16)NrSamples);
/*
* For each section execte the filter unless the gain is 0dB
*/
if (pInstance->NBands != 0)
{
for (LVM_UINT16 i = 0; i < pInstance->NBands; i++)
{
/*
* Check if band is non-zero dB gain
*/
if (pInstance->pBandDefinitions[i].Gain != 0)
{
/*
* Get the address of the biquad instance
*/
Biquad_FLOAT_Instance_t *pBiquad = &pInstance->pEQNB_FilterState_Float[i];
/*
* Select single or double precision as required
*/
switch (pInstance->pBiquadType[i])
{
case LVEQNB_SinglePrecision_Float:
{
#ifdef SUPPORT_MC
PK_Mc_D32F32C14G11_TRC_WRA_01(pBiquad,
pScratch,
pScratch,
(LVM_INT16)NrFrames,
(LVM_INT16)NrChannels);
#else
PK_2I_D32F32C14G11_TRC_WRA_01(pBiquad,
pScratch,
pScratch,
(LVM_INT16)NrFrames);
#endif
break;
}
default:
break;
}
}
}
}
if(pInstance->bInOperatingModeTransition == LVM_TRUE){
#ifdef SUPPORT_MC
LVC_MixSoft_2Mc_D16C31_SAT(&pInstance->BypassMixer,
pScratch,
pInData,
pScratch,
(LVM_INT16)NrFrames,
(LVM_INT16)NrChannels);
#else
LVC_MixSoft_2St_D16C31_SAT(&pInstance->BypassMixer,
pScratch,
pInData,
pScratch,
(LVM_INT16)NrSamples);
#endif
// duplicate with else clause(s)
Copy_Float(pScratch, /* Source */
pOutData, /* Destination */
(LVM_INT16)NrSamples); /* All channel samples */
}
else{
Copy_Float(pScratch, /* Source */
pOutData, /* Destination */
(LVM_INT16)NrSamples); /* All channel samples */
}
}
else
{
/*
* Mode is OFF so copy the data if necessary
*/
if (pInData != pOutData)
{
Copy_Float(pInData, /* Source */
pOutData, /* Destination */
(LVM_INT16)NrSamples); /* All channel samples */
}
}
return LVEQNB_SUCCESS;
}
#else
LVEQNB_ReturnStatus_en LVEQNB_Process(LVEQNB_Handle_t hInstance,
const LVM_INT16 *pInData,
LVM_INT16 *pOutData,
LVM_UINT16 NumSamples)
{
LVM_UINT16 i;
Biquad_Instance_t *pBiquad;
LVEQNB_Instance_t *pInstance = (LVEQNB_Instance_t *)hInstance;
LVM_INT32 *pScratch;
/* Check for NULL pointers */
if((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
{
return LVEQNB_NULLADDRESS;
}
/* Check if the input and output data buffers are 32-bit aligned */
if ((((uintptr_t)pInData % 4) != 0) || (((uintptr_t)pOutData % 4) != 0))
{
return LVEQNB_ALIGNMENTERROR;
}
pScratch = (LVM_INT32 *)pInstance->pFastTemporary;
/*
* Check the number of samples is not too large
*/
if (NumSamples > pInstance->Capabilities.MaxBlockSize)
{
return(LVEQNB_TOOMANYSAMPLES);
}
if (pInstance->Params.OperatingMode == LVEQNB_ON)
{
/*
* Convert from 16-bit to 32-bit
*/
Int16LShiftToInt32_16x32((LVM_INT16 *)pInData, /* Source */
pScratch, /* Destination */
(LVM_INT16)(2*NumSamples), /* Left and Right */
SHIFT); /* Scaling shift */
/*
* For each section execte the filter unless the gain is 0dB
*/
if (pInstance->NBands != 0)
{
for (i=0; i<pInstance->NBands; i++)
{
/*
* Check if band is non-zero dB gain
*/
if (pInstance->pBandDefinitions[i].Gain != 0)
{
/*
* Get the address of the biquad instance
*/
pBiquad = &pInstance->pEQNB_FilterState[i];
/*
* Select single or double precision as required
*/
switch (pInstance->pBiquadType[i])
{
case LVEQNB_SinglePrecision:
{
PK_2I_D32F32C14G11_TRC_WRA_01(pBiquad,
(LVM_INT32 *)pScratch,
(LVM_INT32 *)pScratch,
(LVM_INT16)NumSamples);
break;
}
case LVEQNB_DoublePrecision:
{
PK_2I_D32F32C30G11_TRC_WRA_01(pBiquad,
(LVM_INT32 *)pScratch,
(LVM_INT32 *)pScratch,
(LVM_INT16)NumSamples);
break;
}
default:
break;
}
}
}
}
if(pInstance->bInOperatingModeTransition == LVM_TRUE){
/*
* Convert from 32-bit to 16- bit and saturate
*/
Int32RShiftToInt16_Sat_32x16(pScratch, /* Source */
(LVM_INT16 *)pScratch, /* Destination */
(LVM_INT16)(2*NumSamples), /* Left and Right */
SHIFT); /* Scaling shift */
LVC_MixSoft_2St_D16C31_SAT(&pInstance->BypassMixer,
(LVM_INT16 *)pScratch,
(LVM_INT16 *)pInData,
(LVM_INT16 *)pScratch,
(LVM_INT16)(2*NumSamples));
Copy_16((LVM_INT16*)pScratch, /* Source */
pOutData, /* Destination */
(LVM_INT16)(2*NumSamples)); /* Left and Right samples */
}
else{
/*
* Convert from 32-bit to 16- bit and saturate
*/
Int32RShiftToInt16_Sat_32x16(pScratch, /* Source */
pOutData, /* Destination */
(LVM_INT16 )(2*NumSamples), /* Left and Right */
SHIFT); /* Scaling shift */
}
}
else
{
/*
* Mode is OFF so copy the data if necessary
*/
if (pInData != pOutData)
{
Copy_16(pInData, /* Source */
pOutData, /* Destination */
(LVM_INT16)(2*NumSamples)); /* Left and Right samples */
}
}
return(LVEQNB_SUCCESS);
}
#endif