|
|
|
|
|
|
|
|
|
|
|
|
| #include <math.h>
|
| #include <stdlib.h>
|
| #include <string.h>
|
| #include <stdio.h>
|
|
|
| #include "fscvrt.h"
|
| #include "fscvrt_st.h"
|
| #include "biquad.h"
|
|
|
|
|
|
|
|
|
|
|
| static int AUP_Fscvrt_FilterSet(int resampleRate, int* nsect,
|
| const float* B[_FSCVRT_MAXNSEC],
|
| const float* A[_FSCVRT_MAXNSEC],
|
| const float** G) {
|
| int idx;
|
| if (resampleRate == 2) {
|
| *nsect = _FSCVRT_1over2_LOWPASS_NSEC;
|
| for (idx = 0; idx < (*nsect); idx++) {
|
| B[idx] = &(_FSCVRT_1over2_LOWPASS_B[idx][0]);
|
| A[idx] = &(_FSCVRT_1over2_LOWPASS_A[idx][0]);
|
| }
|
| *G = _FSCVRT_1over2_LOWPASS_G;
|
| } else if (resampleRate == 3) {
|
| *nsect = _FSCVRT_1over3_LOWPASS_NSEC;
|
| for (idx = 0; idx < (*nsect); idx++) {
|
| B[idx] = &(_FSCVRT_1over3_LOWPASS_B[idx][0]);
|
| A[idx] = &(_FSCVRT_1over3_LOWPASS_A[idx][0]);
|
| }
|
| *G = _FSCVRT_1over3_LOWPASS_G;
|
| } else if (resampleRate == 4) {
|
| *nsect = _FSCVRT_1over4_LOWPASS_NSEC;
|
| for (idx = 0; idx < (*nsect); idx++) {
|
| B[idx] = &(_FSCVRT_1over4_LOWPASS_B[idx][0]);
|
| A[idx] = &(_FSCVRT_1over4_LOWPASS_A[idx][0]);
|
| }
|
| *G = _FSCVRT_1over4_LOWPASS_G;
|
| } else if (resampleRate == 6) {
|
| *nsect = _FSCVRT_1over6_LOWPASS_NSEC;
|
| for (idx = 0; idx < (*nsect); idx++) {
|
| B[idx] = &(_FSCVRT_1over6_LOWPASS_B[idx][0]);
|
| A[idx] = &(_FSCVRT_1over6_LOWPASS_A[idx][0]);
|
| }
|
| *G = _FSCVRT_1over6_LOWPASS_G;
|
| } else {
|
| return -1;
|
| }
|
|
|
| return 0;
|
| }
|
|
|
| static int AUP_Fscvrt_dynamMemPrepare(FscvrtSt* stHdl, void* memPtrExt,
|
| size_t memSize) {
|
| char* memPtr = NULL;
|
| int biquadInBufMemSize = 0;
|
| int biquadOutBufMemSize = 0;
|
| int totalMemSize = 0;
|
|
|
| if (stHdl == NULL) {
|
| return -1;
|
| }
|
|
|
| biquadInBufMemSize = _FSCVRT_ALIGN8(sizeof(float) * stHdl->biquadInBufLen);
|
| totalMemSize += biquadInBufMemSize;
|
|
|
| biquadOutBufMemSize = _FSCVRT_ALIGN8(sizeof(float) * stHdl->biquadOutBufLen);
|
| totalMemSize += biquadOutBufMemSize;
|
|
|
| totalMemSize = _FSCVRT_MAX(totalMemSize, 80);
|
|
|
|
|
|
|
| if (memPtrExt == NULL) {
|
| return (totalMemSize);
|
| }
|
|
|
|
|
| if ((size_t)totalMemSize > memSize) {
|
| return -1;
|
| }
|
| memPtr = (char*)memPtrExt;
|
|
|
| stHdl->biquadInBuf = NULL;
|
| if (biquadInBufMemSize != 0) {
|
| stHdl->biquadInBuf = (float*)memPtr;
|
| memPtr += biquadInBufMemSize;
|
| }
|
|
|
| stHdl->biquadOutBuf = NULL;
|
| if (biquadOutBufMemSize != 0) {
|
| stHdl->biquadOutBuf = (float*)memPtr;
|
| memPtr += biquadOutBufMemSize;
|
| }
|
|
|
| if (((int)(memPtr - (char*)memPtrExt)) > totalMemSize) {
|
| return -1;
|
| }
|
|
|
| return (totalMemSize);
|
| }
|
|
|
| static int AUP_Fscvrt_checkStatCfg(FscvrtStaticCfg* pCfg) {
|
| if (pCfg == NULL) {
|
| return -1;
|
| }
|
|
|
| if (pCfg->inputFs != 16000 && pCfg->inputFs != 24000 &&
|
| pCfg->inputFs != 32000 && pCfg->inputFs != 48000) {
|
| return -1;
|
| }
|
|
|
| if (pCfg->outputFs != 16000 && pCfg->outputFs != 24000 &&
|
| pCfg->outputFs != 32000 && pCfg->outputFs != 48000) {
|
| return -1;
|
| }
|
|
|
| if (pCfg->stepSz > AUP_FSCVRT_MAX_INPUT_LEN || pCfg->stepSz < 1) {
|
| return -1;
|
| }
|
|
|
| if (pCfg->inputType != 0) {
|
| pCfg->inputType = 1;
|
| }
|
|
|
| if (pCfg->outputType != 0) {
|
| pCfg->outputType = 1;
|
| }
|
|
|
| return 0;
|
| }
|
|
|
| static int AUP_Fscvrt_publishStaticCfg(FscvrtSt* stHdl) {
|
| int tmpRatio;
|
| int ret;
|
| int maxResmplRate = 0;
|
|
|
| stHdl->mode = 0;
|
| stHdl->upSmplRate = 1;
|
| stHdl->downSmplRate = 1;
|
| if (stHdl->stCfg.inputFs != stHdl->stCfg.outputFs) {
|
| if (stHdl->stCfg.outputFs > stHdl->stCfg.inputFs) {
|
| tmpRatio = (stHdl->stCfg.outputFs / stHdl->stCfg.inputFs);
|
| if (stHdl->stCfg.outputFs == tmpRatio * stHdl->stCfg.inputFs) {
|
| stHdl->mode = 1;
|
| stHdl->upSmplRate = tmpRatio;
|
| stHdl->downSmplRate = 1;
|
| } else {
|
| stHdl->mode = 3;
|
| stHdl->upSmplRate = _FSCVRT_COMMON_FS / stHdl->stCfg.inputFs;
|
| stHdl->downSmplRate = _FSCVRT_COMMON_FS / stHdl->stCfg.outputFs;
|
| }
|
| } else {
|
| tmpRatio = (stHdl->stCfg.inputFs / stHdl->stCfg.outputFs);
|
| if (stHdl->stCfg.inputFs == tmpRatio * stHdl->stCfg.outputFs) {
|
| stHdl->mode = 2;
|
| stHdl->upSmplRate = 1;
|
| stHdl->downSmplRate = tmpRatio;
|
| } else {
|
| stHdl->mode = 3;
|
| stHdl->upSmplRate = _FSCVRT_COMMON_FS / stHdl->stCfg.inputFs;
|
| stHdl->downSmplRate = _FSCVRT_COMMON_FS / stHdl->stCfg.outputFs;
|
| }
|
| }
|
| }
|
|
|
| if (stHdl->mode == 0) {
|
| stHdl->biquadInBufLen = 0;
|
| stHdl->biquadOutBufLen = 0;
|
| } else {
|
| stHdl->biquadInBufLen = stHdl->stCfg.stepSz * stHdl->upSmplRate;
|
| stHdl->biquadOutBufLen = 2 * (stHdl->stCfg.stepSz * stHdl->upSmplRate);
|
| }
|
|
|
| maxResmplRate = _FSCVRT_MAX(stHdl->upSmplRate, stHdl->downSmplRate);
|
|
|
| stHdl->nSec = 0;
|
| memset(stHdl->biquadB, 0, sizeof(stHdl->biquadB));
|
| memset(stHdl->biquadA, 0, sizeof(stHdl->biquadA));
|
| stHdl->biquadG = NULL;
|
|
|
| if (stHdl->mode != 0) {
|
| ret = AUP_Fscvrt_FilterSet(maxResmplRate, &(stHdl->nSec), stHdl->biquadB,
|
| stHdl->biquadA, &(stHdl->biquadG));
|
| if (ret < 0) {
|
| return -1;
|
| }
|
| }
|
|
|
| return 0;
|
| }
|
|
|
| static int AUP_Fscvrt_resetVariables(FscvrtSt* stHdl) {
|
| stHdl->biquadInBufCnt = 0;
|
| stHdl->biquadOutBufCnt = 0;
|
|
|
| if (stHdl->dynamMemPtr != NULL && stHdl->dynamMemSize > 0) {
|
| memset(stHdl->dynamMemPtr, 0, stHdl->dynamMemSize);
|
| }
|
| return 0;
|
| }
|
|
|
|
|
|
|
|
|
|
|
| int AUP_Fscvrt_create(void** stPtr) {
|
| FscvrtSt* tmpPtr;
|
|
|
| if (stPtr == NULL) {
|
| return -1;
|
| }
|
| *stPtr = (void*)malloc(sizeof(FscvrtSt));
|
| if (*stPtr == NULL) {
|
| return -1;
|
| }
|
| memset(*stPtr, 0, sizeof(FscvrtSt));
|
|
|
| tmpPtr = (FscvrtSt*)(*stPtr);
|
|
|
| tmpPtr->dynamMemPtr = NULL;
|
| tmpPtr->dynamMemSize = 0;
|
|
|
| tmpPtr->stCfg.inputFs = 24000;
|
| tmpPtr->stCfg.outputFs = 32000;
|
| tmpPtr->stCfg.stepSz = 240;
|
| tmpPtr->stCfg.inputType = 0;
|
| tmpPtr->stCfg.outputType = 0;
|
|
|
| if (AUP_Biquad_create(&(tmpPtr->biquadSt)) < 0) {
|
| return -1;
|
| }
|
|
|
| return 0;
|
| }
|
|
|
| int AUP_Fscvrt_destroy(void** stPtr) {
|
| FscvrtSt* stHdl;
|
|
|
| if (stPtr == NULL) {
|
| return 0;
|
| }
|
|
|
| stHdl = (FscvrtSt*)(*stPtr);
|
| if (stHdl == NULL) {
|
| return 0;
|
| }
|
|
|
| AUP_Biquad_destroy(&(stHdl->biquadSt));
|
| if (stHdl->dynamMemPtr != NULL) {
|
| free(stHdl->dynamMemPtr);
|
| }
|
| stHdl->dynamMemPtr = NULL;
|
|
|
| free(stHdl);
|
| (*stPtr) = NULL;
|
|
|
| return 0;
|
| }
|
|
|
| int AUP_Fscvrt_memAllocate(void* stPtr, const FscvrtStaticCfg* pCfg) {
|
| FscvrtSt* stHdl = NULL;
|
| FscvrtStaticCfg tmpStatCfg = {0};
|
| Biquad_StaticCfg bqStatCfg;
|
| int idx, ret;
|
| int totalMemSize = 0;
|
|
|
| if (stPtr == NULL || pCfg == NULL) {
|
| return -1;
|
| }
|
| stHdl = (FscvrtSt*)(stPtr);
|
|
|
| memcpy(&tmpStatCfg, pCfg, sizeof(FscvrtStaticCfg));
|
| if (AUP_Fscvrt_checkStatCfg(&tmpStatCfg) < 0) {
|
| return -1;
|
| }
|
| memcpy(&(stHdl->stCfg), &tmpStatCfg, sizeof(FscvrtStaticCfg));
|
|
|
| if (AUP_Fscvrt_publishStaticCfg(stHdl) < 0) {
|
| return -1;
|
| }
|
|
|
|
|
| totalMemSize = AUP_Fscvrt_dynamMemPrepare(stHdl, NULL, 0);
|
| if (totalMemSize < 0) {
|
| return -1;
|
| }
|
|
|
|
|
| if ((size_t)totalMemSize > stHdl->dynamMemSize) {
|
| if (stHdl->dynamMemPtr != NULL) {
|
| free(stHdl->dynamMemPtr);
|
| stHdl->dynamMemSize = 0;
|
| }
|
| stHdl->dynamMemPtr = (void*)malloc(totalMemSize);
|
| if (stHdl->dynamMemPtr == NULL) {
|
| return -1;
|
| }
|
| stHdl->dynamMemSize = totalMemSize;
|
| }
|
| memset(stHdl->dynamMemPtr, 0, stHdl->dynamMemSize);
|
|
|
|
|
| if (AUP_Fscvrt_dynamMemPrepare(stHdl, stHdl->dynamMemPtr,
|
| stHdl->dynamMemSize) < 0) {
|
| return -1;
|
| }
|
|
|
|
|
| if (stHdl->nSec != 0) {
|
| if (stHdl->nSec > AGORA_UAP_BIQUAD_MAX_SECTION) {
|
| return -1;
|
| }
|
| memset(&bqStatCfg, 0, sizeof(Biquad_StaticCfg));
|
| bqStatCfg.maxNSample = (size_t)(stHdl->biquadInBufLen);
|
| bqStatCfg.nsect = stHdl->nSec;
|
| for (idx = 0; idx < stHdl->nSec; idx++) {
|
| bqStatCfg.B[idx] = stHdl->biquadB[idx];
|
| bqStatCfg.A[idx] = stHdl->biquadA[idx];
|
| }
|
| bqStatCfg.G = stHdl->biquadG;
|
|
|
| ret = AUP_Biquad_memAllocate(stHdl->biquadSt, &bqStatCfg);
|
| if (ret < 0) {
|
| return -1;
|
| }
|
| }
|
|
|
| return 0;
|
| }
|
|
|
| int AUP_Fscvrt_init(void* stPtr) {
|
| FscvrtSt* stHdl;
|
|
|
| if (stPtr == NULL) {
|
| return -1;
|
| }
|
| stHdl = (FscvrtSt*)(stPtr);
|
|
|
|
|
| if (AUP_Fscvrt_resetVariables(stHdl) < 0) {
|
| return -1;
|
| }
|
|
|
|
|
| if (stHdl->biquadSt != NULL && stHdl->nSec != 0) {
|
| if (AUP_Biquad_init(stHdl->biquadSt) < 0) {
|
| return -1;
|
| }
|
| }
|
|
|
| return 0;
|
| }
|
|
|
| int AUP_Fscvrt_getStaticCfg(const void* stPtr, FscvrtStaticCfg* pCfg) {
|
| const FscvrtSt* stHdl;
|
|
|
| if (stPtr == NULL || pCfg == NULL) {
|
| return -1;
|
| }
|
| stHdl = (const FscvrtSt*)(stPtr);
|
|
|
| memcpy(pCfg, &(stHdl->stCfg), sizeof(FscvrtStaticCfg));
|
|
|
| return 0;
|
| }
|
|
|
| int AUP_Fscvrt_getInfor(const void* stPtr, FscvrtGetData* buff) {
|
| const FscvrtSt* stHdl;
|
| int delayBiquad = 0;
|
| int tmp;
|
|
|
| if (stPtr == NULL || buff == NULL) {
|
| return -1;
|
| }
|
| stHdl = (const FscvrtSt*)(stPtr);
|
|
|
| if (stHdl->nSec != 0) {
|
| if (AUP_Biquad_getAlgDelay(stHdl->biquadSt, &delayBiquad) < 0) {
|
| return -1;
|
| }
|
| }
|
|
|
| if (stHdl->mode == 0) {
|
| buff->delayInInputFs = 0;
|
| } else if (stHdl->mode == 1) {
|
| buff->delayInInputFs =
|
| (int)roundf(delayBiquad / (float)(stHdl->upSmplRate));
|
| } else if (stHdl->mode == 2) {
|
| buff->delayInInputFs = delayBiquad;
|
| } else {
|
| buff->delayInInputFs =
|
| (int)roundf(delayBiquad / (float)(stHdl->upSmplRate));
|
| }
|
| tmp = stHdl->stCfg.stepSz * stHdl->upSmplRate / stHdl->downSmplRate;
|
| if (tmp * stHdl->downSmplRate == stHdl->stCfg.stepSz * stHdl->upSmplRate) {
|
| buff->maxOutputStepSz = tmp;
|
| } else {
|
| buff->maxOutputStepSz = tmp + 1;
|
| }
|
|
|
| return 0;
|
| }
|
|
|
| int AUP_Fscvrt_proc(void* stPtr, const FscvrtInData* pIn, FscvrtOutData* pOut) {
|
| FscvrtSt* stHdl = NULL;
|
| const FscvrtStaticCfg* pCfg;
|
| Biquad_InputData bqdInData;
|
| Biquad_OutputData bqdOutData;
|
| const short* shortSrcPtr = NULL;
|
| const float* floatSrcPtr = NULL;
|
| short* shortTgtPtr = NULL;
|
| float* floatTgtPtr = NULL;
|
| int idx, tgtIdx;
|
| int nOutSamples = 0, samplesTaken = 0, samplesLeft = 0;
|
| int jumpRate;
|
|
|
| if (stPtr == NULL || pIn == NULL || pOut == NULL || pIn->inDataSeq == NULL ||
|
| pOut->outDataSeq == NULL) {
|
| return -1;
|
| }
|
|
|
| stHdl = (FscvrtSt*)(stPtr);
|
| pCfg = (const FscvrtStaticCfg*)&(stHdl->stCfg);
|
| shortSrcPtr = (const short*)(pIn->inDataSeq);
|
| floatSrcPtr = (const float*)(pIn->inDataSeq);
|
|
|
|
|
| if (stHdl->mode == 0) {
|
| if (pIn->outDataSeqLen < pCfg->stepSz) {
|
| return -1;
|
| }
|
| pOut->nOutData = pCfg->stepSz;
|
| pOut->outDataType = pCfg->outputType;
|
| if (pIn->inDataSeq == pOut->outDataSeq) {
|
| if (pCfg->outputType == pCfg->inputType)
|
| return 0;
|
| return -1;
|
|
|
|
|
| }
|
|
|
| if (pCfg->inputType == 0 && pCfg->outputType == 0) {
|
| memcpy(pOut->outDataSeq, pIn->inDataSeq, sizeof(short) * pCfg->stepSz);
|
| } else if (pCfg->inputType == 1 && pCfg->outputType == 1) {
|
| memcpy(pOut->outDataSeq, pIn->inDataSeq, sizeof(float) * pCfg->stepSz);
|
| } else if (pCfg->inputType == 0 && pCfg->outputType == 1) {
|
| for (idx = 0; idx < pCfg->stepSz; idx++) {
|
| ((float*)pOut->outDataSeq)[idx] = ((short*)pIn->inDataSeq)[idx];
|
| }
|
| } else {
|
| for (idx = 0; idx < pCfg->stepSz; idx++) {
|
| ((short*)pOut->outDataSeq)[idx] =
|
| (short)_FSCVRT_FLOAT2SHORT(((float*)pIn->inDataSeq)[idx]);
|
| }
|
| }
|
|
|
| return 0;
|
| }
|
|
|
|
|
| memset(stHdl->biquadInBuf, 0, sizeof(float) * stHdl->biquadInBufLen);
|
| if (pCfg->inputType == 0) {
|
| for (idx = 0; idx < pCfg->stepSz; idx++) {
|
| stHdl->biquadInBuf[idx * (stHdl->upSmplRate)] =
|
| ((float)shortSrcPtr[idx]) * stHdl->upSmplRate;
|
| }
|
| } else {
|
| for (idx = 0; idx < pCfg->stepSz; idx++) {
|
| stHdl->biquadInBuf[idx * (stHdl->upSmplRate)] =
|
| floatSrcPtr[idx] * stHdl->upSmplRate;
|
| }
|
| }
|
|
|
|
|
| memset(&bqdInData, 0, sizeof(Biquad_InputData));
|
| memset(&bqdOutData, 0, sizeof(Biquad_OutputData));
|
| bqdInData.samplesPtr = (const void*)(stHdl->biquadInBuf);
|
| bqdInData.sampleType = 1;
|
| bqdInData.nsamples = (size_t)(pCfg->stepSz * stHdl->upSmplRate);
|
| bqdOutData.outputBuff = (void*)&(stHdl->biquadOutBuf[stHdl->biquadOutBufCnt]);
|
| if (stHdl->biquadOutBufCnt + (pCfg->stepSz * stHdl->upSmplRate) >
|
| stHdl->biquadOutBufLen) {
|
| return -1;
|
| }
|
| if (AUP_Biquad_proc(stHdl->biquadSt, &bqdInData, &bqdOutData) < 0) {
|
| return -1;
|
| }
|
| stHdl->biquadOutBufCnt += (pCfg->stepSz * stHdl->upSmplRate);
|
|
|
|
|
| nOutSamples = stHdl->biquadOutBufCnt / stHdl->downSmplRate;
|
| if (pIn->outDataSeqLen < nOutSamples) {
|
| return -1;
|
| }
|
|
|
|
|
| pOut->nOutData = nOutSamples;
|
| pOut->outDataType = pCfg->outputType;
|
|
|
| shortTgtPtr = (short*)pOut->outDataSeq;
|
| floatTgtPtr = (float*)pOut->outDataSeq;
|
| jumpRate = stHdl->downSmplRate;
|
| if (pCfg->outputType == 0) {
|
| for (idx = (jumpRate - 1), tgtIdx = 0; idx < stHdl->biquadOutBufCnt;
|
| idx += jumpRate, tgtIdx++) {
|
| shortTgtPtr[tgtIdx] = _FSCVRT_FLOAT2SHORT(stHdl->biquadOutBuf[idx]);
|
| }
|
| } else {
|
| for (idx = (jumpRate - 1), tgtIdx = 0; idx < stHdl->biquadOutBufCnt;
|
| idx += jumpRate, tgtIdx++) {
|
| floatTgtPtr[tgtIdx] = stHdl->biquadOutBuf[idx];
|
| }
|
| }
|
| if (nOutSamples != tgtIdx) {
|
| return -1;
|
| }
|
|
|
|
|
| samplesTaken = nOutSamples * jumpRate;
|
| samplesLeft = stHdl->biquadOutBufCnt - samplesTaken;
|
| if (samplesLeft == 0) {
|
| stHdl->biquadOutBufCnt = 0;
|
| } else if (samplesLeft > 0) {
|
| stHdl->biquadOutBufCnt = samplesLeft;
|
| memmove(stHdl->biquadOutBuf, &(stHdl->biquadOutBuf[samplesTaken]),
|
| sizeof(float) * samplesLeft);
|
| } else {
|
| stHdl->biquadOutBufCnt = 0;
|
| return -1;
|
| }
|
|
|
| return 0;
|
| }
|
|
|