Update to current webrtc library
This is from the upstream library commit id 3326535126e435f1ba647885ce43a8f0f3d317eb, corresponding to Chromium 88.0.4290.1.
This commit is contained in:
81
webrtc/modules/audio_processing/utility/BUILD.gn
Normal file
81
webrtc/modules/audio_processing/utility/BUILD.gn
Normal file
@ -0,0 +1,81 @@
|
||||
# Copyright (c) 2014 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.
|
||||
|
||||
import("../../../webrtc.gni")
|
||||
|
||||
rtc_library("cascaded_biquad_filter") {
|
||||
sources = [
|
||||
"cascaded_biquad_filter.cc",
|
||||
"cascaded_biquad_filter.h",
|
||||
]
|
||||
deps = [
|
||||
"../../../api:array_view",
|
||||
"../../../rtc_base:checks",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_library("legacy_delay_estimator") {
|
||||
sources = [
|
||||
"delay_estimator.cc",
|
||||
"delay_estimator.h",
|
||||
"delay_estimator_internal.h",
|
||||
"delay_estimator_wrapper.cc",
|
||||
"delay_estimator_wrapper.h",
|
||||
]
|
||||
deps = [ "../../../rtc_base:checks" ]
|
||||
}
|
||||
|
||||
rtc_library("pffft_wrapper") {
|
||||
visibility = [ "../*" ]
|
||||
sources = [
|
||||
"pffft_wrapper.cc",
|
||||
"pffft_wrapper.h",
|
||||
]
|
||||
deps = [
|
||||
"../../../api:array_view",
|
||||
"../../../rtc_base:checks",
|
||||
"//third_party/pffft",
|
||||
]
|
||||
}
|
||||
|
||||
if (rtc_include_tests) {
|
||||
rtc_library("cascaded_biquad_filter_unittest") {
|
||||
testonly = true
|
||||
|
||||
sources = [ "cascaded_biquad_filter_unittest.cc" ]
|
||||
deps = [
|
||||
":cascaded_biquad_filter",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../test:test_support",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_library("legacy_delay_estimator_unittest") {
|
||||
testonly = true
|
||||
|
||||
sources = [ "delay_estimator_unittest.cc" ]
|
||||
deps = [
|
||||
":legacy_delay_estimator",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../test:test_support",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_library("pffft_wrapper_unittest") {
|
||||
testonly = true
|
||||
sources = [ "pffft_wrapper_unittest.cc" ]
|
||||
deps = [
|
||||
":pffft_wrapper",
|
||||
"../../../test:test_support",
|
||||
"//testing/gtest",
|
||||
"//third_party/pffft",
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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 "modules/audio_processing/utility/cascaded_biquad_filter.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
CascadedBiQuadFilter::BiQuadParam::BiQuadParam(std::complex<float> zero,
|
||||
std::complex<float> pole,
|
||||
float gain,
|
||||
bool mirror_zero_along_i_axis)
|
||||
: zero(zero),
|
||||
pole(pole),
|
||||
gain(gain),
|
||||
mirror_zero_along_i_axis(mirror_zero_along_i_axis) {}
|
||||
|
||||
CascadedBiQuadFilter::BiQuadParam::BiQuadParam(const BiQuadParam&) = default;
|
||||
|
||||
CascadedBiQuadFilter::BiQuad::BiQuad(
|
||||
const CascadedBiQuadFilter::BiQuadParam& param)
|
||||
: x(), y() {
|
||||
float z_r = std::real(param.zero);
|
||||
float z_i = std::imag(param.zero);
|
||||
float p_r = std::real(param.pole);
|
||||
float p_i = std::imag(param.pole);
|
||||
float gain = param.gain;
|
||||
|
||||
if (param.mirror_zero_along_i_axis) {
|
||||
// Assuming zeroes at z_r and -z_r.
|
||||
RTC_DCHECK(z_i == 0.f);
|
||||
coefficients.b[0] = gain * 1.f;
|
||||
coefficients.b[1] = 0.f;
|
||||
coefficients.b[2] = gain * -(z_r * z_r);
|
||||
} else {
|
||||
// Assuming zeros at (z_r + z_i*i) and (z_r - z_i*i).
|
||||
coefficients.b[0] = gain * 1.f;
|
||||
coefficients.b[1] = gain * -2.f * z_r;
|
||||
coefficients.b[2] = gain * (z_r * z_r + z_i * z_i);
|
||||
}
|
||||
|
||||
// Assuming poles at (p_r + p_i*i) and (p_r - p_i*i).
|
||||
coefficients.a[0] = -2.f * p_r;
|
||||
coefficients.a[1] = p_r * p_r + p_i * p_i;
|
||||
}
|
||||
|
||||
void CascadedBiQuadFilter::BiQuad::BiQuad::Reset() {
|
||||
x[0] = x[1] = y[0] = y[1] = 0.f;
|
||||
}
|
||||
|
||||
CascadedBiQuadFilter::CascadedBiQuadFilter(
|
||||
const CascadedBiQuadFilter::BiQuadCoefficients& coefficients,
|
||||
size_t num_biquads)
|
||||
: biquads_(num_biquads, BiQuad(coefficients)) {}
|
||||
|
||||
CascadedBiQuadFilter::CascadedBiQuadFilter(
|
||||
const std::vector<CascadedBiQuadFilter::BiQuadParam>& biquad_params) {
|
||||
for (const auto& param : biquad_params) {
|
||||
biquads_.push_back(BiQuad(param));
|
||||
}
|
||||
}
|
||||
|
||||
CascadedBiQuadFilter::~CascadedBiQuadFilter() = default;
|
||||
|
||||
void CascadedBiQuadFilter::Process(rtc::ArrayView<const float> x,
|
||||
rtc::ArrayView<float> y) {
|
||||
if (biquads_.size() > 0) {
|
||||
ApplyBiQuad(x, y, &biquads_[0]);
|
||||
for (size_t k = 1; k < biquads_.size(); ++k) {
|
||||
ApplyBiQuad(y, y, &biquads_[k]);
|
||||
}
|
||||
} else {
|
||||
std::copy(x.begin(), x.end(), y.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void CascadedBiQuadFilter::Process(rtc::ArrayView<float> y) {
|
||||
for (auto& biquad : biquads_) {
|
||||
ApplyBiQuad(y, y, &biquad);
|
||||
}
|
||||
}
|
||||
|
||||
void CascadedBiQuadFilter::Reset() {
|
||||
for (auto& biquad : biquads_) {
|
||||
biquad.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CascadedBiQuadFilter::ApplyBiQuad(rtc::ArrayView<const float> x,
|
||||
rtc::ArrayView<float> y,
|
||||
CascadedBiQuadFilter::BiQuad* biquad) {
|
||||
RTC_DCHECK_EQ(x.size(), y.size());
|
||||
const auto* c_b = biquad->coefficients.b;
|
||||
const auto* c_a = biquad->coefficients.a;
|
||||
auto* m_x = biquad->x;
|
||||
auto* m_y = biquad->y;
|
||||
for (size_t k = 0; k < x.size(); ++k) {
|
||||
const float tmp = x[k];
|
||||
y[k] = c_b[0] * tmp + c_b[1] * m_x[0] + c_b[2] * m_x[1] - c_a[0] * m_y[0] -
|
||||
c_a[1] * m_y[1];
|
||||
m_x[1] = m_x[0];
|
||||
m_x[0] = tmp;
|
||||
m_y[1] = m_y[0];
|
||||
m_y[0] = y[k];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_PROCESSING_UTILITY_CASCADED_BIQUAD_FILTER_H_
|
||||
#define MODULES_AUDIO_PROCESSING_UTILITY_CASCADED_BIQUAD_FILTER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
|
||||
#include "api/array_view.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Applies a number of biquads in a cascaded manner. The filter implementation
|
||||
// is direct form 1.
|
||||
class CascadedBiQuadFilter {
|
||||
public:
|
||||
struct BiQuadParam {
|
||||
BiQuadParam(std::complex<float> zero,
|
||||
std::complex<float> pole,
|
||||
float gain,
|
||||
bool mirror_zero_along_i_axis = false);
|
||||
explicit BiQuadParam(const BiQuadParam&);
|
||||
std::complex<float> zero;
|
||||
std::complex<float> pole;
|
||||
float gain;
|
||||
bool mirror_zero_along_i_axis;
|
||||
};
|
||||
|
||||
struct BiQuadCoefficients {
|
||||
float b[3];
|
||||
float a[2];
|
||||
};
|
||||
|
||||
struct BiQuad {
|
||||
explicit BiQuad(const BiQuadCoefficients& coefficients)
|
||||
: coefficients(coefficients), x(), y() {}
|
||||
explicit BiQuad(const CascadedBiQuadFilter::BiQuadParam& param);
|
||||
void Reset();
|
||||
BiQuadCoefficients coefficients;
|
||||
float x[2];
|
||||
float y[2];
|
||||
};
|
||||
|
||||
CascadedBiQuadFilter(
|
||||
const CascadedBiQuadFilter::BiQuadCoefficients& coefficients,
|
||||
size_t num_biquads);
|
||||
explicit CascadedBiQuadFilter(
|
||||
const std::vector<CascadedBiQuadFilter::BiQuadParam>& biquad_params);
|
||||
~CascadedBiQuadFilter();
|
||||
CascadedBiQuadFilter(const CascadedBiQuadFilter&) = delete;
|
||||
CascadedBiQuadFilter& operator=(const CascadedBiQuadFilter&) = delete;
|
||||
|
||||
// Applies the biquads on the values in x in order to form the output in y.
|
||||
void Process(rtc::ArrayView<const float> x, rtc::ArrayView<float> y);
|
||||
// Applies the biquads on the values in y in an in-place manner.
|
||||
void Process(rtc::ArrayView<float> y);
|
||||
// Resets the filter to its initial state.
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
void ApplyBiQuad(rtc::ArrayView<const float> x,
|
||||
rtc::ArrayView<float> y,
|
||||
CascadedBiQuadFilter::BiQuad* biquad);
|
||||
|
||||
std::vector<BiQuad> biquads_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_UTILITY_CASCADED_BIQUAD_FILTER_H_
|
@ -8,20 +8,27 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_processing/utility/delay_estimator.h"
|
||||
#include "modules/audio_processing/utility/delay_estimator.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
// Number of right shifts for scaling is linearly depending on number of bits in
|
||||
// the far-end binary spectrum.
|
||||
static const int kShiftsAtZero = 13; // Right shifts at zero binary spectrum.
|
||||
static const int kShiftsLinearSlope = 3;
|
||||
|
||||
static const int32_t kProbabilityOffset = 1024; // 2 in Q9.
|
||||
static const int32_t kProbabilityOffset = 1024; // 2 in Q9.
|
||||
static const int32_t kProbabilityLowerLimit = 8704; // 17 in Q9.
|
||||
static const int32_t kProbabilityMinSpread = 2816; // 5.5 in Q9.
|
||||
static const int32_t kProbabilityMinSpread = 2816; // 5.5 in Q9.
|
||||
|
||||
// Robust validation settings
|
||||
static const float kHistogramMax = 3000.f;
|
||||
@ -35,15 +42,17 @@ static const float kFractionSlope = 0.05f;
|
||||
static const float kMinFractionWhenPossiblyCausal = 0.5f;
|
||||
static const float kMinFractionWhenPossiblyNonCausal = 0.25f;
|
||||
|
||||
} // namespace
|
||||
|
||||
// Counts and returns number of bits of a 32-bit word.
|
||||
static int BitCount(uint32_t u32) {
|
||||
uint32_t tmp = u32 - ((u32 >> 1) & 033333333333) -
|
||||
((u32 >> 2) & 011111111111);
|
||||
uint32_t tmp =
|
||||
u32 - ((u32 >> 1) & 033333333333) - ((u32 >> 2) & 011111111111);
|
||||
tmp = ((tmp + (tmp >> 3)) & 030707070707);
|
||||
tmp = (tmp + (tmp >> 6));
|
||||
tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077;
|
||||
|
||||
return ((int) tmp);
|
||||
return ((int)tmp);
|
||||
}
|
||||
|
||||
// Compares the |binary_vector| with all rows of the |binary_matrix| and counts
|
||||
@ -67,7 +76,7 @@ static void BitCountComparison(uint32_t binary_vector,
|
||||
|
||||
// Compare |binary_vector| with all rows of the |binary_matrix|
|
||||
for (; n < matrix_size; n++) {
|
||||
bit_counts[n] = (int32_t) BitCount(binary_vector ^ binary_matrix[n]);
|
||||
bit_counts[n] = (int32_t)BitCount(binary_vector ^ binary_matrix[n]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,11 +103,12 @@ static void UpdateRobustValidationStatistics(BinaryDelayEstimator* self,
|
||||
int32_t valley_level_q14) {
|
||||
const float valley_depth = valley_depth_q14 * kQ14Scaling;
|
||||
float decrease_in_last_set = valley_depth;
|
||||
const int max_hits_for_slow_change = (candidate_delay < self->last_delay) ?
|
||||
kMaxHitsWhenPossiblyNonCausal : kMaxHitsWhenPossiblyCausal;
|
||||
const int max_hits_for_slow_change = (candidate_delay < self->last_delay)
|
||||
? kMaxHitsWhenPossiblyNonCausal
|
||||
: kMaxHitsWhenPossiblyCausal;
|
||||
int i = 0;
|
||||
|
||||
assert(self->history_size == self->farend->history_size);
|
||||
RTC_DCHECK_EQ(self->history_size, self->farend->history_size);
|
||||
// Reset |candidate_hits| if we have a new candidate.
|
||||
if (candidate_delay != self->last_candidate_delay) {
|
||||
self->candidate_hits = 0;
|
||||
@ -125,18 +135,20 @@ static void UpdateRobustValidationStatistics(BinaryDelayEstimator* self,
|
||||
// |candidate_delay| is a "potential" candidate and we start decreasing
|
||||
// these histogram bins more rapidly with |valley_depth|.
|
||||
if (self->candidate_hits < max_hits_for_slow_change) {
|
||||
decrease_in_last_set = (self->mean_bit_counts[self->compare_delay] -
|
||||
valley_level_q14) * kQ14Scaling;
|
||||
decrease_in_last_set =
|
||||
(self->mean_bit_counts[self->compare_delay] - valley_level_q14) *
|
||||
kQ14Scaling;
|
||||
}
|
||||
// 4. All other bins are decreased with |valley_depth|.
|
||||
// TODO(bjornv): Investigate how to make this loop more efficient. Split up
|
||||
// the loop? Remove parts that doesn't add too much.
|
||||
for (i = 0; i < self->history_size; ++i) {
|
||||
int is_in_last_set = (i >= self->last_delay - 2) &&
|
||||
(i <= self->last_delay + 1) && (i != candidate_delay);
|
||||
int is_in_candidate_set = (i >= candidate_delay - 2) &&
|
||||
(i <= candidate_delay + 1);
|
||||
self->histogram[i] -= decrease_in_last_set * is_in_last_set +
|
||||
(i <= self->last_delay + 1) && (i != candidate_delay);
|
||||
int is_in_candidate_set =
|
||||
(i >= candidate_delay - 2) && (i <= candidate_delay + 1);
|
||||
self->histogram[i] -=
|
||||
decrease_in_last_set * is_in_last_set +
|
||||
valley_depth * (!is_in_last_set && !is_in_candidate_set);
|
||||
// 5. No histogram bin can go below 0.
|
||||
if (self->histogram[i] < 0) {
|
||||
@ -194,16 +206,18 @@ static int HistogramBasedValidation(const BinaryDelayEstimator* self,
|
||||
// into tables?
|
||||
if (delay_difference > self->allowed_offset) {
|
||||
fraction = 1.f - kFractionSlope * (delay_difference - self->allowed_offset);
|
||||
fraction = (fraction > kMinFractionWhenPossiblyCausal ? fraction :
|
||||
kMinFractionWhenPossiblyCausal);
|
||||
fraction = (fraction > kMinFractionWhenPossiblyCausal
|
||||
? fraction
|
||||
: kMinFractionWhenPossiblyCausal);
|
||||
} else if (delay_difference < 0) {
|
||||
fraction = kMinFractionWhenPossiblyNonCausal -
|
||||
kFractionSlope * delay_difference;
|
||||
fraction =
|
||||
kMinFractionWhenPossiblyNonCausal - kFractionSlope * delay_difference;
|
||||
fraction = (fraction > 1.f ? 1.f : fraction);
|
||||
}
|
||||
histogram_threshold *= fraction;
|
||||
histogram_threshold = (histogram_threshold > kMinHistogramThreshold ?
|
||||
histogram_threshold : kMinHistogramThreshold);
|
||||
histogram_threshold =
|
||||
(histogram_threshold > kMinHistogramThreshold ? histogram_threshold
|
||||
: kMinHistogramThreshold);
|
||||
|
||||
is_histogram_valid =
|
||||
(self->histogram[candidate_delay] >= histogram_threshold) &&
|
||||
@ -241,8 +255,8 @@ static int RobustValidation(const BinaryDelayEstimator* self,
|
||||
// i) Before we actually have a valid estimate (|last_delay| == -2), we say
|
||||
// a candidate is valid if either algorithm states so
|
||||
// (|is_instantaneous_valid| OR |is_histogram_valid|).
|
||||
is_robust = (self->last_delay < 0) &&
|
||||
(is_instantaneous_valid || is_histogram_valid);
|
||||
is_robust =
|
||||
(self->last_delay < 0) && (is_instantaneous_valid || is_histogram_valid);
|
||||
// ii) Otherwise, we need both algorithms to be certain
|
||||
// (|is_instantaneous_valid| AND |is_histogram_valid|)
|
||||
is_robust |= is_instantaneous_valid && is_histogram_valid;
|
||||
@ -250,13 +264,12 @@ static int RobustValidation(const BinaryDelayEstimator* self,
|
||||
// the instantaneous one if |is_histogram_valid| = 1 and the histogram
|
||||
// is significantly strong.
|
||||
is_robust |= is_histogram_valid &&
|
||||
(self->histogram[candidate_delay] > self->last_delay_histogram);
|
||||
(self->histogram[candidate_delay] > self->last_delay_histogram);
|
||||
|
||||
return is_robust;
|
||||
}
|
||||
|
||||
void WebRtc_FreeBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend* self) {
|
||||
|
||||
if (self == NULL) {
|
||||
return;
|
||||
}
|
||||
@ -276,7 +289,8 @@ BinaryDelayEstimatorFarend* WebRtc_CreateBinaryDelayEstimatorFarend(
|
||||
|
||||
if (history_size > 1) {
|
||||
// Sanity conditions fulfilled.
|
||||
self = malloc(sizeof(BinaryDelayEstimatorFarend));
|
||||
self = static_cast<BinaryDelayEstimatorFarend*>(
|
||||
malloc(sizeof(BinaryDelayEstimatorFarend)));
|
||||
}
|
||||
if (self == NULL) {
|
||||
return NULL;
|
||||
@ -294,24 +308,22 @@ BinaryDelayEstimatorFarend* WebRtc_CreateBinaryDelayEstimatorFarend(
|
||||
|
||||
int WebRtc_AllocateFarendBufferMemory(BinaryDelayEstimatorFarend* self,
|
||||
int history_size) {
|
||||
assert(self != NULL);
|
||||
RTC_DCHECK(self);
|
||||
// (Re-)Allocate memory for history buffers.
|
||||
self->binary_far_history =
|
||||
self->binary_far_history = static_cast<uint32_t*>(
|
||||
realloc(self->binary_far_history,
|
||||
history_size * sizeof(*self->binary_far_history));
|
||||
self->far_bit_counts = realloc(self->far_bit_counts,
|
||||
history_size * sizeof(*self->far_bit_counts));
|
||||
history_size * sizeof(*self->binary_far_history)));
|
||||
self->far_bit_counts = static_cast<int*>(realloc(
|
||||
self->far_bit_counts, history_size * sizeof(*self->far_bit_counts)));
|
||||
if ((self->binary_far_history == NULL) || (self->far_bit_counts == NULL)) {
|
||||
history_size = 0;
|
||||
}
|
||||
// Fill with zeros if we have expanded the buffers.
|
||||
if (history_size > self->history_size) {
|
||||
int size_diff = history_size - self->history_size;
|
||||
memset(&self->binary_far_history[self->history_size],
|
||||
0,
|
||||
memset(&self->binary_far_history[self->history_size], 0,
|
||||
sizeof(*self->binary_far_history) * size_diff);
|
||||
memset(&self->far_bit_counts[self->history_size],
|
||||
0,
|
||||
memset(&self->far_bit_counts[self->history_size], 0,
|
||||
sizeof(*self->far_bit_counts) * size_diff);
|
||||
}
|
||||
self->history_size = history_size;
|
||||
@ -320,22 +332,23 @@ int WebRtc_AllocateFarendBufferMemory(BinaryDelayEstimatorFarend* self,
|
||||
}
|
||||
|
||||
void WebRtc_InitBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend* self) {
|
||||
assert(self != NULL);
|
||||
RTC_DCHECK(self);
|
||||
memset(self->binary_far_history, 0, sizeof(uint32_t) * self->history_size);
|
||||
memset(self->far_bit_counts, 0, sizeof(int) * self->history_size);
|
||||
}
|
||||
|
||||
void WebRtc_SoftResetBinaryDelayEstimatorFarend(
|
||||
BinaryDelayEstimatorFarend* self, int delay_shift) {
|
||||
BinaryDelayEstimatorFarend* self,
|
||||
int delay_shift) {
|
||||
int abs_shift = abs(delay_shift);
|
||||
int shift_size = 0;
|
||||
int dest_index = 0;
|
||||
int src_index = 0;
|
||||
int padding_index = 0;
|
||||
|
||||
assert(self != NULL);
|
||||
RTC_DCHECK(self);
|
||||
shift_size = self->history_size - abs_shift;
|
||||
assert(shift_size > 0);
|
||||
RTC_DCHECK_GT(shift_size, 0);
|
||||
if (delay_shift == 0) {
|
||||
return;
|
||||
} else if (delay_shift > 0) {
|
||||
@ -351,8 +364,7 @@ void WebRtc_SoftResetBinaryDelayEstimatorFarend(
|
||||
sizeof(*self->binary_far_history) * shift_size);
|
||||
memset(&self->binary_far_history[padding_index], 0,
|
||||
sizeof(*self->binary_far_history) * abs_shift);
|
||||
memmove(&self->far_bit_counts[dest_index],
|
||||
&self->far_bit_counts[src_index],
|
||||
memmove(&self->far_bit_counts[dest_index], &self->far_bit_counts[src_index],
|
||||
sizeof(*self->far_bit_counts) * shift_size);
|
||||
memset(&self->far_bit_counts[padding_index], 0,
|
||||
sizeof(*self->far_bit_counts) * abs_shift);
|
||||
@ -360,7 +372,7 @@ void WebRtc_SoftResetBinaryDelayEstimatorFarend(
|
||||
|
||||
void WebRtc_AddBinaryFarSpectrum(BinaryDelayEstimatorFarend* handle,
|
||||
uint32_t binary_far_spectrum) {
|
||||
assert(handle != NULL);
|
||||
RTC_DCHECK(handle);
|
||||
// Shift binary spectrum history and insert current |binary_far_spectrum|.
|
||||
memmove(&(handle->binary_far_history[1]), &(handle->binary_far_history[0]),
|
||||
(handle->history_size - 1) * sizeof(uint32_t));
|
||||
@ -374,7 +386,6 @@ void WebRtc_AddBinaryFarSpectrum(BinaryDelayEstimatorFarend* handle,
|
||||
}
|
||||
|
||||
void WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator* self) {
|
||||
|
||||
if (self == NULL) {
|
||||
return;
|
||||
}
|
||||
@ -399,12 +410,14 @@ void WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator* self) {
|
||||
}
|
||||
|
||||
BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator(
|
||||
BinaryDelayEstimatorFarend* farend, int max_lookahead) {
|
||||
BinaryDelayEstimatorFarend* farend,
|
||||
int max_lookahead) {
|
||||
BinaryDelayEstimator* self = NULL;
|
||||
|
||||
if ((farend != NULL) && (max_lookahead >= 0)) {
|
||||
// Sanity conditions fulfilled.
|
||||
self = malloc(sizeof(BinaryDelayEstimator));
|
||||
self = static_cast<BinaryDelayEstimator*>(
|
||||
malloc(sizeof(BinaryDelayEstimator)));
|
||||
}
|
||||
if (self == NULL) {
|
||||
return NULL;
|
||||
@ -422,8 +435,8 @@ BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator(
|
||||
self->mean_bit_counts = NULL;
|
||||
self->bit_counts = NULL;
|
||||
self->histogram = NULL;
|
||||
self->binary_near_history =
|
||||
malloc((max_lookahead + 1) * sizeof(*self->binary_near_history));
|
||||
self->binary_near_history = static_cast<uint32_t*>(
|
||||
malloc((max_lookahead + 1) * sizeof(*self->binary_near_history)));
|
||||
if (self->binary_near_history == NULL ||
|
||||
WebRtc_AllocateHistoryBufferMemory(self, farend->history_size) == 0) {
|
||||
WebRtc_FreeBinaryDelayEstimator(self);
|
||||
@ -444,30 +457,26 @@ int WebRtc_AllocateHistoryBufferMemory(BinaryDelayEstimator* self,
|
||||
// The extra array element in |mean_bit_counts| and |histogram| is a dummy
|
||||
// element only used while |last_delay| == -2, i.e., before we have a valid
|
||||
// estimate.
|
||||
self->mean_bit_counts =
|
||||
self->mean_bit_counts = static_cast<int32_t*>(
|
||||
realloc(self->mean_bit_counts,
|
||||
(history_size + 1) * sizeof(*self->mean_bit_counts));
|
||||
self->bit_counts =
|
||||
realloc(self->bit_counts, history_size * sizeof(*self->bit_counts));
|
||||
self->histogram =
|
||||
realloc(self->histogram, (history_size + 1) * sizeof(*self->histogram));
|
||||
(history_size + 1) * sizeof(*self->mean_bit_counts)));
|
||||
self->bit_counts = static_cast<int32_t*>(
|
||||
realloc(self->bit_counts, history_size * sizeof(*self->bit_counts)));
|
||||
self->histogram = static_cast<float*>(
|
||||
realloc(self->histogram, (history_size + 1) * sizeof(*self->histogram)));
|
||||
|
||||
if ((self->mean_bit_counts == NULL) ||
|
||||
(self->bit_counts == NULL) ||
|
||||
if ((self->mean_bit_counts == NULL) || (self->bit_counts == NULL) ||
|
||||
(self->histogram == NULL)) {
|
||||
history_size = 0;
|
||||
}
|
||||
// Fill with zeros if we have expanded the buffers.
|
||||
if (history_size > self->history_size) {
|
||||
int size_diff = history_size - self->history_size;
|
||||
memset(&self->mean_bit_counts[self->history_size],
|
||||
0,
|
||||
memset(&self->mean_bit_counts[self->history_size], 0,
|
||||
sizeof(*self->mean_bit_counts) * size_diff);
|
||||
memset(&self->bit_counts[self->history_size],
|
||||
0,
|
||||
memset(&self->bit_counts[self->history_size], 0,
|
||||
sizeof(*self->bit_counts) * size_diff);
|
||||
memset(&self->histogram[self->history_size],
|
||||
0,
|
||||
memset(&self->histogram[self->history_size], 0,
|
||||
sizeof(*self->histogram) * size_diff);
|
||||
}
|
||||
self->history_size = history_size;
|
||||
@ -477,18 +486,17 @@ int WebRtc_AllocateHistoryBufferMemory(BinaryDelayEstimator* self,
|
||||
|
||||
void WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* self) {
|
||||
int i = 0;
|
||||
assert(self != NULL);
|
||||
RTC_DCHECK(self);
|
||||
|
||||
memset(self->bit_counts, 0, sizeof(int32_t) * self->history_size);
|
||||
memset(self->binary_near_history,
|
||||
0,
|
||||
memset(self->binary_near_history, 0,
|
||||
sizeof(uint32_t) * self->near_history_size);
|
||||
for (i = 0; i <= self->history_size; ++i) {
|
||||
self->mean_bit_counts[i] = (20 << 9); // 20 in Q9.
|
||||
self->histogram[i] = 0.f;
|
||||
}
|
||||
self->minimum_probability = kMaxBitCountsQ9; // 32 in Q9.
|
||||
self->last_delay_probability = (int) kMaxBitCountsQ9; // 32 in Q9.
|
||||
self->minimum_probability = kMaxBitCountsQ9; // 32 in Q9.
|
||||
self->last_delay_probability = (int)kMaxBitCountsQ9; // 32 in Q9.
|
||||
|
||||
// Default return value if we're unable to estimate. -1 is used for errors.
|
||||
self->last_delay = -2;
|
||||
@ -502,7 +510,7 @@ void WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* self) {
|
||||
int WebRtc_SoftResetBinaryDelayEstimator(BinaryDelayEstimator* self,
|
||||
int delay_shift) {
|
||||
int lookahead = 0;
|
||||
assert(self != NULL);
|
||||
RTC_DCHECK(self);
|
||||
lookahead = self->lookahead;
|
||||
self->lookahead -= delay_shift;
|
||||
if (self->lookahead < 0) {
|
||||
@ -524,7 +532,7 @@ int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator* self,
|
||||
int32_t value_worst_candidate = 0;
|
||||
int32_t valley_depth = 0;
|
||||
|
||||
assert(self != NULL);
|
||||
RTC_DCHECK(self);
|
||||
if (self->farend->history_size != self->history_size) {
|
||||
// Non matching history sizes.
|
||||
return -1;
|
||||
@ -612,22 +620,36 @@ int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator* self,
|
||||
// and deeper than the best estimate so far
|
||||
// (|value_best_candidate| < |last_delay_probability|)
|
||||
valid_candidate = ((valley_depth > kProbabilityOffset) &&
|
||||
((value_best_candidate < self->minimum_probability) ||
|
||||
(value_best_candidate < self->last_delay_probability)));
|
||||
((value_best_candidate < self->minimum_probability) ||
|
||||
(value_best_candidate < self->last_delay_probability)));
|
||||
|
||||
// Check for nonstationary farend signal.
|
||||
const bool non_stationary_farend =
|
||||
std::any_of(self->farend->far_bit_counts,
|
||||
self->farend->far_bit_counts + self->history_size,
|
||||
[](int a) { return a > 0; });
|
||||
|
||||
if (non_stationary_farend) {
|
||||
// Only update the validation statistics when the farend is nonstationary
|
||||
// as the underlying estimates are otherwise frozen.
|
||||
UpdateRobustValidationStatistics(self, candidate_delay, valley_depth,
|
||||
value_best_candidate);
|
||||
}
|
||||
|
||||
UpdateRobustValidationStatistics(self, candidate_delay, valley_depth,
|
||||
value_best_candidate);
|
||||
if (self->robust_validation_enabled) {
|
||||
int is_histogram_valid = HistogramBasedValidation(self, candidate_delay);
|
||||
valid_candidate = RobustValidation(self, candidate_delay, valid_candidate,
|
||||
is_histogram_valid);
|
||||
|
||||
}
|
||||
if (valid_candidate) {
|
||||
|
||||
// Only update the delay estimate when the farend is nonstationary and when
|
||||
// a valid delay candidate is available.
|
||||
if (non_stationary_farend && valid_candidate) {
|
||||
if (candidate_delay != self->last_delay) {
|
||||
self->last_delay_histogram =
|
||||
(self->histogram[candidate_delay] > kLastHistogramMax ?
|
||||
kLastHistogramMax : self->histogram[candidate_delay]);
|
||||
(self->histogram[candidate_delay] > kLastHistogramMax
|
||||
? kLastHistogramMax
|
||||
: self->histogram[candidate_delay]);
|
||||
// Adjust the histogram if we made a change to |last_delay|, though it was
|
||||
// not the most likely one according to the histogram.
|
||||
if (self->histogram[candidate_delay] <
|
||||
@ -646,13 +668,13 @@ int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator* self,
|
||||
}
|
||||
|
||||
int WebRtc_binary_last_delay(BinaryDelayEstimator* self) {
|
||||
assert(self != NULL);
|
||||
RTC_DCHECK(self);
|
||||
return self->last_delay;
|
||||
}
|
||||
|
||||
float WebRtc_binary_last_delay_quality(BinaryDelayEstimator* self) {
|
||||
float quality = 0;
|
||||
assert(self != NULL);
|
||||
RTC_DCHECK(self);
|
||||
|
||||
if (self->robust_validation_enabled) {
|
||||
// Simply a linear function of the histogram height at delay estimate.
|
||||
@ -660,8 +682,8 @@ float WebRtc_binary_last_delay_quality(BinaryDelayEstimator* self) {
|
||||
} else {
|
||||
// Note that |last_delay_probability| states how deep the minimum of the
|
||||
// cost function is, so it is rather an error probability.
|
||||
quality = (float) (kMaxBitCountsQ9 - self->last_delay_probability) /
|
||||
kMaxBitCountsQ9;
|
||||
quality = (float)(kMaxBitCountsQ9 - self->last_delay_probability) /
|
||||
kMaxBitCountsQ9;
|
||||
if (quality < 0) {
|
||||
quality = 0;
|
||||
}
|
||||
@ -682,3 +704,5 @@ void WebRtc_MeanEstimatorFix(int32_t new_value,
|
||||
}
|
||||
*mean_value += diff;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
@ -11,10 +11,12 @@
|
||||
// Performs delay estimation on binary converted spectra.
|
||||
// The return value is 0 - OK and -1 - Error, unless otherwise stated.
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
|
||||
#ifndef MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
|
||||
#define MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
static const int32_t kMaxBitCountsQ9 = (32 << 9); // 32 matching bits in Q9.
|
||||
|
||||
@ -117,7 +119,8 @@ void WebRtc_InitBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend* self);
|
||||
// - delay_shift : The amount of blocks to shift history buffers.
|
||||
//
|
||||
void WebRtc_SoftResetBinaryDelayEstimatorFarend(
|
||||
BinaryDelayEstimatorFarend* self, int delay_shift);
|
||||
BinaryDelayEstimatorFarend* self,
|
||||
int delay_shift);
|
||||
|
||||
// Adds the binary far-end spectrum to the internal far-end history buffer. This
|
||||
// spectrum is used as reference when calculating the delay using
|
||||
@ -153,7 +156,8 @@ void WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator* self);
|
||||
// See WebRtc_CreateDelayEstimator(..) in delay_estimator_wrapper.c for detailed
|
||||
// description.
|
||||
BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator(
|
||||
BinaryDelayEstimatorFarend* farend, int max_lookahead);
|
||||
BinaryDelayEstimatorFarend* farend,
|
||||
int max_lookahead);
|
||||
|
||||
// Re-allocates |history_size| dependent buffers. The far-end buffers will be
|
||||
// updated at the same time if needed.
|
||||
@ -248,4 +252,6 @@ void WebRtc_MeanEstimatorFix(int32_t new_value,
|
||||
int factor,
|
||||
int32_t* mean_value);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
|
||||
|
@ -10,11 +10,12 @@
|
||||
|
||||
// Header file including the delay estimator handle used for testing.
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
|
||||
#ifndef MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
|
||||
#define MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
|
||||
|
||||
#include "webrtc/modules/audio_processing/utility/delay_estimator.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
#include "modules/audio_processing/utility/delay_estimator.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
typedef union {
|
||||
float float_;
|
||||
@ -45,4 +46,6 @@ typedef struct {
|
||||
BinaryDelayEstimator* binary_handle;
|
||||
} DelayEstimator;
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
|
||||
|
@ -8,15 +8,16 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
|
||||
#include "modules/audio_processing/utility/delay_estimator_wrapper.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "webrtc/modules/audio_processing/utility/delay_estimator.h"
|
||||
#include "webrtc/modules/audio_processing/utility/delay_estimator_internal.h"
|
||||
#include "webrtc/system_wrappers/include/compile_assert_c.h"
|
||||
#include "modules/audio_processing/utility/delay_estimator.h"
|
||||
#include "modules/audio_processing/utility/delay_estimator_internal.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Only bit |kBandFirst| through bit |kBandLast| are processed and
|
||||
// |kBandFirst| - |kBandLast| must be < 32.
|
||||
@ -43,7 +44,7 @@ static __inline uint32_t SetBit(uint32_t in, int pos) {
|
||||
static void MeanEstimatorFloat(float new_value,
|
||||
float scale,
|
||||
float* mean_value) {
|
||||
assert(scale < 1.0f);
|
||||
RTC_DCHECK_LT(scale, 1.0f);
|
||||
*mean_value += (new_value - *mean_value) * scale;
|
||||
}
|
||||
|
||||
@ -65,7 +66,7 @@ static uint32_t BinarySpectrumFix(const uint16_t* spectrum,
|
||||
int i = kBandFirst;
|
||||
uint32_t out = 0;
|
||||
|
||||
assert(q_domain < 16);
|
||||
RTC_DCHECK_LT(q_domain, 16);
|
||||
|
||||
if (!(*threshold_initialized)) {
|
||||
// Set the |threshold_spectrum| to half the input |spectrum| as starting
|
||||
@ -73,7 +74,7 @@ static uint32_t BinarySpectrumFix(const uint16_t* spectrum,
|
||||
for (i = kBandFirst; i <= kBandLast; i++) {
|
||||
if (spectrum[i] > 0) {
|
||||
// Convert input spectrum from Q(|q_domain|) to Q15.
|
||||
int32_t spectrum_q15 = ((int32_t) spectrum[i]) << (15 - q_domain);
|
||||
int32_t spectrum_q15 = ((int32_t)spectrum[i]) << (15 - q_domain);
|
||||
threshold_spectrum[i].int32_ = (spectrum_q15 >> 1);
|
||||
*threshold_initialized = 1;
|
||||
}
|
||||
@ -81,7 +82,7 @@ static uint32_t BinarySpectrumFix(const uint16_t* spectrum,
|
||||
}
|
||||
for (i = kBandFirst; i <= kBandLast; i++) {
|
||||
// Convert input spectrum from Q(|q_domain|) to Q15.
|
||||
int32_t spectrum_q15 = ((int32_t) spectrum[i]) << (15 - q_domain);
|
||||
int32_t spectrum_q15 = ((int32_t)spectrum[i]) << (15 - q_domain);
|
||||
// Update the |threshold_spectrum|.
|
||||
WebRtc_MeanEstimatorFix(spectrum_q15, 6, &(threshold_spectrum[i].int32_));
|
||||
// Convert |spectrum| at current frequency bin to a binary value.
|
||||
@ -124,7 +125,7 @@ static uint32_t BinarySpectrumFloat(const float* spectrum,
|
||||
}
|
||||
|
||||
void WebRtc_FreeDelayEstimatorFarend(void* handle) {
|
||||
DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
|
||||
DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
|
||||
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
@ -144,10 +145,11 @@ void* WebRtc_CreateDelayEstimatorFarend(int spectrum_size, int history_size) {
|
||||
|
||||
// Check if the sub band used in the delay estimation is small enough to fit
|
||||
// the binary spectra in a uint32_t.
|
||||
COMPILE_ASSERT(kBandLast - kBandFirst < 32);
|
||||
static_assert(kBandLast - kBandFirst < 32, "");
|
||||
|
||||
if (spectrum_size >= kBandLast) {
|
||||
self = malloc(sizeof(DelayEstimatorFarend));
|
||||
self = static_cast<DelayEstimatorFarend*>(
|
||||
malloc(sizeof(DelayEstimatorFarend)));
|
||||
}
|
||||
|
||||
if (self != NULL) {
|
||||
@ -158,7 +160,8 @@ void* WebRtc_CreateDelayEstimatorFarend(int spectrum_size, int history_size) {
|
||||
memory_fail |= (self->binary_farend == NULL);
|
||||
|
||||
// Allocate memory for spectrum buffers.
|
||||
self->mean_far_spectrum = malloc(spectrum_size * sizeof(SpectrumType));
|
||||
self->mean_far_spectrum = static_cast<SpectrumType*>(
|
||||
malloc(spectrum_size * sizeof(SpectrumType)));
|
||||
memory_fail |= (self->mean_far_spectrum == NULL);
|
||||
|
||||
self->spectrum_size = spectrum_size;
|
||||
@ -173,7 +176,7 @@ void* WebRtc_CreateDelayEstimatorFarend(int spectrum_size, int history_size) {
|
||||
}
|
||||
|
||||
int WebRtc_InitDelayEstimatorFarend(void* handle) {
|
||||
DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
|
||||
DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
|
||||
|
||||
if (self == NULL) {
|
||||
return -1;
|
||||
@ -192,8 +195,8 @@ int WebRtc_InitDelayEstimatorFarend(void* handle) {
|
||||
}
|
||||
|
||||
void WebRtc_SoftResetDelayEstimatorFarend(void* handle, int delay_shift) {
|
||||
DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
|
||||
assert(self != NULL);
|
||||
DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
|
||||
RTC_DCHECK(self);
|
||||
WebRtc_SoftResetBinaryDelayEstimatorFarend(self->binary_farend, delay_shift);
|
||||
}
|
||||
|
||||
@ -201,7 +204,7 @@ int WebRtc_AddFarSpectrumFix(void* handle,
|
||||
const uint16_t* far_spectrum,
|
||||
int spectrum_size,
|
||||
int far_q) {
|
||||
DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
|
||||
DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
|
||||
uint32_t binary_spectrum = 0;
|
||||
|
||||
if (self == NULL) {
|
||||
@ -231,7 +234,7 @@ int WebRtc_AddFarSpectrumFix(void* handle,
|
||||
int WebRtc_AddFarSpectrumFloat(void* handle,
|
||||
const float* far_spectrum,
|
||||
int spectrum_size) {
|
||||
DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
|
||||
DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
|
||||
uint32_t binary_spectrum = 0;
|
||||
|
||||
if (self == NULL) {
|
||||
@ -255,7 +258,7 @@ int WebRtc_AddFarSpectrumFloat(void* handle,
|
||||
}
|
||||
|
||||
void WebRtc_FreeDelayEstimator(void* handle) {
|
||||
DelayEstimator* self = (DelayEstimator*) handle;
|
||||
DelayEstimator* self = (DelayEstimator*)handle;
|
||||
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
@ -272,10 +275,10 @@ void WebRtc_FreeDelayEstimator(void* handle) {
|
||||
|
||||
void* WebRtc_CreateDelayEstimator(void* farend_handle, int max_lookahead) {
|
||||
DelayEstimator* self = NULL;
|
||||
DelayEstimatorFarend* farend = (DelayEstimatorFarend*) farend_handle;
|
||||
DelayEstimatorFarend* farend = (DelayEstimatorFarend*)farend_handle;
|
||||
|
||||
if (farend_handle != NULL) {
|
||||
self = malloc(sizeof(DelayEstimator));
|
||||
self = static_cast<DelayEstimator*>(malloc(sizeof(DelayEstimator)));
|
||||
}
|
||||
|
||||
if (self != NULL) {
|
||||
@ -287,8 +290,8 @@ void* WebRtc_CreateDelayEstimator(void* farend_handle, int max_lookahead) {
|
||||
memory_fail |= (self->binary_handle == NULL);
|
||||
|
||||
// Allocate memory for spectrum buffers.
|
||||
self->mean_near_spectrum = malloc(farend->spectrum_size *
|
||||
sizeof(SpectrumType));
|
||||
self->mean_near_spectrum = static_cast<SpectrumType*>(
|
||||
malloc(farend->spectrum_size * sizeof(SpectrumType)));
|
||||
memory_fail |= (self->mean_near_spectrum == NULL);
|
||||
|
||||
self->spectrum_size = farend->spectrum_size;
|
||||
@ -303,7 +306,7 @@ void* WebRtc_CreateDelayEstimator(void* farend_handle, int max_lookahead) {
|
||||
}
|
||||
|
||||
int WebRtc_InitDelayEstimator(void* handle) {
|
||||
DelayEstimator* self = (DelayEstimator*) handle;
|
||||
DelayEstimator* self = (DelayEstimator*)handle;
|
||||
|
||||
if (self == NULL) {
|
||||
return -1;
|
||||
@ -322,13 +325,13 @@ int WebRtc_InitDelayEstimator(void* handle) {
|
||||
}
|
||||
|
||||
int WebRtc_SoftResetDelayEstimator(void* handle, int delay_shift) {
|
||||
DelayEstimator* self = (DelayEstimator*) handle;
|
||||
assert(self != NULL);
|
||||
DelayEstimator* self = (DelayEstimator*)handle;
|
||||
RTC_DCHECK(self);
|
||||
return WebRtc_SoftResetBinaryDelayEstimator(self->binary_handle, delay_shift);
|
||||
}
|
||||
|
||||
int WebRtc_set_history_size(void* handle, int history_size) {
|
||||
DelayEstimator* self = handle;
|
||||
DelayEstimator* self = static_cast<DelayEstimator*>(handle);
|
||||
|
||||
if ((self == NULL) || (history_size <= 1)) {
|
||||
return -1;
|
||||
@ -337,7 +340,7 @@ int WebRtc_set_history_size(void* handle, int history_size) {
|
||||
}
|
||||
|
||||
int WebRtc_history_size(const void* handle) {
|
||||
const DelayEstimator* self = handle;
|
||||
const DelayEstimator* self = static_cast<const DelayEstimator*>(handle);
|
||||
|
||||
if (self == NULL) {
|
||||
return -1;
|
||||
@ -351,9 +354,9 @@ int WebRtc_history_size(const void* handle) {
|
||||
}
|
||||
|
||||
int WebRtc_set_lookahead(void* handle, int lookahead) {
|
||||
DelayEstimator* self = (DelayEstimator*) handle;
|
||||
assert(self != NULL);
|
||||
assert(self->binary_handle != NULL);
|
||||
DelayEstimator* self = (DelayEstimator*)handle;
|
||||
RTC_DCHECK(self);
|
||||
RTC_DCHECK(self->binary_handle);
|
||||
if ((lookahead > self->binary_handle->near_history_size - 1) ||
|
||||
(lookahead < 0)) {
|
||||
return -1;
|
||||
@ -363,14 +366,14 @@ int WebRtc_set_lookahead(void* handle, int lookahead) {
|
||||
}
|
||||
|
||||
int WebRtc_lookahead(void* handle) {
|
||||
DelayEstimator* self = (DelayEstimator*) handle;
|
||||
assert(self != NULL);
|
||||
assert(self->binary_handle != NULL);
|
||||
DelayEstimator* self = (DelayEstimator*)handle;
|
||||
RTC_DCHECK(self);
|
||||
RTC_DCHECK(self->binary_handle);
|
||||
return self->binary_handle->lookahead;
|
||||
}
|
||||
|
||||
int WebRtc_set_allowed_offset(void* handle, int allowed_offset) {
|
||||
DelayEstimator* self = (DelayEstimator*) handle;
|
||||
DelayEstimator* self = (DelayEstimator*)handle;
|
||||
|
||||
if ((self == NULL) || (allowed_offset < 0)) {
|
||||
return -1;
|
||||
@ -380,7 +383,7 @@ int WebRtc_set_allowed_offset(void* handle, int allowed_offset) {
|
||||
}
|
||||
|
||||
int WebRtc_get_allowed_offset(const void* handle) {
|
||||
const DelayEstimator* self = (const DelayEstimator*) handle;
|
||||
const DelayEstimator* self = (const DelayEstimator*)handle;
|
||||
|
||||
if (self == NULL) {
|
||||
return -1;
|
||||
@ -389,7 +392,7 @@ int WebRtc_get_allowed_offset(const void* handle) {
|
||||
}
|
||||
|
||||
int WebRtc_enable_robust_validation(void* handle, int enable) {
|
||||
DelayEstimator* self = (DelayEstimator*) handle;
|
||||
DelayEstimator* self = (DelayEstimator*)handle;
|
||||
|
||||
if (self == NULL) {
|
||||
return -1;
|
||||
@ -397,13 +400,13 @@ int WebRtc_enable_robust_validation(void* handle, int enable) {
|
||||
if ((enable < 0) || (enable > 1)) {
|
||||
return -1;
|
||||
}
|
||||
assert(self->binary_handle != NULL);
|
||||
RTC_DCHECK(self->binary_handle);
|
||||
self->binary_handle->robust_validation_enabled = enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtc_is_robust_validation_enabled(const void* handle) {
|
||||
const DelayEstimator* self = (const DelayEstimator*) handle;
|
||||
const DelayEstimator* self = (const DelayEstimator*)handle;
|
||||
|
||||
if (self == NULL) {
|
||||
return -1;
|
||||
@ -415,7 +418,7 @@ int WebRtc_DelayEstimatorProcessFix(void* handle,
|
||||
const uint16_t* near_spectrum,
|
||||
int spectrum_size,
|
||||
int near_q) {
|
||||
DelayEstimator* self = (DelayEstimator*) handle;
|
||||
DelayEstimator* self = (DelayEstimator*)handle;
|
||||
uint32_t binary_spectrum = 0;
|
||||
|
||||
if (self == NULL) {
|
||||
@ -435,10 +438,9 @@ int WebRtc_DelayEstimatorProcessFix(void* handle,
|
||||
}
|
||||
|
||||
// Get binary spectra.
|
||||
binary_spectrum = BinarySpectrumFix(near_spectrum,
|
||||
self->mean_near_spectrum,
|
||||
near_q,
|
||||
&(self->near_spectrum_initialized));
|
||||
binary_spectrum =
|
||||
BinarySpectrumFix(near_spectrum, self->mean_near_spectrum, near_q,
|
||||
&(self->near_spectrum_initialized));
|
||||
|
||||
return WebRtc_ProcessBinarySpectrum(self->binary_handle, binary_spectrum);
|
||||
}
|
||||
@ -446,7 +448,7 @@ int WebRtc_DelayEstimatorProcessFix(void* handle,
|
||||
int WebRtc_DelayEstimatorProcessFloat(void* handle,
|
||||
const float* near_spectrum,
|
||||
int spectrum_size) {
|
||||
DelayEstimator* self = (DelayEstimator*) handle;
|
||||
DelayEstimator* self = (DelayEstimator*)handle;
|
||||
uint32_t binary_spectrum = 0;
|
||||
|
||||
if (self == NULL) {
|
||||
@ -469,7 +471,7 @@ int WebRtc_DelayEstimatorProcessFloat(void* handle,
|
||||
}
|
||||
|
||||
int WebRtc_last_delay(void* handle) {
|
||||
DelayEstimator* self = (DelayEstimator*) handle;
|
||||
DelayEstimator* self = (DelayEstimator*)handle;
|
||||
|
||||
if (self == NULL) {
|
||||
return -1;
|
||||
@ -479,7 +481,9 @@ int WebRtc_last_delay(void* handle) {
|
||||
}
|
||||
|
||||
float WebRtc_last_delay_quality(void* handle) {
|
||||
DelayEstimator* self = (DelayEstimator*) handle;
|
||||
assert(self != NULL);
|
||||
DelayEstimator* self = (DelayEstimator*)handle;
|
||||
RTC_DCHECK(self);
|
||||
return WebRtc_binary_last_delay_quality(self->binary_handle);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
@ -11,10 +11,12 @@
|
||||
// Performs delay estimation on block by block basis.
|
||||
// The return value is 0 - OK and -1 - Error, unless otherwise stated.
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
|
||||
#ifndef MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
|
||||
#define MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Releases the memory allocated by WebRtc_CreateDelayEstimatorFarend(...)
|
||||
void WebRtc_FreeDelayEstimatorFarend(void* handle);
|
||||
@ -241,4 +243,6 @@ int WebRtc_last_delay(void* handle);
|
||||
// - delay_quality : >= 0 - Estimation quality of last calculated delay.
|
||||
float WebRtc_last_delay_quality(void* handle);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
|
||||
|
135
webrtc/modules/audio_processing/utility/pffft_wrapper.cc
Normal file
135
webrtc/modules/audio_processing/utility/pffft_wrapper.cc
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2019 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 "modules/audio_processing/utility/pffft_wrapper.h"
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "third_party/pffft/src/pffft.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
size_t GetBufferSize(size_t fft_size, Pffft::FftType fft_type) {
|
||||
return fft_size * (fft_type == Pffft::FftType::kReal ? 1 : 2);
|
||||
}
|
||||
|
||||
float* AllocatePffftBuffer(size_t size) {
|
||||
return static_cast<float*>(pffft_aligned_malloc(size * sizeof(float)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Pffft::FloatBuffer::FloatBuffer(size_t fft_size, FftType fft_type)
|
||||
: size_(GetBufferSize(fft_size, fft_type)),
|
||||
data_(AllocatePffftBuffer(size_)) {}
|
||||
|
||||
Pffft::FloatBuffer::~FloatBuffer() {
|
||||
pffft_aligned_free(data_);
|
||||
}
|
||||
|
||||
rtc::ArrayView<const float> Pffft::FloatBuffer::GetConstView() const {
|
||||
return {data_, size_};
|
||||
}
|
||||
|
||||
rtc::ArrayView<float> Pffft::FloatBuffer::GetView() {
|
||||
return {data_, size_};
|
||||
}
|
||||
|
||||
Pffft::Pffft(size_t fft_size, FftType fft_type)
|
||||
: fft_size_(fft_size),
|
||||
fft_type_(fft_type),
|
||||
pffft_status_(pffft_new_setup(
|
||||
fft_size_,
|
||||
fft_type == Pffft::FftType::kReal ? PFFFT_REAL : PFFFT_COMPLEX)),
|
||||
scratch_buffer_(
|
||||
AllocatePffftBuffer(GetBufferSize(fft_size_, fft_type_))) {
|
||||
RTC_DCHECK(pffft_status_);
|
||||
RTC_DCHECK(scratch_buffer_);
|
||||
}
|
||||
|
||||
Pffft::~Pffft() {
|
||||
pffft_destroy_setup(pffft_status_);
|
||||
pffft_aligned_free(scratch_buffer_);
|
||||
}
|
||||
|
||||
bool Pffft::IsValidFftSize(size_t fft_size, FftType fft_type) {
|
||||
if (fft_size == 0) {
|
||||
return false;
|
||||
}
|
||||
// PFFFT only supports transforms for inputs of length N of the form
|
||||
// N = (2^a)*(3^b)*(5^c) where b >=0 and c >= 0 and a >= 5 for the real FFT
|
||||
// and a >= 4 for the complex FFT.
|
||||
constexpr int kFactors[] = {2, 3, 5};
|
||||
int factorization[] = {0, 0, 0};
|
||||
int n = static_cast<int>(fft_size);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
while (n % kFactors[i] == 0) {
|
||||
n = n / kFactors[i];
|
||||
factorization[i]++;
|
||||
}
|
||||
}
|
||||
int a_min = (fft_type == Pffft::FftType::kReal) ? 5 : 4;
|
||||
return factorization[0] >= a_min && n == 1;
|
||||
}
|
||||
|
||||
bool Pffft::IsSimdEnabled() {
|
||||
return pffft_simd_size() > 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<Pffft::FloatBuffer> Pffft::CreateBuffer() const {
|
||||
// Cannot use make_unique from absl because Pffft is the only friend of
|
||||
// Pffft::FloatBuffer.
|
||||
std::unique_ptr<Pffft::FloatBuffer> buffer(
|
||||
new Pffft::FloatBuffer(fft_size_, fft_type_));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void Pffft::ForwardTransform(const FloatBuffer& in,
|
||||
FloatBuffer* out,
|
||||
bool ordered) {
|
||||
RTC_DCHECK_EQ(in.size(), GetBufferSize(fft_size_, fft_type_));
|
||||
RTC_DCHECK_EQ(in.size(), out->size());
|
||||
RTC_DCHECK(scratch_buffer_);
|
||||
if (ordered) {
|
||||
pffft_transform_ordered(pffft_status_, in.const_data(), out->data(),
|
||||
scratch_buffer_, PFFFT_FORWARD);
|
||||
} else {
|
||||
pffft_transform(pffft_status_, in.const_data(), out->data(),
|
||||
scratch_buffer_, PFFFT_FORWARD);
|
||||
}
|
||||
}
|
||||
|
||||
void Pffft::BackwardTransform(const FloatBuffer& in,
|
||||
FloatBuffer* out,
|
||||
bool ordered) {
|
||||
RTC_DCHECK_EQ(in.size(), GetBufferSize(fft_size_, fft_type_));
|
||||
RTC_DCHECK_EQ(in.size(), out->size());
|
||||
RTC_DCHECK(scratch_buffer_);
|
||||
if (ordered) {
|
||||
pffft_transform_ordered(pffft_status_, in.const_data(), out->data(),
|
||||
scratch_buffer_, PFFFT_BACKWARD);
|
||||
} else {
|
||||
pffft_transform(pffft_status_, in.const_data(), out->data(),
|
||||
scratch_buffer_, PFFFT_BACKWARD);
|
||||
}
|
||||
}
|
||||
|
||||
void Pffft::FrequencyDomainConvolve(const FloatBuffer& fft_x,
|
||||
const FloatBuffer& fft_y,
|
||||
FloatBuffer* out,
|
||||
float scaling) {
|
||||
RTC_DCHECK_EQ(fft_x.size(), GetBufferSize(fft_size_, fft_type_));
|
||||
RTC_DCHECK_EQ(fft_x.size(), fft_y.size());
|
||||
RTC_DCHECK_EQ(fft_x.size(), out->size());
|
||||
pffft_zconvolve_accumulate(pffft_status_, fft_x.const_data(),
|
||||
fft_y.const_data(), out->data(), scaling);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
94
webrtc/modules/audio_processing/utility/pffft_wrapper.h
Normal file
94
webrtc/modules/audio_processing/utility/pffft_wrapper.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2019 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.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_
|
||||
#define MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/array_view.h"
|
||||
|
||||
// Forward declaration.
|
||||
struct PFFFT_Setup;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Pretty-Fast Fast Fourier Transform (PFFFT) wrapper class.
|
||||
// Not thread safe.
|
||||
class Pffft {
|
||||
public:
|
||||
enum class FftType { kReal, kComplex };
|
||||
|
||||
// 1D floating point buffer used as input/output data type for the FFT ops.
|
||||
// It must be constructed using Pffft::CreateBuffer().
|
||||
class FloatBuffer {
|
||||
public:
|
||||
FloatBuffer(const FloatBuffer&) = delete;
|
||||
FloatBuffer& operator=(const FloatBuffer&) = delete;
|
||||
~FloatBuffer();
|
||||
|
||||
rtc::ArrayView<const float> GetConstView() const;
|
||||
rtc::ArrayView<float> GetView();
|
||||
|
||||
private:
|
||||
friend class Pffft;
|
||||
FloatBuffer(size_t fft_size, FftType fft_type);
|
||||
const float* const_data() const { return data_; }
|
||||
float* data() { return data_; }
|
||||
size_t size() const { return size_; }
|
||||
|
||||
const size_t size_;
|
||||
float* const data_;
|
||||
};
|
||||
|
||||
// TODO(https://crbug.com/webrtc/9577): Consider adding a factory and making
|
||||
// the ctor private.
|
||||
// static std::unique_ptr<Pffft> Create(size_t fft_size,
|
||||
// FftType fft_type); Ctor. |fft_size| must be a supported size (see
|
||||
// Pffft::IsValidFftSize()). If not supported, the code will crash.
|
||||
Pffft(size_t fft_size, FftType fft_type);
|
||||
Pffft(const Pffft&) = delete;
|
||||
Pffft& operator=(const Pffft&) = delete;
|
||||
~Pffft();
|
||||
|
||||
// Returns true if the FFT size is supported.
|
||||
static bool IsValidFftSize(size_t fft_size, FftType fft_type);
|
||||
|
||||
// Returns true if SIMD code optimizations are being used.
|
||||
static bool IsSimdEnabled();
|
||||
|
||||
// Creates a buffer of the right size.
|
||||
std::unique_ptr<FloatBuffer> CreateBuffer() const;
|
||||
|
||||
// TODO(https://crbug.com/webrtc/9577): Overload with rtc::ArrayView args.
|
||||
// Computes the forward fast Fourier transform.
|
||||
void ForwardTransform(const FloatBuffer& in, FloatBuffer* out, bool ordered);
|
||||
// Computes the backward fast Fourier transform.
|
||||
void BackwardTransform(const FloatBuffer& in, FloatBuffer* out, bool ordered);
|
||||
|
||||
// Multiplies the frequency components of |fft_x| and |fft_y| and accumulates
|
||||
// them into |out|. The arrays must have been obtained with
|
||||
// ForwardTransform(..., /*ordered=*/false) - i.e., |fft_x| and |fft_y| must
|
||||
// not be ordered.
|
||||
void FrequencyDomainConvolve(const FloatBuffer& fft_x,
|
||||
const FloatBuffer& fft_y,
|
||||
FloatBuffer* out,
|
||||
float scaling = 1.f);
|
||||
|
||||
private:
|
||||
const size_t fft_size_;
|
||||
const FftType fft_type_;
|
||||
PFFFT_Setup* pffft_status_;
|
||||
float* const scratch_buffer_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_
|
Reference in New Issue
Block a user