blob: 05956c2ba5fea031a7aa93116f465312c92a7bb3 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11/*
12 * This file contains the function for updating the background noise estimate.
13 */
14
15#include "dsp.h"
16
17#include "signal_processing_library.h"
18
19#include "dsp_helpfunctions.h"
20
21/* Scratch usage:
22 Designed for BGN_LPC_ORDER <= 10
23
24 Type Name size startpos endpos
25 WebRtc_Word32 pw32_autoCorr 22 0 21 (Length (BGN_LPC_ORDER + 1)*2)
26 WebRtc_Word16 pw16_tempVec 10 22 31 (Length BGN_LPC_ORDER)
27 WebRtc_Word16 pw16_rc 10 32 41 (Length BGN_LPC_ORDER)
28 WebRtc_Word16 pw16_outVec 74 0 73 (Length BGN_LPC_ORDER + 64)
29
30 Total: 74
31 */
32
33#if (BGN_LPC_ORDER > 10) && (defined SCRATCH)
34#error BGN_LPC_ORDER is too large for current scratch memory allocation
35#endif
36
37#define SCRATCH_PW32_AUTO_CORR 0
38#define SCRATCH_PW16_TEMP_VEC 22
39#define SCRATCH_PW16_RC 32
40#define SCRATCH_PW16_OUT_VEC 0
41
42#define NETEQFIX_BGNFRAQINCQ16 229 /* 0.0035 in Q16 */
43
44/****************************************************************************
45 * WebRtcNetEQ_BGNUpdate(...)
46 *
47 * This function updates the background noise parameter estimates.
48 *
49 * Input:
50 * - inst : NetEQ instance, where the speech history is stored.
51 * - scratchPtr : Pointer to scratch vector.
52 *
53 * Output:
54 * - inst : Updated information about the BGN characteristics.
55 *
56 * Return value : No return value
57 */
58
59void WebRtcNetEQ_BGNUpdate(
60#ifdef SCRATCH
61 DSPInst_t *inst, WebRtc_Word16 *pw16_scratchPtr
62#else
63 DSPInst_t *inst
64#endif
65)
66{
67 const WebRtc_Word16 w16_vecLen = 256;
68 BGNInst_t *BGN_Inst = &(inst->BGNInst);
69#ifdef SCRATCH
70 WebRtc_Word32 *pw32_autoCorr = (WebRtc_Word32*) (pw16_scratchPtr + SCRATCH_PW32_AUTO_CORR);
71 WebRtc_Word16 *pw16_tempVec = pw16_scratchPtr + SCRATCH_PW16_TEMP_VEC;
72 WebRtc_Word16 *pw16_rc = pw16_scratchPtr + SCRATCH_PW16_RC;
73 WebRtc_Word16 *pw16_outVec = pw16_scratchPtr + SCRATCH_PW16_OUT_VEC;
74#else
75 WebRtc_Word32 pw32_autoCorr[BGN_LPC_ORDER + 1];
76 WebRtc_Word16 pw16_tempVec[BGN_LPC_ORDER];
77 WebRtc_Word16 pw16_outVec[BGN_LPC_ORDER + 64];
78 WebRtc_Word16 pw16_rc[BGN_LPC_ORDER];
79#endif
80 WebRtc_Word16 pw16_A[BGN_LPC_ORDER + 1];
81 WebRtc_Word32 w32_tmp;
82 WebRtc_Word16 *pw16_vec;
83 WebRtc_Word16 w16_maxSample;
84 WebRtc_Word16 w16_tmp, w16_tmp2;
85 WebRtc_Word16 w16_enSampleShift;
86 WebRtc_Word32 w32_en, w32_enBGN;
87 WebRtc_Word32 w32_enUpdateThreashold;
88 WebRtc_Word16 stability;
89
90 pw16_vec = inst->pw16_speechHistory + inst->w16_speechHistoryLen - w16_vecLen;
91
92#ifdef NETEQ_VAD
93 if( !inst->VADInst.VADEnabled /* we are not using post-decode VAD */
94 || inst->VADInst.VADDecision == 0 )
95 { /* ... or, post-decode VAD says passive speaker */
96#endif /* NETEQ_VAD */
97
98 /*Insert zeros to guarantee that boundary values do not distort autocorrelation */
99 WEBRTC_SPL_MEMCPY_W16(pw16_tempVec, pw16_vec - BGN_LPC_ORDER, BGN_LPC_ORDER);
100 WebRtcSpl_MemSetW16(pw16_vec - BGN_LPC_ORDER, 0, BGN_LPC_ORDER);
101
102 w16_maxSample = WebRtcSpl_MaxAbsValueW16(pw16_vec, w16_vecLen);
103 w16_tmp = 8 /* log2(w16_veclen) = 8 */
104 - WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_maxSample, w16_maxSample));
105 w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp);
106
107 WebRtcNetEQ_CrossCorr(pw32_autoCorr, pw16_vec, pw16_vec, w16_vecLen, BGN_LPC_ORDER + 1,
108 w16_tmp, -1);
109
110 /* Copy back data */
111 WEBRTC_SPL_MEMCPY_W16(pw16_vec - BGN_LPC_ORDER, pw16_tempVec, BGN_LPC_ORDER);
112
113 w16_enSampleShift = 8 - w16_tmp; /* Number of shifts to get energy/sample */
114 /* pw32_autoCorr[0]>>w16_enSampleShift */
115 w32_en = WEBRTC_SPL_RSHIFT_W32(pw32_autoCorr[0], w16_enSampleShift);
116 if ((w32_en < BGN_Inst->w32_energyUpdate
117#ifdef NETEQ_VAD
118 /* post-decode VAD disabled and w32_en sufficiently low */
119 && !inst->VADInst.VADEnabled)
120 /* ... or, post-decode VAD says passive speaker */
121 || (inst->VADInst.VADEnabled && inst->VADInst.VADDecision == 0)
122#else
123 ) /* just close the extra parenthesis */
124#endif /* NETEQ_VAD */
125 )
126 {
127 /* Generate LPC coefficients */
128 if (pw32_autoCorr[0] > 0)
129 {
130 /* regardless of whether the filter is actually updated or not,
131 update energy threshold levels, since we have in fact observed
132 a low energy signal */
133 if (w32_en < BGN_Inst->w32_energyUpdate)
134 {
135 /* Never get under 1.0 in average sample energy */
136 BGN_Inst->w32_energyUpdate = WEBRTC_SPL_MAX(w32_en, 1);
137 BGN_Inst->w32_energyUpdateLow = 0;
138 }
139
140 stability = WebRtcSpl_LevinsonDurbin(pw32_autoCorr, pw16_A, pw16_rc, BGN_LPC_ORDER);
141 /* Only update BGN if filter is stable */
142 if (stability != 1)
143 {
144 return;
145 }
146 }
147 else
148 {
149 /* Do not update */
150 return;
151 }
152 /* Generate the CNG gain factor by looking at the energy of the residual */
153 WebRtcSpl_FilterMAFastQ12(pw16_vec + w16_vecLen - 64, pw16_outVec, pw16_A,
154 BGN_LPC_ORDER + 1, 64);
155 w32_enBGN = WebRtcNetEQ_DotW16W16(pw16_outVec, pw16_outVec, 64, 0);
156 /* Dot product should never overflow since it is BGN and residual! */
157
158 /*
159 * Check spectral flatness
160 * Comparing the residual variance with the input signal variance tells
161 * if the spectrum is flat or not.
162 * (20*w32_enBGN) >= (w32_en<<6)
163 * Also ensure that the energy is non-zero.
164 */
165 if ((WEBRTC_SPL_MUL_32_16(w32_enBGN, 20) >= WEBRTC_SPL_LSHIFT_W32(w32_en, 6))
166 && (w32_en > 0))
167 {
168 /* spectrum is flat enough; save filter parameters */
169
170 WEBRTC_SPL_MEMCPY_W16(BGN_Inst->pw16_filter, pw16_A, BGN_LPC_ORDER+1);
171 WEBRTC_SPL_MEMCPY_W16(BGN_Inst->pw16_filterState,
172 pw16_vec + w16_vecLen - BGN_LPC_ORDER, BGN_LPC_ORDER);
173
174 /* Save energy level */
175 BGN_Inst->w32_energy = WEBRTC_SPL_MAX(w32_en, 1);
176
177 /* Update energy threshold levels */
178 /* Never get under 1.0 in average sample energy */
179 BGN_Inst->w32_energyUpdate = WEBRTC_SPL_MAX(w32_en, 1);
180 BGN_Inst->w32_energyUpdateLow = 0;
181
182 /* Normalize w32_enBGN to 29 or 30 bits before sqrt */
183 w16_tmp2 = WebRtcSpl_NormW32(w32_enBGN) - 1;
184 if (w16_tmp2 & 0x1)
185 {
186 w16_tmp2 -= 1; /* Even number of shifts required */
187 }
188 w32_enBGN = WEBRTC_SPL_SHIFT_W32(w32_enBGN, w16_tmp2);
189
190 /* Calculate scale and shift factor */
henrik.lundin@webrtc.org9f710d02011-09-12 16:44:37 +0000191 BGN_Inst->w16_scale = (WebRtc_Word16) WebRtcSpl_SqrtFloor(w32_enBGN);
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 BGN_Inst->w16_scaleShift = 13 + ((6 + w16_tmp2) >> 1); /* RANDN table is in Q13, */
193 /* 6=log2(64) */
194
195 BGN_Inst->w16_initialized = 1;
196 }
197
198 }
199 else
200 {
201 /*
202 * Will only happen if post-decode VAD is disabled and w32_en is not low enough.
203 * Increase the threshold for update so that it increases by a factor 4 in four
204 * seconds.
205 * energy = energy * 1.0035
206 */
207 w32_tmp = WEBRTC_SPL_MUL_16_16_RSFT(NETEQFIX_BGNFRAQINCQ16,
208 BGN_Inst->w32_energyUpdateLow, 16);
209 w32_tmp += WEBRTC_SPL_MUL_16_16(NETEQFIX_BGNFRAQINCQ16,
210 (WebRtc_Word16)(BGN_Inst->w32_energyUpdate & 0xFF));
211 w32_tmp += (WEBRTC_SPL_MUL_16_16(NETEQFIX_BGNFRAQINCQ16,
212 (WebRtc_Word16)((BGN_Inst->w32_energyUpdate>>8) & 0xFF)) << 8);
213 BGN_Inst->w32_energyUpdateLow += w32_tmp;
214
215 BGN_Inst->w32_energyUpdate += WEBRTC_SPL_MUL_16_16(NETEQFIX_BGNFRAQINCQ16,
216 (WebRtc_Word16)(BGN_Inst->w32_energyUpdate>>16));
217 BGN_Inst->w32_energyUpdate += BGN_Inst->w32_energyUpdateLow >> 16;
218 BGN_Inst->w32_energyUpdateLow = (BGN_Inst->w32_energyUpdateLow & 0x0FFFF);
219
220 /* Update maximum energy */
221 /* Decrease by a factor 1/1024 each time */
222 BGN_Inst->w32_energyMax = BGN_Inst->w32_energyMax - (BGN_Inst->w32_energyMax >> 10);
223 if (w32_en > BGN_Inst->w32_energyMax)
224 {
225 BGN_Inst->w32_energyMax = w32_en;
226 }
227
228 /* Set update level to at the minimum 60.21dB lower then the maximum energy */
229 w32_enUpdateThreashold = (BGN_Inst->w32_energyMax + 524288) >> 20;
230 if (w32_enUpdateThreashold > BGN_Inst->w32_energyUpdate)
231 {
232 BGN_Inst->w32_energyUpdate = w32_enUpdateThreashold;
233 }
234 }
235
236#ifdef NETEQ_VAD
237} /* closing initial if-statement */
238#endif /* NETEQ_VAD */
239
240 return;
241}
242
243#undef SCRATCH_PW32_AUTO_CORR
244#undef SCRATCH_PW16_TEMP_VEC
245#undef SCRATCH_PW16_RC
246#undef SCRATCH_PW16_OUT_VEC
247