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:
Arun Raghavan
2020-10-12 18:08:02 -04:00
parent b1b02581d3
commit bcec8b0b21
859 changed files with 76187 additions and 49580 deletions

View 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",
]
}
}

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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_

View File

@ -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

View File

@ -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_

View 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

View 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_