This changelist is basically a code cleanup and restructuring. Main things is that we now have a function for time to frequency transformation and the delay estimator is separated into its own struct and files.

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@300 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
bjornv@google.com 2011-08-04 07:16:54 +00:00
parent ce7c2a231e
commit 55ce2d8a25
5 changed files with 996 additions and 1026 deletions

View File

@ -31,6 +31,8 @@
'echo_control_mobile.c',
'aecm_core.c',
'aecm_core.h',
'aecm_delay_estimator.c',
'aecm_delay_estimator.h',
],
},
],

File diff suppressed because it is too large Load Diff

View File

@ -17,14 +17,8 @@
//#define AECM_WITH_ABS_APPROX
//#define AECM_SHORT // for 32 sample partition length (otherwise 64)
// TODO(bjornv): These defines will be removed in final version.
//#define STORE_CHANNEL_DATA
//#define VAD_DATA
#include "typedefs.h"
#include "signal_processing_library.h"
// TODO(bjornv): Will be removed in final version.
#include <stdio.h>
// Algorithm parameters
@ -127,29 +121,21 @@ typedef struct
WebRtc_UWord32 seed;
// Delay estimation variables
WebRtc_UWord16 medianYlogspec[PART_LEN1];
WebRtc_UWord16 medianXlogspec[PART_LEN1];
WebRtc_UWord16 medianBCount[MAX_DELAY];
WebRtc_UWord16 xfaHistory[PART_LEN1][MAX_DELAY];
WebRtc_Word16 delHistoryPos;
WebRtc_UWord32 bxHistory[MAX_DELAY];
void* delay_estimator;
WebRtc_UWord16 currentDelay;
WebRtc_UWord16 previousDelay;
WebRtc_Word16 delayAdjust;
WebRtc_Word16 nlpFlag;
WebRtc_Word16 fixedDelay;
WebRtc_UWord32 totCount;
WebRtc_Word16 xfaQDomainBuf[MAX_DELAY];
WebRtc_Word16 dfaCleanQDomain;
WebRtc_Word16 dfaCleanQDomainOld;
WebRtc_Word16 dfaNoisyQDomain;
WebRtc_Word16 dfaNoisyQDomainOld;
WebRtc_Word16 nearLogEnergy[MAX_BUF_LEN];
WebRtc_Word16 farLogEnergy[MAX_BUF_LEN];
WebRtc_Word16 farLogEnergy;
WebRtc_Word16 echoAdaptLogEnergy[MAX_BUF_LEN];
WebRtc_Word16 echoStoredLogEnergy[MAX_BUF_LEN];
@ -176,43 +162,16 @@ typedef struct
WebRtc_Word16 currentVADValue;
WebRtc_Word16 vadUpdateCount;
WebRtc_Word16 delayHistogram[MAX_DELAY];
WebRtc_Word16 delayVadCount;
WebRtc_Word16 maxDelayHistIdx;
WebRtc_Word16 lastMinPos;
WebRtc_Word16 startupState;
WebRtc_Word16 mseChannelCount;
WebRtc_Word16 delayCount;
WebRtc_Word16 newDelayCorrData;
WebRtc_Word16 lastDelayUpdateCount;
WebRtc_Word16 delayCorrelation[CORR_BUF_LEN];
WebRtc_Word16 supGain;
WebRtc_Word16 supGainOld;
WebRtc_Word16 delayOffsetFlag;
WebRtc_Word16 supGainErrParamA;
WebRtc_Word16 supGainErrParamD;
WebRtc_Word16 supGainErrParamDiffAB;
WebRtc_Word16 supGainErrParamDiffBD;
// TODO(bjornv): Will be removed after final version has been committed.
#ifdef VAD_DATA
FILE *vad_file;
FILE *delay_file;
FILE *far_file;
FILE *far_cur_file;
FILE *far_min_file;
FILE *far_max_file;
FILE *far_vad_file;
#endif
// TODO(bjornv): Will be removed after final version has been committed.
#ifdef STORE_CHANNEL_DATA
FILE *channel_file;
FILE *channel_file_init;
#endif
#ifdef AEC_DEBUG
FILE *farFile;
FILE *nearFile;
@ -266,7 +225,7 @@ int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq);
//
int WebRtcAecm_FreeCore(AecmCore_t *aecm);
int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag, int delayOffsetFlag);
int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag);
///////////////////////////////////////////////////////////////////////////////////////////////
// WebRtcAecm_InitEchoPathCore(...)

View File

