blob: 274c821081c22465b8360f8d45b10f8cba424498 [file] [log] [blame]
alessiob3ec96df2017-05-22 06:57:06 -07001/*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "modules/audio_processing/gain_controller2.h"
12
Alessio Bazzica270f7b52017-10-13 11:05:17 +020013#include <algorithm>
Mirko Bonadei317a1f02019-09-17 17:06:18 +020014#include <memory>
alessiob3ec96df2017-05-22 06:57:06 -070015
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "api/array_view.h"
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010017#include "modules/audio_processing/agc2/agc2_testing_common.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/audio_processing/audio_buffer.h"
Alex Loiko5e784612018-11-01 14:51:56 +010019#include "modules/audio_processing/test/audio_buffer_tools.h"
20#include "modules/audio_processing/test/bitexactness_tools.h"
Alessio Bazzica270f7b52017-10-13 11:05:17 +020021#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "test/gtest.h"
alessiob3ec96df2017-05-22 06:57:06 -070023
24namespace webrtc {
25namespace test {
alessiob3ec96df2017-05-22 06:57:06 -070026namespace {
27
alessiob3ec96df2017-05-22 06:57:06 -070028void SetAudioBufferSamples(float value, AudioBuffer* ab) {
Alessio Bazzica270f7b52017-10-13 11:05:17 +020029 // Sets all the samples in |ab| to |value|.
alessiob3ec96df2017-05-22 06:57:06 -070030 for (size_t k = 0; k < ab->num_channels(); ++k) {
Per Åhgrend47941e2019-08-22 11:51:13 +020031 std::fill(ab->channels()[k], ab->channels()[k] + ab->num_frames(), value);
alessiob3ec96df2017-05-22 06:57:06 -070032 }
33}
34
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010035float RunAgc2WithConstantInput(GainController2* agc2,
36 float input_level,
37 size_t num_frames,
38 int sample_rate) {
39 const int num_samples = rtc::CheckedDivExact(sample_rate, 100);
Per Åhgrend47941e2019-08-22 11:51:13 +020040 AudioBuffer ab(sample_rate, 1, sample_rate, 1, sample_rate, 1);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010041
42 // Give time to the level estimator to converge.
43 for (size_t i = 0; i < num_frames + 1; ++i) {
44 SetAudioBufferSamples(input_level, &ab);
45 agc2->Process(&ab);
46 }
47
48 // Return the last sample from the last processed frame.
Per Åhgrend47941e2019-08-22 11:51:13 +020049 return ab.channels()[0][num_samples - 1];
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010050}
51
52AudioProcessing::Config::GainController2 CreateAgc2FixedDigitalModeConfig(
53 float fixed_gain_db) {
54 AudioProcessing::Config::GainController2 config;
Alessio Bazzica1e2542f2018-11-13 14:44:15 +010055 config.adaptive_digital.enabled = false;
56 config.fixed_digital.gain_db = fixed_gain_db;
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010057 // TODO(alessiob): Check why ASSERT_TRUE() below does not compile.
58 EXPECT_TRUE(GainController2::Validate(config));
59 return config;
60}
61
62std::unique_ptr<GainController2> CreateAgc2FixedDigitalMode(
63 float fixed_gain_db,
64 size_t sample_rate_hz) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020065 auto agc2 = std::make_unique<GainController2>();
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010066 agc2->ApplyConfig(CreateAgc2FixedDigitalModeConfig(fixed_gain_db));
67 agc2->Initialize(sample_rate_hz);
68 return agc2;
69}
70
71float GainAfterProcessingFile(GainController2* gain_controller) {
72 // Set up an AudioBuffer to be filled from the speech file.
73 constexpr size_t kStereo = 2u;
74 const StreamConfig capture_config(AudioProcessing::kSampleRate48kHz, kStereo,
75 false);
Per Åhgrend47941e2019-08-22 11:51:13 +020076 AudioBuffer ab(capture_config.sample_rate_hz(), capture_config.num_channels(),
77 capture_config.sample_rate_hz(), capture_config.num_channels(),
78 capture_config.sample_rate_hz(),
79 capture_config.num_channels());
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010080 test::InputAudioFile capture_file(
81 test::GetApmCaptureTestVectorFileName(AudioProcessing::kSampleRate48kHz));
82 std::vector<float> capture_input(capture_config.num_frames() *
83 capture_config.num_channels());
84
85 // The file should contain at least this many frames. Every iteration, we put
86 // a frame through the gain controller.
87 const int kNumFramesToProcess = 100;
88 for (int frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) {
89 ReadFloatSamplesFromStereoFile(capture_config.num_frames(),
90 capture_config.num_channels(), &capture_file,
91 capture_input);
92
93 test::CopyVectorToAudioBuffer(capture_config, capture_input, &ab);
94 gain_controller->Process(&ab);
95 }
96
97 // Send in a last frame with values constant 1 (It's low enough to detect high
98 // gain, and for ease of computation). The applied gain is the result.
99 constexpr float sample_value = 1.f;
100 SetAudioBufferSamples(sample_value, &ab);
101 gain_controller->Process(&ab);
Per Åhgrend47941e2019-08-22 11:51:13 +0200102 return ab.channels()[0][0];
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100103}
104
alessiob3ec96df2017-05-22 06:57:06 -0700105} // namespace
106
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200107TEST(GainController2, CheckDefaultConfig) {
Alessio Bazzica270f7b52017-10-13 11:05:17 +0200108 AudioProcessing::Config::GainController2 config;
109 EXPECT_TRUE(GainController2::Validate(config));
alessiob3ec96df2017-05-22 06:57:06 -0700110}
111
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200112TEST(GainController2, CheckFixedDigitalConfig) {
Alessio Bazzica270f7b52017-10-13 11:05:17 +0200113 AudioProcessing::Config::GainController2 config;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200114 // Attenuation is not allowed.
115 config.fixed_digital.gain_db = -5.f;
116 EXPECT_FALSE(GainController2::Validate(config));
117 // No gain is allowed.
118 config.fixed_digital.gain_db = 0.f;
119 EXPECT_TRUE(GainController2::Validate(config));
120 // Positive gain is allowed.
121 config.fixed_digital.gain_db = 15.f;
122 EXPECT_TRUE(GainController2::Validate(config));
123}
alessiob3ec96df2017-05-22 06:57:06 -0700124
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200125TEST(GainController2, CheckAdaptiveDigitalVadProbabilityAttackConfig) {
126 AudioProcessing::Config::GainController2 config;
127 // Reject invalid attack.
128 config.adaptive_digital.vad_probability_attack = -123.f;
129 EXPECT_FALSE(GainController2::Validate(config));
130 config.adaptive_digital.vad_probability_attack = 0.f;
131 EXPECT_FALSE(GainController2::Validate(config));
132 config.adaptive_digital.vad_probability_attack = 42.f;
133 EXPECT_FALSE(GainController2::Validate(config));
134 // Accept valid attack.
135 config.adaptive_digital.vad_probability_attack = 0.1f;
136 EXPECT_TRUE(GainController2::Validate(config));
137 config.adaptive_digital.vad_probability_attack = 1.f;
138 EXPECT_TRUE(GainController2::Validate(config));
139}
alessiob3ec96df2017-05-22 06:57:06 -0700140
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200141TEST(GainController2,
142 CheckAdaptiveDigitalLevelEstimatorSpeechFramesThresholdConfig) {
143 AudioProcessing::Config::GainController2 config;
144 config.adaptive_digital.level_estimator_adjacent_speech_frames_threshold = 0;
145 EXPECT_FALSE(GainController2::Validate(config));
146 config.adaptive_digital.level_estimator_adjacent_speech_frames_threshold = 1;
147 EXPECT_TRUE(GainController2::Validate(config));
148 config.adaptive_digital.level_estimator_adjacent_speech_frames_threshold = 7;
149 EXPECT_TRUE(GainController2::Validate(config));
150}
151
152TEST(GainController2, CheckAdaptiveDigitalInitialSaturationMarginConfig) {
153 AudioProcessing::Config::GainController2 config;
154 config.adaptive_digital.initial_saturation_margin_db = -1.f;
155 EXPECT_FALSE(GainController2::Validate(config));
156 config.adaptive_digital.initial_saturation_margin_db = 0.f;
157 EXPECT_TRUE(GainController2::Validate(config));
158 config.adaptive_digital.initial_saturation_margin_db = 50.f;
159 EXPECT_TRUE(GainController2::Validate(config));
160}
161
162TEST(GainController2, CheckAdaptiveDigitalExtraSaturationMarginConfig) {
163 AudioProcessing::Config::GainController2 config;
164 config.adaptive_digital.extra_saturation_margin_db = -1.f;
165 EXPECT_FALSE(GainController2::Validate(config));
166 config.adaptive_digital.extra_saturation_margin_db = 0.f;
167 EXPECT_TRUE(GainController2::Validate(config));
168 config.adaptive_digital.extra_saturation_margin_db = 50.f;
169 EXPECT_TRUE(GainController2::Validate(config));
170}
171
172TEST(GainController2,
173 CheckAdaptiveDigitalGainApplierSpeechFramesThresholdConfig) {
174 AudioProcessing::Config::GainController2 config;
175 config.adaptive_digital.gain_applier_adjacent_speech_frames_threshold = 0;
176 EXPECT_FALSE(GainController2::Validate(config));
177 config.adaptive_digital.gain_applier_adjacent_speech_frames_threshold = 1;
178 EXPECT_TRUE(GainController2::Validate(config));
179 config.adaptive_digital.gain_applier_adjacent_speech_frames_threshold = 7;
180 EXPECT_TRUE(GainController2::Validate(config));
181}
182
183TEST(GainController2, CheckAdaptiveDigitalMaxGainChangeSpeedConfig) {
184 AudioProcessing::Config::GainController2 config;
185 config.adaptive_digital.max_gain_change_db_per_second = -1.f;
186 EXPECT_FALSE(GainController2::Validate(config));
187 config.adaptive_digital.max_gain_change_db_per_second = 0.f;
188 EXPECT_FALSE(GainController2::Validate(config));
189 config.adaptive_digital.max_gain_change_db_per_second = 5.f;
190 EXPECT_TRUE(GainController2::Validate(config));
191}
192
193TEST(GainController2, CheckAdaptiveDigitalMaxOutputNoiseLevelConfig) {
194 AudioProcessing::Config::GainController2 config;
195 config.adaptive_digital.max_output_noise_level_dbfs = 5.f;
196 EXPECT_FALSE(GainController2::Validate(config));
197 config.adaptive_digital.max_output_noise_level_dbfs = 0.f;
198 EXPECT_TRUE(GainController2::Validate(config));
199 config.adaptive_digital.max_output_noise_level_dbfs = -5.f;
200 EXPECT_TRUE(GainController2::Validate(config));
201}
202
203// Checks that the default config is applied.
204TEST(GainController2, ApplyDefaultConfig) {
205 auto gain_controller2 = std::make_unique<GainController2>();
206 AudioProcessing::Config::GainController2 config;
207 gain_controller2->ApplyConfig(config);
alessiob3ec96df2017-05-22 06:57:06 -0700208}
209
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100210TEST(GainController2FixedDigital, GainShouldChangeOnSetGain) {
211 constexpr float kInputLevel = 1000.f;
212 constexpr size_t kNumFrames = 5;
213 constexpr size_t kSampleRateHz = 8000;
214 constexpr float kGain0Db = 0.f;
215 constexpr float kGain20Db = 20.f;
Alessio Bazzica270f7b52017-10-13 11:05:17 +0200216
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100217 auto agc2_fixed = CreateAgc2FixedDigitalMode(kGain0Db, kSampleRateHz);
218
219 // Signal level is unchanged with 0 db gain.
220 EXPECT_FLOAT_EQ(RunAgc2WithConstantInput(agc2_fixed.get(), kInputLevel,
221 kNumFrames, kSampleRateHz),
222 kInputLevel);
223
224 // +20 db should increase signal by a factor of 10.
225 agc2_fixed->ApplyConfig(CreateAgc2FixedDigitalModeConfig(kGain20Db));
226 EXPECT_FLOAT_EQ(RunAgc2WithConstantInput(agc2_fixed.get(), kInputLevel,
227 kNumFrames, kSampleRateHz),
228 kInputLevel * 10);
alessiob3ec96df2017-05-22 06:57:06 -0700229}
230
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100231TEST(GainController2FixedDigital, ChangeFixedGainShouldBeFastAndTimeInvariant) {
232 // Number of frames required for the fixed gain controller to adapt on the
233 // input signal when the gain changes.
234 constexpr size_t kNumFrames = 5;
Alex Loiko5e784612018-11-01 14:51:56 +0100235
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100236 constexpr float kInputLevel = 1000.f;
237 constexpr size_t kSampleRateHz = 8000;
238 constexpr float kGainDbLow = 0.f;
239 constexpr float kGainDbHigh = 25.f;
240 static_assert(kGainDbLow < kGainDbHigh, "");
Alex Loiko5e784612018-11-01 14:51:56 +0100241
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100242 auto agc2_fixed = CreateAgc2FixedDigitalMode(kGainDbLow, kSampleRateHz);
243
244 // Start with a lower gain.
245 const float output_level_pre = RunAgc2WithConstantInput(
246 agc2_fixed.get(), kInputLevel, kNumFrames, kSampleRateHz);
247
248 // Increase gain.
249 agc2_fixed->ApplyConfig(CreateAgc2FixedDigitalModeConfig(kGainDbHigh));
250 static_cast<void>(RunAgc2WithConstantInput(agc2_fixed.get(), kInputLevel,
251 kNumFrames, kSampleRateHz));
252
253 // Back to the lower gain.
254 agc2_fixed->ApplyConfig(CreateAgc2FixedDigitalModeConfig(kGainDbLow));
255 const float output_level_post = RunAgc2WithConstantInput(
256 agc2_fixed.get(), kInputLevel, kNumFrames, kSampleRateHz);
257
258 EXPECT_EQ(output_level_pre, output_level_post);
259}
260
261struct FixedDigitalTestParams {
262 FixedDigitalTestParams(float gain_db_min,
263 float gain_db_max,
264 size_t sample_rate,
265 bool saturation_expected)
266 : gain_db_min(gain_db_min),
267 gain_db_max(gain_db_max),
268 sample_rate(sample_rate),
269 saturation_expected(saturation_expected) {}
270 float gain_db_min;
271 float gain_db_max;
272 size_t sample_rate;
273 bool saturation_expected;
274};
275
276class FixedDigitalTest
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200277 : public ::testing::Test,
278 public ::testing::WithParamInterface<FixedDigitalTestParams> {};
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100279
280TEST_P(FixedDigitalTest, CheckSaturationBehaviorWithLimiter) {
281 const float kInputLevel = 32767.f;
282 const size_t kNumFrames = 5;
283
284 const auto params = GetParam();
285
286 const auto gains_db =
287 test::LinSpace(params.gain_db_min, params.gain_db_max, 10);
288 for (const auto gain_db : gains_db) {
289 SCOPED_TRACE(std::to_string(gain_db));
290 auto agc2_fixed = CreateAgc2FixedDigitalMode(gain_db, params.sample_rate);
291 const float processed_sample = RunAgc2WithConstantInput(
292 agc2_fixed.get(), kInputLevel, kNumFrames, params.sample_rate);
293 if (params.saturation_expected) {
294 EXPECT_FLOAT_EQ(processed_sample, 32767.f);
295 } else {
296 EXPECT_LT(processed_sample, 32767.f);
297 }
Alex Loiko5e784612018-11-01 14:51:56 +0100298 }
Alex Loiko5e784612018-11-01 14:51:56 +0100299}
300
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100301static_assert(test::kLimiterMaxInputLevelDbFs < 10, "");
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100302INSTANTIATE_TEST_SUITE_P(
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100303 GainController2,
304 FixedDigitalTest,
305 ::testing::Values(
306 // When gain < |test::kLimiterMaxInputLevelDbFs|, the limiter will not
307 // saturate the signal (at any sample rate).
308 FixedDigitalTestParams(0.1f,
309 test::kLimiterMaxInputLevelDbFs - 0.01f,
310 8000,
311 false),
312 FixedDigitalTestParams(0.1,
313 test::kLimiterMaxInputLevelDbFs - 0.01f,
314 48000,
315 false),
316 // When gain > |test::kLimiterMaxInputLevelDbFs|, the limiter will
317 // saturate the signal (at any sample rate).
318 FixedDigitalTestParams(test::kLimiterMaxInputLevelDbFs + 0.01f,
319 10.f,
320 8000,
321 true),
322 FixedDigitalTestParams(test::kLimiterMaxInputLevelDbFs + 0.01f,
323 10.f,
324 48000,
325 true)));
326
Alex Loiko5e784612018-11-01 14:51:56 +0100327TEST(GainController2, UsageSaturationMargin) {
328 GainController2 gain_controller2;
329 gain_controller2.Initialize(AudioProcessing::kSampleRate48kHz);
330
331 AudioProcessing::Config::GainController2 config;
332 // Check that samples are not amplified as much when extra margin is
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100333 // high. They should not be amplified at all, but only after convergence. GC2
334 // starts with a gain, and it takes time until it's down to 0 dB.
Alessio Bazzica1e2542f2018-11-13 14:44:15 +0100335 config.fixed_digital.gain_db = 0.f;
Alessio Bazzica8da7b352018-11-21 10:50:58 +0100336 config.adaptive_digital.enabled = true;
Alessio Bazzica1e2542f2018-11-13 14:44:15 +0100337 config.adaptive_digital.extra_saturation_margin_db = 50.f;
Alex Loiko5e784612018-11-01 14:51:56 +0100338 gain_controller2.ApplyConfig(config);
339
340 EXPECT_LT(GainAfterProcessingFile(&gain_controller2), 2.f);
341}
342
343TEST(GainController2, UsageNoSaturationMargin) {
344 GainController2 gain_controller2;
345 gain_controller2.Initialize(AudioProcessing::kSampleRate48kHz);
346
347 AudioProcessing::Config::GainController2 config;
348 // Check that some gain is applied if there is no margin.
Alessio Bazzica1e2542f2018-11-13 14:44:15 +0100349 config.fixed_digital.gain_db = 0.f;
Alessio Bazzica8da7b352018-11-21 10:50:58 +0100350 config.adaptive_digital.enabled = true;
Alessio Bazzica1e2542f2018-11-13 14:44:15 +0100351 config.adaptive_digital.extra_saturation_margin_db = 0.f;
Alex Loiko5e784612018-11-01 14:51:56 +0100352 gain_controller2.ApplyConfig(config);
353
Alessio Bazzica61982a72021-04-14 16:17:09 +0200354 EXPECT_GT(GainAfterProcessingFile(&gain_controller2), 1.9f);
Alex Loiko5e784612018-11-01 14:51:56 +0100355}
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100356
alessiob3ec96df2017-05-22 06:57:06 -0700357} // namespace test
358} // namespace webrtc