|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "biquad.h"
|
|
#include "pitch_est.h"
|
|
#include "pitch_est_st.h"
|
|
#include "fftw.h"
|
|
|
|
|
|
|
|
|
|
|
|
static int AUP_PE_checkStatCfg(PE_StaticCfg* pCfg) {
|
|
if (pCfg == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (pCfg->fftSz != 256 && pCfg->fftSz != 512 && pCfg->fftSz != 1024) {
|
|
return -1;
|
|
}
|
|
if (pCfg->fftSz > AUP_PE_MAX_FFTSIZE) {
|
|
return -1;
|
|
}
|
|
if (pCfg->anaWindowSz > pCfg->fftSz || pCfg->anaWindowSz < pCfg->hopSz) {
|
|
return -1;
|
|
}
|
|
if (pCfg->hopSz != 64 && pCfg->hopSz != 80 && pCfg->hopSz != 128 &&
|
|
pCfg->hopSz != 160 && pCfg->hopSz != 256 && pCfg->hopSz != 512) {
|
|
return -1;
|
|
}
|
|
|
|
if (pCfg->useLPCPreFiltering != 0) {
|
|
pCfg->useLPCPreFiltering = 1;
|
|
}
|
|
|
|
if (pCfg->procFs != 2000 && pCfg->procFs != 4000 && pCfg->procFs != 8000 &&
|
|
pCfg->procFs != 16000) {
|
|
pCfg->procFs = 4000;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int AUP_PE_checkDynamCfg(PE_DynamCfg* pCfg) {
|
|
if (pCfg == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
pCfg->voicedThr = AUP_PE_MIN(2.0f, AUP_PE_MAX(pCfg->voicedThr, -1.0f));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int AUP_PE_publishStaticCfg(PE_St* stHdl) {
|
|
const PE_StaticCfg* pStatCfg;
|
|
int idx, jdx;
|
|
int hopSz;
|
|
int excBufShiftLen;
|
|
|
|
if (stHdl == NULL) {
|
|
return -1;
|
|
}
|
|
pStatCfg = (const PE_StaticCfg*)(&(stHdl->stCfg));
|
|
hopSz = (int)pStatCfg->hopSz;
|
|
|
|
stHdl->nBins = ((int)(pStatCfg->fftSz >> 1)) + 1;
|
|
stHdl->procResampleRate = AUP_PE_FS / (int)pStatCfg->procFs;
|
|
stHdl->minPeriod = AUP_PE_MIN_PERIOD_16KHZ / stHdl->procResampleRate;
|
|
stHdl->maxPeriod = AUP_PE_MAX_PERIOD_16KHZ / stHdl->procResampleRate;
|
|
stHdl->difPeriod = stHdl->maxPeriod - stHdl->minPeriod;
|
|
stHdl->inputResampleBufLen = hopSz * 2;
|
|
stHdl->inputQLen = AUP_PE_MAX(AUP_PE_XCORR_TRAINING_OFFSET, hopSz) + hopSz;
|
|
|
|
excBufShiftLen = (int)ceilf(hopSz / (float)stHdl->procResampleRate);
|
|
stHdl->excBufLen = stHdl->maxPeriod + excBufShiftLen + 1;
|
|
|
|
stHdl->nFeat = (int)ceilf(AUP_PE_FEAT_TIME_WINDOW * AUP_PE_FS /
|
|
((float)hopSz * 1000.0f));
|
|
stHdl->nFeat = AUP_PE_MIN(stHdl->nFeat, AUP_PE_FEAT_MAX_NFRM);
|
|
stHdl->estDelay = 0;
|
|
|
|
|
|
for (idx = 0; idx < AUP_PE_NB_BANDS; idx++) {
|
|
for (jdx = 0; jdx < AUP_PE_NB_BANDS; jdx++) {
|
|
stHdl->dct_table[idx * AUP_PE_NB_BANDS + jdx] =
|
|
cosf((idx + .5f) * jdx * AUP_PE_PI / AUP_PE_NB_BANDS);
|
|
if (jdx == 0) stHdl->dct_table[idx * AUP_PE_NB_BANDS + jdx] *= sqrtf(.5f);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int AUP_PE_resetVariables(PE_St* stHdl) {
|
|
|
|
int idx;
|
|
|
|
memset(stHdl->dynamMemPtr, 0, stHdl->dynamMemSize);
|
|
|
|
stHdl->inputResampleBufIdx = 0;
|
|
|
|
for (idx = 0; idx < AUP_PE_LPC_ORDER; idx++) {
|
|
stHdl->lpc[idx] = 0;
|
|
stHdl->pitch_mem[idx] = 0;
|
|
}
|
|
stHdl->pitch_filt = 0;
|
|
|
|
memset(stHdl->tmpFeat, 0, sizeof(stHdl->tmpFeat));
|
|
|
|
stHdl->xCorrOffsetIdx = 0;
|
|
for (idx = 0; idx < (AUP_PE_FEAT_MAX_NFRM * 2); idx++) {
|
|
stHdl->frmWeight[idx] = 0;
|
|
stHdl->frmWeightNorm[idx] = 0;
|
|
}
|
|
|
|
stHdl->pitchMaxPathAll = 0;
|
|
stHdl->bestPeriodEst = 0;
|
|
|
|
stHdl->voiced = 0;
|
|
stHdl->pitchEstResult = 0;
|
|
|
|
if (stHdl->procResampleRate != 1) {
|
|
if (AUP_Biquad_init(stHdl->biquadIIRPtr) < 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int AUP_PE_dynamMemPrepare(PE_St* stHdl, void* memPtrExt,
|
|
size_t memSize) {
|
|
int idx;
|
|
|
|
int inputResampleBufMemSize = 0;
|
|
int inputQMemSize = 0;
|
|
int alignedInMemSize = 0;
|
|
int lpcFilterOutBufMemSize = 0;
|
|
int excBufMemSize = 0;
|
|
int excBufSqMemSize = 0;
|
|
int xCorrInstMemSize = 0;
|
|
int xCorrPerFeatMemSize = 0;
|
|
int xCorrPerFeatTmpMemSize = 0;
|
|
int pitchMaxPathRegPerRegMemSize = 0;
|
|
int pitchPrevPerFeatMemSize = 0;
|
|
int totalMemSize = 0;
|
|
char* memPtr = NULL;
|
|
|
|
inputResampleBufMemSize =
|
|
AUP_PE_ALIGN8(sizeof(float) * stHdl->inputResampleBufLen);
|
|
totalMemSize += inputResampleBufMemSize;
|
|
|
|
inputQMemSize = AUP_PE_ALIGN8(sizeof(float) * stHdl->inputQLen);
|
|
totalMemSize += inputQMemSize;
|
|
|
|
alignedInMemSize = AUP_PE_ALIGN8(sizeof(float) * stHdl->stCfg.hopSz);
|
|
totalMemSize += alignedInMemSize;
|
|
|
|
lpcFilterOutBufMemSize = AUP_PE_ALIGN8(sizeof(float) * stHdl->stCfg.hopSz);
|
|
totalMemSize += lpcFilterOutBufMemSize;
|
|
|
|
excBufMemSize = AUP_PE_ALIGN8(sizeof(float) * stHdl->excBufLen);
|
|
totalMemSize += excBufMemSize;
|
|
excBufSqMemSize = excBufMemSize;
|
|
totalMemSize += excBufSqMemSize;
|
|
|
|
xCorrInstMemSize = AUP_PE_ALIGN8(sizeof(float) * (stHdl->maxPeriod));
|
|
totalMemSize += xCorrInstMemSize;
|
|
|
|
xCorrPerFeatMemSize = AUP_PE_ALIGN8(sizeof(float) * (stHdl->maxPeriod + 1));
|
|
xCorrPerFeatTmpMemSize = xCorrPerFeatMemSize;
|
|
totalMemSize +=
|
|
(xCorrPerFeatMemSize + xCorrPerFeatTmpMemSize) * (stHdl->nFeat * 2);
|
|
|
|
pitchMaxPathRegPerRegMemSize =
|
|
AUP_PE_ALIGN8(sizeof(float) * (stHdl->maxPeriod));
|
|
totalMemSize += pitchMaxPathRegPerRegMemSize * 2;
|
|
|
|
pitchPrevPerFeatMemSize = AUP_PE_ALIGN8(sizeof(int) * (stHdl->maxPeriod));
|
|
totalMemSize += pitchPrevPerFeatMemSize * (stHdl->nFeat * 2);
|
|
|
|
|
|
|
|
if (memPtrExt == NULL) {
|
|
return (totalMemSize);
|
|
}
|
|
|
|
|
|
if ((size_t)totalMemSize > memSize) {
|
|
return -1;
|
|
}
|
|
|
|
memPtr = (char*)memPtrExt;
|
|
|
|
stHdl->inputResampleBuf = (float*)memPtr;
|
|
memPtr += inputResampleBufMemSize;
|
|
|
|
stHdl->inputQ = (float*)memPtr;
|
|
memPtr += inputQMemSize;
|
|
|
|
stHdl->alignedIn = (float*)memPtr;
|
|
memPtr += alignedInMemSize;
|
|
|
|
stHdl->lpcFilterOutBuf = (float*)memPtr;
|
|
memPtr += lpcFilterOutBufMemSize;
|
|
|
|
stHdl->excBuf = (float*)memPtr;
|
|
memPtr += excBufMemSize;
|
|
|
|
stHdl->excBufSq = (float*)memPtr;
|
|
memPtr += excBufSqMemSize;
|
|
|
|
stHdl->xCorrInst = (float*)memPtr;
|
|
memPtr += xCorrInstMemSize;
|
|
|
|
for (idx = 0; idx < AUP_PE_FEAT_MAX_NFRM * 2; idx++) {
|
|
stHdl->xCorr[idx] = NULL;
|
|
stHdl->xCorrTmp[idx] = NULL;
|
|
stHdl->pitchPrev[idx] = NULL;
|
|
}
|
|
for (idx = 0; idx < (stHdl->nFeat * 2); idx++) {
|
|
stHdl->xCorr[idx] = (float*)memPtr;
|
|
memPtr += xCorrPerFeatMemSize;
|
|
|
|
stHdl->xCorrTmp[idx] = (float*)memPtr;
|
|
memPtr += xCorrPerFeatTmpMemSize;
|
|
|
|
stHdl->pitchPrev[idx] = (int*)memPtr;
|
|
memPtr += pitchPrevPerFeatMemSize;
|
|
}
|
|
|
|
stHdl->pitchMaxPathReg[0] = (float*)memPtr;
|
|
memPtr += pitchMaxPathRegPerRegMemSize;
|
|
stHdl->pitchMaxPathReg[1] = (float*)memPtr;
|
|
memPtr += pitchMaxPathRegPerRegMemSize;
|
|
|
|
if (((int)(memPtr - (char*)memPtrExt)) > totalMemSize) {
|
|
return -1;
|
|
}
|
|
|
|
return (totalMemSize);
|
|
}
|
|
|
|
static void AUP_PE_computeBandEnergy(const float* inBinPower,
|
|
const int binPowNFFT,
|
|
float bandE[AUP_PE_NB_BANDS]) {
|
|
int i, j, bandSz;
|
|
|
|
float frac;
|
|
float indexConvRate = 1.0;
|
|
int indexOffset = 0, accIdx;
|
|
int nBins = (binPowNFFT >> 1) + 1;
|
|
|
|
indexConvRate = (float)binPowNFFT / AUP_PE_ASSUMED_FFT_4_BAND_ENG;
|
|
for (i = 0; i < AUP_PE_NB_BANDS; i++) {
|
|
bandE[i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < AUP_PE_NB_BANDS - 1; i++) {
|
|
bandSz = (int)roundf(
|
|
(AUP_PE_BAND_START_INDEX[i + 1] - AUP_PE_BAND_START_INDEX[i]) *
|
|
indexConvRate);
|
|
indexOffset = (int)roundf(AUP_PE_BAND_START_INDEX[i] *
|
|
indexConvRate);
|
|
|
|
for (j = 0; j < bandSz; j++) {
|
|
frac = (float)j / bandSz;
|
|
accIdx = AUP_PE_MIN(nBins - 1, (indexOffset + j));
|
|
|
|
bandE[i] += (1 - frac) * inBinPower[accIdx];
|
|
bandE[i + 1] += frac * inBinPower[accIdx];
|
|
}
|
|
}
|
|
bandE[0] *= 2;
|
|
bandE[AUP_PE_NB_BANDS - 1] *= 2;
|
|
|
|
return;
|
|
}
|
|
|
|
static void AUP_PE_dct(const float DctTable[AUP_PE_NB_BANDS * AUP_PE_NB_BANDS],
|
|
const float* in, float* out) {
|
|
int idx, j;
|
|
float sum;
|
|
float ratio = sqrtf(2.0f / AUP_PE_NB_BANDS);
|
|
for (idx = 0; idx < AUP_PE_NB_BANDS; idx++) {
|
|
sum = 0;
|
|
for (j = 0; j < AUP_PE_NB_BANDS; j++) {
|
|
sum += in[j] * DctTable[j * AUP_PE_NB_BANDS + idx];
|
|
}
|
|
out[idx] = sum * ratio;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void AUP_PE_idct(const float DctTable[AUP_PE_NB_BANDS * AUP_PE_NB_BANDS],
|
|
const float* in, float* out) {
|
|
int idx, j;
|
|
float sum;
|
|
float ratio = sqrtf(2.0f / AUP_PE_NB_BANDS);
|
|
for (idx = 0; idx < AUP_PE_NB_BANDS; idx++) {
|
|
sum = 0;
|
|
for (j = 0; j < AUP_PE_NB_BANDS; j++) {
|
|
sum += in[j] * DctTable[idx * AUP_PE_NB_BANDS + j];
|
|
}
|
|
out[idx] = sum * ratio;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void AUP_PE_interp_band_gain(const int nBins,
|
|
const float bandE[AUP_PE_NB_BANDS],
|
|
float* g) {
|
|
int idx, j, bandSz;
|
|
float indexConvRate = 1.0f;
|
|
int fftSz = (nBins - 1) * 2;
|
|
int indexOffset = 0, accIdx;
|
|
float frac;
|
|
|
|
indexConvRate = ((float)fftSz) / AUP_PE_ASSUMED_FFT_4_BAND_ENG;
|
|
memset(g, 0, sizeof(float) * nBins);
|
|
|
|
for (idx = 0; idx < AUP_PE_NB_BANDS - 1; idx++) {
|
|
bandSz = (int)roundf(
|
|
(AUP_PE_BAND_START_INDEX[idx + 1] - AUP_PE_BAND_START_INDEX[idx]) *
|
|
indexConvRate);
|
|
indexOffset = (int)roundf(AUP_PE_BAND_START_INDEX[idx] *
|
|
indexConvRate);
|
|
|
|
for (j = 0; j < bandSz; j++) {
|
|
frac = (float)j / bandSz;
|
|
accIdx = AUP_PE_MIN(nBins - 1, (indexOffset + j));
|
|
|
|
g[accIdx] = (1 - frac) * bandE[idx] + frac * bandE[idx + 1];
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
static float AUP_PE_celt_lpc(const float* ac, const int p, float* _lpc,
|
|
float* rc) {
|
|
int i, j;
|
|
float r;
|
|
float error = ac[0];
|
|
float* lpc = _lpc;
|
|
float rr;
|
|
float tmp1, tmp2;
|
|
|
|
|
|
memset(lpc, 0, sizeof(float) * p);
|
|
|
|
memset(rc, 0, sizeof(float) * p);
|
|
|
|
if (ac[0] != 0) {
|
|
for (i = 0; i < p; i++) {
|
|
|
|
rr = 0;
|
|
for (j = 0; j < i; j++) rr += lpc[j] * ac[i - j];
|
|
rr += ac[i + 1];
|
|
r = (-rr) / error;
|
|
rc[i] = r;
|
|
|
|
lpc[i] = r;
|
|
for (j = 0; j<(i + 1)>> 1; j++) {
|
|
tmp1 = lpc[j];
|
|
tmp2 = lpc[i - 1 - j];
|
|
lpc[j] = tmp1 + (r * tmp2);
|
|
lpc[i - 1 - j] = tmp2 + (r * tmp1);
|
|
}
|
|
|
|
error = error - (r * r * error);
|
|
|
|
|
|
if (error < .001f * ac[0]) break;
|
|
}
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
static float AUP_PE_lpc_from_bands(const int windowSz, const int nBins,
|
|
const float Ex[AUP_PE_NB_BANDS],
|
|
float lpc[AUP_PE_LPC_ORDER]) {
|
|
int i;
|
|
float e;
|
|
float ac[AUP_PE_LPC_ORDER + 1] = {0};
|
|
float rc[AUP_PE_LPC_ORDER] = {0};
|
|
float Xr[AUP_PE_MAX_NBINS] = {0};
|
|
float X_auto[AUP_PE_MAX_FFTSIZE + 4] = {0};
|
|
float x_auto[AUP_PE_MAX_FFTSIZE + 4] = {0};
|
|
float DC0_BIAS;
|
|
int fftSz = (nBins - 1) * 2;
|
|
|
|
AUP_PE_interp_band_gain(nBins, Ex, Xr);
|
|
Xr[nBins - 1] = 0;
|
|
|
|
|
|
X_auto[0] = Xr[0];
|
|
X_auto[1] = Xr[nBins - 1];
|
|
for (i = 1; i < (nBins - 1); i++) {
|
|
X_auto[i << 1] = Xr[i];
|
|
}
|
|
|
|
|
|
|
|
AUP_FFTW_InplaceTransf(0, fftSz, X_auto);
|
|
if (fftSz == 256) {
|
|
AUP_FFTW_c2r_256(X_auto, x_auto);
|
|
} else if (fftSz == 512) {
|
|
AUP_FFTW_c2r_512(X_auto, x_auto);
|
|
} else if (fftSz == 1024) {
|
|
AUP_FFTW_c2r_1024(X_auto, x_auto);
|
|
}
|
|
AUP_FFTW_RescaleIFFTOut(fftSz, x_auto);
|
|
|
|
for (i = 0; i < (AUP_PE_LPC_ORDER + 1);
|
|
i++) {
|
|
ac[i] = x_auto[i];
|
|
}
|
|
|
|
|
|
DC0_BIAS = (windowSz / 12 / 38.0f);
|
|
|
|
ac[0] += ac[0] * 1e-4f + DC0_BIAS;
|
|
|
|
for (i = 1; i < (AUP_PE_LPC_ORDER + 1); i++) {
|
|
ac[i] *= (1 - 6e-5f * i * i);
|
|
}
|
|
|
|
e = AUP_PE_celt_lpc(ac, AUP_PE_LPC_ORDER, lpc, rc);
|
|
|
|
return (e);
|
|
}
|
|
|
|
|
|
static float AUP_PE_lpcCompute(
|
|
const int windowSz, const int nBins,
|
|
const float DctTable[AUP_PE_NB_BANDS * AUP_PE_NB_BANDS],
|
|
const float* cepstrum, float* lpc) {
|
|
int i;
|
|
float Ex[AUP_PE_NB_BANDS] = {0};
|
|
float tmp[AUP_PE_NB_BANDS] = {0};
|
|
float errValue = 0;
|
|
|
|
|
|
memcpy(tmp, cepstrum, sizeof(float) * AUP_PE_NB_BANDS);
|
|
|
|
AUP_PE_idct(DctTable, tmp, Ex);
|
|
for (i = 0; i < AUP_PE_NB_BANDS; i++) {
|
|
Ex[i] = powf(10.f, Ex[i]) * AUP_PE_BAND_LPC_COMP[i];
|
|
}
|
|
|
|
errValue = AUP_PE_lpc_from_bands(windowSz, nBins, Ex, lpc);
|
|
|
|
return (errValue);
|
|
}
|
|
|
|
static void AUP_PE_xcorr_kernel(const float* x, const float* y, float sum[4],
|
|
int len) {
|
|
int j;
|
|
float y_0, y_1, y_2, y_3;
|
|
y_3 = 0;
|
|
y_0 = *y++;
|
|
y_1 = *y++;
|
|
y_2 = *y++;
|
|
for (j = 0; j < len - 3; j += 4) {
|
|
float tmp;
|
|
tmp = *x++;
|
|
y_3 = *y++;
|
|
sum[0] += tmp * y_0;
|
|
sum[1] += tmp * y_1;
|
|
sum[2] += tmp * y_2;
|
|
sum[3] += tmp * y_3;
|
|
tmp = *x++;
|
|
y_0 = *y++;
|
|
sum[0] += tmp * y_1;
|
|
sum[1] += tmp * y_2;
|
|
sum[2] += tmp * y_3;
|
|
sum[3] += tmp * y_0;
|
|
tmp = *x++;
|
|
y_1 = *y++;
|
|
sum[0] += tmp * y_2;
|
|
sum[1] += tmp * y_3;
|
|
sum[2] += tmp * y_0;
|
|
sum[3] += tmp * y_1;
|
|
tmp = *x++;
|
|
y_2 = *y++;
|
|
sum[0] += tmp * y_3;
|
|
sum[1] += tmp * y_0;
|
|
sum[2] += tmp * y_1;
|
|
sum[3] += tmp * y_2;
|
|
}
|
|
if (j++ < len) {
|
|
float tmp = *x++;
|
|
y_3 = *y++;
|
|
sum[0] += tmp * y_0;
|
|
sum[1] += tmp * y_1;
|
|
sum[2] += tmp * y_2;
|
|
sum[3] += tmp * y_3;
|
|
}
|
|
if (j++ < len) {
|
|
float tmp = *x++;
|
|
y_0 = *y++;
|
|
sum[0] += tmp * y_1;
|
|
sum[1] += tmp * y_2;
|
|
sum[2] += tmp * y_3;
|
|
sum[3] += tmp * y_0;
|
|
}
|
|
if (j < len) {
|
|
float tmp = *x++;
|
|
y_1 = *y++;
|
|
sum[0] += tmp * y_2;
|
|
sum[1] += tmp * y_3;
|
|
sum[2] += tmp * y_0;
|
|
sum[3] += tmp * y_1;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static float AUP_PE_celt_inner_prod(const float* x, const float* y, int N) {
|
|
int i;
|
|
float xy = 0;
|
|
for (i = 0; i < N; i++) {
|
|
xy += (x[i] * y[i]);
|
|
}
|
|
|
|
return (xy);
|
|
}
|
|
|
|
static void AUP_PE_MvingXCorr(int corrWindowLen, int corrShiftTimes,
|
|
const float* refIn, const float* yInToShift,
|
|
float* xcorr) {
|
|
|
|
int i;
|
|
float tmp;
|
|
|
|
for (i = 0; i < corrShiftTimes - 3; i += 4) {
|
|
float sum[4] = {0, 0, 0, 0};
|
|
AUP_PE_xcorr_kernel(refIn, yInToShift + i, sum, corrWindowLen);
|
|
xcorr[i] = sum[0];
|
|
xcorr[i + 1] = sum[1];
|
|
xcorr[i + 2] = sum[2];
|
|
xcorr[i + 3] = sum[3];
|
|
}
|
|
|
|
for (; i < corrShiftTimes; i++) {
|
|
tmp = AUP_PE_celt_inner_prod(refIn, yInToShift + i, corrWindowLen);
|
|
xcorr[i] = tmp;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int AUP_PE_create(void** stPtr) {
|
|
PE_St* tmpPtr;
|
|
|
|
if (stPtr == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
*stPtr = (void*)malloc(sizeof(PE_St));
|
|
if (*stPtr == NULL) {
|
|
return -1;
|
|
}
|
|
memset(*stPtr, 0, sizeof(PE_St));
|
|
|
|
tmpPtr = (PE_St*)(*stPtr);
|
|
|
|
tmpPtr->dynamMemPtr = NULL;
|
|
tmpPtr->dynamMemSize = 0;
|
|
|
|
if (AUP_Biquad_create(&(tmpPtr->biquadIIRPtr)) < 0 ||
|
|
tmpPtr->biquadIIRPtr == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
tmpPtr->stCfg.fftSz = 1024;
|
|
tmpPtr->stCfg.anaWindowSz = 768;
|
|
tmpPtr->stCfg.hopSz = 256;
|
|
tmpPtr->stCfg.useLPCPreFiltering = 1;
|
|
tmpPtr->stCfg.procFs = 4000;
|
|
|
|
tmpPtr->dynamCfg.voicedThr = 0.4f;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int AUP_PE_destroy(void** stPtr) {
|
|
PE_St* stHdl;
|
|
|
|
if (stPtr == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
stHdl = (PE_St*)(*stPtr);
|
|
if (stHdl == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (stHdl->dynamMemPtr != NULL) {
|
|
free(stHdl->dynamMemPtr);
|
|
}
|
|
stHdl->dynamMemPtr = NULL;
|
|
|
|
if (stHdl->biquadIIRPtr != NULL) {
|
|
AUP_Biquad_destroy(&(stHdl->biquadIIRPtr));
|
|
}
|
|
|
|
free(stHdl);
|
|
(*stPtr) = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int AUP_PE_memAllocate(void* stPtr, const PE_StaticCfg* pCfg) {
|
|
PE_St* stHdl = NULL;
|
|
PE_StaticCfg localStCfg;
|
|
Biquad_StaticCfg biquadStCfg = {0, 0, 0, {0}, {0}, 0};
|
|
int idx;
|
|
int totalMemSize = 0;
|
|
|
|
if (stPtr == NULL || pCfg == NULL) {
|
|
return -1;
|
|
}
|
|
stHdl = (PE_St*)(stPtr);
|
|
|
|
memcpy(&localStCfg, pCfg, sizeof(PE_StaticCfg));
|
|
if (AUP_PE_checkStatCfg(&localStCfg) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
memcpy(&(stHdl->stCfg), &localStCfg, sizeof(PE_StaticCfg));
|
|
|
|
|
|
if (AUP_PE_publishStaticCfg(stHdl) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
|
|
totalMemSize = AUP_PE_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 = malloc(totalMemSize);
|
|
if (stHdl->dynamMemPtr == NULL) {
|
|
return -1;
|
|
}
|
|
stHdl->dynamMemSize = totalMemSize;
|
|
}
|
|
memset(stHdl->dynamMemPtr, 0, stHdl->dynamMemSize);
|
|
|
|
|
|
if (AUP_PE_dynamMemPrepare(stHdl, stHdl->dynamMemPtr, stHdl->dynamMemSize) <
|
|
0) {
|
|
return -1;
|
|
}
|
|
|
|
if (AUP_Biquad_getStaticCfg(stHdl->biquadIIRPtr, &biquadStCfg) < 0) {
|
|
return -1;
|
|
}
|
|
biquadStCfg.maxNSample = stHdl->stCfg.hopSz;
|
|
if (stHdl->procResampleRate != 1) {
|
|
biquadStCfg.nsect = AUP_PE_LOWPSS_NSEC;
|
|
if (stHdl->stCfg.procFs == 2000) {
|
|
biquadStCfg.G = AUP_PE_G_2KHZ;
|
|
for (idx = 0; idx < biquadStCfg.nsect; idx++) {
|
|
biquadStCfg.B[idx] = AUP_PE_B_2KHZ[idx];
|
|
biquadStCfg.A[idx] = AUP_PE_A_2KHZ[idx];
|
|
}
|
|
} else if (stHdl->stCfg.procFs == 4000) {
|
|
biquadStCfg.G = AUP_PE_G_4KHZ;
|
|
for (idx = 0; idx < biquadStCfg.nsect; idx++) {
|
|
biquadStCfg.B[idx] = AUP_PE_B_4KHZ[idx];
|
|
biquadStCfg.A[idx] = AUP_PE_A_4KHZ[idx];
|
|
}
|
|
} else if (stHdl->stCfg.procFs == 8000) {
|
|
biquadStCfg.G = AUP_PE_G_8KHZ;
|
|
for (idx = 0; idx < biquadStCfg.nsect; idx++) {
|
|
biquadStCfg.B[idx] = AUP_PE_B_8KHZ[idx];
|
|
biquadStCfg.A[idx] = AUP_PE_A_8KHZ[idx];
|
|
}
|
|
}
|
|
} else {
|
|
biquadStCfg.nsect = -1;
|
|
}
|
|
if (AUP_Biquad_memAllocate(stHdl->biquadIIRPtr, &biquadStCfg) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int AUP_PE_init(void* stPtr) {
|
|
PE_St* stHdl;
|
|
|
|
if (stPtr == NULL) {
|
|
return -1;
|
|
}
|
|
stHdl = (PE_St*)(stPtr);
|
|
|
|
if (AUP_PE_resetVariables(stHdl) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int AUP_PE_setDynamCfg(void* stPtr, const PE_DynamCfg* pCfg) {
|
|
PE_St* stHdl;
|
|
PE_DynamCfg localCfg;
|
|
|
|
if (stPtr == NULL || pCfg == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
memcpy(&localCfg, pCfg, sizeof(PE_DynamCfg));
|
|
if (AUP_PE_checkDynamCfg(&localCfg) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
stHdl = (PE_St*)(stPtr);
|
|
|
|
memcpy(&(stHdl->dynamCfg), &localCfg, sizeof(PE_DynamCfg));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int AUP_PE_getStaticCfg(const void* stPtr, PE_StaticCfg* pCfg) {
|
|
const PE_St* stHdl;
|
|
|
|
if (stPtr == NULL || pCfg == NULL) {
|
|
return -1;
|
|
}
|
|
stHdl = (const PE_St*)(stPtr);
|
|
|
|
memcpy(pCfg, &(stHdl->stCfg), sizeof(PE_StaticCfg));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int AUP_PE_getDynamCfg(const void* stPtr, PE_DynamCfg* pCfg) {
|
|
const PE_St* stHdl;
|
|
|
|
if (stPtr == NULL || pCfg == NULL) {
|
|
return -1;
|
|
}
|
|
stHdl = (const PE_St*)(stPtr);
|
|
|
|
memcpy(pCfg, &(stHdl->dynamCfg), sizeof(PE_DynamCfg));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int AUP_PE_getAlgDelay(const void* stPtr, int* delayInFrms) {
|
|
const PE_St* stHdl;
|
|
|
|
if (stPtr == NULL || delayInFrms == NULL) {
|
|
return -1;
|
|
}
|
|
stHdl = (const PE_St*)(stPtr);
|
|
|
|
*delayInFrms = stHdl->estDelay;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int AUP_PE_proc(void* stPtr, const PE_InputData* pIn, PE_OutputData* pOut) {
|
|
PE_St* stHdl = NULL;
|
|
Biquad_InputData bqInData = {0, 0, 0};
|
|
Biquad_OutputData bqOutData = {0};
|
|
int nBins, fftSz, hopSz, idx, jdx, sub, offset, tmpInt, xcorrAccIdx;
|
|
float bandPow[AUP_PE_NB_BANDS] = {0};
|
|
float Ly[AUP_PE_NB_BANDS] = {0};
|
|
float follow, lpcErr, logMax;
|
|
float energy0, slidWinSum, tmpDenom = 0, maxTrackReg = 0, maxPathReg = 0;
|
|
float frmCorr = 0;
|
|
const float* startPtr = NULL;
|
|
const float* refSeqPtr = NULL;
|
|
const float* mvSeqPtr = NULL;
|
|
int CORR_HALF_HOPSZ, SIDXT, XCIdx;
|
|
int bestPeriodEstLocal[AUP_PE_TOTAL_NFEAT * 2] = {0};
|
|
float w, sx = 0, sxx = 0, sxy = 0, sy = 0, sw = 0;
|
|
float bestA = 0, bestB = 0;
|
|
float estimatedPeriod;
|
|
|
|
if (stPtr == NULL || pIn == NULL || pIn->timeSignal == NULL) {
|
|
return -1;
|
|
}
|
|
stHdl = (PE_St*)(stPtr);
|
|
|
|
nBins = (int)(stHdl->nBins);
|
|
fftSz = (int)(stHdl->stCfg.fftSz);
|
|
hopSz = (int)(stHdl->stCfg.hopSz);
|
|
CORR_HALF_HOPSZ = hopSz / (stHdl->procResampleRate * 2);
|
|
|
|
if (pIn->hopSz != (int)stHdl->stCfg.hopSz) {
|
|
return -1;
|
|
}
|
|
|
|
if (stHdl->stCfg.useLPCPreFiltering == 1 && pIn->inBinPow == NULL) {
|
|
return -1;
|
|
}
|
|
if (stHdl->stCfg.useLPCPreFiltering == 1 && pIn->nBins != stHdl->nBins) {
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stHdl->stCfg.useLPCPreFiltering == 1) {
|
|
|
|
AUP_PE_computeBandEnergy(pIn->inBinPow, fftSz, bandPow);
|
|
logMax = -2.0f;
|
|
follow = -2.0f;
|
|
for (idx = 0; idx < AUP_PE_NB_BANDS; idx++) {
|
|
Ly[idx] = log10f(1e-2f + bandPow[idx]);
|
|
Ly[idx] = AUP_PE_MAX(logMax - 8.0f, AUP_PE_MAX(follow - 2.5f, Ly[idx]));
|
|
logMax = AUP_PE_MAX(logMax, Ly[idx]);
|
|
|
|
follow = AUP_PE_MAX(follow - 2.5f, Ly[idx]);
|
|
}
|
|
|
|
AUP_PE_dct(stHdl->dct_table, Ly, stHdl->tmpFeat);
|
|
|
|
lpcErr = AUP_PE_lpcCompute((int)(stHdl->stCfg.anaWindowSz), nBins,
|
|
stHdl->dct_table, stHdl->tmpFeat, stHdl->lpc);
|
|
|
|
memmove(stHdl->inputQ, stHdl->inputQ + hopSz,
|
|
sizeof(float) * (stHdl->inputQLen - hopSz));
|
|
memcpy(&(stHdl->inputQ[stHdl->inputQLen - hopSz]), pIn->timeSignal,
|
|
sizeof(float) * hopSz);
|
|
|
|
offset =
|
|
AUP_PE_MAX(0, stHdl->inputQLen - hopSz - AUP_PE_XCORR_TRAINING_OFFSET);
|
|
memcpy(stHdl->alignedIn, stHdl->inputQ + offset, sizeof(float) * hopSz);
|
|
|
|
for (idx = 0; idx < hopSz; idx++) {
|
|
|
|
slidWinSum = stHdl->alignedIn[idx];
|
|
for (jdx = 0; jdx < AUP_PE_LPC_ORDER; jdx++) {
|
|
slidWinSum += stHdl->lpc[jdx] * stHdl->pitch_mem[jdx];
|
|
}
|
|
|
|
memmove(stHdl->pitch_mem + 1, stHdl->pitch_mem,
|
|
sizeof(float) * (AUP_PE_LPC_ORDER - 1));
|
|
stHdl->pitch_mem[0] =
|
|
stHdl->alignedIn[idx];
|
|
|
|
|
|
stHdl->lpcFilterOutBuf[idx] = slidWinSum + 0.7f * stHdl->pitch_filt;
|
|
stHdl->pitch_filt = slidWinSum;
|
|
}
|
|
|
|
if (stHdl->procResampleRate != 1) {
|
|
|
|
bqInData.nsamples = (size_t)hopSz;
|
|
bqInData.samplesPtr = (const void*)(stHdl->lpcFilterOutBuf);
|
|
bqInData.sampleType = 1;
|
|
bqOutData.outputBuff =
|
|
(void*)(stHdl->inputResampleBuf + stHdl->inputResampleBufIdx);
|
|
if (AUP_Biquad_proc(stHdl->biquadIIRPtr, &bqInData, &bqOutData) < 0) {
|
|
return -1;
|
|
}
|
|
tmpInt = stHdl->inputResampleBufIdx;
|
|
for (idx = tmpInt; idx < (tmpInt + hopSz);
|
|
idx += stHdl->procResampleRate) {
|
|
stHdl->inputResampleBuf[stHdl->inputResampleBufIdx] =
|
|
stHdl->inputResampleBuf[idx];
|
|
stHdl->inputResampleBufIdx++;
|
|
}
|
|
|
|
tmpInt = stHdl->inputResampleBufIdx;
|
|
memmove(stHdl->excBuf, stHdl->excBuf + tmpInt,
|
|
sizeof(float) * (stHdl->excBufLen - tmpInt));
|
|
memcpy(stHdl->excBuf + (stHdl->excBufLen - tmpInt),
|
|
stHdl->inputResampleBuf, sizeof(float) * tmpInt);
|
|
stHdl->inputResampleBufIdx = 0;
|
|
} else {
|
|
tmpInt = hopSz;
|
|
memmove(stHdl->excBuf, stHdl->excBuf + tmpInt,
|
|
sizeof(float) * (stHdl->excBufLen - tmpInt));
|
|
memcpy(stHdl->excBuf + (stHdl->excBufLen - tmpInt),
|
|
stHdl->lpcFilterOutBuf, sizeof(float) * tmpInt);
|
|
}
|
|
|
|
} else {
|
|
if (stHdl->procResampleRate != 1) {
|
|
|
|
bqInData.nsamples = (size_t)hopSz;
|
|
bqInData.samplesPtr = (const void*)(pIn->timeSignal);
|
|
bqInData.sampleType = 1;
|
|
bqOutData.outputBuff =
|
|
(void*)(stHdl->inputResampleBuf + stHdl->inputResampleBufIdx);
|
|
if (AUP_Biquad_proc(stHdl->biquadIIRPtr, &bqInData, &bqOutData) < 0) {
|
|
return -1;
|
|
}
|
|
tmpInt = stHdl->inputResampleBufIdx;
|
|
for (idx = tmpInt; idx < (tmpInt + hopSz);
|
|
idx += stHdl->procResampleRate) {
|
|
stHdl->inputResampleBuf[stHdl->inputResampleBufIdx] =
|
|
stHdl->inputResampleBuf[idx];
|
|
stHdl->inputResampleBufIdx++;
|
|
}
|
|
|
|
|
|
tmpInt = stHdl->inputResampleBufIdx;
|
|
memmove(stHdl->excBuf, stHdl->excBuf + tmpInt,
|
|
sizeof(float) * (stHdl->excBufLen - tmpInt));
|
|
memcpy(stHdl->excBuf + (stHdl->excBufLen - tmpInt),
|
|
stHdl->inputResampleBuf, sizeof(float) * tmpInt);
|
|
stHdl->inputResampleBufIdx = 0;
|
|
} else {
|
|
tmpInt = hopSz;
|
|
memmove(stHdl->excBuf, stHdl->excBuf + tmpInt,
|
|
sizeof(float) * (stHdl->excBufLen - tmpInt));
|
|
memcpy(stHdl->excBuf + (stHdl->excBufLen - tmpInt), pIn->timeSignal,
|
|
sizeof(float) * tmpInt);
|
|
}
|
|
}
|
|
|
|
|
|
for (idx = 0; idx < stHdl->excBufLen; idx++) {
|
|
stHdl->excBufSq[idx] = (stHdl->excBuf[idx] * stHdl->excBuf[idx]);
|
|
}
|
|
|
|
|
|
for (idx = 0; idx < (stHdl->nFeat - 1); idx++) {
|
|
stHdl->frmWeight[2 * (idx)] = stHdl->frmWeight[2 * (idx + 1)];
|
|
stHdl->frmWeight[2 * (idx) + 1] = stHdl->frmWeight[2 * (idx + 1) + 1];
|
|
}
|
|
|
|
|
|
for (sub = 0; sub < 2; sub++) {
|
|
xcorrAccIdx = 2 * (stHdl->xCorrOffsetIdx) + sub;
|
|
offset = sub * CORR_HALF_HOPSZ;
|
|
|
|
refSeqPtr = stHdl->excBuf + (stHdl->maxPeriod + offset);
|
|
mvSeqPtr = stHdl->excBuf + offset;
|
|
AUP_PE_MvingXCorr(CORR_HALF_HOPSZ, stHdl->maxPeriod, refSeqPtr, mvSeqPtr,
|
|
stHdl->xCorrInst);
|
|
|
|
energy0 = 0;
|
|
startPtr = stHdl->excBufSq + (stHdl->maxPeriod + offset);
|
|
for (idx = 0; idx < CORR_HALF_HOPSZ; idx++) {
|
|
energy0 += startPtr[idx];
|
|
}
|
|
stHdl->frmWeight[2 * (stHdl->nFeat - 1) + sub] = energy0;
|
|
|
|
slidWinSum = 0;
|
|
startPtr = stHdl->excBufSq + offset;
|
|
for (idx = 0; idx < CORR_HALF_HOPSZ; idx++) {
|
|
slidWinSum += startPtr[idx];
|
|
}
|
|
|
|
|
|
tmpDenom = AUP_PE_MAX(1e-12f, slidWinSum + (1 + energy0));
|
|
stHdl->xCorr[xcorrAccIdx][0] = 2 * stHdl->xCorrInst[0] / tmpDenom;
|
|
|
|
for (idx = 1; idx < stHdl->maxPeriod; idx++) {
|
|
|
|
slidWinSum =
|
|
AUP_PE_MAX(0, slidWinSum - stHdl->excBufSq[offset + idx - 1]);
|
|
slidWinSum += stHdl->excBufSq[offset + idx + CORR_HALF_HOPSZ - 1];
|
|
|
|
tmpDenom = AUP_PE_MAX(1e-12f, slidWinSum + (1 + energy0));
|
|
stHdl->xCorr[xcorrAccIdx][idx] = 2 * stHdl->xCorrInst[idx] / tmpDenom;
|
|
}
|
|
|
|
|
|
for (idx = 0; idx < (stHdl->maxPeriod - 2 * stHdl->minPeriod); idx++) {
|
|
tmpDenom = stHdl->xCorr[xcorrAccIdx][(stHdl->maxPeriod + idx) / 2];
|
|
tmpDenom = AUP_PE_MAX(
|
|
tmpDenom,
|
|
stHdl->xCorr[xcorrAccIdx][(stHdl->maxPeriod + idx + 2) / 2]);
|
|
tmpDenom = AUP_PE_MAX(
|
|
tmpDenom,
|
|
stHdl->xCorr[xcorrAccIdx][(stHdl->maxPeriod + idx - 1) / 2]);
|
|
|
|
if (stHdl->xCorr[xcorrAccIdx][idx] < (tmpDenom * 1.1f))
|
|
stHdl->xCorr[xcorrAccIdx][idx] *= 0.8f;
|
|
}
|
|
}
|
|
stHdl->xCorrOffsetIdx++;
|
|
if (stHdl->xCorrOffsetIdx >= stHdl->nFeat) {
|
|
stHdl->xCorrOffsetIdx = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
slidWinSum = 1e-15f;
|
|
for (sub = 0; sub < (stHdl->nFeat * 2); sub++) {
|
|
slidWinSum += stHdl->frmWeight[sub];
|
|
}
|
|
for (sub = 0; sub < (stHdl->nFeat * 2); sub++) {
|
|
stHdl->frmWeightNorm[sub] =
|
|
stHdl->frmWeight[sub] * ((stHdl->nFeat * 2) / slidWinSum);
|
|
}
|
|
|
|
|
|
|
|
for (idx = 0; idx < (stHdl->nFeat * 2); idx++) {
|
|
memcpy(stHdl->xCorrTmp[idx], stHdl->xCorr[idx],
|
|
sizeof(float) * (stHdl->maxPeriod + 1));
|
|
}
|
|
|
|
|
|
for (sub = 0; sub < (stHdl->nFeat * 2 - 2); sub += 2) {
|
|
memcpy(stHdl->pitchPrev[sub], stHdl->pitchPrev[sub + 2],
|
|
sizeof(int) * stHdl->maxPeriod);
|
|
memcpy(stHdl->pitchPrev[sub + 1], stHdl->pitchPrev[sub + 3],
|
|
sizeof(int) * stHdl->maxPeriod);
|
|
}
|
|
for (sub = (stHdl->nFeat * 2 - 2); sub < (stHdl->nFeat * 2); sub++) {
|
|
XCIdx = sub + (stHdl->xCorrOffsetIdx * 2);
|
|
if (XCIdx >= (2 * stHdl->nFeat)) {
|
|
XCIdx -= (2 * stHdl->nFeat);
|
|
}
|
|
|
|
for (idx = 0; idx < stHdl->difPeriod; idx++) {
|
|
maxTrackReg = stHdl->pitchMaxPathAll - 1e10f;
|
|
stHdl->pitchPrev[sub][idx] = stHdl->bestPeriodEst;
|
|
|
|
SIDXT = AUP_PE_MIN(0, 4 - idx);
|
|
for (jdx = SIDXT; jdx <= 4 && (idx + jdx) < stHdl->difPeriod; jdx++) {
|
|
tmpDenom = stHdl->pitchMaxPathReg[0][idx + jdx] -
|
|
(AUP_PE_PITCHMAXPATH_W * abs(jdx) * abs(jdx));
|
|
if (tmpDenom > maxTrackReg) {
|
|
maxTrackReg = tmpDenom;
|
|
stHdl->pitchPrev[sub][idx] = idx + jdx;
|
|
}
|
|
}
|
|
|
|
|
|
stHdl->pitchMaxPathReg[1][idx] =
|
|
maxTrackReg + stHdl->frmWeightNorm[sub] * stHdl->xCorrTmp[XCIdx][idx];
|
|
}
|
|
|
|
maxPathReg = -1e15f;
|
|
tmpInt = 0;
|
|
for (idx = 0; idx < stHdl->difPeriod; idx++) {
|
|
if (stHdl->pitchMaxPathReg[1][idx] > maxPathReg) {
|
|
maxPathReg = stHdl->pitchMaxPathReg[1][idx];
|
|
tmpInt = idx;
|
|
}
|
|
}
|
|
stHdl->pitchMaxPathAll = maxPathReg;
|
|
stHdl->bestPeriodEst = tmpInt;
|
|
|
|
memcpy(&(stHdl->pitchMaxPathReg[0][0]), &(stHdl->pitchMaxPathReg[1][0]),
|
|
sizeof(float) * stHdl->maxPeriod);
|
|
for (idx = 0; idx < stHdl->difPeriod; idx++) {
|
|
stHdl->pitchMaxPathReg[0][idx] -= maxPathReg;
|
|
}
|
|
}
|
|
|
|
tmpInt = stHdl->bestPeriodEst;
|
|
frmCorr = 0;
|
|
|
|
for (sub = (stHdl->nFeat * 2) - 1; sub >= 0; sub--) {
|
|
bestPeriodEstLocal[sub] = stHdl->maxPeriod - tmpInt;
|
|
|
|
XCIdx = sub + (stHdl->xCorrOffsetIdx * 2);
|
|
if (XCIdx >= (2 * stHdl->nFeat)) {
|
|
XCIdx -= (2 * stHdl->nFeat);
|
|
}
|
|
frmCorr += stHdl->frmWeightNorm[sub] * stHdl->xCorrTmp[XCIdx][tmpInt];
|
|
tmpInt = stHdl->pitchPrev[sub][tmpInt];
|
|
}
|
|
frmCorr = AUP_PE_MAX(0, frmCorr / (float)(stHdl->nFeat * 2));
|
|
stHdl->voiced = (frmCorr >= stHdl->dynamCfg.voicedThr) ? 1 : 0;
|
|
|
|
for (sub = 0; sub < (stHdl->nFeat * 2); sub++) {
|
|
w = stHdl->frmWeightNorm[sub];
|
|
sw += w;
|
|
sx += w * sub;
|
|
sxx += w * sub * sub;
|
|
sxy += w * sub * bestPeriodEstLocal[sub];
|
|
sy += w * bestPeriodEstLocal[sub];
|
|
}
|
|
|
|
|
|
|
|
tmpDenom = (sw * sxx - sx * sx);
|
|
if (tmpDenom == 0)
|
|
bestA = (sw * sxy - sx * sy) / 1e-15f;
|
|
else
|
|
bestA = (sw * sxy - sx * sy) / tmpDenom;
|
|
|
|
if (stHdl->voiced == 1) {
|
|
tmpDenom = (sy / sw) / (4 * 2 * stHdl->nFeat);
|
|
bestA = AUP_PE_MIN(tmpDenom, AUP_PE_MAX(-tmpDenom, bestA));
|
|
} else {
|
|
bestA = 0;
|
|
}
|
|
bestB = (sy - bestA * sx) / sw;
|
|
estimatedPeriod = bestB + 5.5f * bestA;
|
|
|
|
if (stHdl->voiced == 1) {
|
|
stHdl->pitchEstResult =
|
|
((float)(stHdl->stCfg.procFs)) / AUP_PE_MAX(1.0f, estimatedPeriod);
|
|
} else {
|
|
stHdl->pitchEstResult = 0;
|
|
}
|
|
|
|
if (pOut != NULL) {
|
|
pOut->pitchFreq = stHdl->pitchEstResult;
|
|
pOut->voiced = stHdl->voiced;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|