mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-17 15:47:53 +01:00
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:
parent
26335a94de
commit
c04242548c
10 changed files with 114 additions and 47 deletions
|
@ -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>>(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1 +1 @@
|
|||
8d368435bbc80edab08205c6f21db1416e119119
|
||||
d22d4b0bc8f59aa27da61e158b9d35596f3844f5
|
Loading…
Reference in a new issue