blob: b18d943a781e911babf85f6de086086c48affd05 [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>
Alessio Bazzica980c4602021-04-14 19:09:17 +020014#include <cmath>
Mirko Bonadei317a1f02019-09-17 17:06:18 +020015#include <memory>
Alessio Bazzica6ee97342021-09-27 17:06:40 +020016#include <numeric>
Alessio Bazzica38901042021-10-14 12:14:21 +020017#include <tuple>
alessiob3ec96df2017-05-22 06:57:06 -070018
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "api/array_view.h"
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010020#include "modules/audio_processing/agc2/agc2_testing_common.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "modules/audio_processing/audio_buffer.h"
Alex Loiko5e784612018-11-01 14:51:56 +010022#include "modules/audio_processing/test/audio_buffer_tools.h"
23#include "modules/audio_processing/test/bitexactness_tools.h"
Alessio Bazzica270f7b52017-10-13 11:05:17 +020024#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "test/gtest.h"
alessiob3ec96df2017-05-22 06:57:06 -070026
27namespace webrtc {
28namespace test {
alessiob3ec96df2017-05-22 06:57:06 -070029namespace {
30
Alessio Bazzica38901042021-10-14 12:14:21 +020031using Agc2Config = AudioProcessing::Config::GainController2;
32
Alessio Bazzica6ee97342021-09-27 17:06:40 +020033// Sets all the samples in `ab` to `value`.
34void SetAudioBufferSamples(float value, AudioBuffer& ab) {
35 for (size_t k = 0; k < ab.num_channels(); ++k) {
36 std::fill(ab.channels()[k], ab.channels()[k] + ab.num_frames(), value);
alessiob3ec96df2017-05-22 06:57:06 -070037 }
38}
39
Alessio Bazzica6ee97342021-09-27 17:06:40 +020040float RunAgc2WithConstantInput(GainController2& agc2,
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010041 float input_level,
Alessio Bazzica6ee97342021-09-27 17:06:40 +020042 int num_frames,
43 int sample_rate_hz) {
44 const int num_samples = rtc::CheckedDivExact(sample_rate_hz, 100);
45 AudioBuffer ab(sample_rate_hz, 1, sample_rate_hz, 1, sample_rate_hz, 1);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010046
47 // Give time to the level estimator to converge.
Alessio Bazzica6ee97342021-09-27 17:06:40 +020048 for (int i = 0; i < num_frames + 1; ++i) {
49 SetAudioBufferSamples(input_level, ab);
50 agc2.Process(&ab);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010051 }
52
53 // Return the last sample from the last processed frame.
Per Ã…hgrend47941e2019-08-22 11:51:13 +020054 return ab.channels()[0][num_samples - 1];
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010055}
56
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010057std::unique_ptr<GainController2> CreateAgc2FixedDigitalMode(
58 float fixed_gain_db,
Alessio Bazzica6ee97342021-09-27 17:06:40 +020059 int sample_rate_hz) {
Alessio Bazzica38901042021-10-14 12:14:21 +020060 Agc2Config config;
61 config.adaptive_digital.enabled = false;
62 config.fixed_digital.gain_db = fixed_gain_db;
63 EXPECT_TRUE(GainController2::Validate(config));
64 return std::make_unique<GainController2>(config, sample_rate_hz,
65 /*num_channels=*/1);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010066}
67
alessiob3ec96df2017-05-22 06:57:06 -070068} // namespace
69
Alessio Bazzica0c83e152020-10-14 12:49:54 +020070TEST(GainController2, CheckDefaultConfig) {
Alessio Bazzica38901042021-10-14 12:14:21 +020071 Agc2Config config;
Alessio Bazzica270f7b52017-10-13 11:05:17 +020072 EXPECT_TRUE(GainController2::Validate(config));
alessiob3ec96df2017-05-22 06:57:06 -070073}
74
Alessio Bazzica0c83e152020-10-14 12:49:54 +020075TEST(GainController2, CheckFixedDigitalConfig) {
Alessio Bazzica38901042021-10-14 12:14:21 +020076 Agc2Config config;
Alessio Bazzica0c83e152020-10-14 12:49:54 +020077 // Attenuation is not allowed.
Alessio Bazzica6ee97342021-09-27 17:06:40 +020078 config.fixed_digital.gain_db = -5.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +020079 EXPECT_FALSE(GainController2::Validate(config));
80 // No gain is allowed.
Alessio Bazzica6ee97342021-09-27 17:06:40 +020081 config.fixed_digital.gain_db = 0.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +020082 EXPECT_TRUE(GainController2::Validate(config));
83 // Positive gain is allowed.
Alessio Bazzica6ee97342021-09-27 17:06:40 +020084 config.fixed_digital.gain_db = 15.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +020085 EXPECT_TRUE(GainController2::Validate(config));
86}
alessiob3ec96df2017-05-22 06:57:06 -070087
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +020088TEST(GainController2, CheckHeadroomDb) {
Alessio Bazzica38901042021-10-14 12:14:21 +020089 Agc2Config config;
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +020090 config.adaptive_digital.headroom_db = -1.0f;
91 EXPECT_FALSE(GainController2::Validate(config));
92 config.adaptive_digital.headroom_db = 0.0f;
93 EXPECT_TRUE(GainController2::Validate(config));
94 config.adaptive_digital.headroom_db = 5.0f;
95 EXPECT_TRUE(GainController2::Validate(config));
96}
97
98TEST(GainController2, CheckMaxGainDb) {
Alessio Bazzica38901042021-10-14 12:14:21 +020099 Agc2Config config;
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +0200100 config.adaptive_digital.max_gain_db = -1.0f;
101 EXPECT_FALSE(GainController2::Validate(config));
102 config.adaptive_digital.max_gain_db = 0.0f;
103 EXPECT_FALSE(GainController2::Validate(config));
104 config.adaptive_digital.max_gain_db = 5.0f;
105 EXPECT_TRUE(GainController2::Validate(config));
106}
107
108TEST(GainController2, CheckInitialGainDb) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200109 Agc2Config config;
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +0200110 config.adaptive_digital.initial_gain_db = -1.0f;
111 EXPECT_FALSE(GainController2::Validate(config));
112 config.adaptive_digital.initial_gain_db = 0.0f;
113 EXPECT_TRUE(GainController2::Validate(config));
114 config.adaptive_digital.initial_gain_db = 5.0f;
115 EXPECT_TRUE(GainController2::Validate(config));
116}
117
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200118TEST(GainController2, CheckAdaptiveDigitalMaxGainChangeSpeedConfig) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200119 Agc2Config config;
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200120 config.adaptive_digital.max_gain_change_db_per_second = -1.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200121 EXPECT_FALSE(GainController2::Validate(config));
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200122 config.adaptive_digital.max_gain_change_db_per_second = 0.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200123 EXPECT_FALSE(GainController2::Validate(config));
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200124 config.adaptive_digital.max_gain_change_db_per_second = 5.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200125 EXPECT_TRUE(GainController2::Validate(config));
126}
127
128TEST(GainController2, CheckAdaptiveDigitalMaxOutputNoiseLevelConfig) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200129 Agc2Config config;
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200130 config.adaptive_digital.max_output_noise_level_dbfs = 5.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200131 EXPECT_FALSE(GainController2::Validate(config));
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200132 config.adaptive_digital.max_output_noise_level_dbfs = 0.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200133 EXPECT_TRUE(GainController2::Validate(config));
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200134 config.adaptive_digital.max_output_noise_level_dbfs = -5.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200135 EXPECT_TRUE(GainController2::Validate(config));
136}
137
138// Checks that the default config is applied.
139TEST(GainController2, ApplyDefaultConfig) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200140 auto gain_controller2 = std::make_unique<GainController2>(
141 Agc2Config{}, /*sample_rate_hz=*/16000, /*num_channels=*/2);
142 EXPECT_TRUE(gain_controller2.get());
alessiob3ec96df2017-05-22 06:57:06 -0700143}
144
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100145TEST(GainController2FixedDigital, GainShouldChangeOnSetGain) {
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200146 constexpr float kInputLevel = 1000.0f;
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100147 constexpr size_t kNumFrames = 5;
148 constexpr size_t kSampleRateHz = 8000;
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200149 constexpr float kGain0Db = 0.0f;
150 constexpr float kGain20Db = 20.0f;
Alessio Bazzica270f7b52017-10-13 11:05:17 +0200151
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100152 auto agc2_fixed = CreateAgc2FixedDigitalMode(kGain0Db, kSampleRateHz);
153
154 // Signal level is unchanged with 0 db gain.
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200155 EXPECT_FLOAT_EQ(RunAgc2WithConstantInput(*agc2_fixed, kInputLevel, kNumFrames,
156 kSampleRateHz),
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100157 kInputLevel);
158
159 // +20 db should increase signal by a factor of 10.
Alessio Bazzica38901042021-10-14 12:14:21 +0200160 agc2_fixed->SetFixedGainDb(kGain20Db);
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200161 EXPECT_FLOAT_EQ(RunAgc2WithConstantInput(*agc2_fixed, kInputLevel, kNumFrames,
162 kSampleRateHz),
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100163 kInputLevel * 10);
alessiob3ec96df2017-05-22 06:57:06 -0700164}
165
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100166TEST(GainController2FixedDigital, ChangeFixedGainShouldBeFastAndTimeInvariant) {
167 // Number of frames required for the fixed gain controller to adapt on the
168 // input signal when the gain changes.
169 constexpr size_t kNumFrames = 5;
Alex Loiko5e784612018-11-01 14:51:56 +0100170
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200171 constexpr float kInputLevel = 1000.0f;
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100172 constexpr size_t kSampleRateHz = 8000;
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200173 constexpr float kGainDbLow = 0.0f;
174 constexpr float kGainDbHigh = 25.0f;
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100175 static_assert(kGainDbLow < kGainDbHigh, "");
Alex Loiko5e784612018-11-01 14:51:56 +0100176
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100177 auto agc2_fixed = CreateAgc2FixedDigitalMode(kGainDbLow, kSampleRateHz);
178
179 // Start with a lower gain.
180 const float output_level_pre = RunAgc2WithConstantInput(
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200181 *agc2_fixed, kInputLevel, kNumFrames, kSampleRateHz);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100182
183 // Increase gain.
Alessio Bazzica38901042021-10-14 12:14:21 +0200184 agc2_fixed->SetFixedGainDb(kGainDbHigh);
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200185 static_cast<void>(RunAgc2WithConstantInput(*agc2_fixed, kInputLevel,
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100186 kNumFrames, kSampleRateHz));
187
188 // Back to the lower gain.
Alessio Bazzica38901042021-10-14 12:14:21 +0200189 agc2_fixed->SetFixedGainDb(kGainDbLow);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100190 const float output_level_post = RunAgc2WithConstantInput(
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200191 *agc2_fixed, kInputLevel, kNumFrames, kSampleRateHz);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100192
193 EXPECT_EQ(output_level_pre, output_level_post);
194}
195
Alessio Bazzica38901042021-10-14 12:14:21 +0200196class FixedDigitalTest
197 : public ::testing::TestWithParam<std::tuple<float, float, int, bool>> {
198 protected:
199 float gain_db_min() const { return std::get<0>(GetParam()); }
200 float gain_db_max() const { return std::get<1>(GetParam()); }
201 int sample_rate_hz() const { return std::get<2>(GetParam()); }
202 bool saturation_expected() const { return std::get<3>(GetParam()); }
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100203};
204
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100205TEST_P(FixedDigitalTest, CheckSaturationBehaviorWithLimiter) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200206 for (const float gain_db : test::LinSpace(gain_db_min(), gain_db_max(), 10)) {
207 SCOPED_TRACE(gain_db);
208 auto agc2_fixed = CreateAgc2FixedDigitalMode(gain_db, sample_rate_hz());
209 const float processed_sample =
210 RunAgc2WithConstantInput(*agc2_fixed, /*input_level=*/32767.0f,
211 /*num_frames=*/5, sample_rate_hz());
212 if (saturation_expected()) {
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200213 EXPECT_FLOAT_EQ(processed_sample, 32767.0f);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100214 } else {
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200215 EXPECT_LT(processed_sample, 32767.0f);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100216 }
Alex Loiko5e784612018-11-01 14:51:56 +0100217 }
Alex Loiko5e784612018-11-01 14:51:56 +0100218}
219
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100220static_assert(test::kLimiterMaxInputLevelDbFs < 10, "");
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100221INSTANTIATE_TEST_SUITE_P(
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100222 GainController2,
223 FixedDigitalTest,
224 ::testing::Values(
Artem Titovcfea2182021-08-10 01:22:31 +0200225 // When gain < `test::kLimiterMaxInputLevelDbFs`, the limiter will not
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100226 // saturate the signal (at any sample rate).
Alessio Bazzica38901042021-10-14 12:14:21 +0200227 std::make_tuple(0.1f,
228 test::kLimiterMaxInputLevelDbFs - 0.01f,
229 8000,
230 false),
231 std::make_tuple(0.1,
232 test::kLimiterMaxInputLevelDbFs - 0.01f,
233 48000,
234 false),
Artem Titovcfea2182021-08-10 01:22:31 +0200235 // When gain > `test::kLimiterMaxInputLevelDbFs`, the limiter will
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100236 // saturate the signal (at any sample rate).
Alessio Bazzica38901042021-10-14 12:14:21 +0200237 std::make_tuple(test::kLimiterMaxInputLevelDbFs + 0.01f,
238 10.0f,
239 8000,
240 true),
241 std::make_tuple(test::kLimiterMaxInputLevelDbFs + 0.01f,
242 10.0f,
243 48000,
244 true)));
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100245
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200246// Processes a test audio file and checks that the gain applied at the end of
247// the recording is close to the expected value.
248TEST(GainController2, CheckFinalGainWithAdaptiveDigitalController) {
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200249 constexpr int kSampleRateHz = AudioProcessing::kSampleRate48kHz;
250 constexpr int kStereo = 2;
Alessio Bazzica38901042021-10-14 12:14:21 +0200251
252 // Create AGC2 enabling only the adaptive digital controller.
253 Agc2Config config;
254 config.fixed_digital.gain_db = 0.0f;
255 config.adaptive_digital.enabled = true;
256 GainController2 agc2(config, kSampleRateHz, kStereo);
257
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200258 test::InputAudioFile input_file(
259 test::GetApmCaptureTestVectorFileName(kSampleRateHz),
260 /*loop_at_end=*/true);
261 const StreamConfig stream_config(kSampleRateHz, kStereo,
262 /*has_keyboard=*/false);
263
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200264 // Init buffers.
265 constexpr int kFrameDurationMs = 10;
266 std::vector<float> frame(kStereo * stream_config.num_frames());
267 AudioBuffer audio_buffer(kSampleRateHz, kStereo, kSampleRateHz, kStereo,
268 kSampleRateHz, kStereo);
269
270 // Simulate.
271 constexpr float kGainDb = -6.0f;
272 const float gain = std::pow(10.0f, kGainDb / 20.0f);
273 constexpr int kDurationMs = 10000;
274 constexpr int kNumFramesToProcess = kDurationMs / kFrameDurationMs;
275 for (int i = 0; i < kNumFramesToProcess; ++i) {
276 ReadFloatSamplesFromStereoFile(stream_config.num_frames(),
277 stream_config.num_channels(), &input_file,
278 frame);
279 // Apply a fixed gain to the input audio.
280 for (float& x : frame)
281 x *= gain;
282 test::CopyVectorToAudioBuffer(stream_config, frame, &audio_buffer);
283 // Process.
284 agc2.Process(&audio_buffer);
285 }
286
287 // Estimate the applied gain by processing a probing frame.
288 SetAudioBufferSamples(/*value=*/1.0f, audio_buffer);
289 agc2.Process(&audio_buffer);
290 const float applied_gain_db =
291 20.0f * std::log10(audio_buffer.channels_const()[0][0]);
292
293 constexpr float kExpectedGainDb = 5.6f;
294 constexpr float kToleranceDb = 0.3f;
295 EXPECT_NEAR(applied_gain_db, kExpectedGainDb, kToleranceDb);
Alex Loiko5e784612018-11-01 14:51:56 +0100296}
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100297
alessiob3ec96df2017-05-22 06:57:06 -0700298} // namespace test
299} // namespace webrtc