@ -0,0 +1,550 @@
/*
* 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.
*/
#include "aecm_delay_estimator.h"
#include <assert.h>
#include <stdlib.h>
#include "signal_processing_library.h"
#include "typedefs.h"
typedef struct
{
// Pointers to mean values of spectrum and bit counts
WebRtc_Word32* mean_far_spectrum;
WebRtc_Word32* mean_near_spectrum;
WebRtc_Word32* mean_bit_counts;
// Binary history variables
WebRtc_UWord32* binary_far_history;
// Far end history variables
WebRtc_UWord16* far_history;
int far_history_position;
WebRtc_Word16* far_q_domains;
// Delay histogram variables
WebRtc_Word16* delay_histogram;
WebRtc_Word16 vad_counter;
// Delay memory
int last_delay;
// Buffer size parameters
int history_size;
int spectrum_size;
} DelayEstimator_t;
// Only bit |kBandFirst| through bit |kBandLast| are processed
// |kBandFirst| - |kBandLast| must be < 32
static const int kBandFirst = 12;
static const int kBandLast = 43;
static __inline WebRtc_UWord32 SetBit(WebRtc_UWord32 in,
WebRtc_Word32 pos)
{
WebRtc_UWord32 mask = WEBRTC_SPL_LSHIFT_W32(1, pos);
WebRtc_UWord32 out = (in | mask);
return out;
}
// Compares the binary vector |binary_vector| with all rows of the binary
// matrix |binary_matrix| and counts per row the number of times they have the
// same value.
// Input:
// - binary_vector : binary "vector" stored in a long
// - binary_matrix : binary "matrix" stored as a vector of long
// - matrix_size : size of binary "matrix"
// Output:
// - bit_counts : "Vector" stored as a long, containing for each
// row the number of times the matrix row and the
// input vector have the same value
//
static void BitCountComparison(const WebRtc_UWord32 binary_vector,
const WebRtc_UWord32* binary_matrix,
int matrix_size,
WebRtc_Word32* bit_counts)
{
int n = 0;
WebRtc_UWord32 a = binary_vector;
register WebRtc_UWord32 tmp;
// compare binary vector |binary_vector| with all rows of the binary matrix
// |binary_matrix|
for (; n < matrix_size; n++)
{
a = (binary_vector ^ binary_matrix[n]);
// Returns bit counts in tmp
tmp = a - ((a >> 1) & 033333333333) - ((a >> 2) & 011111111111);
tmp = ((tmp + (tmp >> 3)) & 030707070707);
tmp = (tmp + (tmp >> 6));
tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077;
bit_counts[n] = (WebRtc_Word32)tmp;
}
}
// Computes the binary spectrum by comparing the input |spectrum| with a
// |threshold_spectrum|.
//
// Input:
// - spectrum : Spectrum of which the binary spectrum should
// be calculated.
// - threshold_spectrum : Threshold spectrum with which the input
// spectrum is compared.
// Return:
// - out : Binary spectrum
//
static WebRtc_UWord32 GetBinarySpectrum(WebRtc_Word32* spectrum,
WebRtc_Word32* threshold_spectrum)
{
int k = kBandFirst;
WebRtc_UWord32 out = 0;
for (; k <= kBandLast; k++)
{
if (spectrum[k] > threshold_spectrum[k])
{
out = SetBit(out, k - kBandFirst);
}
}
return out;
}
// Calculates the mean recursively.
//
// Input:
// - new_value : new additional value
// - factor : factor for smoothing
//
// Input/Output:
// - mean_value : pointer to the mean value that should be updated
//
static void MeanEstimator(const WebRtc_Word32 new_value,
int factor,
WebRtc_Word32* mean_value)
{
WebRtc_Word32 mean_new = *mean_value;
WebRtc_Word32 diff = new_value - mean_new;
// mean_new = mean_value + ((new_value - mean_value) >> factor);
if (diff < 0)
{
diff = -WEBRTC_SPL_RSHIFT_W32(-diff, factor);
}
else
{
diff = WEBRTC_SPL_RSHIFT_W32(diff, factor);
}
mean_new += diff;
*mean_value = mean_new;
}
// Moves the pointer to the next entry and inserts new far end spectrum and
// corresponding Q-domain in its buffer.
//
// Input:
// - handle : Pointer to the delay estimation instance
// - far_spectrum : Pointer to the far end spectrum
// - far_q : Q-domain of far end spectrum
//
static void UpdateFarHistory(DelayEstimator_t* self,
WebRtc_UWord16* far_spectrum,
WebRtc_Word16 far_q)
{
// Get new buffer position
self->far_history_position++;
if (self->far_history_position >= self->history_size)
{
self->far_history_position = 0;
}
// Update Q-domain buffer
self->far_q_domains[self->far_history_position] = far_q;
// Update far end spectrum buffer
memcpy(&(self->far_history[self->far_history_position * self->spectrum_size]),
far_spectrum,
sizeof(WebRtc_UWord16) * self->spectrum_size);
}
int WebRtcAecm_FreeDelayEstimator(void* handle)
{
DelayEstimator_t* self = (DelayEstimator_t*)handle;
if (self == NULL)
{
return -1;
}
if (self->mean_far_spectrum != NULL)
{
free(self->mean_far_spectrum);
self->mean_far_spectrum = NULL;
}
if (self->mean_near_spectrum != NULL)
{
free(self->mean_near_spectrum);
self->mean_near_spectrum = NULL;
}
if (self->far_history != NULL)
{
free(self->far_history);
self->far_history = NULL;
}
if (self->mean_bit_counts != NULL)
{
free(self->mean_bit_counts);
self->mean_bit_counts = NULL;
}
if (self->binary_far_history != NULL)
{
free(self->binary_far_history);
self->binary_far_history = NULL;
}
if (self->far_q_domains != NULL)
{
free(self->far_q_domains);
self->far_q_domains = NULL;
}
if (self->delay_histogram != NULL)
{
free(self->delay_histogram);
self->delay_histogram = NULL;
}
free(self);
return 0;
}
int WebRtcAecm_CreateDelayEstimator(void** handle,
int spectrum_size,
int history_size)
{
// Check if the sub band used in the delay estimation is small enough to
// fit in a Word32.
assert(kBandLast - kBandFirst < 32);
DelayEstimator_t *self = NULL;
if (spectrum_size < kBandLast)
{
return -1;
}
if (history_size < 0)
{
return -1;
}
self = malloc(sizeof(DelayEstimator_t));
*handle = self;
if (self == NULL)
{
return -1;
}
self->mean_far_spectrum = NULL;
self->mean_near_spectrum = NULL;
self->far_history = NULL;
self->mean_bit_counts = NULL;
self->binary_far_history = NULL;
self->far_q_domains = NULL;
self->delay_histogram = NULL;
// Allocate memory for spectrum buffers
self->mean_far_spectrum = malloc(spectrum_size * sizeof(WebRtc_Word32));
if (self->mean_far_spectrum == NULL)
{
WebRtcAecm_FreeDelayEstimator(self);
self = NULL;
return -1;
}
self->mean_near_spectrum = malloc(spectrum_size * sizeof(WebRtc_Word32));
if (self->mean_near_spectrum == NULL)
{
WebRtcAecm_FreeDelayEstimator(self);
self = NULL;
return -1;
}
// Allocate memory for history buffers
self->far_history = malloc(spectrum_size * history_size *
sizeof(WebRtc_UWord16));
if (self->far_history == NULL)
{
WebRtcAecm_FreeDelayEstimator(self);
self = NULL;
return -1;
}
self->mean_bit_counts = malloc(history_size * sizeof(WebRtc_Word32));
if (self->mean_bit_counts == NULL)
{
WebRtcAecm_FreeDelayEstimator(self);
self = NULL;
return -1;
}
self->binary_far_history = malloc(history_size * sizeof(WebRtc_UWord32));
if (self->binary_far_history == NULL)
{
WebRtcAecm_FreeDelayEstimator(self);
self = NULL;
return -1;
}
self->far_q_domains = malloc(history_size * sizeof(WebRtc_Word16));
if (self->far_q_domains == NULL)
{
WebRtcAecm_FreeDelayEstimator(self);
self = NULL;
return -1;
}
self->delay_histogram = malloc(history_size * sizeof(WebRtc_Word16));
if (self->delay_histogram == NULL)
{
WebRtcAecm_FreeDelayEstimator(self);
self = NULL;
return -1;
}
self->spectrum_size = spectrum_size;
self->history_size = history_size;
return 0;
}
int WebRtcAecm_InitDelayEstimator(void* handle)
{
DelayEstimator_t* self = (DelayEstimator_t*)handle;
if (self == NULL)
{
return -1;
}
// Set averaged far and near end spectra to zero
memset(self->mean_far_spectrum,
0,
sizeof(WebRtc_Word32) * self->spectrum_size);
memset(self->mean_near_spectrum,
0,
sizeof(WebRtc_Word32) * self->spectrum_size);
// Set averaged bit counts to zero
memset(self->mean_bit_counts,
0,
sizeof(WebRtc_Word32) * self->history_size);
// Set far end histories to zero
memset(self->binary_far_history,
0,
sizeof(WebRtc_UWord32) * self->history_size);
memset(self->far_history,
0,
sizeof(WebRtc_UWord16) * self->spectrum_size *
self->history_size);
memset(self->far_q_domains,
0,
sizeof(WebRtc_Word16) * self->history_size);
self->far_history_position = self->history_size;
// Set delay histogram to zero
memset(self->delay_histogram,
0,
sizeof(WebRtc_Word16) * self->history_size);
// Set VAD counter to zero
self->vad_counter = 0;
// Set delay memory to zero
self->last_delay = 0;
return 0;
}
int WebRtcAecm_DelayEstimatorProcess(void* handle,
WebRtc_UWord16* far_spectrum,
WebRtc_UWord16* near_spectrum,
int spectrum_size,
WebRtc_Word16 far_q,
WebRtc_Word16 vad_value)
{
DelayEstimator_t* self = (DelayEstimator_t*)handle;
WebRtc_UWord32 bxspectrum, byspectrum;
int i;
WebRtc_Word32 dtmp1;
WebRtc_Word16 maxHistLvl = 0;
WebRtc_Word16 minpos = -1;
const int kVadCountThreshold = 25;
const int kMaxHistogram = 600;
if (self == NULL)
{
return -1;
}
WebRtc_Word32 bit_counts[self->history_size];
WebRtc_Word32 far_spectrum_32[self->spectrum_size];
WebRtc_Word32 near_spectrum_32[self->spectrum_size];
if (spectrum_size != self->spectrum_size)
{
// Data sizes don't match
return -1;
}
if (far_q > 15)
{
// If far_Q is larger than 15 we can not guarantee no wrap around
return -1;
}
// Update far end history
UpdateFarHistory(self, far_spectrum, far_q);
// Update the far and near end means
for (i = 0; i < self->spectrum_size; i++)
{
far_spectrum_32[i] = (WebRtc_Word32)far_spectrum[i];
MeanEstimator(far_spectrum_32[i], 6, &(self->mean_far_spectrum[i]));
near_spectrum_32[i] = (WebRtc_Word32)near_spectrum[i];
MeanEstimator(near_spectrum_32[i], 6, &(self->mean_near_spectrum[i]));
}
// Shift binary spectrum history
memmove(&(self->binary_far_history[1]),
&(self->binary_far_history[0]),
(self->history_size - 1) * sizeof(WebRtc_UWord32));
// Get binary spectra
bxspectrum = GetBinarySpectrum(far_spectrum_32, self->mean_far_spectrum);
byspectrum = GetBinarySpectrum(near_spectrum_32, self->mean_near_spectrum);
// Insert new binary spectrum
self->binary_far_history[0] = bxspectrum;
// Compare with delayed spectra
BitCountComparison(byspectrum,
self->binary_far_history,
self->history_size,
bit_counts);
// Smooth bit count curve
for (i = 0; i < self->history_size; i++)
{
// Update sum
// |bit_counts| is constrained to [0, 32], meaning we can smooth with a
// factor up to 2^26. We use Q9.
dtmp1 = WEBRTC_SPL_LSHIFT_W32(bit_counts[i], 9); // Q9
MeanEstimator(dtmp1, 9, &(self->mean_bit_counts[i]));
}
// Find minimum position of bit count curve
minpos = WebRtcSpl_MinIndexW32(self->mean_bit_counts, self->history_size);
// If the farend has been active sufficiently long, begin accumulating a
// histogram of the minimum positions. Search for the maximum bin to
// determine the delay.
if (vad_value == 1)
{
if (self->vad_counter >= kVadCountThreshold)
{
// Increment the histogram at the current minimum position.
if (self->delay_histogram[minpos] < kMaxHistogram)
{
self->delay_histogram[minpos] += 3;
}
#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
// Decrement the entire histogram.
// Select the histogram index corresponding to the maximum bin as
// the delay.
self->last_delay = 0;
for (i = 0; i < self->history_size; i++)
{
if (self->delay_histogram[i] > 0)
{
self->delay_histogram[i]--;
}
if (self->delay_histogram[i] > maxHistLvl)
{
maxHistLvl = self->delay_histogram[i];
self->last_delay = i;
}
}
#else
self->last_delay = 0;
for (i = 0; i < self->history_size; i++)
{
WebRtc_Word16 tempVar = self->delay_histogram[i];
// Decrement the entire histogram.
if (tempVar > 0)
{
tempVar--;
self->delay_histogram[i] = tempVar;
// Select the histogram index corresponding to the maximum
// bin as the delay.
if (tempVar > maxHistLvl)
{
maxHistLvl = tempVar;
self->last_delay = i;
}
}
}
#endif
} else
{
self->vad_counter++;
}
} else
{
self->vad_counter = 0;
}
return self->last_delay;
}
const WebRtc_UWord16* WebRtcAecm_GetAlignedFarend(void* handle,
WebRtc_Word16* far_q)
{
DelayEstimator_t* self = (DelayEstimator_t*)handle;
int buffer_position = 0;
if (self == NULL)
{
return NULL;
}
// Get buffer position
buffer_position = self->far_history_position - self->last_delay;
if (buffer_position < 0)
{
buffer_position += self->history_size;
}
// Get Q-domain
*far_q = self->far_q_domains[buffer_position];
// Return far end spectrum
return (self->far_history + (buffer_position * self->spectrum_size));
}
int WebRtcAecm_GetLastDelay(void* handle)
{
DelayEstimator_t* self = (DelayEstimator_t*)handle;
if (self == NULL)
{
return -1;
}
// Return last calculated delay
return self->last_delay;
}

