Corresponds to upstream commit 524e9b043e7e86fd72353b987c9d5f6a1ebf83e1 Update notes: * Moved src/ to webrtc/ to easily diff against the third_party/webrtc in the chromium tree * ARM/NEON/MIPS support is not yet hooked up * Tests have not been copied
289 lines
8.3 KiB
C
289 lines
8.3 KiB
C
/*
|
|
* 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 "delay_estimator_float.h"
|
|
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "delay_estimator.h"
|
|
#include "signal_processing_library.h"
|
|
|
|
typedef struct {
|
|
// Fixed point spectra
|
|
uint16_t* far_spectrum_u16;
|
|
uint16_t* near_spectrum_u16;
|
|
|
|
// Far end history variables
|
|
float* far_history;
|
|
int far_history_pos;
|
|
|
|
// Fixed point delay estimator
|
|
void* fixed_handle;
|
|
|
|
} DelayEstimatorFloat_t;
|
|
|
|
// Moves the pointer to the next buffer entry and inserts new far end spectrum.
|
|
// Only used when alignment is enabled.
|
|
//
|
|
// Inputs:
|
|
// - self : Pointer to the delay estimation instance
|
|
// - far_spectrum : Pointer to the far end spectrum
|
|
//
|
|
static void UpdateFarHistory(DelayEstimatorFloat_t* self, float* far_spectrum) {
|
|
int spectrum_size = WebRtc_spectrum_size(self->fixed_handle);
|
|
// Get new buffer position
|
|
self->far_history_pos++;
|
|
if (self->far_history_pos >= WebRtc_history_size(self->fixed_handle)) {
|
|
self->far_history_pos = 0;
|
|
}
|
|
// Update far end spectrum buffer
|
|
memcpy(&(self->far_history[self->far_history_pos * spectrum_size]),
|
|
far_spectrum,
|
|
sizeof(float) * spectrum_size);
|
|
}
|
|
|
|
int WebRtc_FreeDelayEstimatorFloat(void* handle) {
|
|
DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle;
|
|
|
|
if (self == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (self->far_history != NULL) {
|
|
free(self->far_history);
|
|
self->far_history = NULL;
|
|
}
|
|
if (self->far_spectrum_u16 != NULL) {
|
|
free(self->far_spectrum_u16);
|
|
self->far_spectrum_u16 = NULL;
|
|
}
|
|
if (self->near_spectrum_u16 != NULL) {
|
|
free(self->near_spectrum_u16);
|
|
self->near_spectrum_u16 = NULL;
|
|
}
|
|
|
|
WebRtc_FreeDelayEstimator(self->fixed_handle);
|
|
free(self);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int WebRtc_CreateDelayEstimatorFloat(void** handle,
|
|
int spectrum_size,
|
|
int history_size,
|
|
int enable_alignment) {
|
|
DelayEstimatorFloat_t *self = NULL;
|
|
if ((enable_alignment != 0) && (enable_alignment != 1)) {
|
|
return -1;
|
|
}
|
|
|
|
self = malloc(sizeof(DelayEstimatorFloat_t));
|
|
*handle = self;
|
|
if (self == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
self->far_history = NULL;
|
|
self->far_spectrum_u16 = NULL;
|
|
self->near_spectrum_u16 = NULL;
|
|
|
|
// Create fixed point core delay estimator
|
|
if (WebRtc_CreateDelayEstimator(&self->fixed_handle,
|
|
spectrum_size,
|
|
history_size,
|
|
enable_alignment) != 0) {
|
|
WebRtc_FreeDelayEstimatorFloat(self);
|
|
self = NULL;
|
|
return -1;
|
|
}
|
|
|
|
// Allocate memory for far history buffer
|
|
if (enable_alignment) {
|
|
self->far_history = malloc(spectrum_size * history_size * sizeof(float));
|
|
if (self->far_history == NULL) {
|
|
WebRtc_FreeDelayEstimatorFloat(self);
|
|
self = NULL;
|
|
return -1;
|
|
}
|
|
}
|
|
// Allocate memory for fixed point spectra
|
|
self->far_spectrum_u16 = malloc(spectrum_size * sizeof(uint16_t));
|
|
if (self->far_spectrum_u16 == NULL) {
|
|
WebRtc_FreeDelayEstimatorFloat(self);
|
|
self = NULL;
|
|
return -1;
|
|
}
|
|
self->near_spectrum_u16 = malloc(spectrum_size * sizeof(uint16_t));
|
|
if (self->near_spectrum_u16 == NULL) {
|
|
WebRtc_FreeDelayEstimatorFloat(self);
|
|
self = NULL;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int WebRtc_InitDelayEstimatorFloat(void* handle) {
|
|
DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle;
|
|
|
|
if (self == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (WebRtc_InitDelayEstimator(self->fixed_handle) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
{
|
|
int history_size = WebRtc_history_size(self->fixed_handle);
|
|
int spectrum_size = WebRtc_spectrum_size(self->fixed_handle);
|
|
if (WebRtc_is_alignment_enabled(self->fixed_handle) == 1) {
|
|
// Set far end histories to zero
|
|
memset(self->far_history,
|
|
0,
|
|
sizeof(float) * spectrum_size * history_size);
|
|
self->far_history_pos = history_size;
|
|
}
|
|
// Set fixed point spectra to zero
|
|
memset(self->far_spectrum_u16, 0, sizeof(uint16_t) * spectrum_size);
|
|
memset(self->near_spectrum_u16, 0, sizeof(uint16_t) * spectrum_size);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int WebRtc_DelayEstimatorProcessFloat(void* handle,
|
|
float* far_spectrum,
|
|
float* near_spectrum,
|
|
int spectrum_size,
|
|
int vad_value) {
|
|
DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle;
|
|
|
|
const float kFftSize = (float) (2 * (spectrum_size - 1));
|
|
const float kLogOf2Inverse = 1.4426950f;
|
|
float max_value = 0.0f;
|
|
float scaling = 0;
|
|
|
|
int far_q = 0;
|
|
int scaling_log = 0;
|
|
int i = 0;
|
|
|
|
if (self == NULL) {
|
|
return -1;
|
|
}
|
|
if (far_spectrum == NULL) {
|
|
// Empty far end spectrum
|
|
return -1;
|
|
}
|
|
if (near_spectrum == NULL) {
|
|
// Empty near end spectrum
|
|
return -1;
|
|
}
|
|
if (spectrum_size != WebRtc_spectrum_size(self->fixed_handle)) {
|
|
// Data sizes don't match
|
|
return -1;
|
|
}
|
|
|
|
// Convert floating point spectrum to fixed point
|
|
// 1) Find largest value
|
|
// 2) Scale largest value to fit in Word16
|
|
for (i = 0; i < spectrum_size; ++i) {
|
|
if (near_spectrum[i] > max_value) {
|
|
max_value = near_spectrum[i];
|
|
}
|
|
}
|
|
// Find the largest possible scaling that is a multiple of two.
|
|
// With largest we mean to fit in a Word16.
|
|
// TODO(bjornv): I've taken the size of FFT into account, since there is a
|
|
// different scaling in float vs fixed point FFTs. I'm not completely sure
|
|
// this is necessary.
|
|
scaling_log = 14 - (int) (log(max_value / kFftSize + 1) * kLogOf2Inverse);
|
|
scaling = (float) (1 << scaling_log) / kFftSize;
|
|
for (i = 0; i < spectrum_size; ++i) {
|
|
self->near_spectrum_u16[i] = (uint16_t) (near_spectrum[i] * scaling);
|
|
}
|
|
|
|
// Same for far end
|
|
max_value = 0.0f;
|
|
for (i = 0; i < spectrum_size; ++i) {
|
|
if (far_spectrum[i] > max_value) {
|
|
max_value = far_spectrum[i];
|
|
}
|
|
}
|
|
// Find the largest possible scaling that is a multiple of two.
|
|
// With largest we mean to fit in a Word16.
|
|
scaling_log = 14 - (int) (log(max_value / kFftSize + 1) * kLogOf2Inverse);
|
|
scaling = (float) (1 << scaling_log) / kFftSize;
|
|
for (i = 0; i < spectrum_size; ++i) {
|
|
self->far_spectrum_u16[i] = (uint16_t) (far_spectrum[i] * scaling);
|
|
}
|
|
far_q = (int) scaling_log;
|
|
assert(far_q < 16); // Catch too large scaling, which should never be able to
|
|
// occur.
|
|
|
|
if (WebRtc_is_alignment_enabled(self->fixed_handle) == 1) {
|
|
// Update far end history
|
|
UpdateFarHistory(self, far_spectrum);
|
|
}
|
|
|
|
return WebRtc_DelayEstimatorProcess(self->fixed_handle,
|
|
self->far_spectrum_u16,
|
|
self->near_spectrum_u16,
|
|
spectrum_size,
|
|
far_q,
|
|
vad_value);
|
|
}
|
|
|
|
const float* WebRtc_AlignedFarendFloat(void* handle, int far_spectrum_size) {
|
|
DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle;
|
|
int buffer_pos = 0;
|
|
|
|
if (self == NULL) {
|
|
return NULL;
|
|
}
|
|
if (far_spectrum_size != WebRtc_spectrum_size(self->fixed_handle)) {
|
|
return NULL;
|
|
}
|
|
if (WebRtc_is_alignment_enabled(self->fixed_handle) != 1) {
|
|
return NULL;
|
|
}
|
|
|
|
// Get buffer position
|
|
buffer_pos = self->far_history_pos - WebRtc_last_delay(self->fixed_handle);
|
|
if (buffer_pos < 0) {
|
|
buffer_pos += WebRtc_history_size(self->fixed_handle);
|
|
}
|
|
// Return pointer to far end spectrum
|
|
return (self->far_history + (buffer_pos * far_spectrum_size));
|
|
}
|
|
|
|
int WebRtc_last_delay_float(void* handle) {
|
|
DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle;
|
|
|
|
if (self == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
return WebRtc_last_delay(self->fixed_handle);
|
|
}
|
|
|
|
int WebRtc_is_alignment_enabled_float(void* handle) {
|
|
DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle;
|
|
|
|
if (self == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
return WebRtc_is_alignment_enabled(self->fixed_handle);
|
|
}
|