AEC3: Update SpectrumBuffer API

- RenderBuffer::Spectrum() loses its channel argument, allowing for
  greater flexibility in passing the multi-channel spectrum data into
  functions.
- The FFT spectra lengths are made compile-time constant, rendering
  some DCHECKs obsolete.

Bug: webrtc:10913
Change-Id: Ied0c50cf72d974cfef7279fd2b9c572d049b8b16
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/157104
Commit-Queue: Sam Zackrisson <saza@webrtc.org>
Reviewed-by: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29528}
This commit is contained in:
Sam Zackrisson 2019-10-18 08:20:09 +02:00 committed by Commit Bot
parent c336dd1cb6
commit 98872dc556
14 changed files with 49 additions and 62 deletions

View File

@ -46,11 +46,11 @@ void ComputeAvgRenderReverb(
if (num_render_channels > 1) {
auto average_channels =
[](size_t num_render_channels,
const std::vector<std::vector<float>>& spectrum_band_0,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
spectrum_band_0,
rtc::ArrayView<float, kFftLengthBy2Plus1> render_power) {
std::fill(render_power.begin(), render_power.end(), 0.f);
for (size_t ch = 0; ch < num_render_channels; ++ch) {
RTC_DCHECK_EQ(spectrum_band_0[ch].size(), kFftLengthBy2Plus1);
for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
render_power[k] += spectrum_band_0[ch][k];
}
@ -231,9 +231,8 @@ void AecState::Update(
subtractor_output_analyzer_.ConvergedFilters());
// TODO(bugs.webrtc.org/10913): Take all channels into account.
const auto& X2 =
render_buffer.Spectrum(delay_state_.MinDirectPathFilterDelay(),
/*channel=*/0);
const auto& X2 = render_buffer.Spectrum(
delay_state_.MinDirectPathFilterDelay())[/*channel=*/0];
erl_estimator_.Update(subtractor_output_analyzer_.ConvergedFilters()[0], X2,
Y2[0]);

View File

@ -461,8 +461,8 @@ void EchoRemoverImpl::ProcessCapture(
data_dumper_->DumpRaw("aec3_S2_linear", S2_linear[0]);
data_dumper_->DumpRaw("aec3_Y2", Y2[0]);
data_dumper_->DumpRaw(
"aec3_X2", render_buffer->Spectrum(aec_state_.MinDirectPathFilterDelay(),
/*channel=*/0));
"aec3_X2", render_buffer->Spectrum(
aec_state_.MinDirectPathFilterDelay())[/*channel=*/0]);
data_dumper_->DumpRaw("aec3_R2", R2[0]);
data_dumper_->DumpRaw("aec3_filter_delay",
aec_state_.MinDirectPathFilterDelay());

View File

@ -38,11 +38,10 @@ void ErlEstimator::Reset() {
blocks_since_reset_ = 0;
}
void ErlEstimator::Update(bool converged_filter,
rtc::ArrayView<const float> render_spectrum,
rtc::ArrayView<const float> capture_spectrum) {
RTC_DCHECK_EQ(kFftLengthBy2Plus1, render_spectrum.size());
RTC_DCHECK_EQ(kFftLengthBy2Plus1, capture_spectrum.size());
void ErlEstimator::Update(
bool converged_filter,
rtc::ArrayView<const float, kFftLengthBy2Plus1> render_spectrum,
rtc::ArrayView<const float, kFftLengthBy2Plus1> capture_spectrum) {
const auto& X2 = render_spectrum;
const auto& Y2 = capture_spectrum;

View File

@ -32,8 +32,8 @@ class ErlEstimator {
// Updates the ERL estimate.
void Update(bool converged_filter,
rtc::ArrayView<const float> render_spectrum,
rtc::ArrayView<const float> capture_spectrum);
rtc::ArrayView<const float, kFftLengthBy2Plus1> render_spectrum,
rtc::ArrayView<const float, kFftLengthBy2Plus1> capture_spectrum);
// Returns the most recent ERL estimate.
const std::array<float, kFftLengthBy2Plus1>& Erl() const { return erl_; }

View File

@ -19,9 +19,7 @@ MockRenderDelayBuffer::MockRenderDelayBuffer(int sample_rate_hz,
NumBandsForRate(sample_rate_hz),
num_channels,
kBlockSize),
spectrum_buffer_(block_buffer_.buffer.size(),
num_channels,
kFftLengthBy2Plus1),
spectrum_buffer_(block_buffer_.buffer.size(), num_channels),
fft_buffer_(block_buffer_.buffer.size(), num_channels),
render_buffer_(&block_buffer_, &spectrum_buffer_, &fft_buffer_),
downsampled_render_buffer_(GetDownSampledBufferSize(4, 4)) {

View File

@ -44,11 +44,11 @@ class RenderBuffer {
}
// Get the spectrum from one of the FFTs in the buffer.
rtc::ArrayView<const float> Spectrum(int buffer_offset_ffts,
size_t channel) const {
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Spectrum(
int buffer_offset_ffts) const {
int position = spectrum_buffer_->OffsetIndex(spectrum_buffer_->read,
buffer_offset_ffts);
return spectrum_buffer_->buffer[position][channel];
return spectrum_buffer_->buffer[position];
}
// Returns the circular fft buffer.

View File

@ -23,7 +23,7 @@ namespace webrtc {
// Verifies the check for non-null fft buffer.
TEST(RenderBuffer, NullExternalFftBuffer) {
BlockBuffer block_buffer(10, 3, 1, kBlockSize);
SpectrumBuffer spectrum_buffer(10, 1, kFftLengthBy2Plus1);
SpectrumBuffer spectrum_buffer(10, 1);
EXPECT_DEATH(RenderBuffer(&block_buffer, &spectrum_buffer, nullptr), "");
}
@ -37,7 +37,7 @@ TEST(RenderBuffer, NullExternalSpectrumBuffer) {
// Verifies the check for non-null block buffer.
TEST(RenderBuffer, NullExternalBlockBuffer) {
FftBuffer fft_buffer(10, 1);
SpectrumBuffer spectrum_buffer(10, 1, kFftLengthBy2Plus1);
SpectrumBuffer spectrum_buffer(10, 1);
EXPECT_DEATH(RenderBuffer(nullptr, &spectrum_buffer, &fft_buffer), "");
}

View File

@ -131,7 +131,7 @@ RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config,
NumBandsForRate(sample_rate_hz),
num_render_channels,
kBlockSize),
spectra_(blocks_.buffer.size(), num_render_channels, kFftLengthBy2Plus1),
spectra_(blocks_.buffer.size(), num_render_channels),
ffts_(blocks_.buffer.size(), num_render_channels),
delay_(config_.delay.default_delay),
echo_remover_buffer_(&blocks_, &spectra_, &ffts_),

View File

@ -38,13 +38,11 @@ void IdentifySmallNarrowBandRegions(
std::array<size_t, kFftLengthBy2 - 1> channel_counters;
channel_counters.fill(0);
for (size_t channel = 0; channel < render_buffer.Block(0)[0].size();
++channel) {
rtc::ArrayView<const float> X2 =
render_buffer.Spectrum(*delay_partitions, channel);
RTC_DCHECK_EQ(kFftLengthBy2Plus1, X2.size());
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> X2 =
render_buffer.Spectrum(*delay_partitions);
for (size_t ch = 0; ch < X2.size(); ++ch) {
for (size_t k = 1; k < kFftLengthBy2; ++k) {
if (X2[k] > 3 * std::max(X2[k - 1], X2[k + 1])) {
if (X2[ch][k] > 3 * std::max(X2[ch][k - 1], X2[ch][k + 1])) {
++channel_counters[k - 1];
}
}
@ -72,7 +70,8 @@ void IdentifyStrongNarrowBandComponent(const RenderBuffer& render_buffer,
render_buffer.Block(0);
float max_peak_level = 0.f;
for (size_t channel = 0; channel < x_latest[0].size(); ++channel) {
const auto X2_latest = render_buffer.Spectrum(0, channel);
rtc::ArrayView<const float, kFftLengthBy2Plus1> X2_latest =
render_buffer.Spectrum(0)[channel];
// Identify the spectral peak.
const int peak_bin =

View File

@ -244,21 +244,20 @@ void ResidualEchoEstimator::Reset() {
void ResidualEchoEstimator::UpdateRenderNoisePower(
const RenderBuffer& render_buffer) {
std::array<float, kFftLengthBy2Plus1> render_power_data;
rtc::ArrayView<const float> render_power;
if (num_render_channels_ == 1) {
render_power = render_buffer.Spectrum(0, /*channel=*/0);
} else {
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> X2 =
render_buffer.Spectrum(0);
rtc::ArrayView<const float, kFftLengthBy2Plus1> render_power =
X2[/*channel=*/0];
if (num_render_channels_ > 1) {
render_power_data.fill(0.f);
for (size_t ch = 0; ch < num_render_channels_; ++ch) {
const auto& channel_power = render_buffer.Spectrum(0, ch);
RTC_DCHECK_EQ(channel_power.size(), kFftLengthBy2Plus1);
const auto& channel_power = X2[ch];
for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
render_power_data[k] += channel_power[k];
}
}
render_power = render_power_data;
}
RTC_DCHECK_EQ(render_power.size(), kFftLengthBy2Plus1);
// Estimate the stationary noise power in a minimum statistics manner.
for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
@ -295,23 +294,20 @@ void ResidualEchoEstimator::AddReverb(
// Compute render power for the reverb.
std::array<float, kFftLengthBy2Plus1> render_power_data;
rtc::ArrayView<const float> render_power;
if (num_render_channels_ == 1) {
render_power =
render_buffer.Spectrum(first_reverb_partition, /*channel=*/0);
} else {
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> X2 =
render_buffer.Spectrum(first_reverb_partition);
rtc::ArrayView<const float, kFftLengthBy2Plus1> render_power =
X2[/*channel=*/0];
if (num_render_channels_ > 1) {
render_power_data.fill(0.f);
for (size_t ch = 0; ch < num_render_channels_; ++ch) {
const auto& channel_power =
render_buffer.Spectrum(first_reverb_partition, ch);
RTC_DCHECK_EQ(channel_power.size(), kFftLengthBy2Plus1);
const auto& channel_power = X2[ch];
for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
render_power_data[k] += channel_power[k];
}
}
render_power = render_power_data;
}
RTC_DCHECK_EQ(render_power.size(), kFftLengthBy2Plus1);
// Update the reverb estimate.
if (reverb_type == ReverbType::kLinear) {

View File

@ -14,14 +14,10 @@
namespace webrtc {
SpectrumBuffer::SpectrumBuffer(size_t size,
size_t num_channels,
size_t spectrum_length)
SpectrumBuffer::SpectrumBuffer(size_t size, size_t num_channels)
: size(static_cast<int>(size)),
buffer(size,
std::vector<std::vector<float>>(
num_channels,
std::vector<float>(spectrum_length, 0.f))) {
std::vector<std::array<float, kFftLengthBy2Plus1>>(num_channels)) {
for (auto& channel : buffer) {
for (auto& c : channel) {
std::fill(c.begin(), c.end(), 0.f);

View File

@ -13,8 +13,10 @@
#include <stddef.h>
#include <array>
#include <vector>
#include "modules/audio_processing/aec3/aec3_common.h"
#include "rtc_base/checks.h"
namespace webrtc {
@ -22,7 +24,7 @@ namespace webrtc {
// Struct for bundling a circular buffer of one dimensional vector objects
// together with the read and write indices.
struct SpectrumBuffer {
SpectrumBuffer(size_t size, size_t num_channels, size_t spectrum_length);
SpectrumBuffer(size_t size, size_t num_channels);
~SpectrumBuffer();
int IncIndex(int index) const {
@ -50,7 +52,7 @@ struct SpectrumBuffer {
void DecReadIndex() { read = DecIndex(read); }
const int size;
std::vector<std::vector<std::vector<float>>> buffer;
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>> buffer;
int write = 0;
int read = 0;
};

View File

@ -12,7 +12,6 @@
#include <algorithm>
#include <array>
#include <vector>
#include "api/array_view.h"
#include "modules/audio_processing/aec3/aec3_common.h"
@ -45,7 +44,7 @@ void StationarityEstimator::Reset() {
// Update just the noise estimator. Usefull until the delay is known
void StationarityEstimator::UpdateNoiseEstimator(
rtc::ArrayView<const std::vector<float>> spectrum) {
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum) {
noise_.Update(spectrum);
data_dumper_->DumpRaw("aec3_stationarity_noise_spectrum", noise_.Spectrum());
data_dumper_->DumpRaw("aec3_stationarity_is_block_stationary",
@ -168,13 +167,12 @@ void StationarityEstimator::NoiseSpectrum::Reset() {
}
void StationarityEstimator::NoiseSpectrum::Update(
rtc::ArrayView<const std::vector<float>> spectrum) {
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum) {
RTC_DCHECK_LE(1, spectrum[0].size());
const int num_render_channels = static_cast<int>(spectrum.size());
std::array<float, kFftLengthBy2Plus1> avg_spectrum_data;
rtc::ArrayView<const float> avg_spectrum;
RTC_DCHECK_EQ(kFftLengthBy2Plus1, spectrum[0].size());
if (num_render_channels == 1) {
avg_spectrum = spectrum[0];
} else {
@ -184,7 +182,6 @@ void StationarityEstimator::NoiseSpectrum::Update(
std::copy(spectrum[0].begin(), spectrum[0].end(),
avg_spectrum_data.begin());
for (int ch = 1; ch < num_render_channels; ++ch) {
RTC_DCHECK_EQ(kFftLengthBy2Plus1, spectrum[ch].size());
for (size_t k = 1; k < kFftLengthBy2Plus1; ++k) {
avg_spectrum_data[k] += spectrum[ch][k];
}

View File

@ -15,7 +15,6 @@
#include <array>
#include <memory>
#include <vector>
#include "api/array_view.h"
#include "modules/audio_processing/aec3/aec3_common.h" // kFftLengthBy2Plus1...
@ -36,7 +35,8 @@ class StationarityEstimator {
void Reset();
// Update just the noise estimator. Usefull until the delay is known
void UpdateNoiseEstimator(rtc::ArrayView<const std::vector<float>> spectrum);
void UpdateNoiseEstimator(
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum);
// Update the flag indicating whether this current frame is stationary. For
// getting a more robust estimation, it looks at future and/or past frames.
@ -86,7 +86,8 @@ class StationarityEstimator {
void Reset();
// Update the noise power spectrum with a new frame.
void Update(rtc::ArrayView<const std::vector<float>> spectrum);
void Update(
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum);
// Get the noise estimation power spectrum.
rtc::ArrayView<const float> Spectrum() const { return noise_spectrum_; }