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}
diff --git a/modules/audio_processing/aec3/echo_canceller3.cc b/modules/audio_processing/aec3/echo_canceller3.cc
index 632b91b..dafb14f 100644
--- a/modules/audio_processing/aec3/echo_canceller3.cc
+++ b/modules/audio_processing/aec3/echo_canceller3.cc
@@ -248,7 +248,7 @@
: 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>>(
diff --git a/modules/audio_processing/aec3/echo_canceller3_unittest.cc b/modules/audio_processing/aec3/echo_canceller3_unittest.cc
index 8d9199c..4fc68ff 100644
--- a/modules/audio_processing/aec3/echo_canceller3_unittest.cc
+++ b/modules/audio_processing/aec3/echo_canceller3_unittest.cc
@@ -237,7 +237,7 @@
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 @@
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(
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index d544304..6d8b209 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -75,6 +75,11 @@
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 @@
!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 @@
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 @@
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 @@
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 @@
!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();
}
diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h
index 08379ad..29a3c8d 100644
--- a/modules/audio_processing/audio_processing_impl.h
+++ b/modules/audio_processing/audio_processing_impl.h
@@ -372,7 +372,8 @@
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 @@
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 @@
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 {
diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc
index 0fd07bf..9355c11 100644
--- a/modules/audio_processing/audio_processing_unittest.cc
+++ b/modules/audio_processing/audio_processing_unittest.cc
@@ -209,6 +209,7 @@
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 @@
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 @@
} 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 @@
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 @@
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 @@
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 @@
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),
diff --git a/modules/audio_processing/high_pass_filter.cc b/modules/audio_processing/high_pass_filter.cc
index bd953e3..bff7209 100644
--- a/modules/audio_processing/high_pass_filter.cc
+++ b/modules/audio_processing/high_pass_filter.cc
@@ -18,30 +18,67 @@
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 @@
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));
}
}
}
diff --git a/modules/audio_processing/high_pass_filter.h b/modules/audio_processing/high_pass_filter.h
index 87105ce..d396383 100644
--- a/modules/audio_processing/high_pass_filter.h
+++ b/modules/audio_processing/high_pass_filter.h
@@ -21,20 +21,20 @@
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
diff --git a/modules/audio_processing/high_pass_filter_unittest.cc b/modules/audio_processing/high_pass_filter_unittest.cc
index 56ccb95..f8e7226 100644
--- a/modules/audio_processing/high_pass_filter_unittest.cc
+++ b/modules/audio_processing/high_pass_filter_unittest.cc
@@ -32,7 +32,7 @@
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 @@
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 @@
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 @@
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);
diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h
index 2f67919..5ab591b 100644
--- a/modules/audio_processing/include/audio_processing.h
+++ b/modules/audio_processing/include/audio_processing.h
@@ -224,6 +224,7 @@
struct HighPassFilter {
bool enabled = false;
+ bool apply_in_full_band = true;
} high_pass_filter;
struct EchoCanceller {