View File

@ -0,0 +1,110 @@
/*
* 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.
*/
// Performs delay estimation on a block by block basis
// The return value is 0 - OK and -1 - Error, unless otherwise stated.
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_DELAY_ESTIMATOR_H_
#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_DELAY_ESTIMATOR_H_
#include "typedefs.h"
// Releases the memory allocated by WebRtcAecm_CreateDelayEstimator(...)
// Input:
// - handle : Pointer to the delay estimation instance
//
int WebRtcAecm_FreeDelayEstimator(void* handle);
// Allocates the memory needed by the delay estimation. The memory needs to be
// initialized separately using the WebRtcAecm_InitDelayEstimator(...) function.
//
// Input:
// - handle : Instance that should be created
// - spectrum_size : Size of the spectrum used both in far end and near
// end. Used to allocate memory for spectrum specific
// buffers.
// - history_size : Size of the far end history used to estimate the
// delay from. Used to allocate memory for history
// specific buffers.
//
// Output:
// - handle : Created instance
//
int WebRtcAecm_CreateDelayEstimator(void** handle,
int spectrum_size,
int history_size);
// Initializes the delay estimation instance created with
// WebRtcAecm_CreateDelayEstimator(...)
// Input:
// - handle : Pointer to the delay estimation instance
//
// Output:
// - handle : Initialized instance
//
int WebRtcAecm_InitDelayEstimator(void* handle);
// Estimates and returns the delay between the far end and near end blocks.
// Input:
// - handle : Pointer to the delay estimation instance
// - far_spectrum : Pointer to the far end spectrum data
// - near_spectrum : Pointer to the near end spectrum data of the current
// block
// - spectrum_size : The size of the data arrays (same for both far and
// near end)
// - far_q : The Q-domain of the far end data
// - vad_value : The VAD decision of the current block
//
// Output:
// - handle : Updated instance
//
// Return value:
// - delay : >= 0 - Calculated delay value
// -1 - Error
//
int WebRtcAecm_DelayEstimatorProcess(void* handle,
WebRtc_UWord16* far_spectrum,
WebRtc_UWord16* near_spectrum,
int spectrum_size,
WebRtc_Word16 far_q,
WebRtc_Word16 vad_value);
// Returns a pointer to the far end spectrum aligned to current near end
// spectrum. The function WebRtcAecm_DelayEstimatorProcess(...) should
// have been called before WebRtcAecm_GetAlignedFarend(...). Otherwise, you get
// the pointer to the previous frame. The memory is only valid until the next
// call of WebRtcAecm_DelayEstimatorProcess(...).
//
// Inputs:
// - handle : Pointer to the delay estimation instance
//
// Output:
// - far_q : The Q-domain of the aligned far end spectrum
//
// Return value:
// - far_spectrum : Pointer to the aligned far end spectrum
// NULL - Error
//
const WebRtc_UWord16* WebRtcAecm_GetAlignedFarend(void* handle,
WebRtc_Word16* far_q);
// Returns the last calculated delay updated by the function
// WebRtcAecm_DelayEstimatorProcess(...)
//
// Inputs:
// - handle : Pointer to the delay estimation instance
//
// Return value:
// - delay : >= 0 - Last calculated delay value
// -1 - Error
//
int WebRtcAecm_GetLastDelay(void* handle);
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_DELAY_ESTIMATOR_H_