blob: 05956c2ba5fea031a7aa93116f465312c92a7bb3 [file] [log] [blame]
/*
* 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 file contains the function for updating the background noise estimate.
*/
#include "dsp.h"
#include "signal_processing_library.h"
#include "dsp_helpfunctions.h"
/* Scratch usage:
Designed for BGN_LPC_ORDER <= 10
Type Name size startpos endpos
WebRtc_Word32 pw32_autoCorr 22 0 21 (Length (BGN_LPC_ORDER + 1)*2)
WebRtc_Word16 pw16_tempVec 10 22 31 (Length BGN_LPC_ORDER)
WebRtc_Word16 pw16_rc 10 32 41 (Length BGN_LPC_ORDER)
WebRtc_Word16 pw16_outVec 74 0 73 (Length BGN_LPC_ORDER + 64)
Total: 74
*/
#if (BGN_LPC_ORDER > 10) && (defined SCRATCH)
#error BGN_LPC_ORDER is too large for current scratch memory allocation
#endif
#define SCRATCH_PW32_AUTO_CORR 0
#define SCRATCH_PW16_TEMP_VEC 22
#define SCRATCH_PW16_RC 32
#define SCRATCH_PW16_OUT_VEC 0
#define NETEQFIX_BGNFRAQINCQ16 229 /* 0.0035 in Q16 */
/****************************************************************************
* WebRtcNetEQ_BGNUpdate(...)
*
* This function updates the background noise parameter estimates.
*
* Input:
* - inst : NetEQ instance, where the speech history is stored.
* - scratchPtr : Pointer to scratch vector.
*
* Output:
* - inst : Updated information about the BGN characteristics.
*
* Return value : No return value
*/
void WebRtcNetEQ_BGNUpdate(
#ifdef SCRATCH
DSPInst_t *inst, WebRtc_Word16 *pw16_scratchPtr
#else
DSPInst_t *inst
#endif
)
{
const WebRtc_Word16 w16_vecLen = 256;
BGNInst_t *BGN_Inst = &(inst->BGNInst);
#ifdef SCRATCH
WebRtc_Word32 *pw32_autoCorr = (WebRtc_Word32*) (pw16_scratchPtr + SCRATCH_PW32_AUTO_CORR);
WebRtc_Word16 *pw16_tempVec = pw16_scratchPtr + SCRATCH_PW16_TEMP_VEC;
WebRtc_Word16 *pw16_rc = pw16_scratchPtr + SCRATCH_PW16_RC;
WebRtc_Word16 *pw16_outVec = pw16_scratchPtr + SCRATCH_PW16_OUT_VEC;
#else
WebRtc_Word32 pw32_autoCorr[BGN_LPC_ORDER + 1];
WebRtc_Word16 pw16_tempVec[BGN_LPC_ORDER];
WebRtc_Word16 pw16_outVec[BGN_LPC_ORDER + 64];
WebRtc_Word16 pw16_rc[BGN_LPC_ORDER];
#endif
WebRtc_Word16 pw16_A[BGN_LPC_ORDER + 1];
WebRtc_Word32 w32_tmp;
WebRtc_Word16 *pw16_vec;
WebRtc_Word16 w16_maxSample;
WebRtc_Word16 w16_tmp, w16_tmp2;
WebRtc_Word16 w16_enSampleShift;
WebRtc_Word32 w32_en, w32_enBGN;
WebRtc_Word32 w32_enUpdateThreashold;
WebRtc_Word16 stability;
pw16_vec = inst->pw16_speechHistory + inst->w16_speechHistoryLen - w16_vecLen;
#ifdef NETEQ_VAD
if( !inst->VADInst.VADEnabled /* we are not using post-decode VAD */
|| inst->VADInst.VADDecision == 0 )
{ /* ... or, post-decode VAD says passive speaker */
#endif /* NETEQ_VAD */
/*Insert zeros to guarantee that boundary values do not distort autocorrelation */
WEBRTC_SPL_MEMCPY_W16(pw16_tempVec, pw16_vec - BGN_LPC_ORDER, BGN_LPC_ORDER);
WebRtcSpl_MemSetW16(pw16_vec - BGN_LPC_ORDER, 0, BGN_LPC_ORDER);
w16_maxSample = WebRtcSpl_MaxAbsValueW16(pw16_vec, w16_vecLen);
w16_tmp = 8 /* log2(w16_veclen) = 8 */
- WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_maxSample, w16_maxSample));
w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp);
WebRtcNetEQ_CrossCorr(pw32_autoCorr, pw16_vec, pw16_vec, w16_vecLen, BGN_LPC_ORDER + 1,
w16_tmp, -1);
/* Copy back data */
WEBRTC_SPL_MEMCPY_W16(pw16_vec - BGN_LPC_ORDER, pw16_tempVec, BGN_LPC_ORDER);
w16_enSampleShift = 8 - w16_tmp; /* Number of shifts to get energy/sample */
/* pw32_autoCorr[0]>>w16_enSampleShift */
w32_en = WEBRTC_SPL_RSHIFT_W32(pw32_autoCorr[0], w16_enSampleShift);
if ((w32_en < BGN_Inst->w32_energyUpdate
#ifdef NETEQ_VAD
/* post-decode VAD disabled and w32_en sufficiently low */
&& !inst->VADInst.VADEnabled)
/* ... or, post-decode VAD says passive speaker */
|| (inst->VADInst.VADEnabled && inst->VADInst.VADDecision == 0)
#else
) /* just close the extra parenthesis */
#endif /* NETEQ_VAD */
)
{
/* Generate LPC coefficients */
if (pw32_autoCorr[0] > 0)
{
/* regardless of whether the filter is actually updated or not,
update energy threshold levels, since we have in fact observed
a low energy signal */
if (w32_en < BGN_Inst->w32_energyUpdate)
{
/* Never get under 1.0 in average sample energy */
BGN_Inst->w32_energyUpdate = WEBRTC_SPL_MAX(w32_en, 1);
BGN_Inst->w32_energyUpdateLow = 0;
}
stability = WebRtcSpl_LevinsonDurbin(pw32_autoCorr, pw16_A, pw16_rc, BGN_LPC_ORDER);
/* Only update BGN if filter is stable */
if (stability != 1)
{
return;
}
}
else
{
/* Do not update */
return;
}
/* Generate the CNG gain factor by looking at the energy of the residual */
WebRtcSpl_FilterMAFastQ12(pw16_vec + w16_vecLen - 64, pw16_outVec, pw16_A,
BGN_LPC_ORDER + 1, 64);
w32_enBGN = WebRtcNetEQ_DotW16W16(pw16_outVec, pw16_outVec, 64, 0);
/* Dot product should never overflow since it is BGN and residual! */
/*
* Check spectral flatness
* Comparing the residual variance with the input signal variance tells
* if the spectrum is flat or not.
* (20*w32_enBGN) >= (w32_en<<6)
* Also ensure that the energy is non-zero.
*/
if ((WEBRTC_SPL_MUL_32_16(w32_enBGN, 20) >= WEBRTC_SPL_LSHIFT_W32(w32_en, 6))
&& (w32_en > 0))
{
/* spectrum is flat enough; save filter parameters */
WEBRTC_SPL_MEMCPY_W16(BGN_Inst->pw16_filter, pw16_A, BGN_LPC_ORDER+1);
WEBRTC_SPL_MEMCPY_W16(BGN_Inst->pw16_filterState,
pw16_vec + w16_vecLen - BGN_LPC_ORDER, BGN_LPC_ORDER);
/* Save energy level */
BGN_Inst->w32_energy = WEBRTC_SPL_MAX(w32_en, 1);
/* Update energy threshold levels */
/* Never get under 1.0 in average sample energy */
BGN_Inst->w32_energyUpdate = WEBRTC_SPL_MAX(w32_en, 1);
BGN_Inst->w32_energyUpdateLow = 0;
/* Normalize w32_enBGN to 29 or 30 bits before sqrt */
w16_tmp2 = WebRtcSpl_NormW32(w32_enBGN) - 1;
if (w16_tmp2 & 0x1)
{
w16_tmp2 -= 1; /* Even number of shifts required */
}
w32_enBGN = WEBRTC_SPL_SHIFT_W32(w32_enBGN, w16_tmp2);
/* Calculate scale and shift factor */
BGN_Inst->w16_scale = (WebRtc_Word16) WebRtcSpl_SqrtFloor(w32_enBGN);
BGN_Inst->w16_scaleShift = 13 + ((6 + w16_tmp2) >> 1); /* RANDN table is in Q13, */
/* 6=log2(64) */
BGN_Inst->w16_initialized = 1;
}
}
else
{
/*
* Will only happen if post-decode VAD is disabled and w32_en is not low enough.
* Increase the threshold for update so that it increases by a factor 4 in four
* seconds.
* energy = energy * 1.0035
*/
w32_tmp = WEBRTC_SPL_MUL_16_16_RSFT(NETEQFIX_BGNFRAQINCQ16,
BGN_Inst->w32_energyUpdateLow, 16);
w32_tmp += WEBRTC_SPL_MUL_16_16(NETEQFIX_BGNFRAQINCQ16,
(WebRtc_Word16)(BGN_Inst->w32_energyUpdate & 0xFF));
w32_tmp += (WEBRTC_SPL_MUL_16_16(NETEQFIX_BGNFRAQINCQ16,
(WebRtc_Word16)((BGN_Inst->w32_energyUpdate>>8) & 0xFF)) << 8);
BGN_Inst->w32_energyUpdateLow += w32_tmp;
BGN_Inst->w32_energyUpdate += WEBRTC_SPL_MUL_16_16(NETEQFIX_BGNFRAQINCQ16,
(WebRtc_Word16)(BGN_Inst->w32_energyUpdate>>16));
BGN_Inst->w32_energyUpdate += BGN_Inst->w32_energyUpdateLow >> 16;
BGN_Inst->w32_energyUpdateLow = (BGN_Inst->w32_energyUpdateLow & 0x0FFFF);
/* Update maximum energy */
/* Decrease by a factor 1/1024 each time */
BGN_Inst->w32_energyMax = BGN_Inst->w32_energyMax - (BGN_Inst->w32_energyMax >> 10);
if (w32_en > BGN_Inst->w32_energyMax)
{
BGN_Inst->w32_energyMax = w32_en;
}
/* Set update level to at the minimum 60.21dB lower then the maximum energy */
w32_enUpdateThreashold = (BGN_Inst->w32_energyMax + 524288) >> 20;
if (w32_enUpdateThreashold > BGN_Inst->w32_energyUpdate)
{
BGN_Inst->w32_energyUpdate = w32_enUpdateThreashold;
}
}
#ifdef NETEQ_VAD
} /* closing initial if-statement */
#endif /* NETEQ_VAD */
return;
}
#undef SCRATCH_PW32_AUTO_CORR
#undef SCRATCH_PW16_TEMP_VEC
#undef SCRATCH_PW16_RC
#undef SCRATCH_PW16_OUT_VEC