Changes to comfort noise generation; 1) faster convergence initially, 2) lower startup shape, 3) few code optimizations, 4) removed a bug that could cause noise estimate to go to zero, 5) removed a bug that could cause noise estimate to never recover from low values.

Review URL: http://webrtc-codereview.appspot.com/73001

git-svn-id: http://webrtc.googlecode.com/svn/trunk@222 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
bjornv@google.com 2011-07-18 10:07:45 +00:00
parent 61b100d3cc
commit 521d5932cb
2 changed files with 69 additions and 57 deletions

View File

@ -99,6 +99,9 @@ static const WebRtc_Word16 kChannelStored16kHz[PART_LEN1] = {
3153 3153
}; };
static const WebRtc_Word16 kNoiseEstQDomain = 15;
static const WebRtc_Word16 kNoiseEstIncCount = 5;
#ifdef ARM_WINM_LOG #ifdef ARM_WINM_LOG
HANDLE logFile = NULL; HANDLE logFile = NULL;
#endif #endif
@ -288,8 +291,9 @@ void WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const WebRtc_Word16* echo_pat
int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq) int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq)
{ {
int retVal = 0; int retVal = 0;
WebRtc_Word16 i; int i = 0;
WebRtc_Word16 tmp16; WebRtc_Word32 tmp32 = PART_LEN1 * PART_LEN1;
WebRtc_Word16 tmp16 = PART_LEN1;
if (samplingFreq != 8000 && samplingFreq != 16000) if (samplingFreq != 8000 && samplingFreq != 16000)
{ {
@ -361,47 +365,19 @@ int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq)
aecm->cngMode = AecmTrue; aecm->cngMode = AecmTrue;
// Increase the noise Q domain with increasing frequency, to correspond to the memset(aecm->noiseEstTooLowCtr, 0, sizeof(int) * PART_LEN1);
// expected energy levels. memset(aecm->noiseEstTooHighCtr, 0, sizeof(int) * PART_LEN1);
// Also shape the initial noise level with this consideration. // Shape the initial noise level to an approximate pink noise.
#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT) for (i = 0; i < (PART_LEN1 >> 1) - 1; i++)
for (i = 0; i < PART_LEN1; i++)
{ {
if (i < PART_LEN1 >> 2) aecm->noiseEst[i] = (tmp32 << 8);
{ tmp16--;
aecm->noiseEstQDomain[i] = 10; tmp32 -= (WebRtc_Word32)((tmp16 << 1) + 1);
tmp16 = PART_LEN1 - i;
aecm->noiseEst[i] = (tmp16 * tmp16) << 4;
} else if (i < PART_LEN1 >> 1)
{
aecm->noiseEstQDomain[i] = 11;
tmp16 = PART_LEN1 - i;
aecm->noiseEst[i] = ((tmp16 * tmp16) << 4) << 1;
} else
{
aecm->noiseEstQDomain[i] = 12;
aecm->noiseEst[i] = aecm->noiseEst[(PART_LEN1 >> 1) - 1] << 1;
}
}
#else
for (i = 0; i < PART_LEN1 >> 2; i++)
{
aecm->noiseEstQDomain[i] = 10;
tmp16 = PART_LEN1 - i;
aecm->noiseEst[i] = (tmp16 * tmp16) << 4;
}
for (; i < PART_LEN1 >> 1; i++)
{
aecm->noiseEstQDomain[i] = 11;
tmp16 = PART_LEN1 - i;
aecm->noiseEst[i] = ((tmp16 * tmp16) << 4) << 1;
} }
for (; i < PART_LEN1; i++) for (; i < PART_LEN1; i++)
{ {
aecm->noiseEstQDomain[i] = 12; aecm->noiseEst[i] = (tmp32 << 8);
aecm->noiseEst[i] = aecm->noiseEst[(PART_LEN1 >> 1) - 1] << 1;
} }
#endif
aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX; aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN; aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
@ -2407,19 +2383,22 @@ static void WebRtcAecm_ComfortNoise(AecmCore_t * const aecm, const WebRtc_UWord1
WebRtc_Word16 randW16[PART_LEN]; WebRtc_Word16 randW16[PART_LEN];
WebRtc_Word16 uReal[PART_LEN1]; WebRtc_Word16 uReal[PART_LEN1];
WebRtc_Word16 uImag[PART_LEN1]; WebRtc_Word16 uImag[PART_LEN1];
WebRtc_Word32 outLShift32[PART_LEN1]; WebRtc_Word32 outLShift32;
WebRtc_Word16 noiseRShift16[PART_LEN1]; WebRtc_Word16 noiseRShift16[PART_LEN1];
WebRtc_Word16 shiftFromNearToNoise[PART_LEN1]; WebRtc_Word16 shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain;
WebRtc_Word16 minTrackShift; WebRtc_Word16 minTrackShift;
WebRtc_Word32 upper32; WebRtc_Word32 upper32;
WebRtc_Word32 lower32; WebRtc_Word32 lower32;
assert(shiftFromNearToNoise >= 0);
assert(shiftFromNearToNoise < 16);
if (aecm->noiseEstCtr < 100) if (aecm->noiseEstCtr < 100)
{ {
// Track the minimum more quickly initially. // Track the minimum more quickly initially.
aecm->noiseEstCtr++; aecm->noiseEstCtr++;
minTrackShift = 7; minTrackShift = 6;
} else } else
{ {
minTrackShift = 9; minTrackShift = 9;
@ -2428,40 +2407,72 @@ static void WebRtcAecm_ComfortNoise(AecmCore_t * const aecm, const WebRtc_UWord1
// Estimate noise power. // Estimate noise power.
for (i = 0; i < PART_LEN1; i++) for (i = 0; i < PART_LEN1; i++)
{ {
shiftFromNearToNoise[i] = aecm->noiseEstQDomain[i] - aecm->dfaCleanQDomain;
// Shift to the noise domain. // Shift to the noise domain.
tmp32 = (WebRtc_Word32)dfa[i]; tmp32 = (WebRtc_Word32)dfa[i];
outLShift32[i] = WEBRTC_SPL_SHIFT_W32(tmp32, shiftFromNearToNoise[i]); outLShift32 = WEBRTC_SPL_LSHIFT_W32(tmp32, shiftFromNearToNoise);
if (outLShift32[i] < aecm->noiseEst[i]) if (outLShift32 < aecm->noiseEst[i])
{ {
// Reset "too low" counter
aecm->noiseEstTooLowCtr[i] = 0;
// Track the minimum. // Track the minimum.
aecm->noiseEst[i] += ((outLShift32[i] - aecm->noiseEst[i]) >> minTrackShift); if (aecm->noiseEst[i] < (1 << minTrackShift))
{
// For small values, decrease noiseEst[i] every
// |kNoiseEstIncCount| block. The regular approach below can not
// go further down due to truncation.
aecm->noiseEstTooHighCtr[i]++;
if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount)
{
aecm->noiseEst[i]--;
aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter
}
}
else
{
aecm->noiseEst[i] -= ((aecm->noiseEst[i] - outLShift32) >> minTrackShift);
}
} else } else
{ {
// Reset "too high" counter
aecm->noiseEstTooHighCtr[i] = 0;
// Ramp slowly upwards until we hit the minimum again. // Ramp slowly upwards until we hit the minimum again.
if ((aecm->noiseEst[i] >> 19) > 0)
// Avoid overflow.
if (aecm->noiseEst[i] < 2146435583)
{ {
// Store the fractional portion. // Avoid overflow.
upper32 = (aecm->noiseEst[i] & 0xffff0000) >> 16; // Multiplication with 2049 will cause wrap around. Scale
lower32 = aecm->noiseEst[i] & 0x0000ffff; // down first and then multiply
upper32 = ((upper32 * 2049) >> 11); aecm->noiseEst[i] >>= 11;
lower32 = ((lower32 * 2049) >> 11); aecm->noiseEst[i] *= 2049;
aecm->noiseEst[i] = WEBRTC_SPL_ADD_SAT_W32(upper32 << 16, lower32); }
else if ((aecm->noiseEst[i] >> 11) > 0)
{
// Large enough for relative increase
aecm->noiseEst[i] *= 2049;
aecm->noiseEst[i] >>= 11;
}
else
{
// Make incremental increases based on size every
// |kNoiseEstIncCount| block
aecm->noiseEstTooLowCtr[i]++;
if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount)
{
aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1;
aecm->noiseEstTooLowCtr[i] = 0; // Reset counter
}
} }
} }
} }
for (i = 0; i < PART_LEN1; i++) for (i = 0; i < PART_LEN1; i++)
{ {
tmp32 = WEBRTC_SPL_SHIFT_W32(aecm->noiseEst[i], -shiftFromNearToNoise[i]); tmp32 = WEBRTC_SPL_RSHIFT_W32(aecm->noiseEst[i], shiftFromNearToNoise);
if (tmp32 > 32767) if (tmp32 > 32767)
{ {
tmp32 = 32767; tmp32 = 32767;
aecm->noiseEst[i] = WEBRTC_SPL_SHIFT_W32(tmp32, shiftFromNearToNoise[i]); aecm->noiseEst[i] = WEBRTC_SPL_LSHIFT_W32(tmp32, shiftFromNearToNoise);
} }
noiseRShift16[i] = (WebRtc_Word16)tmp32; noiseRShift16[i] = (WebRtc_Word16)tmp32;

View File

@ -159,7 +159,8 @@ typedef struct
WebRtc_Word32 echoFilt[PART_LEN1]; WebRtc_Word32 echoFilt[PART_LEN1];
WebRtc_Word16 nearFilt[PART_LEN1]; WebRtc_Word16 nearFilt[PART_LEN1];
WebRtc_Word32 noiseEst[PART_LEN1]; WebRtc_Word32 noiseEst[PART_LEN1];
WebRtc_Word16 noiseEstQDomain[PART_LEN1]; int noiseEstTooLowCtr[PART_LEN1];
int noiseEstTooHighCtr[PART_LEN1];
WebRtc_Word16 noiseEstCtr; WebRtc_Word16 noiseEstCtr;
WebRtc_Word16 cngMode; WebRtc_Word16 cngMode;