AGC2: retuning and large refactoring
- Bug fix: the desired initial gain quickly dropped to 0 dB hence starting a call with a too low level - New tuning to make AGC2 more robust to VAD mistakes - Smarter max gain increase speed: to deal with an increased threshold of adjacent speech frames, the gain applier temporarily allows a faster gain increase to deal with a longer time spent waiting for enough speech frames in a row to be observed - Saturation protector isolated from `AdaptiveModeLevelEstimator` to simplify the unit tests for the latter (non bit-exact change) - AGC2 adaptive digital config: unnecessary params deprecated - Code readability improvements - Data dumps clean-up and better naming Bug: webrtc:7494 Change-Id: I4e36059bdf2566cc2a7e1a7e95b7430ba9ae9844 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/215140 Commit-Queue: Alessio Bazzica <alessiob@webrtc.org> Reviewed-by: Jesus de Vicente Pena <devicentepena@webrtc.org> Cr-Commit-Position: refs/heads/master@{#33736}
This commit is contained in:
committed by
Commit Bot
parent
d28434bd3f
commit
980c4601e1
@ -11,6 +11,7 @@
|
||||
#include "modules/audio_processing/gain_controller2.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
|
||||
#include "api/array_view.h"
|
||||
@ -68,7 +69,8 @@ std::unique_ptr<GainController2> CreateAgc2FixedDigitalMode(
|
||||
return agc2;
|
||||
}
|
||||
|
||||
float GainAfterProcessingFile(GainController2* gain_controller) {
|
||||
float GainDbAfterProcessingFile(GainController2& gain_controller,
|
||||
int max_duration_ms) {
|
||||
// Set up an AudioBuffer to be filled from the speech file.
|
||||
constexpr size_t kStereo = 2u;
|
||||
const StreamConfig capture_config(AudioProcessing::kSampleRate48kHz, kStereo,
|
||||
@ -82,24 +84,29 @@ float GainAfterProcessingFile(GainController2* gain_controller) {
|
||||
std::vector<float> capture_input(capture_config.num_frames() *
|
||||
capture_config.num_channels());
|
||||
|
||||
// The file should contain at least this many frames. Every iteration, we put
|
||||
// a frame through the gain controller.
|
||||
const int kNumFramesToProcess = 100;
|
||||
for (int frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) {
|
||||
// Process the input file which must be long enough to cover
|
||||
// `max_duration_ms`.
|
||||
RTC_DCHECK_GT(max_duration_ms, 0);
|
||||
const int num_frames = rtc::CheckedDivExact(max_duration_ms, 10);
|
||||
for (int i = 0; i < num_frames; ++i) {
|
||||
ReadFloatSamplesFromStereoFile(capture_config.num_frames(),
|
||||
capture_config.num_channels(), &capture_file,
|
||||
capture_input);
|
||||
|
||||
test::CopyVectorToAudioBuffer(capture_config, capture_input, &ab);
|
||||
gain_controller->Process(&ab);
|
||||
gain_controller.Process(&ab);
|
||||
}
|
||||
|
||||
// Send in a last frame with values constant 1 (It's low enough to detect high
|
||||
// gain, and for ease of computation). The applied gain is the result.
|
||||
// Send in a last frame with minimum dBFS level.
|
||||
constexpr float sample_value = 1.f;
|
||||
SetAudioBufferSamples(sample_value, &ab);
|
||||
gain_controller->Process(&ab);
|
||||
return ab.channels()[0][0];
|
||||
gain_controller.Process(&ab);
|
||||
// Measure the RMS level after processing.
|
||||
float rms = 0.0f;
|
||||
for (size_t i = 0; i < capture_config.num_frames(); ++i) {
|
||||
rms += ab.channels()[0][i] * ab.channels()[0][i];
|
||||
}
|
||||
// Return the applied gain in dB.
|
||||
return 20.0f * std::log10(std::sqrt(rms / capture_config.num_frames()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -324,34 +331,20 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
48000,
|
||||
true)));
|
||||
|
||||
TEST(GainController2, UsageSaturationMargin) {
|
||||
// Checks that the gain applied at the end of a PCM samples file is close to the
|
||||
// expected value.
|
||||
TEST(GainController2, CheckGainAdaptiveDigital) {
|
||||
constexpr float kExpectedGainDb = 4.3f;
|
||||
constexpr float kToleranceDb = 0.5f;
|
||||
GainController2 gain_controller2;
|
||||
gain_controller2.Initialize(AudioProcessing::kSampleRate48kHz);
|
||||
|
||||
AudioProcessing::Config::GainController2 config;
|
||||
// Check that samples are not amplified as much when extra margin is
|
||||
// high. They should not be amplified at all, but only after convergence. GC2
|
||||
// starts with a gain, and it takes time until it's down to 0 dB.
|
||||
config.fixed_digital.gain_db = 0.f;
|
||||
config.adaptive_digital.enabled = true;
|
||||
config.adaptive_digital.extra_saturation_margin_db = 50.f;
|
||||
gain_controller2.ApplyConfig(config);
|
||||
|
||||
EXPECT_LT(GainAfterProcessingFile(&gain_controller2), 2.f);
|
||||
}
|
||||
|
||||
TEST(GainController2, UsageNoSaturationMargin) {
|
||||
GainController2 gain_controller2;
|
||||
gain_controller2.Initialize(AudioProcessing::kSampleRate48kHz);
|
||||
|
||||
AudioProcessing::Config::GainController2 config;
|
||||
// Check that some gain is applied if there is no margin.
|
||||
config.fixed_digital.gain_db = 0.f;
|
||||
config.adaptive_digital.enabled = true;
|
||||
config.adaptive_digital.extra_saturation_margin_db = 0.f;
|
||||
gain_controller2.ApplyConfig(config);
|
||||
|
||||
EXPECT_GT(GainAfterProcessingFile(&gain_controller2), 1.9f);
|
||||
EXPECT_NEAR(
|
||||
GainDbAfterProcessingFile(gain_controller2, /*max_duration_ms=*/2000),
|
||||
kExpectedGainDb, kToleranceDb);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
Reference in New Issue
Block a user