1205 lines
47 KiB
C
1205 lines
47 KiB
C
|
/*
|
||
|
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||
|
*
|
||
|
* Use of this source code is governed by a BSD-style license
|
||
|
* that can be found in the LICENSE file in the root of the source
|
||
|
* tree. An additional intellectual property rights grant can be found
|
||
|
* in the file PATENTS. All contributing project authors may
|
||
|
* be found in the AUTHORS file in the root of the source tree.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* This is the function to expand from the speech history, to produce concealment data or
|
||
|
* increasing delay.
|
||
|
*/
|
||
|
|
||
|
#include "dsp.h"
|
||
|
|
||
|
#include "signal_processing_library.h"
|
||
|
|
||
|
#include "dsp_helpfunctions.h"
|
||
|
#include "neteq_error_codes.h"
|
||
|
|
||
|
#define CHECK_NO_OF_CORRMAX 3
|
||
|
#define DISTLEN 20
|
||
|
#define LPCANALASYSLEN 160
|
||
|
|
||
|
/* Scratch usage:
|
||
|
|
||
|
Type Name size startpos endpos
|
||
|
(First part of first expand)
|
||
|
WebRtc_Word16 pw16_bestCorrIndex 3 0 2
|
||
|
WebRtc_Word16 pw16_bestCorr 3 3 5
|
||
|
WebRtc_Word16 pw16_bestDistIndex 3 6 8
|
||
|
WebRtc_Word16 pw16_bestDist 3 9 11
|
||
|
WebRtc_Word16 pw16_corrVec 102*fs/8000 12 11+102*fs/8000
|
||
|
func WebRtcNetEQ_Correlator 232 12+102*fs/8000 243+102*fs/8000
|
||
|
|
||
|
(Second part of first expand)
|
||
|
WebRtc_Word32 pw32_corr2 99*fs/8000+1 0 99*fs/8000
|
||
|
WebRtc_Word32 pw32_autoCorr 2*7 0 13
|
||
|
WebRtc_Word16 pw16_rc 6 14 19
|
||
|
|
||
|
Signal combination:
|
||
|
WebRtc_Word16 pw16_randVec 30+120*fs/8000 0 29+120*fs/8000
|
||
|
WebRtc_Word16 pw16_scaledRandVec 125*fs/8000 30+120*fs/8000 29+245*fs/8000
|
||
|
WebRtc_Word16 pw16_unvoicedVecSpace 10+125*fs/8000 30+245*fs/8000 39+370*fs/8000
|
||
|
|
||
|
Total: 40+370*fs/8000 (size depends on UNVOICED_LPC_ORDER and BGN_LPC_ORDER)
|
||
|
*/
|
||
|
|
||
|
#if ((BGN_LPC_ORDER > 10) || (UNVOICED_LPC_ORDER > 10)) && (defined SCRATCH)
|
||
|
#error BGN_LPC_ORDER and/or BGN_LPC_ORDER are too large for current scratch memory allocation
|
||
|
#endif
|
||
|
|
||
|
#define SCRATCH_PW16_BEST_CORR_INDEX 0
|
||
|
#define SCRATCH_PW16_BEST_CORR 3
|
||
|
#define SCRATCH_PW16_BEST_DIST_INDEX 6
|
||
|
#define SCRATCH_PW16_BEST_DIST 9
|
||
|
#define SCRATCH_PW16_CORR_VEC 12
|
||
|
#define SCRATCH_PW16_CORR2 0
|
||
|
#define SCRATCH_PW32_AUTO_CORR 0
|
||
|
#define SCRATCH_PW16_RC 14
|
||
|
#define SCRATCH_PW16_RAND_VEC 0
|
||
|
|
||
|
#if (defined(NETEQ_48KHZ_WIDEBAND))
|
||
|
#define SCRATCH_NETEQDSP_CORRELATOR 624
|
||
|
#define SCRATCH_PW16_SCALED_RAND_VEC 750
|
||
|
#define SCRATCH_PW16_UNVOICED_VEC_SPACE 1500
|
||
|
#elif (defined(NETEQ_32KHZ_WIDEBAND))
|
||
|
#define SCRATCH_NETEQDSP_CORRELATOR 420
|
||
|
#define SCRATCH_PW16_SCALED_RAND_VEC 510
|
||
|
#define SCRATCH_PW16_UNVOICED_VEC_SPACE 1010
|
||
|
#elif (defined(NETEQ_WIDEBAND))
|
||
|
#define SCRATCH_NETEQDSP_CORRELATOR 216
|
||
|
#define SCRATCH_PW16_SCALED_RAND_VEC 270
|
||
|
#define SCRATCH_PW16_UNVOICED_VEC_SPACE 520
|
||
|
#else /* NB */
|
||
|
#define SCRATCH_NETEQDSP_CORRELATOR 114
|
||
|
#define SCRATCH_PW16_SCALED_RAND_VEC 150
|
||
|
#define SCRATCH_PW16_UNVOICED_VEC_SPACE 275
|
||
|
#endif
|
||
|
|
||
|
/****************************************************************************
|
||
|
* WebRtcNetEQ_Expand(...)
|
||
|
*
|
||
|
* This function produces one "chunk" of expansion data (PLC audio). The
|
||
|
* length of the produced audio depends on the speech history.
|
||
|
*
|
||
|
* Input:
|
||
|
* - inst : DSP instance
|
||
|
* - scratchPtr : Pointer to scratch vector
|
||
|
* - outdata : Pointer to a memory space where the output data
|
||
|
* should be stored
|
||
|
* - BGNonly : If non-zero, "expand" will only produce background noise.
|
||
|
* - pw16_len : Desired number of samples (only for BGN mode).
|
||
|
*
|
||
|
* Output:
|
||
|
* - inst : Updated instance
|
||
|
* - pw16_len : Number of samples that were output from NetEq
|
||
|
*
|
||
|
* Return value : 0 - Ok
|
||
|
* <0 - Error
|
||
|
*/
|
||
|
|
||
|
int WebRtcNetEQ_Expand(DSPInst_t *inst,
|
||
|
#ifdef SCRATCH
|
||
|
WebRtc_Word16 *pw16_scratchPtr,
|
||
|
#endif
|
||
|
WebRtc_Word16 *pw16_outData, WebRtc_Word16 *pw16_len,
|
||
|
WebRtc_Word16 BGNonly)
|
||
|
{
|
||
|
|
||
|
WebRtc_Word16 fs_mult;
|
||
|
ExpandInst_t *ExpandState = &(inst->ExpandInst);
|
||
|
BGNInst_t *BGNState = &(inst->BGNInst);
|
||
|
int i;
|
||
|
#ifdef SCRATCH
|
||
|
WebRtc_Word16 *pw16_randVec = pw16_scratchPtr + SCRATCH_PW16_RAND_VEC;
|
||
|
WebRtc_Word16 *pw16_scaledRandVec = pw16_scratchPtr + SCRATCH_PW16_SCALED_RAND_VEC;
|
||
|
WebRtc_Word16 *pw16_unvoicedVecSpace = pw16_scratchPtr + SCRATCH_PW16_UNVOICED_VEC_SPACE;
|
||
|
#else
|
||
|
WebRtc_Word16 pw16_randVec[FSMULT * 120 + 30]; /* 125 for NB and 250 for WB */
|
||
|
WebRtc_Word16 pw16_scaledRandVec[FSMULT * 125]; /* 125 for NB and 250 for WB */
|
||
|
WebRtc_Word16 pw16_unvoicedVecSpace[BGN_LPC_ORDER + FSMULT * 125];
|
||
|
#endif
|
||
|
/* 125 for NB and 250 for WB etc. Reuse pw16_outData[] for this vector */
|
||
|
WebRtc_Word16 *pw16_voicedVecStorage = pw16_outData;
|
||
|
WebRtc_Word16 *pw16_voicedVec = &pw16_voicedVecStorage[ExpandState->w16_overlap];
|
||
|
WebRtc_Word16 *pw16_unvoicedVec = pw16_unvoicedVecSpace + UNVOICED_LPC_ORDER;
|
||
|
WebRtc_Word16 *pw16_cngVec = pw16_unvoicedVecSpace + BGN_LPC_ORDER;
|
||
|
WebRtc_Word16 w16_expVecsLen, w16_lag = 0, w16_expVecPos;
|
||
|
WebRtc_Word16 w16_randLen;
|
||
|
WebRtc_Word16 w16_vfractionChange; /* in Q14 */
|
||
|
WebRtc_Word16 w16_winMute = 0, w16_winMuteInc = 0, w16_winUnMute = 0, w16_winUnMuteInc = 0;
|
||
|
WebRtc_Word32 w32_tmp;
|
||
|
WebRtc_Word16 w16_tmp, w16_tmp2;
|
||
|
WebRtc_Word16 stability;
|
||
|
enum BGNMode bgnMode = inst->BGNInst.bgnMode;
|
||
|
|
||
|
/* Pre-calculate common multiplications with fs_mult */
|
||
|
WebRtc_Word16 fsMult4;
|
||
|
WebRtc_Word16 fsMult20;
|
||
|
WebRtc_Word16 fsMult120;
|
||
|
WebRtc_Word16 fsMultDistLen;
|
||
|
WebRtc_Word16 fsMultLPCAnalasysLen;
|
||
|
|
||
|
#ifdef NETEQ_STEREO
|
||
|
MasterSlaveInfo *msInfo = inst->msInfo;
|
||
|
#endif
|
||
|
|
||
|
/* fs is WebRtc_UWord16 (to hold fs=48000) */
|
||
|
fs_mult = WebRtcNetEQ_CalcFsMult(inst->fs); /* calculate fs/8000 */
|
||
|
|
||
|
/* Pre-calculate common multiplications with fs_mult */
|
||
|
fsMult4 = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16(fs_mult, 4);
|
||
|
fsMult20 = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16(fs_mult, 20);
|
||
|
fsMult120 = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16(fs_mult, 120);
|
||
|
fsMultDistLen = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16(fs_mult, DISTLEN);
|
||
|
fsMultLPCAnalasysLen = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16(fs_mult, LPCANALASYSLEN);
|
||
|
|
||
|
/*
|
||
|
* Perform all the initial setup if it's the first expansion.
|
||
|
* If background noise (BGN) only, this setup is not needed.
|
||
|
*/
|
||
|
if (ExpandState->w16_consecExp == 0 && !BGNonly)
|
||
|
{
|
||
|
/* Setup more variables */
|
||
|
#ifdef SCRATCH
|
||
|
WebRtc_Word32 *pw32_autoCorr = (WebRtc_Word32*) (pw16_scratchPtr
|
||
|
+ SCRATCH_PW32_AUTO_CORR);
|
||
|
WebRtc_Word16 *pw16_rc = pw16_scratchPtr + SCRATCH_PW16_RC;
|
||
|
WebRtc_Word16 *pw16_bestCorrIndex = pw16_scratchPtr + SCRATCH_PW16_BEST_CORR_INDEX;
|
||
|
WebRtc_Word16 *pw16_bestCorr = pw16_scratchPtr + SCRATCH_PW16_BEST_CORR;
|
||
|
WebRtc_Word16 *pw16_bestDistIndex = pw16_scratchPtr + SCRATCH_PW16_BEST_DIST_INDEX;
|
||
|
WebRtc_Word16 *pw16_bestDist = pw16_scratchPtr + SCRATCH_PW16_BEST_DIST;
|
||
|
WebRtc_Word16 *pw16_corrVec = pw16_scratchPtr + SCRATCH_PW16_CORR_VEC;
|
||
|
WebRtc_Word32 *pw32_corr2 = (WebRtc_Word32*) (pw16_scratchPtr + SCRATCH_PW16_CORR2);
|
||
|
#else
|
||
|
WebRtc_Word32 pw32_autoCorr[UNVOICED_LPC_ORDER+1];
|
||
|
WebRtc_Word16 pw16_rc[UNVOICED_LPC_ORDER];
|
||
|
WebRtc_Word16 pw16_corrVec[FSMULT*102]; /* 102 for NB */
|
||
|
WebRtc_Word16 pw16_bestCorrIndex[CHECK_NO_OF_CORRMAX];
|
||
|
WebRtc_Word16 pw16_bestCorr[CHECK_NO_OF_CORRMAX];
|
||
|
WebRtc_Word16 pw16_bestDistIndex[CHECK_NO_OF_CORRMAX];
|
||
|
WebRtc_Word16 pw16_bestDist[CHECK_NO_OF_CORRMAX];
|
||
|
WebRtc_Word32 pw32_corr2[(99*FSMULT)+1];
|
||
|
#endif
|
||
|
WebRtc_Word32 pw32_bestDist[CHECK_NO_OF_CORRMAX];
|
||
|
WebRtc_Word16 w16_ind = 0;
|
||
|
WebRtc_Word16 w16_corrVecLen;
|
||
|
WebRtc_Word16 w16_corrScale;
|
||
|
WebRtc_Word16 w16_distScale;
|
||
|
WebRtc_Word16 w16_indMin, w16_indMax;
|
||
|
WebRtc_Word16 w16_len;
|
||
|
WebRtc_Word32 w32_en1, w32_en2, w32_cc;
|
||
|
WebRtc_Word16 w16_en1Scale, w16_en2Scale;
|
||
|
WebRtc_Word16 w16_en1, w16_en2;
|
||
|
WebRtc_Word32 w32_en1_mul_en2;
|
||
|
WebRtc_Word16 w16_sqrt_en1en2;
|
||
|
WebRtc_Word16 w16_ccShiftL;
|
||
|
WebRtc_Word16 w16_bestcorr; /* Correlation in Q14 */
|
||
|
WebRtc_Word16 *pw16_vec1, *pw16_vec2;
|
||
|
WebRtc_Word16 w16_factor;
|
||
|
WebRtc_Word16 w16_DistLag, w16_CorrLag, w16_diffLag;
|
||
|
WebRtc_Word16 w16_energyLen;
|
||
|
WebRtc_Word16 w16_slope;
|
||
|
WebRtc_Word16 w16_startInd;
|
||
|
WebRtc_Word16 w16_noOfcorr2;
|
||
|
WebRtc_Word16 w16_scale;
|
||
|
|
||
|
/* Initialize some variables */
|
||
|
ExpandState->w16_lagsDirection = 1;
|
||
|
ExpandState->w16_lagsPosition = -1;
|
||
|
ExpandState->w16_expandMuteFactor = 16384; /* Start from 1.0 (Q14) */
|
||
|
BGNState->w16_mutefactor = 0; /* Start with 0 gain for BGN (value in Q14) */
|
||
|
inst->w16_seedInc = 1;
|
||
|
|
||
|
#ifdef NETEQ_STEREO
|
||
|
/* Sanity for msInfo */
|
||
|
if (msInfo == NULL)
|
||
|
{
|
||
|
/* this should not happen here */
|
||
|
return MASTER_SLAVE_ERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Do not calculate correlations for slave instance(s)
|
||
|
* unless lag info from master is corrupt
|
||
|
*/
|
||
|
if ((msInfo->msMode != NETEQ_SLAVE)
|
||
|
|| ((msInfo->distLag <= 0) || (msInfo->corrLag <= 0)))
|
||
|
{
|
||
|
#endif
|
||
|
/* Calculate correlation vector in downsampled domain (4 kHz sample rate) */
|
||
|
w16_corrVecLen = WebRtcNetEQ_Correlator(inst,
|
||
|
#ifdef SCRATCH
|
||
|
pw16_scratchPtr + SCRATCH_NETEQDSP_CORRELATOR,
|
||
|
#endif
|
||
|
inst->pw16_speechHistory, inst->w16_speechHistoryLen, pw16_corrVec,
|
||
|
&w16_corrScale);
|
||
|
|
||
|
/* Find peaks in correlation vector using parabolic fit method */
|
||
|
WebRtcNetEQ_PeakDetection(pw16_corrVec, w16_corrVecLen, CHECK_NO_OF_CORRMAX, fs_mult,
|
||
|
pw16_bestCorrIndex, pw16_bestCorr);
|
||
|
|
||
|
/*
|
||
|
* Adjust peak locations; cross-correlation lags start at 2.5 ms
|
||
|
* (20*fs_mult samples)
|
||
|
*/
|
||
|
pw16_bestCorrIndex[0] += fsMult20;
|
||
|
pw16_bestCorrIndex[1] += fsMult20;
|
||
|
pw16_bestCorrIndex[2] += fsMult20;
|
||
|
|
||
|
/* Calculate distortion around the 3 (CHECK_NO_OF_CORRMAX) best lags */
|
||
|
w16_distScale = 0;
|
||
|
for (i = 0; i < CHECK_NO_OF_CORRMAX; i++)
|
||
|
{
|
||
|
w16_tmp = fsMult20;
|
||
|
w16_tmp2 = pw16_bestCorrIndex[i] - fsMult4;
|
||
|
w16_indMin = WEBRTC_SPL_MAX(w16_tmp, w16_tmp2);
|
||
|
w16_tmp = fsMult120 - 1;
|
||
|
w16_tmp2 = pw16_bestCorrIndex[i] + fsMult4;
|
||
|
w16_indMax = WEBRTC_SPL_MIN(w16_tmp, w16_tmp2);
|
||
|
|
||
|
pw16_bestDistIndex[i] = WebRtcNetEQ_MinDistortion(
|
||
|
&(inst->pw16_speechHistory[inst->w16_speechHistoryLen - fsMultDistLen]),
|
||
|
w16_indMin, w16_indMax, fsMultDistLen, &pw32_bestDist[i]);
|
||
|
|
||
|
w16_distScale
|
||
|
= WEBRTC_SPL_MAX(16 - WebRtcSpl_NormW32(pw32_bestDist[i]), w16_distScale);
|
||
|
|
||
|
}
|
||
|
|
||
|
/* Shift the distortion values to fit in WebRtc_Word16 */
|
||
|
WebRtcSpl_VectorBitShiftW32ToW16(pw16_bestDist, CHECK_NO_OF_CORRMAX, pw32_bestDist,
|
||
|
w16_distScale);
|
||
|
|
||
|
/*
|
||
|
* Find index of maximum criteria, where crit[i] = bestCorr[i])/(bestDist[i])
|
||
|
* Do this by a cross multiplication.
|
||
|
*/
|
||
|
|
||
|
w32_en1 = WEBRTC_SPL_MUL_16_16((WebRtc_Word32) pw16_bestCorr[0],pw16_bestDist[1]);
|
||
|
w32_en2 = WEBRTC_SPL_MUL_16_16((WebRtc_Word32) pw16_bestCorr[1],pw16_bestDist[0]);
|
||
|
if (w32_en1 >= w32_en2)
|
||
|
{
|
||
|
/* 0 wins over 1 */
|
||
|
w32_en1
|
||
|
= WEBRTC_SPL_MUL_16_16((WebRtc_Word32) pw16_bestCorr[0], pw16_bestDist[2]);
|
||
|
w32_en2
|
||
|
= WEBRTC_SPL_MUL_16_16((WebRtc_Word32) pw16_bestCorr[2], pw16_bestDist[0]);
|
||
|
if (w32_en1 >= w32_en2)
|
||
|
{
|
||
|
/* 0 wins over 2 */
|
||
|
w16_ind = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* 2 wins over 0 */
|
||
|
w16_ind = 2;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* 1 wins over 0 */
|
||
|
w32_en1
|
||
|
= WEBRTC_SPL_MUL_16_16((WebRtc_Word32) pw16_bestCorr[1],pw16_bestDist[2]);
|
||
|
w32_en2
|
||
|
= WEBRTC_SPL_MUL_16_16((WebRtc_Word32) pw16_bestCorr[2],pw16_bestDist[1]);
|
||
|
if ((WebRtc_Word32) w32_en1 >= (WebRtc_Word32) w32_en2)
|
||
|
{
|
||
|
/* 1 wins over 2 */
|
||
|
w16_ind = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* 2 wins over 1 */
|
||
|
w16_ind = 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef NETEQ_STEREO
|
||
|
}
|
||
|
|
||
|
/* Store DistLag and CorrLag of the position with highest criteria */
|
||
|
if ((msInfo->msMode == NETEQ_MASTER) || (msInfo->msMode == NETEQ_MONO)
|
||
|
|| ((msInfo->msMode == NETEQ_SLAVE) && (msInfo->distLag <= 0 || msInfo->corrLag
|
||
|
<= 0)))
|
||
|
{
|
||
|
/* lags not provided externally */
|
||
|
w16_DistLag = pw16_bestDistIndex[w16_ind];
|
||
|
w16_CorrLag = pw16_bestCorrIndex[w16_ind];
|
||
|
if (msInfo->msMode == NETEQ_MASTER)
|
||
|
{
|
||
|
msInfo->distLag = w16_DistLag;
|
||
|
msInfo->corrLag = w16_CorrLag;
|
||
|
}
|
||
|
}
|
||
|
else if (msInfo->msMode == NETEQ_SLAVE)
|
||
|
{
|
||
|
/* lags provided externally (from master) */
|
||
|
w16_DistLag = msInfo->distLag;
|
||
|
w16_CorrLag = msInfo->corrLag;
|
||
|
|
||
|
/* sanity for lag values */
|
||
|
if ((w16_DistLag <= 0) || (w16_CorrLag <= 0))
|
||
|
{
|
||
|
return MASTER_SLAVE_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Invalid mode */
|
||
|
return MASTER_SLAVE_ERROR;
|
||
|
}
|
||
|
#else /* not NETEQ_STEREO */
|
||
|
w16_DistLag = pw16_bestDistIndex[w16_ind];
|
||
|
w16_CorrLag = pw16_bestCorrIndex[w16_ind];
|
||
|
#endif
|
||
|
|
||
|
ExpandState->w16_maxLag = WEBRTC_SPL_MAX(w16_DistLag, w16_CorrLag);
|
||
|
|
||
|
/* Calculate the exact best correlation (in the range within CorrLag-DistLag) */
|
||
|
w16_len = w16_DistLag + 10;
|
||
|
w16_len = WEBRTC_SPL_MIN(w16_len, fsMult120);
|
||
|
w16_len = WEBRTC_SPL_MAX(w16_len, 60 * fs_mult);
|
||
|
|
||
|
w16_startInd = WEBRTC_SPL_MIN(w16_DistLag, w16_CorrLag);
|
||
|
w16_noOfcorr2 = WEBRTC_SPL_ABS_W16((w16_DistLag-w16_CorrLag)) + 1;
|
||
|
/* w16_noOfcorr2 maximum value is 99*fs_mult + 1 */
|
||
|
|
||
|
/* Calculate suitable scaling */
|
||
|
w16_tmp
|
||
|
= WebRtcSpl_MaxAbsValueW16(
|
||
|
&inst->pw16_speechHistory[inst->w16_speechHistoryLen - w16_len - w16_startInd
|
||
|
- w16_noOfcorr2],
|
||
|
(WebRtc_Word16) (w16_len + w16_startInd + w16_noOfcorr2 - 1));
|
||
|
w16_corrScale = ((31 - WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_tmp, w16_tmp)))
|
||
|
+ (31 - WebRtcSpl_NormW32(w16_len))) - 31;
|
||
|
w16_corrScale = WEBRTC_SPL_MAX(0, w16_corrScale);
|
||
|
|
||
|
/*
|
||
|
* Perform the correlation, store in pw32_corr2
|
||
|
*/
|
||
|
|
||
|
WebRtcNetEQ_CrossCorr(pw32_corr2,
|
||
|
&(inst->pw16_speechHistory[inst->w16_speechHistoryLen - w16_len]),
|
||
|
&(inst->pw16_speechHistory[inst->w16_speechHistoryLen - w16_len - w16_startInd]),
|
||
|
w16_len, w16_noOfcorr2, w16_corrScale, -1);
|
||
|
|
||
|
/* Find maximizing index */
|
||
|
w16_ind = WebRtcSpl_MaxIndexW32(pw32_corr2, w16_noOfcorr2);
|
||
|
w32_cc = pw32_corr2[w16_ind]; /* this is maximum correlation */
|
||
|
w16_ind = w16_ind + w16_startInd; /* correct index for start offset */
|
||
|
|
||
|
/* Calculate energies */
|
||
|
w32_en1 = WebRtcNetEQ_DotW16W16(
|
||
|
&(inst->pw16_speechHistory[inst->w16_speechHistoryLen - w16_len]),
|
||
|
&(inst->pw16_speechHistory[inst->w16_speechHistoryLen - w16_len]), w16_len,
|
||
|
w16_corrScale);
|
||
|
w32_en2 = WebRtcNetEQ_DotW16W16(
|
||
|
&(inst->pw16_speechHistory[inst->w16_speechHistoryLen - w16_len - w16_ind]),
|
||
|
&(inst->pw16_speechHistory[inst->w16_speechHistoryLen - w16_len - w16_ind]),
|
||
|
w16_len, w16_corrScale);
|
||
|
|
||
|
/* Calculate the correlation value w16_bestcorr */
|
||
|
if ((w32_en1 > 0) && (w32_en2 > 0))
|
||
|
{
|
||
|
w16_en1Scale = 16 - WebRtcSpl_NormW32(w32_en1);
|
||
|
w16_en1Scale = WEBRTC_SPL_MAX(0, w16_en1Scale);
|
||
|
w16_en2Scale = 16 - WebRtcSpl_NormW32(w32_en2);
|
||
|
w16_en2Scale = WEBRTC_SPL_MAX(0, w16_en2Scale);
|
||
|
/* Make sure total scaling is even (to simplify scale factor after sqrt) */
|
||
|
if ((w16_en1Scale + w16_en2Scale) & 1)
|
||
|
{
|
||
|
/* if sum is odd */
|
||
|
w16_en1Scale += 1;
|
||
|
}
|
||
|
w16_en1 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(w32_en1, w16_en1Scale);
|
||
|
w16_en2 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(w32_en2, w16_en2Scale);
|
||
|
w32_en1_mul_en2 = WEBRTC_SPL_MUL_16_16(w16_en1, w16_en2);
|
||
|
w16_sqrt_en1en2 = (WebRtc_Word16) WebRtcSpl_Sqrt(w32_en1_mul_en2);
|
||
|
|
||
|
/* Calculate cc/sqrt(en1*en2) in Q14 */
|
||
|
w16_ccShiftL = 14 - ((w16_en1Scale + w16_en2Scale) >> 1);
|
||
|
w32_cc = WEBRTC_SPL_SHIFT_W32(w32_cc, w16_ccShiftL);
|
||
|
w16_bestcorr = (WebRtc_Word16) WebRtcSpl_DivW32W16(w32_cc, w16_sqrt_en1en2);
|
||
|
w16_bestcorr = WEBRTC_SPL_MIN(16384, w16_bestcorr); /* set maximum to 1.0 */
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* if either en1 or en2 is zero */
|
||
|
w16_bestcorr = 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Extract the two vectors, pw16_expVecs[0][] and pw16_expVecs[1][],
|
||
|
* from the SpeechHistory[]
|
||
|
*/
|
||
|
w16_expVecsLen = ExpandState->w16_maxLag + ExpandState->w16_overlap;
|
||
|
pw16_vec1 = &(inst->pw16_speechHistory[inst->w16_speechHistoryLen - w16_expVecsLen]);
|
||
|
pw16_vec2 = pw16_vec1 - w16_DistLag;
|
||
|
/* Normalize the second vector to the same energy as the first */
|
||
|
w32_en1 = WebRtcNetEQ_DotW16W16(pw16_vec1, pw16_vec1, w16_expVecsLen, w16_corrScale);
|
||
|
w32_en2 = WebRtcNetEQ_DotW16W16(pw16_vec2, pw16_vec2, w16_expVecsLen, w16_corrScale);
|
||
|
|
||
|
/*
|
||
|
* Confirm that energy factor sqrt(w32_en1/w32_en2) is within difference 0.5 - 2.0
|
||
|
* w32_en1/w32_en2 within 0.25 - 4
|
||
|
*/
|
||
|
if (((w32_en1 >> 2) < w32_en2) && ((w32_en1) > (w32_en2 >> 2)))
|
||
|
{
|
||
|
|
||
|
/* Energy constraint fulfilled => use both vectors and scale them accordingly */
|
||
|
w16_en2Scale = 16 - WebRtcSpl_NormW32(w32_en2);
|
||
|
w16_en2Scale = WEBRTC_SPL_MAX(0, w16_en2Scale);
|
||
|
w16_en1Scale = w16_en2Scale - 13;
|
||
|
|
||
|
/* calculate w32_en1/w32_en2 in Q13 */
|
||
|
w32_en1_mul_en2 = WebRtcSpl_DivW32W16(
|
||
|
WEBRTC_SPL_SHIFT_W32(w32_en1, -w16_en1Scale),
|
||
|
(WebRtc_Word16) (WEBRTC_SPL_RSHIFT_W32(w32_en2, w16_en2Scale)));
|
||
|
|
||
|
/* calculate factor in Q13 (sqrt of en1/en2 in Q26) */
|
||
|
w16_factor = (WebRtc_Word16) WebRtcSpl_Sqrt(
|
||
|
WEBRTC_SPL_LSHIFT_W32(w32_en1_mul_en2, 13));
|
||
|
|
||
|
/* Copy the two vectors and give them the same energy */
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(ExpandState->pw16_expVecs[0], pw16_vec1, w16_expVecsLen);
|
||
|
WebRtcSpl_AffineTransformVector(ExpandState->pw16_expVecs[1], pw16_vec2,
|
||
|
w16_factor, 4096, 13, w16_expVecsLen);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Energy change constraint not fulfilled => only use last vector */
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(ExpandState->pw16_expVecs[0], pw16_vec1, w16_expVecsLen);
|
||
|
WEBRTC_SPL_MEMCPY_W16(ExpandState->pw16_expVecs[1], ExpandState->pw16_expVecs[0],
|
||
|
w16_expVecsLen);
|
||
|
|
||
|
/* Set the w16_factor since it is used by muting slope */
|
||
|
if (((w32_en1 >> 2) < w32_en2) || (w32_en2 == 0))
|
||
|
{
|
||
|
w16_factor = 4096; /* 0.5 in Q13*/
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w16_factor = 16384; /* 2.0 in Q13*/
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Set the 3 lag values */
|
||
|
w16_diffLag = w16_DistLag - w16_CorrLag;
|
||
|
if (w16_diffLag == 0)
|
||
|
{
|
||
|
/* DistLag and CorrLag are equal */
|
||
|
ExpandState->w16_lags[0] = w16_DistLag;
|
||
|
ExpandState->w16_lags[1] = w16_DistLag;
|
||
|
ExpandState->w16_lags[2] = w16_DistLag;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* DistLag and CorrLag are not equal; use different combinations of the two */
|
||
|
ExpandState->w16_lags[0] = w16_DistLag; /* DistLag only */
|
||
|
ExpandState->w16_lags[1] = ((w16_DistLag + w16_CorrLag) >> 1); /* 50/50 */
|
||
|
/* Third lag, move one half-step towards CorrLag (in both cases) */
|
||
|
if (w16_diffLag > 0)
|
||
|
{
|
||
|
ExpandState->w16_lags[2] = (w16_DistLag + w16_CorrLag - 1) >> 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ExpandState->w16_lags[2] = (w16_DistLag + w16_CorrLag + 1) >> 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*************************************************
|
||
|
* Calculate the LPC and the gain of the filters *
|
||
|
*************************************************/
|
||
|
|
||
|
/* Calculate scale value needed for autocorrelation */
|
||
|
w16_tmp = WebRtcSpl_MaxAbsValueW16(
|
||
|
&(inst->pw16_speechHistory[inst->w16_speechHistoryLen - fsMultLPCAnalasysLen]),
|
||
|
fsMultLPCAnalasysLen);
|
||
|
|
||
|
w16_tmp = 16 - WebRtcSpl_NormW32(w16_tmp);
|
||
|
w16_tmp = WEBRTC_SPL_MIN(w16_tmp,0);
|
||
|
w16_tmp = (w16_tmp << 1) + 7;
|
||
|
w16_tmp = WEBRTC_SPL_MAX(w16_tmp,0);
|
||
|
|
||
|
/* set w16_ind to simplify the following expressions */
|
||
|
w16_ind = inst->w16_speechHistoryLen - fsMultLPCAnalasysLen - UNVOICED_LPC_ORDER;
|
||
|
|
||
|
/* store first UNVOICED_LPC_ORDER samples in pw16_rc */
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(pw16_rc, &inst->pw16_speechHistory[w16_ind], UNVOICED_LPC_ORDER);
|
||
|
|
||
|
/* set first samples to zero */
|
||
|
WebRtcSpl_MemSetW16(&inst->pw16_speechHistory[w16_ind], 0, UNVOICED_LPC_ORDER);
|
||
|
|
||
|
/* Calculate UNVOICED_LPC_ORDER+1 lags of the ACF */
|
||
|
|
||
|
WebRtcNetEQ_CrossCorr(
|
||
|
pw32_autoCorr, &(inst->pw16_speechHistory[w16_ind + UNVOICED_LPC_ORDER]),
|
||
|
&(inst->pw16_speechHistory[w16_ind + UNVOICED_LPC_ORDER]), fsMultLPCAnalasysLen,
|
||
|
UNVOICED_LPC_ORDER + 1, w16_tmp, -1);
|
||
|
|
||
|
/* Recover the stored samples from pw16_rc */
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(&inst->pw16_speechHistory[w16_ind], pw16_rc, UNVOICED_LPC_ORDER);
|
||
|
|
||
|
if (pw32_autoCorr[0] > 0)
|
||
|
{ /* check that variance is positive */
|
||
|
|
||
|
/* estimate AR filter parameters using Levinson-Durbin algorithm
|
||
|
(UNVOICED_LPC_ORDER+1 filter coefficients) */
|
||
|
stability = WebRtcSpl_LevinsonDurbin(pw32_autoCorr, ExpandState->pw16_arFilter,
|
||
|
pw16_rc, UNVOICED_LPC_ORDER);
|
||
|
|
||
|
/* Only update BGN if filter is stable */
|
||
|
if (stability != 1)
|
||
|
{
|
||
|
/* Set first coefficient to 4096 (1.0 in Q12)*/
|
||
|
ExpandState->pw16_arFilter[0] = 4096;
|
||
|
/* Set remaining UNVOICED_LPC_ORDER coefficients to zero */
|
||
|
WebRtcSpl_MemSetW16(ExpandState->pw16_arFilter + 1, 0, UNVOICED_LPC_ORDER);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (w16_DistLag < 40)
|
||
|
{
|
||
|
w16_energyLen = 2 * w16_DistLag;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w16_energyLen = w16_DistLag;
|
||
|
}
|
||
|
w16_randLen = w16_energyLen + 30; /* Startup part */
|
||
|
|
||
|
/* Extract a noise segment */
|
||
|
if (w16_randLen <= RANDVEC_NO_OF_SAMPLES)
|
||
|
{
|
||
|
WEBRTC_SPL_MEMCPY_W16(pw16_randVec,
|
||
|
(WebRtc_Word16*) WebRtcNetEQ_kRandnTbl, w16_randLen);
|
||
|
}
|
||
|
else
|
||
|
{ /* only applies to SWB where length could be larger than 256 */
|
||
|
WEBRTC_SPL_MEMCPY_W16(pw16_randVec, (WebRtc_Word16*) WebRtcNetEQ_kRandnTbl,
|
||
|
RANDVEC_NO_OF_SAMPLES);
|
||
|
inst->w16_seedInc = (inst->w16_seedInc + 2) & (RANDVEC_NO_OF_SAMPLES - 1);
|
||
|
WebRtcNetEQ_RandomVec(&inst->uw16_seed, &pw16_randVec[RANDVEC_NO_OF_SAMPLES],
|
||
|
(WebRtc_Word16) (w16_randLen - RANDVEC_NO_OF_SAMPLES), inst->w16_seedInc);
|
||
|
}
|
||
|
|
||
|
/* Set up state vector and calculate scale factor for unvoiced filtering */
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(ExpandState->pw16_arState,
|
||
|
&(inst->pw16_speechHistory[inst->w16_speechHistoryLen - UNVOICED_LPC_ORDER]),
|
||
|
UNVOICED_LPC_ORDER);
|
||
|
WEBRTC_SPL_MEMCPY_W16(pw16_unvoicedVec - UNVOICED_LPC_ORDER,
|
||
|
&(inst->pw16_speechHistory[inst->w16_speechHistoryLen - 128 - UNVOICED_LPC_ORDER]),
|
||
|
UNVOICED_LPC_ORDER);
|
||
|
WebRtcSpl_FilterMAFastQ12(&inst->pw16_speechHistory[inst->w16_speechHistoryLen - 128],
|
||
|
pw16_unvoicedVec, ExpandState->pw16_arFilter, UNVOICED_LPC_ORDER + 1, 128);
|
||
|
if (WebRtcSpl_MaxAbsValueW16(pw16_unvoicedVec, 128) > 4000)
|
||
|
{
|
||
|
w16_scale = 4;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w16_scale = 0;
|
||
|
}
|
||
|
w32_tmp = WebRtcNetEQ_DotW16W16(pw16_unvoicedVec, pw16_unvoicedVec, 128, w16_scale);
|
||
|
|
||
|
/* Normalize w32_tmp to 28 or 29 bits to preserve sqrt() accuracy */
|
||
|
w16_tmp = WebRtcSpl_NormW32(w32_tmp) - 3;
|
||
|
w16_tmp += ((w16_tmp & 0x1) ^ 0x1); /* Make sure we do an odd number of shifts since we
|
||
|
from earlier have 7 shifts from dividing with 128.*/
|
||
|
w32_tmp = WEBRTC_SPL_SHIFT_W32(w32_tmp, w16_tmp);
|
||
|
w32_tmp = WebRtcSpl_Sqrt(w32_tmp);
|
||
|
ExpandState->w16_arGainScale = 13 + ((w16_tmp + 7 - w16_scale) >> 1);
|
||
|
ExpandState->w16_arGain = (WebRtc_Word16) w32_tmp;
|
||
|
|
||
|
/********************************************************************
|
||
|
* Calculate vfraction from bestcorr *
|
||
|
* if (bestcorr>0.480665) *
|
||
|
* vfraction = ((bestcorr-0.4)/(1-0.4)).^2 *
|
||
|
* else vfraction = 0 *
|
||
|
* *
|
||
|
* approximation (coefficients in Q12): *
|
||
|
* if (x>0.480665) (y(x)<0.3) *
|
||
|
* y(x) = -1.264421 + 4.8659148*x - 4.0092827*x^2 + 1.4100529*x^3 *
|
||
|
* else y(x) = 0; *
|
||
|
********************************************************************/
|
||
|
|
||
|
if (w16_bestcorr > 7875)
|
||
|
{
|
||
|
/* if x>0.480665 */
|
||
|
WebRtc_Word16 w16_x1, w16_x2, w16_x3;
|
||
|
w16_x1 = w16_bestcorr;
|
||
|
w32_tmp = WEBRTC_SPL_MUL_16_16((WebRtc_Word32) w16_x1, w16_x1);
|
||
|
w16_x2 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(w32_tmp, 14);
|
||
|
w32_tmp = WEBRTC_SPL_MUL_16_16(w16_x1, w16_x2);
|
||
|
w16_x3 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(w32_tmp, 14);
|
||
|
w32_tmp
|
||
|
= (WebRtc_Word32) WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32) WebRtcNetEQ_kMixFractionFuncTbl[0], 14);
|
||
|
w32_tmp
|
||
|
+= (WebRtc_Word32) WEBRTC_SPL_MUL_16_16(WebRtcNetEQ_kMixFractionFuncTbl[1], w16_x1);
|
||
|
w32_tmp
|
||
|
+= (WebRtc_Word32) WEBRTC_SPL_MUL_16_16(WebRtcNetEQ_kMixFractionFuncTbl[2], w16_x2);
|
||
|
w32_tmp
|
||
|
+= (WebRtc_Word32) WEBRTC_SPL_MUL_16_16(WebRtcNetEQ_kMixFractionFuncTbl[3], w16_x3);
|
||
|
ExpandState->w16_vFraction = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(w32_tmp, 12);
|
||
|
ExpandState->w16_vFraction = WEBRTC_SPL_MIN(ExpandState->w16_vFraction, 16384);
|
||
|
ExpandState->w16_vFraction = WEBRTC_SPL_MAX(ExpandState->w16_vFraction, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ExpandState->w16_vFraction = 0;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
* Calculate muting slope, reuse value from earlier scaling of ExpVecs *
|
||
|
***********************************************************************/
|
||
|
w16_slope = w16_factor;
|
||
|
|
||
|
if (w16_slope > 12288)
|
||
|
{
|
||
|
/* w16_slope > 1.5 ? */
|
||
|
/* Calculate (1-(1/slope))/w16_DistLag = (slope-1)/(w16_DistLag*slope) */
|
||
|
w32_tmp = w16_slope - 8192;
|
||
|
w32_tmp = WEBRTC_SPL_LSHIFT_W32(w32_tmp, 12); /* Value in Q25 (13+12=25) */
|
||
|
w16_tmp = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(w16_DistLag,
|
||
|
w16_slope, 8); /* Value in Q5 (13-8=5) */
|
||
|
w16_tmp = (WebRtc_Word16) WebRtcSpl_DivW32W16(w32_tmp,
|
||
|
w16_tmp); /* Res in Q20 (25-5=20) */
|
||
|
|
||
|
if (w16_slope > 14746)
|
||
|
{ /* w16_slope > 1.8 ? */
|
||
|
ExpandState->w16_muteSlope = (w16_tmp + 1) >> 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ExpandState->w16_muteSlope = (w16_tmp + 4) >> 3;
|
||
|
}
|
||
|
ExpandState->w16_onset = 1;
|
||
|
}
|
||
|
else if (ExpandState->w16_vFraction > 13107)
|
||
|
{
|
||
|
/* w16_vFraction > 0.8 ? */
|
||
|
if (w16_slope > 8028)
|
||
|
{
|
||
|
/* w16_vFraction > 0.98 ? */
|
||
|
ExpandState->w16_muteSlope = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Calculate (1-slope)/w16_DistLag */
|
||
|
w32_tmp = 8192 - w16_slope;
|
||
|
w32_tmp = WEBRTC_SPL_LSHIFT_W32(w32_tmp, 7); /* Value in Q20 (13+7=20) */
|
||
|
ExpandState->w16_muteSlope = (WebRtc_Word16) WebRtcSpl_DivW32W16(w32_tmp,
|
||
|
w16_DistLag); /* Res in Q20 (20-0=20) */
|
||
|
}
|
||
|
ExpandState->w16_onset = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
* Use the minimum of 0.005 (0.9 on 50 samples in NB and the slope)
|
||
|
* and ((1-slope)/w16_DistLag)
|
||
|
*/
|
||
|
w32_tmp = 8192 - w16_slope;
|
||
|
w32_tmp = WEBRTC_SPL_LSHIFT_W32(w32_tmp, 7); /* Value in Q20 (13+7=20) */
|
||
|
w32_tmp = WEBRTC_SPL_MAX(w32_tmp, 0);
|
||
|
ExpandState->w16_muteSlope = (WebRtc_Word16) WebRtcSpl_DivW32W16(w32_tmp,
|
||
|
w16_DistLag); /* Res in Q20 (20-0=20) */
|
||
|
w16_tmp = WebRtcNetEQ_k5243div[fs_mult]; /* 0.005/fs_mult = 5243/fs_mult */
|
||
|
ExpandState->w16_muteSlope = WEBRTC_SPL_MAX(w16_tmp, ExpandState->w16_muteSlope);
|
||
|
ExpandState->w16_onset = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* This is not the first Expansion, parameters are already estimated. */
|
||
|
|
||
|
/* Extract a noise segment */
|
||
|
if (BGNonly) /* If we should produce nothing but background noise */
|
||
|
{
|
||
|
if (*pw16_len > 0)
|
||
|
{
|
||
|
/*
|
||
|
* Set length to input parameter length, but not more than length
|
||
|
* of pw16_randVec
|
||
|
*/
|
||
|
w16_lag = WEBRTC_SPL_MIN(*pw16_len, FSMULT * 120 + 30);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* set length to 15 ms */
|
||
|
w16_lag = fsMult120;
|
||
|
}
|
||
|
w16_randLen = w16_lag;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w16_randLen = ExpandState->w16_maxLag;
|
||
|
}
|
||
|
|
||
|
if (w16_randLen <= RANDVEC_NO_OF_SAMPLES)
|
||
|
{
|
||
|
inst->w16_seedInc = (inst->w16_seedInc + 2) & (RANDVEC_NO_OF_SAMPLES - 1);
|
||
|
WebRtcNetEQ_RandomVec(&inst->uw16_seed, pw16_randVec, w16_randLen,
|
||
|
inst->w16_seedInc);
|
||
|
}
|
||
|
else
|
||
|
{ /* only applies to SWB where length could be larger than 256 */
|
||
|
inst->w16_seedInc = (inst->w16_seedInc + 2) & (RANDVEC_NO_OF_SAMPLES - 1);
|
||
|
WebRtcNetEQ_RandomVec(&inst->uw16_seed, pw16_randVec, RANDVEC_NO_OF_SAMPLES,
|
||
|
inst->w16_seedInc);
|
||
|
inst->w16_seedInc = (inst->w16_seedInc + 2) & (RANDVEC_NO_OF_SAMPLES - 1);
|
||
|
WebRtcNetEQ_RandomVec(&inst->uw16_seed, &pw16_randVec[RANDVEC_NO_OF_SAMPLES],
|
||
|
(WebRtc_Word16) (w16_randLen - RANDVEC_NO_OF_SAMPLES), inst->w16_seedInc);
|
||
|
}
|
||
|
} /* end if(first expand or BGNonly) ... else ... */
|
||
|
|
||
|
if (!BGNonly) /* Voiced and unvoiced parts not used if generating BGN only */
|
||
|
{
|
||
|
|
||
|
/*************************************************
|
||
|
* Generate signal *
|
||
|
*************************************************/
|
||
|
|
||
|
/*
|
||
|
* Voiced part
|
||
|
*/
|
||
|
|
||
|
/* Linearly mute the use_vfraction value from 1 to vfraction */
|
||
|
if (ExpandState->w16_consecExp == 0)
|
||
|
{
|
||
|
ExpandState->w16_currentVFraction = 16384; /* 1.0 in Q14 */
|
||
|
}
|
||
|
|
||
|
ExpandState->w16_lagsPosition = ExpandState->w16_lagsPosition
|
||
|
+ ExpandState->w16_lagsDirection;
|
||
|
|
||
|
/* Change direction if needed */
|
||
|
if (ExpandState->w16_lagsPosition == 0)
|
||
|
{
|
||
|
ExpandState->w16_lagsDirection = 1;
|
||
|
}
|
||
|
if (ExpandState->w16_lagsPosition == 2)
|
||
|
{
|
||
|
ExpandState->w16_lagsDirection = -1;
|
||
|
}
|
||
|
|
||
|
/* Generate a weighted vector with the selected lag */
|
||
|
w16_expVecsLen = ExpandState->w16_maxLag + ExpandState->w16_overlap;
|
||
|
w16_lag = ExpandState->w16_lags[ExpandState->w16_lagsPosition];
|
||
|
/* Copy lag+overlap data */
|
||
|
w16_expVecPos = w16_expVecsLen - w16_lag - ExpandState->w16_overlap;
|
||
|
w16_tmp = w16_lag + ExpandState->w16_overlap;
|
||
|
if (ExpandState->w16_lagsPosition == 0)
|
||
|
{
|
||
|
WEBRTC_SPL_MEMCPY_W16(pw16_voicedVecStorage,
|
||
|
&(ExpandState->pw16_expVecs[0][w16_expVecPos]), w16_tmp);
|
||
|
}
|
||
|
else if (ExpandState->w16_lagsPosition == 1)
|
||
|
{
|
||
|
WebRtcSpl_ScaleAndAddVectorsWithRound(&ExpandState->pw16_expVecs[0][w16_expVecPos], 3,
|
||
|
&ExpandState->pw16_expVecs[1][w16_expVecPos], 1, 2, pw16_voicedVecStorage,
|
||
|
w16_tmp);
|
||
|
|
||
|
}
|
||
|
else if (ExpandState->w16_lagsPosition == 2)
|
||
|
{
|
||
|
WebRtcSpl_ScaleAndAddVectorsWithRound(&ExpandState->pw16_expVecs[0][w16_expVecPos], 1,
|
||
|
&ExpandState->pw16_expVecs[1][w16_expVecPos], 1, 1, pw16_voicedVecStorage,
|
||
|
w16_tmp);
|
||
|
}
|
||
|
|
||
|
if (inst->fs == 8000)
|
||
|
{
|
||
|
/* Windowing in Q15 */
|
||
|
w16_winMute = NETEQ_OVERLAP_WINMUTE_8KHZ_START;
|
||
|
w16_winMuteInc = NETEQ_OVERLAP_WINMUTE_8KHZ_INC;
|
||
|
w16_winUnMute = NETEQ_OVERLAP_WINUNMUTE_8KHZ_START;
|
||
|
w16_winUnMuteInc = NETEQ_OVERLAP_WINUNMUTE_8KHZ_INC;
|
||
|
#ifdef NETEQ_WIDEBAND
|
||
|
}
|
||
|
else if (inst->fs == 16000)
|
||
|
{
|
||
|
/* Windowing in Q15 */
|
||
|
w16_winMute = NETEQ_OVERLAP_WINMUTE_16KHZ_START;
|
||
|
w16_winMuteInc = NETEQ_OVERLAP_WINMUTE_16KHZ_INC;
|
||
|
w16_winUnMute = NETEQ_OVERLAP_WINUNMUTE_16KHZ_START;
|
||
|
w16_winUnMuteInc = NETEQ_OVERLAP_WINUNMUTE_16KHZ_INC;
|
||
|
#endif
|
||
|
#ifdef NETEQ_32KHZ_WIDEBAND
|
||
|
}
|
||
|
else if (inst->fs == 32000)
|
||
|
{
|
||
|
/* Windowing in Q15 */
|
||
|
w16_winMute = NETEQ_OVERLAP_WINMUTE_32KHZ_START;
|
||
|
w16_winMuteInc = NETEQ_OVERLAP_WINMUTE_32KHZ_INC;
|
||
|
w16_winUnMute = NETEQ_OVERLAP_WINUNMUTE_32KHZ_START;
|
||
|
w16_winUnMuteInc = NETEQ_OVERLAP_WINUNMUTE_32KHZ_INC;
|
||
|
#endif
|
||
|
#ifdef NETEQ_48KHZ_WIDEBAND
|
||
|
}
|
||
|
else /* if (inst->fs==48000) */
|
||
|
{
|
||
|
/* Windowing in Q15 */
|
||
|
w16_winMute = NETEQ_OVERLAP_WINMUTE_48KHZ_START;
|
||
|
w16_winMuteInc = NETEQ_OVERLAP_WINMUTE_48KHZ_INC;
|
||
|
w16_winUnMute = NETEQ_OVERLAP_WINUNMUTE_48KHZ_START;
|
||
|
w16_winUnMuteInc = NETEQ_OVERLAP_WINUNMUTE_48KHZ_INC;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/* Smooth the expanded if it has not been muted to or vfraction is larger than 0.5 */
|
||
|
if ((ExpandState->w16_expandMuteFactor > 819) && (ExpandState->w16_currentVFraction
|
||
|
> 8192))
|
||
|
{
|
||
|
for (i = 0; i < ExpandState->w16_overlap; i++)
|
||
|
{
|
||
|
/* Do overlap add between new vector and overlap */
|
||
|
ExpandState->pw16_overlapVec[i] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(
|
||
|
WEBRTC_SPL_MUL_16_16(ExpandState->pw16_overlapVec[i], w16_winMute) +
|
||
|
WEBRTC_SPL_MUL_16_16(
|
||
|
WEBRTC_SPL_MUL_16_16_RSFT(ExpandState->w16_expandMuteFactor,
|
||
|
pw16_voicedVecStorage[i], 14), w16_winUnMute) + 16384, 15);
|
||
|
w16_winMute += w16_winMuteInc;
|
||
|
w16_winUnMute += w16_winUnMuteInc;
|
||
|
}
|
||
|
}
|
||
|
else if (ExpandState->w16_expandMuteFactor == 0
|
||
|
#ifdef NETEQ_STEREO
|
||
|
&& msInfo->msMode == NETEQ_MONO /* only if mono mode is selected */
|
||
|
#endif
|
||
|
)
|
||
|
{
|
||
|
/* if ExpandState->w16_expandMuteFactor = 0 => all is CNG component
|
||
|
set the output length to 15ms (for best CNG production) */
|
||
|
w16_tmp = fsMult120;
|
||
|
ExpandState->w16_maxLag = w16_tmp;
|
||
|
ExpandState->w16_lags[0] = w16_tmp;
|
||
|
ExpandState->w16_lags[1] = w16_tmp;
|
||
|
ExpandState->w16_lags[2] = w16_tmp;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Unvoiced part
|
||
|
*/
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(pw16_unvoicedVec - UNVOICED_LPC_ORDER,
|
||
|
ExpandState->pw16_arState,
|
||
|
UNVOICED_LPC_ORDER);
|
||
|
if (ExpandState->w16_arGainScale > 0)
|
||
|
{
|
||
|
w32_tmp = ((WebRtc_Word32) 1) << (ExpandState->w16_arGainScale - 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w32_tmp = 0;
|
||
|
}
|
||
|
|
||
|
/* Note that shift value can be >16 which complicates things for some DSPs */
|
||
|
WebRtcSpl_AffineTransformVector(pw16_scaledRandVec, pw16_randVec,
|
||
|
ExpandState->w16_arGain, w32_tmp, ExpandState->w16_arGainScale, w16_lag);
|
||
|
|
||
|
WebRtcSpl_FilterARFastQ12(pw16_scaledRandVec, pw16_unvoicedVec,
|
||
|
ExpandState->pw16_arFilter, UNVOICED_LPC_ORDER + 1, w16_lag);
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(ExpandState->pw16_arState,
|
||
|
&(pw16_unvoicedVec[w16_lag - UNVOICED_LPC_ORDER]),
|
||
|
UNVOICED_LPC_ORDER);
|
||
|
|
||
|
/*
|
||
|
* Voiced + Unvoiced
|
||
|
*/
|
||
|
|
||
|
/* For lag =
|
||
|
<=31*fs_mult => go from 1 to 0 in about 8 ms
|
||
|
(>=31..<=63)*fs_mult => go from 1 to 0 in about 16 ms
|
||
|
>=64*fs_mult => go from 1 to 0 in about 32 ms
|
||
|
*/
|
||
|
w16_tmp = (31 - WebRtcSpl_NormW32(ExpandState->w16_maxLag)) - 5; /* getbits(w16_maxLag) -5 */
|
||
|
w16_vfractionChange = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(256, w16_tmp);
|
||
|
if (ExpandState->w16_stopMuting == 1)
|
||
|
{
|
||
|
w16_vfractionChange = 0;
|
||
|
}
|
||
|
|
||
|
/* Create combined signal (unmuted) by shifting in more and more of unvoiced part */
|
||
|
w16_tmp = 8 - w16_tmp; /* getbits(w16_vfractionChange) */
|
||
|
w16_tmp = (ExpandState->w16_currentVFraction - ExpandState->w16_vFraction) >> w16_tmp;
|
||
|
w16_tmp = WEBRTC_SPL_MIN(w16_tmp, w16_lag);
|
||
|
WebRtcNetEQ_MixVoiceUnvoice(pw16_outData, pw16_voicedVec, pw16_unvoicedVec,
|
||
|
&ExpandState->w16_currentVFraction, w16_vfractionChange, w16_tmp);
|
||
|
|
||
|
if (w16_tmp < w16_lag)
|
||
|
{
|
||
|
if (w16_vfractionChange != 0)
|
||
|
{
|
||
|
ExpandState->w16_currentVFraction = ExpandState->w16_vFraction;
|
||
|
}
|
||
|
w16_tmp2 = 16384 - ExpandState->w16_currentVFraction;
|
||
|
WebRtcSpl_ScaleAndAddVectorsWithRound(pw16_voicedVec + w16_tmp,
|
||
|
ExpandState->w16_currentVFraction, pw16_unvoicedVec + w16_tmp, w16_tmp2, 14,
|
||
|
pw16_outData + w16_tmp, (WebRtc_Word16) (w16_lag - w16_tmp));
|
||
|
}
|
||
|
|
||
|
/* Select muting factor */
|
||
|
if (ExpandState->w16_consecExp == 3)
|
||
|
{
|
||
|
/* 0.95 on 50 samples in NB (0.0010/fs_mult in Q20) */
|
||
|
ExpandState->w16_muteSlope = WEBRTC_SPL_MAX(ExpandState->w16_muteSlope,
|
||
|
WebRtcNetEQ_k1049div[fs_mult]);
|
||
|
}
|
||
|
if (ExpandState->w16_consecExp == 7)
|
||
|
{
|
||
|
/* 0.90 on 50 samples in NB (0.0020/fs_mult in Q20) */
|
||
|
ExpandState->w16_muteSlope = WEBRTC_SPL_MAX(ExpandState->w16_muteSlope,
|
||
|
WebRtcNetEQ_k2097div[fs_mult]);
|
||
|
}
|
||
|
|
||
|
/* Mute segment according to slope value */
|
||
|
if ((ExpandState->w16_consecExp != 0) || (ExpandState->w16_onset != 1))
|
||
|
{
|
||
|
/* Mute to the previous level, then continue with the muting */
|
||
|
WebRtcSpl_AffineTransformVector(pw16_outData, pw16_outData,
|
||
|
ExpandState->w16_expandMuteFactor, 8192, 14, w16_lag);
|
||
|
|
||
|
if ((ExpandState->w16_stopMuting != 1))
|
||
|
{
|
||
|
WebRtcNetEQ_MuteSignal(pw16_outData, ExpandState->w16_muteSlope, w16_lag);
|
||
|
|
||
|
w16_tmp = 16384 - (WebRtc_Word16) ((WEBRTC_SPL_MUL_16_16(w16_lag,
|
||
|
ExpandState->w16_muteSlope) + 8192) >> 6); /* 20-14 = 6 */
|
||
|
w16_tmp = (WebRtc_Word16) ((WEBRTC_SPL_MUL_16_16(w16_tmp,
|
||
|
ExpandState->w16_expandMuteFactor) + 8192) >> 14);
|
||
|
|
||
|
/* Guard against getting stuck with very small (but sometimes audible) gain */
|
||
|
if ((ExpandState->w16_consecExp > 3) && (w16_tmp
|
||
|
>= ExpandState->w16_expandMuteFactor))
|
||
|
{
|
||
|
ExpandState->w16_expandMuteFactor = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ExpandState->w16_expandMuteFactor = w16_tmp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} /* end if(!BGNonly) */
|
||
|
|
||
|
/*
|
||
|
* BGN
|
||
|
*/
|
||
|
|
||
|
if (BGNState->w16_initialized == 1)
|
||
|
{
|
||
|
/* BGN parameters are initialized; use them */
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(pw16_cngVec - BGN_LPC_ORDER,
|
||
|
BGNState->pw16_filterState,
|
||
|
BGN_LPC_ORDER);
|
||
|
|
||
|
if (BGNState->w16_scaleShift > 1)
|
||
|
{
|
||
|
w32_tmp = ((WebRtc_Word32) 1) << (BGNState->w16_scaleShift - 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w32_tmp = 0;
|
||
|
}
|
||
|
|
||
|
/* Scale random vector to correct energy level */
|
||
|
/* Note that shift value can be >16 which complicates things for some DSPs */
|
||
|
WebRtcSpl_AffineTransformVector(pw16_scaledRandVec, pw16_randVec,
|
||
|
BGNState->w16_scale, w32_tmp, BGNState->w16_scaleShift, w16_lag);
|
||
|
|
||
|
WebRtcSpl_FilterARFastQ12(pw16_scaledRandVec, pw16_cngVec, BGNState->pw16_filter,
|
||
|
BGN_LPC_ORDER + 1, w16_lag);
|
||
|
|
||
|
WEBRTC_SPL_MEMCPY_W16(BGNState->pw16_filterState,
|
||
|
&(pw16_cngVec[w16_lag-BGN_LPC_ORDER]),
|
||
|
BGN_LPC_ORDER);
|
||
|
|
||
|
/* Unmute the insertion of background noise */
|
||
|
|
||
|
if (bgnMode == BGN_FADE && ExpandState->w16_consecExp >= FADE_BGN_TIME
|
||
|
&& BGNState->w16_mutefactor > 0)
|
||
|
{
|
||
|
/* fade BGN to zero */
|
||
|
/* calculate muting slope, approx 2^18/fsHz */
|
||
|
WebRtc_Word16 muteFactor;
|
||
|
if (fs_mult == 1)
|
||
|
{
|
||
|
muteFactor = -32;
|
||
|
}
|
||
|
else if (fs_mult == 2)
|
||
|
{
|
||
|
muteFactor = -16;
|
||
|
}
|
||
|
else if (fs_mult == 4)
|
||
|
{
|
||
|
muteFactor = -8;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
muteFactor = -5;
|
||
|
}
|
||
|
/* use UnmuteSignal function with negative slope */
|
||
|
WebRtcNetEQ_UnmuteSignal(pw16_cngVec, &BGNState->w16_mutefactor, /* In Q14 */
|
||
|
pw16_cngVec, muteFactor, /* In Q20 */
|
||
|
w16_lag);
|
||
|
}
|
||
|
else if (BGNState->w16_mutefactor < 16384 && !BGNonly)
|
||
|
{
|
||
|
/* if (w16_mutefactor < 1) and not BGN only (since then we use no muting) */
|
||
|
|
||
|
/*
|
||
|
* If BGN_OFF, or if BNG_FADE has started fading,
|
||
|
* mutefactor should not be increased.
|
||
|
*/
|
||
|
if (ExpandState->w16_stopMuting != 1 && bgnMode != BGN_OFF && !(bgnMode
|
||
|
== BGN_FADE && ExpandState->w16_consecExp >= FADE_BGN_TIME))
|
||
|
{
|
||
|
WebRtcNetEQ_UnmuteSignal(pw16_cngVec, &BGNState->w16_mutefactor, /* In Q14 */
|
||
|
pw16_cngVec, ExpandState->w16_muteSlope, /* In Q20 */
|
||
|
w16_lag);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* BGN_ON and stop muting, or
|
||
|
* BGN_OFF (mute factor is always 0), or
|
||
|
* BGN_FADE has reached 0 */
|
||
|
WebRtcSpl_AffineTransformVector(pw16_cngVec, pw16_cngVec,
|
||
|
BGNState->w16_mutefactor, 8192, 14, w16_lag);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* BGN parameters have not been initialized; use zero noise */
|
||
|
WebRtcSpl_MemSetW16(pw16_cngVec, 0, w16_lag);
|
||
|
}
|
||
|
|
||
|
if (BGNonly)
|
||
|
{
|
||
|
/* Copy BGN to outdata */
|
||
|
for (i = 0; i < w16_lag; i++)
|
||
|
{
|
||
|
pw16_outData[i] = pw16_cngVec[i];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Add CNG vector to the Voiced + Unvoiced vectors */
|
||
|
for (i = 0; i < w16_lag; i++)
|
||
|
{
|
||
|
pw16_outData[i] = pw16_outData[i] + pw16_cngVec[i];
|
||
|
}
|
||
|
|
||
|
/* increase call number */
|
||
|
ExpandState->w16_consecExp = ExpandState->w16_consecExp + 1;
|
||
|
if (ExpandState->w16_consecExp < 0) /* Guard against overflow */
|
||
|
ExpandState->w16_consecExp = FADE_BGN_TIME; /* "Arbitrary" large num of expands */
|
||
|
}
|
||
|
|
||
|
inst->w16_mode = MODE_EXPAND;
|
||
|
*pw16_len = w16_lag;
|
||
|
|
||
|
/* Update in-call and post-call statistics */
|
||
|
if (ExpandState->w16_stopMuting != 1 || BGNonly)
|
||
|
{
|
||
|
/*
|
||
|
* Only do this if StopMuting != 1 or if explicitly BGNonly, otherwise Expand is
|
||
|
* called from Merge or Normal and special measures must be taken.
|
||
|
*/
|
||
|
inst->statInst.expandLength += (WebRtc_UWord32) *pw16_len;
|
||
|
if (ExpandState->w16_expandMuteFactor == 0 || BGNonly)
|
||
|
{
|
||
|
/* Only noise expansion */
|
||
|
inst->statInst.expandedNoiseSamples += *pw16_len;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Voice expand (note: not necessarily _voiced_) */
|
||
|
inst->statInst.expandedVoiceSamples += *pw16_len;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* WebRtcNetEQ_GenerateBGN(...)
|
||
|
*
|
||
|
* This function generates and writes len samples of background noise to the
|
||
|
* output vector. The Expand function will be called repeatedly until the
|
||
|
* correct number of samples is produced.
|
||
|
*
|
||
|
* Input:
|
||
|
* - inst : NetEq instance, i.e. the user that requests more
|
||
|
* speech/audio data
|
||
|
* - scratchPtr : Pointer to scratch vector
|
||
|
* - len : Desired length of produced BGN.
|
||
|
*
|
||
|
*
|
||
|
* Output:
|
||
|
* - pw16_outData : Pointer to a memory space where the output data
|
||
|
* should be stored
|
||
|
*
|
||
|
* Return value : >=0 - Number of noise samples produced and written
|
||
|
* to output
|
||
|
* -1 - Error
|
||
|
*/
|
||
|
|
||
|
int WebRtcNetEQ_GenerateBGN(DSPInst_t *inst,
|
||
|
#ifdef SCRATCH
|
||
|
WebRtc_Word16 *pw16_scratchPtr,
|
||
|
#endif
|
||
|
WebRtc_Word16 *pw16_outData, WebRtc_Word16 len)
|
||
|
{
|
||
|
|
||
|
WebRtc_Word16 pos = 0;
|
||
|
WebRtc_Word16 tempLen = len;
|
||
|
|
||
|
while (tempLen > 0)
|
||
|
{
|
||
|
/* while we still need more noise samples, call Expand to obtain background noise */
|
||
|
WebRtcNetEQ_Expand(inst,
|
||
|
#ifdef SCRATCH
|
||
|
pw16_scratchPtr,
|
||
|
#endif
|
||
|
&pw16_outData[pos], &tempLen, 1 /*BGNonly*/);
|
||
|
|
||
|
pos += tempLen; /* we got this many samples */
|
||
|
tempLen = len - pos; /* this is the number of samples we still need */
|
||
|
}
|
||
|
|
||
|
return pos;
|
||
|
}
|
||
|
|
||
|
#undef SCRATCH_PW16_BEST_CORR_INDEX
|
||
|
#undef SCRATCH_PW16_BEST_CORR
|
||
|
#undef SCRATCH_PW16_BEST_DIST_INDEX
|
||
|
#undef SCRATCH_PW16_BEST_DIST
|
||
|
#undef SCRATCH_PW16_CORR_VEC
|
||
|
#undef SCRATCH_PW16_CORR2
|
||
|
#undef SCRATCH_PW32_AUTO_CORR
|
||
|
#undef SCRATCH_PW16_RC
|
||
|
#undef SCRATCH_PW16_RAND_VEC
|
||
|
#undef SCRATCH_NETEQDSP_CORRELATOR
|
||
|
#undef SCRATCH_PW16_SCALED_RAND_VEC
|
||
|
#undef SCRATCH_PW16_UNVOICED_VEC_SPACE
|
||
|
|