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
11 #include "modules/audio_processing/agc2/clipping_predictor.h"
12
13 #include <cstdint>
14 #include <limits>
15 #include <tuple>
16
17 #include "rtc_base/checks.h"
18 #include "test/gmock.h"
19 #include "test/gtest.h"
20
21 namespace webrtc {
22 namespace {
23
24 using ::testing::Eq;
25 using ::testing::Optional;
26 using ClippingPredictorConfig = AudioProcessing::Config::GainController1::
27 AnalogGainController::ClippingPredictor;
28 using ClippingPredictorMode = AudioProcessing::Config::GainController1::
29 AnalogGainController::ClippingPredictor::Mode;
30
31 constexpr int kSampleRateHz = 32000;
32 constexpr int kNumChannels = 1;
33 constexpr int kSamplesPerChannel = kSampleRateHz / 100;
34 constexpr int kMaxMicLevel = 255;
35 constexpr int kMinMicLevel = 12;
36 constexpr int kDefaultClippedLevelStep = 15;
37 constexpr float kMaxSampleS16 =
38 static_cast<float>(std::numeric_limits<int16_t>::max());
39
40 // Threshold in dB corresponding to a signal with an amplitude equal to 99% of
41 // the dynamic range - i.e., computed as `20*log10(0.99)`.
42 constexpr float kClippingThresholdDb = -0.08729610804900176f;
43
CallAnalyze(int num_calls,const AudioFrameView<const float> & frame,ClippingPredictor & predictor)44 void CallAnalyze(int num_calls,
45 const AudioFrameView<const float>& frame,
46 ClippingPredictor& predictor) {
47 for (int i = 0; i < num_calls; ++i) {
48 predictor.Analyze(frame);
49 }
50 }
51
52 // Creates and analyzes an audio frame with a non-zero (approx. 4.15dB) crest
53 // factor.
AnalyzeNonZeroCrestFactorAudio(int num_calls,int num_channels,float peak_ratio,ClippingPredictor & predictor)54 void AnalyzeNonZeroCrestFactorAudio(int num_calls,
55 int num_channels,
56 float peak_ratio,
57 ClippingPredictor& predictor) {
58 RTC_DCHECK_GT(num_calls, 0);
59 RTC_DCHECK_GT(num_channels, 0);
60 RTC_DCHECK_LE(peak_ratio, 1.0f);
61 std::vector<float*> audio(num_channels);
62 std::vector<float> audio_data(num_channels * kSamplesPerChannel, 0.0f);
63 for (int channel = 0; channel < num_channels; ++channel) {
64 audio[channel] = &audio_data[channel * kSamplesPerChannel];
65 for (int sample = 0; sample < kSamplesPerChannel; sample += 10) {
66 audio[channel][sample] = 0.1f * peak_ratio * kMaxSampleS16;
67 audio[channel][sample + 1] = 0.2f * peak_ratio * kMaxSampleS16;
68 audio[channel][sample + 2] = 0.3f * peak_ratio * kMaxSampleS16;
69 audio[channel][sample + 3] = 0.4f * peak_ratio * kMaxSampleS16;
70 audio[channel][sample + 4] = 0.5f * peak_ratio * kMaxSampleS16;
71 audio[channel][sample + 5] = 0.6f * peak_ratio * kMaxSampleS16;
72 audio[channel][sample + 6] = 0.7f * peak_ratio * kMaxSampleS16;
73 audio[channel][sample + 7] = 0.8f * peak_ratio * kMaxSampleS16;
74 audio[channel][sample + 8] = 0.9f * peak_ratio * kMaxSampleS16;
75 audio[channel][sample + 9] = 1.0f * peak_ratio * kMaxSampleS16;
76 }
77 }
78 AudioFrameView<const float> frame(audio.data(), num_channels,
79 kSamplesPerChannel);
80 CallAnalyze(num_calls, frame, predictor);
81 }
82
CheckChannelEstimatesWithValue(int num_channels,int level,int default_step,int min_mic_level,int max_mic_level,const ClippingPredictor & predictor,int expected)83 void CheckChannelEstimatesWithValue(int num_channels,
84 int level,
85 int default_step,
86 int min_mic_level,
87 int max_mic_level,
88 const ClippingPredictor& predictor,
89 int expected) {
90 for (int i = 0; i < num_channels; ++i) {
91 SCOPED_TRACE(i);
92 EXPECT_THAT(predictor.EstimateClippedLevelStep(
93 i, level, default_step, min_mic_level, max_mic_level),
94 Optional(Eq(expected)));
95 }
96 }
97
CheckChannelEstimatesWithoutValue(int num_channels,int level,int default_step,int min_mic_level,int max_mic_level,const ClippingPredictor & predictor)98 void CheckChannelEstimatesWithoutValue(int num_channels,
99 int level,
100 int default_step,
101 int min_mic_level,
102 int max_mic_level,
103 const ClippingPredictor& predictor) {
104 for (int i = 0; i < num_channels; ++i) {
105 SCOPED_TRACE(i);
106 EXPECT_EQ(predictor.EstimateClippedLevelStep(i, level, default_step,
107 min_mic_level, max_mic_level),
108 absl::nullopt);
109 }
110 }
111
112 // Creates and analyzes an audio frame with a zero crest factor.
AnalyzeZeroCrestFactorAudio(int num_calls,int num_channels,float peak_ratio,ClippingPredictor & predictor)113 void AnalyzeZeroCrestFactorAudio(int num_calls,
114 int num_channels,
115 float peak_ratio,
116 ClippingPredictor& predictor) {
117 RTC_DCHECK_GT(num_calls, 0);
118 RTC_DCHECK_GT(num_channels, 0);
119 RTC_DCHECK_LE(peak_ratio, 1.f);
120 std::vector<float*> audio(num_channels);
121 std::vector<float> audio_data(num_channels * kSamplesPerChannel, 0.f);
122 for (int channel = 0; channel < num_channels; ++channel) {
123 audio[channel] = &audio_data[channel * kSamplesPerChannel];
124 for (int sample = 0; sample < kSamplesPerChannel; ++sample) {
125 audio[channel][sample] = peak_ratio * kMaxSampleS16;
126 }
127 }
128 auto frame = AudioFrameView<const float>(audio.data(), num_channels,
129 kSamplesPerChannel);
130 CallAnalyze(num_calls, frame, predictor);
131 }
132
TEST(ClippingPeakPredictorTest,NoPredictorCreated)133 TEST(ClippingPeakPredictorTest, NoPredictorCreated) {
134 auto predictor =
135 CreateClippingPredictor(kNumChannels, /*config=*/{/*enabled=*/false});
136 EXPECT_FALSE(predictor);
137 }
138
TEST(ClippingPeakPredictorTest,ClippingEventPredictionCreated)139 TEST(ClippingPeakPredictorTest, ClippingEventPredictionCreated) {
140 // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed.
141 auto predictor = CreateClippingPredictor(
142 kNumChannels,
143 /*config=*/{/*enabled=*/true,
144 /*mode=*/ClippingPredictorMode::kClippingEventPrediction});
145 EXPECT_TRUE(predictor);
146 }
147
TEST(ClippingPeakPredictorTest,AdaptiveStepClippingPeakPredictionCreated)148 TEST(ClippingPeakPredictorTest, AdaptiveStepClippingPeakPredictionCreated) {
149 // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed.
150 auto predictor = CreateClippingPredictor(
151 kNumChannels, /*config=*/{
152 /*enabled=*/true,
153 /*mode=*/ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction});
154 EXPECT_TRUE(predictor);
155 }
156
TEST(ClippingPeakPredictorTest,FixedStepClippingPeakPredictionCreated)157 TEST(ClippingPeakPredictorTest, FixedStepClippingPeakPredictionCreated) {
158 // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed.
159 auto predictor = CreateClippingPredictor(
160 kNumChannels, /*config=*/{
161 /*enabled=*/true,
162 /*mode=*/ClippingPredictorMode::kFixedStepClippingPeakPrediction});
163 EXPECT_TRUE(predictor);
164 }
165
166 class ClippingPredictorParameterization
167 : public ::testing::TestWithParam<std::tuple<int, int, int, int>> {
168 protected:
num_channels() const169 int num_channels() const { return std::get<0>(GetParam()); }
GetConfig(ClippingPredictorMode mode) const170 ClippingPredictorConfig GetConfig(ClippingPredictorMode mode) const {
171 // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed.
172 return {/*enabled=*/true,
173 /*mode=*/mode,
174 /*window_length=*/std::get<1>(GetParam()),
175 /*reference_window_length=*/std::get<2>(GetParam()),
176 /*reference_window_delay=*/std::get<3>(GetParam()),
177 /*clipping_threshold=*/-1.0f,
178 /*crest_factor_margin=*/0.5f};
179 }
180 };
181
TEST_P(ClippingPredictorParameterization,CheckClippingEventPredictorEstimateAfterCrestFactorDrop)182 TEST_P(ClippingPredictorParameterization,
183 CheckClippingEventPredictorEstimateAfterCrestFactorDrop) {
184 const ClippingPredictorConfig config =
185 GetConfig(ClippingPredictorMode::kClippingEventPrediction);
186 if (config.reference_window_length + config.reference_window_delay <=
187 config.window_length) {
188 return;
189 }
190 auto predictor = CreateClippingPredictor(num_channels(), config);
191 AnalyzeNonZeroCrestFactorAudio(
192 /*num_calls=*/config.reference_window_length +
193 config.reference_window_delay - config.window_length,
194 num_channels(), /*peak_ratio=*/0.99f, *predictor);
195 CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255,
196 kDefaultClippedLevelStep, kMinMicLevel,
197 kMaxMicLevel, *predictor);
198 AnalyzeZeroCrestFactorAudio(config.window_length, num_channels(),
199 /*peak_ratio=*/0.99f, *predictor);
200 CheckChannelEstimatesWithValue(
201 num_channels(), /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel,
202 kMaxMicLevel, *predictor, kDefaultClippedLevelStep);
203 }
204
TEST_P(ClippingPredictorParameterization,CheckClippingEventPredictorNoEstimateAfterConstantCrestFactor)205 TEST_P(ClippingPredictorParameterization,
206 CheckClippingEventPredictorNoEstimateAfterConstantCrestFactor) {
207 const ClippingPredictorConfig config =
208 GetConfig(ClippingPredictorMode::kClippingEventPrediction);
209 if (config.reference_window_length + config.reference_window_delay <=
210 config.window_length) {
211 return;
212 }
213 auto predictor = CreateClippingPredictor(num_channels(), config);
214 AnalyzeNonZeroCrestFactorAudio(
215 /*num_calls=*/config.reference_window_length +
216 config.reference_window_delay - config.window_length,
217 num_channels(), /*peak_ratio=*/0.99f, *predictor);
218 CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255,
219 kDefaultClippedLevelStep, kMinMicLevel,
220 kMaxMicLevel, *predictor);
221 AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.window_length,
222 num_channels(),
223 /*peak_ratio=*/0.99f, *predictor);
224 CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255,
225 kDefaultClippedLevelStep, kMinMicLevel,
226 kMaxMicLevel, *predictor);
227 }
228
TEST_P(ClippingPredictorParameterization,CheckClippingPeakPredictorEstimateAfterHighCrestFactor)229 TEST_P(ClippingPredictorParameterization,
230 CheckClippingPeakPredictorEstimateAfterHighCrestFactor) {
231 const ClippingPredictorConfig config =
232 GetConfig(ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction);
233 if (config.reference_window_length + config.reference_window_delay <=
234 config.window_length) {
235 return;
236 }
237 auto predictor = CreateClippingPredictor(num_channels(), config);
238 AnalyzeNonZeroCrestFactorAudio(
239 /*num_calls=*/config.reference_window_length +
240 config.reference_window_delay - config.window_length,
241 num_channels(), /*peak_ratio=*/0.99f, *predictor);
242 CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255,
243 kDefaultClippedLevelStep, kMinMicLevel,
244 kMaxMicLevel, *predictor);
245 AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.window_length,
246 num_channels(),
247 /*peak_ratio=*/0.99f, *predictor);
248 CheckChannelEstimatesWithValue(
249 num_channels(), /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel,
250 kMaxMicLevel, *predictor, kDefaultClippedLevelStep);
251 }
252
TEST_P(ClippingPredictorParameterization,CheckClippingPeakPredictorNoEstimateAfterLowCrestFactor)253 TEST_P(ClippingPredictorParameterization,
254 CheckClippingPeakPredictorNoEstimateAfterLowCrestFactor) {
255 const ClippingPredictorConfig config =
256 GetConfig(ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction);
257 if (config.reference_window_length + config.reference_window_delay <=
258 config.window_length) {
259 return;
260 }
261 auto predictor = CreateClippingPredictor(num_channels(), config);
262 AnalyzeZeroCrestFactorAudio(
263 /*num_calls=*/config.reference_window_length +
264 config.reference_window_delay - config.window_length,
265 num_channels(), /*peak_ratio=*/0.99f, *predictor);
266 CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255,
267 kDefaultClippedLevelStep, kMinMicLevel,
268 kMaxMicLevel, *predictor);
269 AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.window_length,
270 num_channels(),
271 /*peak_ratio=*/0.99f, *predictor);
272 CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255,
273 kDefaultClippedLevelStep, kMinMicLevel,
274 kMaxMicLevel, *predictor);
275 }
276
277 INSTANTIATE_TEST_SUITE_P(GainController1ClippingPredictor,
278 ClippingPredictorParameterization,
279 ::testing::Combine(::testing::Values(1, 5),
280 ::testing::Values(1, 5, 10),
281 ::testing::Values(1, 5),
282 ::testing::Values(0, 1, 5)));
283
284 class ClippingEventPredictorParameterization
285 : public ::testing::TestWithParam<std::tuple<float, float>> {
286 protected:
GetConfig() const287 ClippingPredictorConfig GetConfig() const {
288 // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed.
289 return {/*enabled=*/true,
290 /*mode=*/ClippingPredictorMode::kClippingEventPrediction,
291 /*window_length=*/5,
292 /*reference_window_length=*/5,
293 /*reference_window_delay=*/5,
294 /*clipping_threshold=*/std::get<0>(GetParam()),
295 /*crest_factor_margin=*/std::get<1>(GetParam())};
296 }
297 };
298
TEST_P(ClippingEventPredictorParameterization,CheckEstimateAfterCrestFactorDrop)299 TEST_P(ClippingEventPredictorParameterization,
300 CheckEstimateAfterCrestFactorDrop) {
301 const ClippingPredictorConfig config = GetConfig();
302 auto predictor = CreateClippingPredictor(kNumChannels, config);
303 AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.reference_window_length,
304 kNumChannels, /*peak_ratio=*/0.99f,
305 *predictor);
306 CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255,
307 kDefaultClippedLevelStep, kMinMicLevel,
308 kMaxMicLevel, *predictor);
309 AnalyzeZeroCrestFactorAudio(config.window_length, kNumChannels,
310 /*peak_ratio=*/0.99f, *predictor);
311 // TODO(bugs.webrtc.org/12774): Add clarifying comment.
312 // TODO(bugs.webrtc.org/12774): Remove 4.15f threshold and split tests.
313 if (config.clipping_threshold < kClippingThresholdDb &&
314 config.crest_factor_margin < 4.15f) {
315 CheckChannelEstimatesWithValue(
316 kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel,
317 kMaxMicLevel, *predictor, kDefaultClippedLevelStep);
318 } else {
319 CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255,
320 kDefaultClippedLevelStep, kMinMicLevel,
321 kMaxMicLevel, *predictor);
322 }
323 }
324
325 INSTANTIATE_TEST_SUITE_P(GainController1ClippingPredictor,
326 ClippingEventPredictorParameterization,
327 ::testing::Combine(::testing::Values(-1.0f, 0.0f),
328 ::testing::Values(3.0f, 4.16f)));
329
330 class ClippingPredictorModeParameterization
331 : public ::testing::TestWithParam<ClippingPredictorMode> {
332 protected:
GetConfig(float clipping_threshold_dbfs) const333 ClippingPredictorConfig GetConfig(float clipping_threshold_dbfs) const {
334 // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed.
335 return {/*enabled=*/true,
336 /*mode=*/GetParam(),
337 /*window_length=*/5,
338 /*reference_window_length=*/5,
339 /*reference_window_delay=*/5,
340 /*clipping_threshold=*/clipping_threshold_dbfs,
341 /*crest_factor_margin=*/3.0f};
342 }
343 };
344
TEST_P(ClippingPredictorModeParameterization,CheckEstimateAfterHighCrestFactorWithNoClippingMargin)345 TEST_P(ClippingPredictorModeParameterization,
346 CheckEstimateAfterHighCrestFactorWithNoClippingMargin) {
347 const ClippingPredictorConfig config = GetConfig(
348 /*clipping_threshold_dbfs=*/0.0f);
349 auto predictor = CreateClippingPredictor(kNumChannels, config);
350 AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.reference_window_length,
351 kNumChannels, /*peak_ratio=*/0.99f,
352 *predictor);
353 CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255,
354 kDefaultClippedLevelStep, kMinMicLevel,
355 kMaxMicLevel, *predictor);
356 AnalyzeZeroCrestFactorAudio(config.window_length, kNumChannels,
357 /*peak_ratio=*/0.99f, *predictor);
358 // Since the clipping threshold is set to 0 dBFS, `EstimateClippedLevelStep()`
359 // is expected to return an unavailable value.
360 CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255,
361 kDefaultClippedLevelStep, kMinMicLevel,
362 kMaxMicLevel, *predictor);
363 }
364
TEST_P(ClippingPredictorModeParameterization,CheckEstimateAfterHighCrestFactorWithClippingMargin)365 TEST_P(ClippingPredictorModeParameterization,
366 CheckEstimateAfterHighCrestFactorWithClippingMargin) {
367 const ClippingPredictorConfig config =
368 GetConfig(/*clipping_threshold_dbfs=*/-1.0f);
369 auto predictor = CreateClippingPredictor(kNumChannels, config);
370 AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.reference_window_length,
371 kNumChannels,
372 /*peak_ratio=*/0.99f, *predictor);
373 CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255,
374 kDefaultClippedLevelStep, kMinMicLevel,
375 kMaxMicLevel, *predictor);
376 AnalyzeZeroCrestFactorAudio(config.window_length, kNumChannels,
377 /*peak_ratio=*/0.99f, *predictor);
378 // TODO(bugs.webrtc.org/12774): Add clarifying comment.
379 const float expected_step =
380 config.mode == ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction
381 ? 17
382 : kDefaultClippedLevelStep;
383 CheckChannelEstimatesWithValue(kNumChannels, /*level=*/255,
384 kDefaultClippedLevelStep, kMinMicLevel,
385 kMaxMicLevel, *predictor, expected_step);
386 }
387
388 INSTANTIATE_TEST_SUITE_P(
389 GainController1ClippingPredictor,
390 ClippingPredictorModeParameterization,
391 ::testing::Values(
392 ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction,
393 ClippingPredictorMode::kFixedStepClippingPeakPrediction));
394
TEST(ClippingEventPredictorTest,CheckEstimateAfterReset)395 TEST(ClippingEventPredictorTest, CheckEstimateAfterReset) {
396 // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed.
397 constexpr ClippingPredictorConfig kConfig{
398 /*enabled=*/true,
399 /*mode=*/ClippingPredictorMode::kClippingEventPrediction,
400 /*window_length=*/5,
401 /*reference_window_length=*/5,
402 /*reference_window_delay=*/5,
403 /*clipping_threshold=*/-1.0f,
404 /*crest_factor_margin=*/3.0f};
405 auto predictor = CreateClippingPredictor(kNumChannels, kConfig);
406 AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/kConfig.reference_window_length,
407 kNumChannels,
408 /*peak_ratio=*/0.99f, *predictor);
409 CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255,
410 kDefaultClippedLevelStep, kMinMicLevel,
411 kMaxMicLevel, *predictor);
412 predictor->Reset();
413 AnalyzeZeroCrestFactorAudio(kConfig.window_length, kNumChannels,
414 /*peak_ratio=*/0.99f, *predictor);
415 CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255,
416 kDefaultClippedLevelStep, kMinMicLevel,
417 kMaxMicLevel, *predictor);
418 }
419
TEST(ClippingPeakPredictorTest,CheckNoEstimateAfterReset)420 TEST(ClippingPeakPredictorTest, CheckNoEstimateAfterReset) {
421 // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed.
422 constexpr ClippingPredictorConfig kConfig{
423 /*enabled=*/true,
424 /*mode=*/ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction,
425 /*window_length=*/5,
426 /*reference_window_length=*/5,
427 /*reference_window_delay=*/5,
428 /*clipping_threshold=*/-1.0f};
429 auto predictor = CreateClippingPredictor(kNumChannels, kConfig);
430 AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/kConfig.reference_window_length,
431 kNumChannels,
432 /*peak_ratio=*/0.99f, *predictor);
433 CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255,
434 kDefaultClippedLevelStep, kMinMicLevel,
435 kMaxMicLevel, *predictor);
436 predictor->Reset();
437 AnalyzeZeroCrestFactorAudio(kConfig.window_length, kNumChannels,
438 /*peak_ratio=*/0.99f, *predictor);
439 CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255,
440 kDefaultClippedLevelStep, kMinMicLevel,
441 kMaxMicLevel, *predictor);
442 }
443
TEST(ClippingPeakPredictorTest,CheckAdaptiveStepEstimate)444 TEST(ClippingPeakPredictorTest, CheckAdaptiveStepEstimate) {
445 // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed.
446 constexpr ClippingPredictorConfig kConfig{
447 /*enabled=*/true,
448 /*mode=*/ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction,
449 /*window_length=*/5,
450 /*reference_window_length=*/5,
451 /*reference_window_delay=*/5,
452 /*clipping_threshold=*/-1.0f};
453 auto predictor = CreateClippingPredictor(kNumChannels, kConfig);
454 AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/kConfig.reference_window_length,
455 kNumChannels, /*peak_ratio=*/0.99f,
456 *predictor);
457 CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255,
458 kDefaultClippedLevelStep, kMinMicLevel,
459 kMaxMicLevel, *predictor);
460 AnalyzeZeroCrestFactorAudio(kConfig.window_length, kNumChannels,
461 /*peak_ratio=*/0.99f, *predictor);
462 CheckChannelEstimatesWithValue(kNumChannels, /*level=*/255,
463 kDefaultClippedLevelStep, kMinMicLevel,
464 kMaxMicLevel, *predictor, /*expected=*/17);
465 }
466
TEST(ClippingPeakPredictorTest,CheckFixedStepEstimate)467 TEST(ClippingPeakPredictorTest, CheckFixedStepEstimate) {
468 // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed.
469 constexpr ClippingPredictorConfig kConfig{
470 /*enabled=*/true,
471 /*mode=*/ClippingPredictorMode::kFixedStepClippingPeakPrediction,
472 /*window_length=*/5,
473 /*reference_window_length=*/5,
474 /*reference_window_delay=*/5,
475 /*clipping_threshold=*/-1.0f};
476 auto predictor = CreateClippingPredictor(kNumChannels, kConfig);
477 AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/kConfig.reference_window_length,
478 kNumChannels, /*peak_ratio=*/0.99f,
479 *predictor);
480 CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255,
481 kDefaultClippedLevelStep, kMinMicLevel,
482 kMaxMicLevel, *predictor);
483 AnalyzeZeroCrestFactorAudio(kConfig.window_length, kNumChannels,
484 /*peak_ratio=*/0.99f, *predictor);
485 CheckChannelEstimatesWithValue(
486 kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel,
487 kMaxMicLevel, *predictor, kDefaultClippedLevelStep);
488 }
489
490 } // namespace
491 } // namespace webrtc
492