/* * 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_Sqrt(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