1 /*
2 * Copyright (c) 2021 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 #include "modules/audio_processing/capture_levels_adjuster/audio_samples_scaler.h"
11
12 #include <tuple>
13
14 #include "modules/audio_processing/test/audio_buffer_tools.h"
15 #include "rtc_base/strings/string_builder.h"
16 #include "test/gtest.h"
17
18 namespace webrtc {
19 namespace {
20
SampleValueForChannel(int channel)21 float SampleValueForChannel(int channel) {
22 constexpr float kSampleBaseValue = 100.f;
23 constexpr float kSampleChannelOffset = 1.f;
24 return kSampleBaseValue + channel * kSampleChannelOffset;
25 }
26
PopulateBuffer(AudioBuffer & audio_buffer)27 void PopulateBuffer(AudioBuffer& audio_buffer) {
28 for (size_t ch = 0; ch < audio_buffer.num_channels(); ++ch) {
29 test::FillBufferChannel(SampleValueForChannel(ch), ch, audio_buffer);
30 }
31 }
32
33 constexpr int kNumFramesToProcess = 10;
34
35 class AudioSamplesScalerTest
36 : public ::testing::Test,
37 public ::testing::WithParamInterface<std::tuple<int, int, float>> {
38 protected:
sample_rate_hz() const39 int sample_rate_hz() const { return std::get<0>(GetParam()); }
num_channels() const40 int num_channels() const { return std::get<1>(GetParam()); }
initial_gain() const41 float initial_gain() const { return std::get<2>(GetParam()); }
42 };
43
44 INSTANTIATE_TEST_SUITE_P(
45 AudioSamplesScalerTestSuite,
46 AudioSamplesScalerTest,
47 ::testing::Combine(::testing::Values(16000, 32000, 48000),
48 ::testing::Values(1, 2, 4),
49 ::testing::Values(0.1f, 1.f, 2.f, 4.f)));
50
TEST_P(AudioSamplesScalerTest,InitialGainIsRespected)51 TEST_P(AudioSamplesScalerTest, InitialGainIsRespected) {
52 AudioSamplesScaler scaler(initial_gain());
53
54 AudioBuffer audio_buffer(sample_rate_hz(), num_channels(), sample_rate_hz(),
55 num_channels(), sample_rate_hz(), num_channels());
56
57 for (int frame = 0; frame < kNumFramesToProcess; ++frame) {
58 PopulateBuffer(audio_buffer);
59 scaler.Process(audio_buffer);
60 for (int ch = 0; ch < num_channels(); ++ch) {
61 for (size_t i = 0; i < audio_buffer.num_frames(); ++i) {
62 EXPECT_FLOAT_EQ(audio_buffer.channels_const()[ch][i],
63 initial_gain() * SampleValueForChannel(ch));
64 }
65 }
66 }
67 }
68
TEST_P(AudioSamplesScalerTest,VerifyGainAdjustment)69 TEST_P(AudioSamplesScalerTest, VerifyGainAdjustment) {
70 const float higher_gain = initial_gain();
71 const float lower_gain = higher_gain / 2.f;
72
73 AudioSamplesScaler scaler(lower_gain);
74
75 AudioBuffer audio_buffer(sample_rate_hz(), num_channels(), sample_rate_hz(),
76 num_channels(), sample_rate_hz(), num_channels());
77
78 // Allow the intial, lower, gain to take effect.
79 PopulateBuffer(audio_buffer);
80
81 scaler.Process(audio_buffer);
82
83 // Set the new, higher, gain.
84 scaler.SetGain(higher_gain);
85
86 // Ensure that the new, higher, gain is achieved gradually over one frame.
87 PopulateBuffer(audio_buffer);
88
89 scaler.Process(audio_buffer);
90 for (int ch = 0; ch < num_channels(); ++ch) {
91 for (size_t i = 0; i < audio_buffer.num_frames() - 1; ++i) {
92 EXPECT_LT(audio_buffer.channels_const()[ch][i],
93 higher_gain * SampleValueForChannel(ch));
94 EXPECT_LE(audio_buffer.channels_const()[ch][i],
95 audio_buffer.channels_const()[ch][i + 1]);
96 }
97 EXPECT_LE(audio_buffer.channels_const()[ch][audio_buffer.num_frames() - 1],
98 higher_gain * SampleValueForChannel(ch));
99 }
100
101 // Ensure that the new, higher, gain is achieved and stay unchanged.
102 for (int frame = 0; frame < kNumFramesToProcess; ++frame) {
103 PopulateBuffer(audio_buffer);
104 scaler.Process(audio_buffer);
105
106 for (int ch = 0; ch < num_channels(); ++ch) {
107 for (size_t i = 0; i < audio_buffer.num_frames(); ++i) {
108 EXPECT_FLOAT_EQ(audio_buffer.channels_const()[ch][i],
109 higher_gain * SampleValueForChannel(ch));
110 }
111 }
112 }
113
114 // Set the new, lower, gain.
115 scaler.SetGain(lower_gain);
116
117 // Ensure that the new, lower, gain is achieved gradually over one frame.
118 PopulateBuffer(audio_buffer);
119 scaler.Process(audio_buffer);
120 for (int ch = 0; ch < num_channels(); ++ch) {
121 for (size_t i = 0; i < audio_buffer.num_frames() - 1; ++i) {
122 EXPECT_GT(audio_buffer.channels_const()[ch][i],
123 lower_gain * SampleValueForChannel(ch));
124 EXPECT_GE(audio_buffer.channels_const()[ch][i],
125 audio_buffer.channels_const()[ch][i + 1]);
126 }
127 EXPECT_GE(audio_buffer.channels_const()[ch][audio_buffer.num_frames() - 1],
128 lower_gain * SampleValueForChannel(ch));
129 }
130
131 // Ensure that the new, lower, gain is achieved and stay unchanged.
132 for (int frame = 0; frame < kNumFramesToProcess; ++frame) {
133 PopulateBuffer(audio_buffer);
134 scaler.Process(audio_buffer);
135
136 for (int ch = 0; ch < num_channels(); ++ch) {
137 for (size_t i = 0; i < audio_buffer.num_frames(); ++i) {
138 EXPECT_FLOAT_EQ(audio_buffer.channels_const()[ch][i],
139 lower_gain * SampleValueForChannel(ch));
140 }
141 }
142 }
143 }
144
TEST(AudioSamplesScaler,UpwardsClamping)145 TEST(AudioSamplesScaler, UpwardsClamping) {
146 constexpr int kSampleRateHz = 48000;
147 constexpr int kNumChannels = 1;
148 constexpr float kGain = 10.f;
149 constexpr float kMaxClampedSampleValue = 32767.f;
150 static_assert(kGain > 1.f, "");
151
152 AudioSamplesScaler scaler(kGain);
153
154 AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz,
155 kNumChannels, kSampleRateHz, kNumChannels);
156
157 for (int frame = 0; frame < kNumFramesToProcess; ++frame) {
158 for (size_t ch = 0; ch < audio_buffer.num_channels(); ++ch) {
159 test::FillBufferChannel(
160 kMaxClampedSampleValue - audio_buffer.num_channels() + 1.f + ch, ch,
161 audio_buffer);
162 }
163
164 scaler.Process(audio_buffer);
165 for (int ch = 0; ch < kNumChannels; ++ch) {
166 for (size_t i = 0; i < audio_buffer.num_frames(); ++i) {
167 EXPECT_FLOAT_EQ(audio_buffer.channels_const()[ch][i],
168 kMaxClampedSampleValue);
169 }
170 }
171 }
172 }
173
TEST(AudioSamplesScaler,DownwardsClamping)174 TEST(AudioSamplesScaler, DownwardsClamping) {
175 constexpr int kSampleRateHz = 48000;
176 constexpr int kNumChannels = 1;
177 constexpr float kGain = 10.f;
178 constexpr float kMinClampedSampleValue = -32768.f;
179 static_assert(kGain > 1.f, "");
180
181 AudioSamplesScaler scaler(kGain);
182
183 AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz,
184 kNumChannels, kSampleRateHz, kNumChannels);
185
186 for (int frame = 0; frame < kNumFramesToProcess; ++frame) {
187 for (size_t ch = 0; ch < audio_buffer.num_channels(); ++ch) {
188 test::FillBufferChannel(
189 kMinClampedSampleValue + audio_buffer.num_channels() - 1.f + ch, ch,
190 audio_buffer);
191 }
192
193 scaler.Process(audio_buffer);
194 for (int ch = 0; ch < kNumChannels; ++ch) {
195 for (size_t i = 0; i < audio_buffer.num_frames(); ++i) {
196 EXPECT_FLOAT_EQ(audio_buffer.channels_const()[ch][i],
197 kMinClampedSampleValue);
198 }
199 }
200 }
201 }
202
203 } // namespace
204 } // namespace webrtc
205