|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "biquad.h"
|
|
|
|
|
|
#include <math.h>
|
|
|
#include <stdlib.h>
|
|
|
#include <string.h>
|
|
|
#include <stdio.h>
|
|
|
|
|
|
#include "biquad_st.h"
|
|
|
|
|
|
#define AUP_BIQUAD_NUM_DUMP_FILES (20)
|
|
|
#define AUP_BIQUAD_DUMP_FILENAMES (200)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int AUP_Biquad_checkStatCfg(const Biquad_StaticCfg* pCfg) {
|
|
|
int secIdx;
|
|
|
if (pCfg == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
if (pCfg->maxNSample == 0 ||
|
|
|
pCfg->maxNSample > AGORA_UAP_BIQUAD_MAX_INPUT_LEN) {
|
|
|
return -1;
|
|
|
}
|
|
|
if (pCfg->nsect > AGORA_UAP_BIQUAD_MAX_SECTION) {
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (pCfg->nsect > 0) {
|
|
|
for (secIdx = 0; secIdx < pCfg->nsect; secIdx++) {
|
|
|
if (pCfg->B[secIdx] == NULL || pCfg->A[secIdx] == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
if (pCfg->G == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int AUP_Biquad_publishStaticCfg(Biquad_St* stHdl) {
|
|
|
const Biquad_StaticCfg* pStatCfg;
|
|
|
int idx;
|
|
|
|
|
|
if (stHdl == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
pStatCfg = (const Biquad_StaticCfg*)(&(stHdl->stCfg));
|
|
|
|
|
|
stHdl->maxNSample = (int)pStatCfg->maxNSample;
|
|
|
|
|
|
|
|
|
for (idx = 0; idx < AGORA_UAP_BIQUAD_MAX_SECTION; idx++) {
|
|
|
stHdl->BCoeff[idx][0] = 1.0f;
|
|
|
stHdl->BCoeff[idx][1] = 0;
|
|
|
stHdl->BCoeff[idx][2] = 0;
|
|
|
stHdl->ACoeff[idx][0] = 1.0f;
|
|
|
stHdl->ACoeff[idx][1] = 0;
|
|
|
stHdl->ACoeff[idx][2] = 0;
|
|
|
stHdl->GCoeff[idx] = 1.0f;
|
|
|
}
|
|
|
|
|
|
if (pStatCfg->nsect <= 0) {
|
|
|
stHdl->nsect = _BIQUAD_DC_REMOVAL_NSECT;
|
|
|
for (idx = 0; idx < stHdl->nsect; idx++) {
|
|
|
stHdl->BCoeff[idx][0] = _BIQUAD_DC_REMOVAL_B[idx][0];
|
|
|
stHdl->BCoeff[idx][1] = _BIQUAD_DC_REMOVAL_B[idx][1];
|
|
|
stHdl->BCoeff[idx][2] = _BIQUAD_DC_REMOVAL_B[idx][2];
|
|
|
stHdl->ACoeff[idx][0] = _BIQUAD_DC_REMOVAL_A[idx][0];
|
|
|
stHdl->ACoeff[idx][1] = _BIQUAD_DC_REMOVAL_A[idx][1];
|
|
|
stHdl->ACoeff[idx][2] = _BIQUAD_DC_REMOVAL_A[idx][2];
|
|
|
stHdl->GCoeff[idx] = _BIQUAD_DC_REMOVAL_G[idx];
|
|
|
}
|
|
|
} else {
|
|
|
stHdl->nsect = pStatCfg->nsect;
|
|
|
for (idx = 0; idx < stHdl->nsect; idx++) {
|
|
|
stHdl->BCoeff[idx][0] = pStatCfg->B[idx][0];
|
|
|
stHdl->BCoeff[idx][1] = pStatCfg->B[idx][1];
|
|
|
stHdl->BCoeff[idx][2] = pStatCfg->B[idx][2];
|
|
|
|
|
|
stHdl->ACoeff[idx][0] = pStatCfg->A[idx][0];
|
|
|
stHdl->ACoeff[idx][1] = pStatCfg->A[idx][1];
|
|
|
stHdl->ACoeff[idx][2] = pStatCfg->A[idx][2];
|
|
|
|
|
|
stHdl->GCoeff[idx] = pStatCfg->G[idx];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int AUP_Biquad_resetVariables(Biquad_St* stHdl) {
|
|
|
memset(stHdl->dynamMemPtr, 0, stHdl->dynamMemSize);
|
|
|
memset(stHdl->sectW, 0, sizeof(stHdl->sectW));
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int AUP_Biquad_create(void** stPtr) {
|
|
|
Biquad_St* tmpPtr;
|
|
|
|
|
|
if (stPtr == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
*stPtr = (void*)malloc(sizeof(Biquad_St));
|
|
|
if (*stPtr == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
memset(*stPtr, 0, sizeof(Biquad_St));
|
|
|
|
|
|
tmpPtr = (Biquad_St*)(*stPtr);
|
|
|
|
|
|
tmpPtr->dynamMemPtr = NULL;
|
|
|
tmpPtr->dynamMemSize = 0;
|
|
|
|
|
|
tmpPtr->stCfg.maxNSample = 768;
|
|
|
tmpPtr->stCfg.nsect = 0;
|
|
|
for (int idx = 0; idx < AGORA_UAP_BIQUAD_MAX_SECTION; idx++) {
|
|
|
tmpPtr->stCfg.A[idx] = NULL;
|
|
|
tmpPtr->stCfg.B[idx] = NULL;
|
|
|
}
|
|
|
tmpPtr->stCfg.G = NULL;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AUP_Biquad_destroy(void** stPtr) {
|
|
|
Biquad_St* stHdl;
|
|
|
|
|
|
if (stPtr == NULL) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
stHdl = (Biquad_St*)(*stPtr);
|
|
|
if (stHdl == NULL) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
if (stHdl->dynamMemPtr != NULL) {
|
|
|
free(stHdl->dynamMemPtr);
|
|
|
}
|
|
|
stHdl->dynamMemPtr = NULL;
|
|
|
|
|
|
free(stHdl);
|
|
|
|
|
|
(*stPtr) = NULL;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AUP_Biquad_memAllocate(void* stPtr, const Biquad_StaticCfg* pCfg) {
|
|
|
Biquad_St* stHdl = NULL;
|
|
|
char* memPtr = NULL;
|
|
|
int maxNSample, nsect, idx;
|
|
|
|
|
|
int inputTempBufMemSize = 0;
|
|
|
int sectOutputBufMemSize_EACH = 0;
|
|
|
int totalMemSize = 0;
|
|
|
|
|
|
if (stPtr == NULL || pCfg == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
stHdl = (Biquad_St*)(stPtr);
|
|
|
|
|
|
if (AUP_Biquad_checkStatCfg(pCfg) < 0) {
|
|
|
return -1;
|
|
|
}
|
|
|
memcpy(&(stHdl->stCfg), pCfg, sizeof(Biquad_StaticCfg));
|
|
|
|
|
|
if (AUP_Biquad_publishStaticCfg(stHdl) < 0) {
|
|
|
return -1;
|
|
|
}
|
|
|
maxNSample = stHdl->maxNSample;
|
|
|
nsect = stHdl->nsect;
|
|
|
|
|
|
|
|
|
inputTempBufMemSize = AGORA_UAP_BIQUAD_ALIGN8(sizeof(float) * maxNSample);
|
|
|
totalMemSize += inputTempBufMemSize;
|
|
|
|
|
|
sectOutputBufMemSize_EACH =
|
|
|
AGORA_UAP_BIQUAD_ALIGN8(sizeof(float) * maxNSample);
|
|
|
totalMemSize += sectOutputBufMemSize_EACH * nsect;
|
|
|
|
|
|
|
|
|
if ((size_t)totalMemSize > stHdl->dynamMemSize) {
|
|
|
if (stHdl->dynamMemPtr != NULL) {
|
|
|
free(stHdl->dynamMemPtr);
|
|
|
stHdl->dynamMemSize = 0;
|
|
|
}
|
|
|
stHdl->dynamMemPtr = malloc(totalMemSize);
|
|
|
if (stHdl->dynamMemPtr == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
stHdl->dynamMemSize = totalMemSize;
|
|
|
}
|
|
|
memset(stHdl->dynamMemPtr, 0, stHdl->dynamMemSize);
|
|
|
|
|
|
|
|
|
memPtr = (char*)(stHdl->dynamMemPtr);
|
|
|
|
|
|
stHdl->inputTempBuf = (float*)memPtr;
|
|
|
memPtr += inputTempBufMemSize;
|
|
|
|
|
|
for (idx = 0; idx < nsect; idx++) {
|
|
|
stHdl->sectOutputBuf[idx] = (float*)memPtr;
|
|
|
memPtr += sectOutputBufMemSize_EACH;
|
|
|
}
|
|
|
for (; idx < AGORA_UAP_BIQUAD_MAX_SECTION; idx++) {
|
|
|
stHdl->sectOutputBuf[idx] = NULL;
|
|
|
}
|
|
|
|
|
|
if (((int)(memPtr - (char*)(stHdl->dynamMemPtr))) > totalMemSize) {
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AUP_Biquad_init(void* stPtr) {
|
|
|
Biquad_St* stHdl;
|
|
|
|
|
|
if (stPtr == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
stHdl = (Biquad_St*)(stPtr);
|
|
|
|
|
|
if (AUP_Biquad_resetVariables(stHdl) < 0) {
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AUP_Biquad_getStaticCfg(const void* stPtr, Biquad_StaticCfg* pCfg) {
|
|
|
const Biquad_St* stHdl;
|
|
|
|
|
|
if (stPtr == NULL || pCfg == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
stHdl = (const Biquad_St*)(stPtr);
|
|
|
|
|
|
memcpy(pCfg, &(stHdl->stCfg), sizeof(Biquad_StaticCfg));
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AUP_Biquad_getAlgDelay(const void* stPtr, int* delayInSamples) {
|
|
|
const Biquad_St* stHdl;
|
|
|
|
|
|
if (stPtr == NULL || delayInSamples == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
stHdl = (const Biquad_St*)(stPtr);
|
|
|
|
|
|
*delayInSamples = stHdl->nsect;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int AUP_Biquad_proc(void* stPtr, const Biquad_InputData* pIn,
|
|
|
Biquad_OutputData* pOut) {
|
|
|
Biquad_St* stHdl = NULL;
|
|
|
int isFloatIO = 0;
|
|
|
int inputNSamples, nSect;
|
|
|
int sectIdx, smplIdx;
|
|
|
float tmp1;
|
|
|
const short* pShortTemp;
|
|
|
float* src;
|
|
|
float* tgt;
|
|
|
|
|
|
if (stPtr == NULL || pIn == NULL || pOut == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
if (pIn->samplesPtr == NULL || pOut->outputBuff == NULL) {
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
stHdl = (Biquad_St*)(stPtr);
|
|
|
|
|
|
if (((int)pIn->nsamples) > stHdl->maxNSample) {
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
isFloatIO = 0;
|
|
|
if (pIn->sampleType != 0) {
|
|
|
isFloatIO = 1;
|
|
|
}
|
|
|
|
|
|
inputNSamples = (int)pIn->nsamples;
|
|
|
nSect = stHdl->nsect;
|
|
|
|
|
|
|
|
|
if (isFloatIO == 0) {
|
|
|
pShortTemp = (const short*)pIn->samplesPtr;
|
|
|
for (smplIdx = 0; smplIdx < inputNSamples; smplIdx++) {
|
|
|
stHdl->inputTempBuf[smplIdx] = (float)pShortTemp[smplIdx];
|
|
|
}
|
|
|
} else {
|
|
|
memcpy(stHdl->inputTempBuf, (const float*)pIn->samplesPtr,
|
|
|
sizeof(float) * inputNSamples);
|
|
|
}
|
|
|
|
|
|
for (sectIdx = 0; sectIdx < nSect; sectIdx++) {
|
|
|
if (sectIdx == 0) {
|
|
|
src = stHdl->inputTempBuf;
|
|
|
} else {
|
|
|
src = stHdl->sectOutputBuf[sectIdx - 1];
|
|
|
}
|
|
|
tgt = stHdl->sectOutputBuf[sectIdx];
|
|
|
|
|
|
for (smplIdx = 0; smplIdx < inputNSamples; smplIdx++) {
|
|
|
tmp1 = src[smplIdx] -
|
|
|
stHdl->ACoeff[sectIdx][1] * stHdl->sectW[sectIdx][0] -
|
|
|
stHdl->ACoeff[sectIdx][2] * stHdl->sectW[sectIdx][1];
|
|
|
|
|
|
tgt[smplIdx] = stHdl->GCoeff[sectIdx] *
|
|
|
(stHdl->BCoeff[sectIdx][0] * tmp1 +
|
|
|
stHdl->BCoeff[sectIdx][1] * stHdl->sectW[sectIdx][0] +
|
|
|
stHdl->BCoeff[sectIdx][2] * stHdl->sectW[sectIdx][1]);
|
|
|
|
|
|
stHdl->sectW[sectIdx][1] = stHdl->sectW[sectIdx][0];
|
|
|
stHdl->sectW[sectIdx][0] = tmp1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
if (isFloatIO == 0) {
|
|
|
for (smplIdx = 0; smplIdx < inputNSamples; smplIdx++) {
|
|
|
((short*)pOut->outputBuff)[smplIdx] =
|
|
|
(short)_BIQUAD_FLOAT2SHORT(stHdl->sectOutputBuf[nSect - 1][smplIdx]);
|
|
|
}
|
|
|
} else {
|
|
|
memcpy(pOut->outputBuff, stHdl->sectOutputBuf[nSect - 1],
|
|
|
sizeof(float) * inputNSamples);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|