Make the high-pass filter operate in full-band

This CL moves the high-pass filter to run in the full-band domain
instead of the split-band domain.

Bug: webrtc:11193
Change-Id: Ie61f4a80afda11236ecbb1ad544bbd0350c7bbfd
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/161453
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Commit-Queue: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30112}
This commit is contained in:
Per Åhgren 2019-12-10 13:04:15 +01:00 committed by Commit Bot
parent 26335a94de
commit c04242548c
10 changed files with 114 additions and 47 deletions

View file

@ -248,7 +248,7 @@ EchoCanceller3::RenderWriter::RenderWriter(
: data_dumper_(data_dumper),
num_bands_(num_bands),
num_channels_(num_channels),
high_pass_filter_(num_channels),
high_pass_filter_(16000, num_channels),
render_queue_input_frame_(
num_bands_,
std::vector<std::vector<float>>(

View file

@ -237,7 +237,7 @@ class EchoCanceller3Tester {
capture_output.push_back(capture_buffer_.split_bands(0)[0][k]);
}
}
HighPassFilter hp_filter(1);
HighPassFilter hp_filter(16000, 1);
hp_filter.Process(&render_input);
EXPECT_TRUE(
@ -530,7 +530,7 @@ class EchoCanceller3Tester {
capture_output.push_back(capture_buffer_.split_bands(0)[0][k]);
}
}
HighPassFilter hp_filter(1);
HighPassFilter hp_filter(16000, 1);
hp_filter.Process(&render_input);
EXPECT_TRUE(

View file

@ -75,6 +75,11 @@ bool DetectLegacyNsEnforcement() {
return field_trial::IsEnabled("WebRTC-NewNoiseSuppressionKillSwitch");
}
// Checks whether the high-pass filter should be done in the full-band.
bool EnforceSplitBandHpf() {
return field_trial::IsEnabled("WebRTC-FullBandHpfKillSwitch");
}
// Checks whether AEC3 should be allowed to decide what the default
// configuration should be based on the render and capture channel configuration
// at hand.
@ -343,7 +348,8 @@ AudioProcessingImpl::AudioProcessingImpl(
!field_trial::IsEnabled(
"WebRTC-ApmExperimentalMultiChannelRenderKillSwitch"),
!field_trial::IsEnabled(
"WebRTC-ApmExperimentalMultiChannelCaptureKillSwitch")),
"WebRTC-ApmExperimentalMultiChannelCaptureKillSwitch"),
EnforceSplitBandHpf()),
#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
capture_(false),
#else
@ -629,7 +635,9 @@ void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) {
config_.pipeline.multi_channel_render !=
config.pipeline.multi_channel_render ||
config_.pipeline.multi_channel_capture !=
config.pipeline.multi_channel_capture;
config.pipeline.multi_channel_capture ||
config_.pipeline.maximum_internal_processing_rate !=
config.pipeline.maximum_internal_processing_rate;
const bool aec_config_changed =
config_.echo_canceller.enabled != config.echo_canceller.enabled ||
@ -1199,6 +1207,13 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
AudioBuffer* capture_buffer = capture_.capture_audio.get(); // For brevity.
if (submodules_.high_pass_filter &&
config_.high_pass_filter.apply_in_full_band &&
!constants_.enforce_split_band_hpf) {
submodules_.high_pass_filter->Process(capture_buffer,
/*use_split_band_data=*/false);
}
if (submodules_.pre_amplifier) {
submodules_.pre_amplifier->ApplyGain(AudioFrameView<float>(
capture_buffer->channels(), capture_buffer->num_channels(),
@ -1267,8 +1282,11 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
capture_buffer->set_num_channels(1);
}
if (submodules_.high_pass_filter) {
submodules_.high_pass_filter->Process(capture_buffer);
if (submodules_.high_pass_filter &&
(!config_.high_pass_filter.apply_in_full_band ||
constants_.enforce_split_band_hpf)) {
submodules_.high_pass_filter->Process(capture_buffer,
/*use_split_band_data=*/true);
}
RETURN_ON_ERR(submodules_.gain_control->AnalyzeCaptureAudio(*capture_buffer));
@ -1760,7 +1778,14 @@ void AudioProcessingImpl::InitializeHighPassFilter() {
!config_.echo_canceller.mobile_mode;
if (submodule_states_.HighPassFilteringRequired() ||
high_pass_filter_needed_by_aec) {
submodules_.high_pass_filter.reset(new HighPassFilter(num_proc_channels()));
bool use_full_band = config_.high_pass_filter.apply_in_full_band &&
!constants_.enforce_split_band_hpf;
int rate = use_full_band ? proc_fullband_sample_rate_hz()
: proc_split_sample_rate_hz();
size_t num_channels =
use_full_band ? num_output_channels() : num_proc_channels();
submodules_.high_pass_filter.reset(new HighPassFilter(rate, num_channels));
} else {
submodules_.high_pass_filter.reset();
}

View file

@ -372,7 +372,8 @@ class AudioProcessingImpl : public AudioProcessing {
bool use_experimental_agc_agc2_level_estimation,
bool use_experimental_agc_agc2_digital_adaptive,
bool multi_channel_render_support,
bool multi_channel_capture_support)
bool multi_channel_capture_support,
bool enforce_split_band_hpf)
: agc_startup_min_volume(agc_startup_min_volume),
agc_clipped_level_min(agc_clipped_level_min),
use_experimental_agc(use_experimental_agc),
@ -381,7 +382,8 @@ class AudioProcessingImpl : public AudioProcessing {
use_experimental_agc_agc2_digital_adaptive(
use_experimental_agc_agc2_digital_adaptive),
multi_channel_render_support(multi_channel_render_support),
multi_channel_capture_support(multi_channel_capture_support) {}
multi_channel_capture_support(multi_channel_capture_support),
enforce_split_band_hpf(enforce_split_band_hpf) {}
int agc_startup_min_volume;
int agc_clipped_level_min;
bool use_experimental_agc;
@ -389,6 +391,7 @@ class AudioProcessingImpl : public AudioProcessing {
bool use_experimental_agc_agc2_digital_adaptive;
bool multi_channel_render_support;
bool multi_channel_capture_support;
bool enforce_split_band_hpf;
} constants_;
struct ApmCaptureState {

View file

@ -209,6 +209,7 @@ void EnableAllAPComponents(AudioProcessing* ap) {
apm_config.high_pass_filter.enabled = true;
apm_config.level_estimation.enabled = true;
apm_config.voice_detection.enabled = true;
apm_config.pipeline.maximum_internal_processing_rate = 48000;
ap->ApplyConfig(apm_config);
}
@ -432,6 +433,9 @@ ApmTest::ApmTest()
Config config;
config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
apm_.reset(AudioProcessingBuilder().Create(config));
AudioProcessing::Config apm_config = apm_->GetConfig();
apm_config.pipeline.maximum_internal_processing_rate = 48000;
apm_->ApplyConfig(apm_config);
}
void ApmTest::SetUp() {
@ -1961,11 +1965,7 @@ TEST_P(AudioProcessingTest, Formats) {
} else {
ref_rate = 8000;
}
#ifdef WEBRTC_ARCH_ARM_FAMILY
if (file_direction == kForward) {
ref_rate = std::min(ref_rate, 32000);
}
#endif
FILE* out_file = fopen(
OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_,
reverse_output_rate_, cf[i].num_input,
@ -2087,9 +2087,9 @@ INSTANTIATE_TEST_SUITE_P(
std::make_tuple(44100, 16000, 32000, 16000, 25, 20),
std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
std::make_tuple(32000, 48000, 48000, 48000, 30, 0),
std::make_tuple(32000, 48000, 32000, 48000, 32, 30),
std::make_tuple(32000, 48000, 16000, 48000, 30, 20),
std::make_tuple(32000, 48000, 48000, 48000, 15, 0),
std::make_tuple(32000, 48000, 32000, 48000, 15, 30),
std::make_tuple(32000, 48000, 16000, 48000, 15, 20),
std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
@ -2100,9 +2100,9 @@ INSTANTIATE_TEST_SUITE_P(
std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
std::make_tuple(16000, 48000, 48000, 48000, 23, 0),
std::make_tuple(16000, 48000, 32000, 48000, 24, 30),
std::make_tuple(16000, 48000, 16000, 48000, 24, 20),
std::make_tuple(16000, 48000, 48000, 48000, 9, 0),
std::make_tuple(16000, 48000, 32000, 48000, 9, 30),
std::make_tuple(16000, 48000, 16000, 48000, 9, 20),
std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
@ -2143,9 +2143,9 @@ INSTANTIATE_TEST_SUITE_P(
std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
std::make_tuple(32000, 48000, 48000, 48000, 27, 0),
std::make_tuple(32000, 48000, 32000, 48000, 65, 30),
std::make_tuple(32000, 48000, 16000, 48000, 30, 20),
std::make_tuple(32000, 48000, 48000, 48000, 17, 0),
std::make_tuple(32000, 48000, 32000, 48000, 17, 30),
std::make_tuple(32000, 48000, 16000, 48000, 17, 20),
std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
@ -2156,9 +2156,9 @@ INSTANTIATE_TEST_SUITE_P(
std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
std::make_tuple(16000, 48000, 48000, 48000, 23, 0),
std::make_tuple(16000, 48000, 32000, 48000, 24, 30),
std::make_tuple(16000, 48000, 16000, 48000, 25, 20),
std::make_tuple(16000, 48000, 48000, 48000, 11, 0),
std::make_tuple(16000, 48000, 32000, 48000, 11, 30),
std::make_tuple(16000, 48000, 16000, 48000, 11, 20),
std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
std::make_tuple(16000, 44100, 16000, 44100, 15, 15),

View file

@ -18,30 +18,67 @@ namespace webrtc {
namespace {
// [B,A] = butter(2,100/8000,'high')
constexpr CascadedBiQuadFilter::BiQuadCoefficients kHighPassFilterCoefficients =
{{0.97261f, -1.94523f, 0.97261f}, {-1.94448f, 0.94598f}};
constexpr CascadedBiQuadFilter::BiQuadCoefficients
kHighPassFilterCoefficients16kHz = {{0.97261f, -1.94523f, 0.97261f},
{-1.94448f, 0.94598f}};
// [B,A] = butter(2,100/16000,'high')
constexpr CascadedBiQuadFilter::BiQuadCoefficients
kHighPassFilterCoefficients32kHz = {{0.98621f, -1.97242f, 0.98621f},
{-1.97223f, 0.97261f}};
// [B,A] = butter(2,100/24000,'high')
constexpr CascadedBiQuadFilter::BiQuadCoefficients
kHighPassFilterCoefficients48kHz = {{0.99079f, -1.98157f, 0.99079f},
{-1.98149f, 0.98166f}};
constexpr size_t kNumberOfHighPassBiQuads = 1;
const CascadedBiQuadFilter::BiQuadCoefficients& ChooseCoefficients(
int sample_rate_hz) {
switch (sample_rate_hz) {
case 16000:
return kHighPassFilterCoefficients16kHz;
case 32000:
return kHighPassFilterCoefficients32kHz;
case 48000:
return kHighPassFilterCoefficients48kHz;
default:
RTC_NOTREACHED();
}
RTC_NOTREACHED();
return kHighPassFilterCoefficients16kHz;
}
} // namespace
HighPassFilter::HighPassFilter(size_t num_channels) {
HighPassFilter::HighPassFilter(int sample_rate_hz, size_t num_channels)
: sample_rate_hz_(sample_rate_hz) {
filters_.resize(num_channels);
const auto& coefficients = ChooseCoefficients(sample_rate_hz_);
for (size_t k = 0; k < filters_.size(); ++k) {
filters_[k].reset(new CascadedBiQuadFilter(kHighPassFilterCoefficients,
kNumberOfHighPassBiQuads));
filters_[k].reset(
new CascadedBiQuadFilter(coefficients, kNumberOfHighPassBiQuads));
}
}
HighPassFilter::~HighPassFilter() = default;
void HighPassFilter::Process(AudioBuffer* audio) {
void HighPassFilter::Process(AudioBuffer* audio, bool use_split_band_data) {
RTC_DCHECK(audio);
RTC_DCHECK_EQ(filters_.size(), audio->num_channels());
for (size_t k = 0; k < audio->num_channels(); ++k) {
rtc::ArrayView<float> channel_data = rtc::ArrayView<float>(
audio->split_bands(k)[0], audio->num_frames_per_band());
filters_[k]->Process(channel_data);
if (use_split_band_data) {
for (size_t k = 0; k < audio->num_channels(); ++k) {
rtc::ArrayView<float> channel_data = rtc::ArrayView<float>(
audio->split_bands(k)[0], audio->num_frames_per_band());
filters_[k]->Process(channel_data);
}
} else {
for (size_t k = 0; k < audio->num_channels(); ++k) {
rtc::ArrayView<float> channel_data =
rtc::ArrayView<float>(&audio->channels()[k][0], audio->num_frames());
filters_[k]->Process(channel_data);
}
}
}
@ -67,9 +104,10 @@ void HighPassFilter::Reset(size_t num_channels) {
for (size_t k = 0; k < old_num_channels; ++k) {
filters_[k]->Reset();
}
const auto& coefficients = ChooseCoefficients(sample_rate_hz_);
for (size_t k = old_num_channels; k < filters_.size(); ++k) {
filters_[k].reset(new CascadedBiQuadFilter(kHighPassFilterCoefficients,
kNumberOfHighPassBiQuads));
filters_[k].reset(
new CascadedBiQuadFilter(coefficients, kNumberOfHighPassBiQuads));
}
}
}

View file

@ -21,20 +21,20 @@ namespace webrtc {
class AudioBuffer;
// Filters that high
class HighPassFilter {
public:
explicit HighPassFilter(size_t num_channels);
HighPassFilter(int sample_rate_hz, size_t num_channels);
~HighPassFilter();
HighPassFilter(const HighPassFilter&) = delete;
HighPassFilter& operator=(const HighPassFilter&) = delete;
void Process(AudioBuffer* audio);
void Process(AudioBuffer* audio, bool use_split_band_data);
void Process(std::vector<std::vector<float>>* audio);
void Reset();
void Reset(size_t num_channels);
private:
const int sample_rate_hz_;
std::vector<std::unique_ptr<CascadedBiQuadFilter>> filters_;
};
} // namespace webrtc

View file

@ -32,7 +32,7 @@ std::vector<float> ProcessOneFrameAsAudioBuffer(
stream_config.sample_rate_hz(), stream_config.num_channels());
test::CopyVectorToAudioBuffer(stream_config, frame_input, &audio_buffer);
high_pass_filter->Process(&audio_buffer);
high_pass_filter->Process(&audio_buffer, /*use_split_band_data=*/false);
std::vector<float> frame_output;
test::ExtractVectorFromAudioBuffer(stream_config, &audio_buffer,
&frame_output);
@ -76,7 +76,7 @@ void RunBitexactnessTest(int num_channels,
const std::vector<float>& input,
const std::vector<float>& reference) {
const StreamConfig stream_config(16000, num_channels, false);
HighPassFilter high_pass_filter(num_channels);
HighPassFilter high_pass_filter(16000, num_channels);
std::vector<float> output;
const size_t num_frames_to_process =
@ -135,7 +135,7 @@ TEST(HighPassFilterAccuracyTest, ResetWithAudioBufferInterface) {
const StreamConfig stream_config_mono(16000, 1, false);
std::vector<float> x_mono(160, 1.f);
std::vector<float> x_stereo(320, 1.f);
HighPassFilter hpf(1);
HighPassFilter hpf(16000, 1);
std::vector<float> y =
ProcessOneFrameAsAudioBuffer(x_mono, stream_config_mono, &hpf);
hpf.Reset(2);
@ -151,7 +151,7 @@ TEST(HighPassFilterAccuracyTest, ResetWithVectorInterface) {
const StreamConfig stream_config_mono(16000, 1, false);
std::vector<float> x_mono(160, 1.f);
std::vector<float> x_stereo(320, 1.f);
HighPassFilter hpf(1);
HighPassFilter hpf(16000, 1);
std::vector<float> y =
ProcessOneFrameAsVector(x_mono, stream_config_mono, &hpf);
hpf.Reset(2);

View file

@ -224,6 +224,7 @@ class RTC_EXPORT AudioProcessing : public rtc::RefCountInterface {
struct HighPassFilter {
bool enabled = false;
bool apply_in_full_band = true;
} high_pass_filter;
struct EchoCanceller {

View file

@ -1 +1 @@
8d368435bbc80edab08205c6f21db1416e119119
d22d4b0bc8f59aa27da61e158b9d35596f3844f5