From 98ff0280ce69ae2c060e3cc98b1ea80fcf94704a Mon Sep 17 00:00:00 2001 From: Alessio Bazzica Date: Wed, 16 Jun 2021 11:24:31 +0200 Subject: [PATCH] AGC analog ClippingPredictor refactoring 2/2 Uunit test code readability improvements. Bug: webrtc:12774 Change-Id: I66f552d23680ddb03824618dab869946e0940334 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/221900 Commit-Queue: Alessio Bazzica Reviewed-by: Hanna Silen Cr-Commit-Position: refs/heads/master@{#34300} --- .../agc/clipping_predictor_unittest.cc | 512 ++++++++++-------- 1 file changed, 289 insertions(+), 223 deletions(-) diff --git a/modules/audio_processing/agc/clipping_predictor_unittest.cc b/modules/audio_processing/agc/clipping_predictor_unittest.cc index e5220ea258..e848e1a724 100644 --- a/modules/audio_processing/agc/clipping_predictor_unittest.cc +++ b/modules/audio_processing/agc/clipping_predictor_unittest.cc @@ -10,6 +10,8 @@ #include "modules/audio_processing/agc/clipping_predictor.h" +#include +#include #include #include "rtc_base/checks.h" @@ -21,23 +23,25 @@ namespace { using ::testing::Eq; using ::testing::Optional; - -constexpr int kSampleRateHz = 32000; -constexpr int kNumChannels = 1; -constexpr int kSamplesPerChannel = kSampleRateHz / 100; -constexpr int kWindowLength = 5; -constexpr int kReferenceWindowLength = 5; -constexpr int kReferenceWindowDelay = 5; -constexpr int kMaxMicLevel = 255; -constexpr int kMinMicLevel = 12; -constexpr int kDefaultClippedLevelStep = 15; - using ClippingPredictorConfig = AudioProcessing::Config::GainController1:: AnalogGainController::ClippingPredictor; using ClippingPredictorMode = AudioProcessing::Config::GainController1:: AnalogGainController::ClippingPredictor::Mode; -void CallProcess(int num_calls, +constexpr int kSampleRateHz = 32000; +constexpr int kNumChannels = 1; +constexpr int kSamplesPerChannel = kSampleRateHz / 100; +constexpr int kMaxMicLevel = 255; +constexpr int kMinMicLevel = 12; +constexpr int kDefaultClippedLevelStep = 15; +constexpr float kMaxSampleS16 = + static_cast(std::numeric_limits::max()); + +// Threshold in dB corresponding to a signal with an amplitude equal to 99% of +// the dynamic range - i.e., computed as `20*log10(0.99)`. +constexpr float kClippingThresholdDb = -0.08729610804900176f; + +void CallAnalyze(int num_calls, const AudioFrameView& frame, ClippingPredictor& predictor) { for (int i = 0; i < num_calls; ++i) { @@ -45,35 +49,35 @@ void CallProcess(int num_calls, } } -// Creates and processes an audio frame with a non-zero (approx. 4.15dB) crest +// Creates and analyzes an audio frame with a non-zero (approx. 4.15dB) crest // factor. -void ProcessNonZeroCrestFactorAudio(int num_calls, +void AnalyzeNonZeroCrestFactorAudio(int num_calls, int num_channels, float peak_ratio, ClippingPredictor& predictor) { RTC_DCHECK_GT(num_calls, 0); RTC_DCHECK_GT(num_channels, 0); - RTC_DCHECK_LE(peak_ratio, 1.f); + RTC_DCHECK_LE(peak_ratio, 1.0f); std::vector audio(num_channels); - std::vector audio_data(num_channels * kSamplesPerChannel, 0.f); + std::vector audio_data(num_channels * kSamplesPerChannel, 0.0f); for (int channel = 0; channel < num_channels; ++channel) { audio[channel] = &audio_data[channel * kSamplesPerChannel]; for (int sample = 0; sample < kSamplesPerChannel; sample += 10) { - audio[channel][sample] = 0.1f * peak_ratio * 32767.f; - audio[channel][sample + 1] = 0.2f * peak_ratio * 32767.f; - audio[channel][sample + 2] = 0.3f * peak_ratio * 32767.f; - audio[channel][sample + 3] = 0.4f * peak_ratio * 32767.f; - audio[channel][sample + 4] = 0.5f * peak_ratio * 32767.f; - audio[channel][sample + 5] = 0.6f * peak_ratio * 32767.f; - audio[channel][sample + 6] = 0.7f * peak_ratio * 32767.f; - audio[channel][sample + 7] = 0.8f * peak_ratio * 32767.f; - audio[channel][sample + 8] = 0.9f * peak_ratio * 32767.f; - audio[channel][sample + 9] = 1.f * peak_ratio * 32767.f; + audio[channel][sample] = 0.1f * peak_ratio * kMaxSampleS16; + audio[channel][sample + 1] = 0.2f * peak_ratio * kMaxSampleS16; + audio[channel][sample + 2] = 0.3f * peak_ratio * kMaxSampleS16; + audio[channel][sample + 3] = 0.4f * peak_ratio * kMaxSampleS16; + audio[channel][sample + 4] = 0.5f * peak_ratio * kMaxSampleS16; + audio[channel][sample + 5] = 0.6f * peak_ratio * kMaxSampleS16; + audio[channel][sample + 6] = 0.7f * peak_ratio * kMaxSampleS16; + audio[channel][sample + 7] = 0.8f * peak_ratio * kMaxSampleS16; + audio[channel][sample + 8] = 0.9f * peak_ratio * kMaxSampleS16; + audio[channel][sample + 9] = 1.0f * peak_ratio * kMaxSampleS16; } } - auto frame = AudioFrameView(audio.data(), num_channels, - kSamplesPerChannel); - CallProcess(num_calls, frame, predictor); + AudioFrameView frame(audio.data(), num_channels, + kSamplesPerChannel); + CallAnalyze(num_calls, frame, predictor); } void CheckChannelEstimatesWithValue(int num_channels, @@ -84,6 +88,7 @@ void CheckChannelEstimatesWithValue(int num_channels, const ClippingPredictor& predictor, int expected) { for (int i = 0; i < num_channels; ++i) { + SCOPED_TRACE(i); EXPECT_THAT(predictor.EstimateClippedLevelStep( i, level, default_step, min_mic_level, max_mic_level), Optional(Eq(expected))); @@ -97,14 +102,15 @@ void CheckChannelEstimatesWithoutValue(int num_channels, int max_mic_level, const ClippingPredictor& predictor) { for (int i = 0; i < num_channels; ++i) { + SCOPED_TRACE(i); EXPECT_EQ(predictor.EstimateClippedLevelStep(i, level, default_step, min_mic_level, max_mic_level), absl::nullopt); } } -// Creates and processes an audio frame with a zero crest factor. -void ProcessZeroCrestFactorAudio(int num_calls, +// Creates and analyzes an audio frame with a zero crest factor. +void AnalyzeZeroCrestFactorAudio(int num_calls, int num_channels, float peak_ratio, ClippingPredictor& predictor) { @@ -116,137 +122,156 @@ void ProcessZeroCrestFactorAudio(int num_calls, for (int channel = 0; channel < num_channels; ++channel) { audio[channel] = &audio_data[channel * kSamplesPerChannel]; for (int sample = 0; sample < kSamplesPerChannel; ++sample) { - audio[channel][sample] = peak_ratio * 32767.f; + audio[channel][sample] = peak_ratio * kMaxSampleS16; } } auto frame = AudioFrameView(audio.data(), num_channels, kSamplesPerChannel); - CallProcess(num_calls, frame, predictor); + CallAnalyze(num_calls, frame, predictor); +} + +TEST(ClippingPeakPredictorTest, NoPredictorCreated) { + auto predictor = + CreateClippingPredictor(kNumChannels, /*config=*/{/*enabled=*/false}); + EXPECT_FALSE(predictor); +} + +TEST(ClippingPeakPredictorTest, ClippingEventPredictionCreated) { + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + auto predictor = CreateClippingPredictor( + kNumChannels, + /*config=*/{/*enabled=*/true, + /*mode=*/ClippingPredictorMode::kClippingEventPrediction}); + EXPECT_TRUE(predictor); +} + +TEST(ClippingPeakPredictorTest, AdaptiveStepClippingPeakPredictionCreated) { + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + auto predictor = CreateClippingPredictor( + kNumChannels, /*config=*/{ + /*enabled=*/true, + /*mode=*/ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction}); + EXPECT_TRUE(predictor); +} + +TEST(ClippingPeakPredictorTest, FixedStepClippingPeakPredictionCreated) { + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + auto predictor = CreateClippingPredictor( + kNumChannels, /*config=*/{ + /*enabled=*/true, + /*mode=*/ClippingPredictorMode::kFixedStepClippingPeakPrediction}); + EXPECT_TRUE(predictor); } class ClippingPredictorParameterization : public ::testing::TestWithParam> { protected: int num_channels() const { return std::get<0>(GetParam()); } - int window_length() const { return std::get<1>(GetParam()); } - int reference_window_length() const { return std::get<2>(GetParam()); } - int reference_window_delay() const { return std::get<3>(GetParam()); } -}; - -class ClippingEventPredictorParameterization - : public ::testing::TestWithParam> { - protected: - float clipping_threshold() const { return std::get<0>(GetParam()); } - float crest_factor_margin() const { return std::get<1>(GetParam()); } -}; - -class ClippingPeakPredictorParameterization - : public ::testing::TestWithParam> { - protected: - float adaptive_step_estimation() const { return std::get<0>(GetParam()); } - float clipping_threshold() const { return std::get<1>(GetParam()); } + ClippingPredictorConfig GetConfig(ClippingPredictorMode mode) const { + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + return {/*enabled=*/true, + /*mode=*/mode, + /*window_length=*/std::get<1>(GetParam()), + /*reference_window_length=*/std::get<2>(GetParam()), + /*reference_window_delay=*/std::get<3>(GetParam()), + /*clipping_threshold=*/-1.0f, + /*crest_factor_margin=*/0.5f}; + } }; TEST_P(ClippingPredictorParameterization, CheckClippingEventPredictorEstimateAfterCrestFactorDrop) { - if (reference_window_length() + reference_window_delay() > window_length()) { - ClippingPredictorConfig config; - config.enabled = true; - config.mode = ClippingPredictorMode::kClippingEventPrediction; - config.window_length = window_length(); - config.reference_window_length = reference_window_length(); - config.reference_window_delay = reference_window_delay(); - config.clipping_threshold = -1.0f; - config.crest_factor_margin = 0.5f; - auto predictor = CreateClippingPredictor(num_channels(), config); - ProcessNonZeroCrestFactorAudio( - reference_window_length() + reference_window_delay() - window_length(), - num_channels(), /*peak_ratio=*/0.99f, *predictor); - CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, - kDefaultClippedLevelStep, kMinMicLevel, - kMaxMicLevel, *predictor); - ProcessZeroCrestFactorAudio(window_length(), num_channels(), - /*peak_ratio=*/0.99f, *predictor); - CheckChannelEstimatesWithValue( - num_channels(), /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, - kMaxMicLevel, *predictor, kDefaultClippedLevelStep); + const ClippingPredictorConfig config = + GetConfig(ClippingPredictorMode::kClippingEventPrediction); + if (config.reference_window_length + config.reference_window_delay <= + config.window_length) { + return; } + auto predictor = CreateClippingPredictor(num_channels(), config); + AnalyzeNonZeroCrestFactorAudio( + /*num_calls=*/config.reference_window_length + + config.reference_window_delay - config.window_length, + num_channels(), /*peak_ratio=*/0.99f, *predictor); + CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, + kDefaultClippedLevelStep, kMinMicLevel, + kMaxMicLevel, *predictor); + AnalyzeZeroCrestFactorAudio(config.window_length, num_channels(), + /*peak_ratio=*/0.99f, *predictor); + CheckChannelEstimatesWithValue( + num_channels(), /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, + kMaxMicLevel, *predictor, kDefaultClippedLevelStep); } TEST_P(ClippingPredictorParameterization, CheckClippingEventPredictorNoEstimateAfterConstantCrestFactor) { - if (reference_window_length() + reference_window_delay() > window_length()) { - ClippingPredictorConfig config; - config.enabled = true; - config.mode = ClippingPredictorMode::kClippingEventPrediction; - config.window_length = window_length(); - config.reference_window_length = reference_window_length(); - config.reference_window_delay = reference_window_delay(); - config.clipping_threshold = -1.0f; - config.crest_factor_margin = 0.5f; - auto predictor = CreateClippingPredictor(num_channels(), config); - ProcessNonZeroCrestFactorAudio( - reference_window_length() + reference_window_delay() - window_length(), - num_channels(), /*peak_ratio=*/0.99f, *predictor); - CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, - kDefaultClippedLevelStep, kMinMicLevel, - kMaxMicLevel, *predictor); - ProcessNonZeroCrestFactorAudio(window_length(), num_channels(), - /*peak_ratio=*/0.99f, *predictor); - CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, - kDefaultClippedLevelStep, kMinMicLevel, - kMaxMicLevel, *predictor); + const ClippingPredictorConfig config = + GetConfig(ClippingPredictorMode::kClippingEventPrediction); + if (config.reference_window_length + config.reference_window_delay <= + config.window_length) { + return; } + auto predictor = CreateClippingPredictor(num_channels(), config); + AnalyzeNonZeroCrestFactorAudio( + /*num_calls=*/config.reference_window_length + + config.reference_window_delay - config.window_length, + num_channels(), /*peak_ratio=*/0.99f, *predictor); + CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, + kDefaultClippedLevelStep, kMinMicLevel, + kMaxMicLevel, *predictor); + AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.window_length, + num_channels(), + /*peak_ratio=*/0.99f, *predictor); + CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, + kDefaultClippedLevelStep, kMinMicLevel, + kMaxMicLevel, *predictor); } TEST_P(ClippingPredictorParameterization, CheckClippingPeakPredictorEstimateAfterHighCrestFactor) { - if (reference_window_length() + reference_window_delay() > window_length()) { - ClippingPredictorConfig config; - config.enabled = true; - config.mode = ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction; - config.window_length = window_length(); - config.reference_window_length = reference_window_length(); - config.reference_window_delay = reference_window_delay(); - config.clipping_threshold = -1.0f; - auto predictor = CreateClippingPredictor(num_channels(), config); - ProcessNonZeroCrestFactorAudio( - reference_window_length() + reference_window_delay() - window_length(), - num_channels(), /*peak_ratio=*/0.99f, *predictor); - CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, - kDefaultClippedLevelStep, kMinMicLevel, - kMaxMicLevel, *predictor); - ProcessNonZeroCrestFactorAudio(window_length(), num_channels(), - /*peak_ratio=*/0.99f, *predictor); - CheckChannelEstimatesWithValue( - num_channels(), /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, - kMaxMicLevel, *predictor, kDefaultClippedLevelStep); + const ClippingPredictorConfig config = + GetConfig(ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction); + if (config.reference_window_length + config.reference_window_delay <= + config.window_length) { + return; } + auto predictor = CreateClippingPredictor(num_channels(), config); + AnalyzeNonZeroCrestFactorAudio( + /*num_calls=*/config.reference_window_length + + config.reference_window_delay - config.window_length, + num_channels(), /*peak_ratio=*/0.99f, *predictor); + CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, + kDefaultClippedLevelStep, kMinMicLevel, + kMaxMicLevel, *predictor); + AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.window_length, + num_channels(), + /*peak_ratio=*/0.99f, *predictor); + CheckChannelEstimatesWithValue( + num_channels(), /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, + kMaxMicLevel, *predictor, kDefaultClippedLevelStep); } TEST_P(ClippingPredictorParameterization, CheckClippingPeakPredictorNoEstimateAfterLowCrestFactor) { - if (reference_window_length() + reference_window_delay() > window_length()) { - ClippingPredictorConfig config; - config.enabled = true; - config.mode = ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction; - config.window_length = window_length(); - config.reference_window_length = reference_window_length(); - config.reference_window_delay = reference_window_delay(); - config.clipping_threshold = -1.0f; - auto predictor = CreateClippingPredictor(num_channels(), config); - ProcessZeroCrestFactorAudio( - reference_window_length() + reference_window_delay() - window_length(), - num_channels(), /*peak_ratio=*/0.99f, *predictor); - CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, - kDefaultClippedLevelStep, kMinMicLevel, - kMaxMicLevel, *predictor); - ProcessNonZeroCrestFactorAudio(window_length(), num_channels(), - /*peak_ratio=*/0.99f, *predictor); - CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, - kDefaultClippedLevelStep, kMinMicLevel, - kMaxMicLevel, *predictor); + const ClippingPredictorConfig config = + GetConfig(ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction); + if (config.reference_window_length + config.reference_window_delay <= + config.window_length) { + return; } + auto predictor = CreateClippingPredictor(num_channels(), config); + AnalyzeZeroCrestFactorAudio( + /*num_calls=*/config.reference_window_length + + config.reference_window_delay - config.window_length, + num_channels(), /*peak_ratio=*/0.99f, *predictor); + CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, + kDefaultClippedLevelStep, kMinMicLevel, + kMaxMicLevel, *predictor); + AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.window_length, + num_channels(), + /*peak_ratio=*/0.99f, *predictor); + CheckChannelEstimatesWithoutValue(num_channels(), /*level=*/255, + kDefaultClippedLevelStep, kMinMicLevel, + kMaxMicLevel, *predictor); } INSTANTIATE_TEST_SUITE_P(GainController1ClippingPredictor, @@ -256,26 +281,37 @@ INSTANTIATE_TEST_SUITE_P(GainController1ClippingPredictor, ::testing::Values(1, 5), ::testing::Values(0, 1, 5))); +class ClippingEventPredictorParameterization + : public ::testing::TestWithParam> { + protected: + ClippingPredictorConfig GetConfig() const { + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + return {/*enabled=*/true, + /*mode=*/ClippingPredictorMode::kClippingEventPrediction, + /*window_length=*/5, + /*reference_window_length=*/5, + /*reference_window_delay=*/5, + /*clipping_threshold=*/std::get<0>(GetParam()), + /*crest_factor_margin=*/std::get<1>(GetParam())}; + } +}; + TEST_P(ClippingEventPredictorParameterization, CheckEstimateAfterCrestFactorDrop) { - ClippingPredictorConfig config; - config.enabled = true; - config.mode = ClippingPredictorMode::kClippingEventPrediction; - config.window_length = kWindowLength; - config.reference_window_length = kReferenceWindowLength; - config.reference_window_delay = kReferenceWindowDelay; - config.clipping_threshold = clipping_threshold(); - config.crest_factor_margin = crest_factor_margin(); + const ClippingPredictorConfig config = GetConfig(); auto predictor = CreateClippingPredictor(kNumChannels, config); - ProcessNonZeroCrestFactorAudio(kReferenceWindowLength, kNumChannels, - /*peak_ratio=*/0.99f, *predictor); + AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.reference_window_length, + kNumChannels, /*peak_ratio=*/0.99f, + *predictor); CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, kMaxMicLevel, *predictor); - ProcessZeroCrestFactorAudio(kWindowLength, kNumChannels, /*peak_ratio=*/0.99f, - *predictor); - if (clipping_threshold() < 20 * std::log10f(0.99f) && - crest_factor_margin() < 4.15f) { + AnalyzeZeroCrestFactorAudio(config.window_length, kNumChannels, + /*peak_ratio=*/0.99f, *predictor); + // TODO(bugs.webrtc.org/12774): Add clarifying comment. + // TODO(bugs.webrtc.org/12774): Remove 4.15f threshold and split tests. + if (config.clipping_threshold < kClippingThresholdDb && + config.crest_factor_margin < 4.15f) { CheckChannelEstimatesWithValue( kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, kMaxMicLevel, *predictor, kDefaultClippedLevelStep); @@ -291,65 +327,90 @@ INSTANTIATE_TEST_SUITE_P(GainController1ClippingPredictor, ::testing::Combine(::testing::Values(-1.0f, 0.0f), ::testing::Values(3.0f, 4.16f))); -TEST_P(ClippingPeakPredictorParameterization, - CheckEstimateAfterHighCrestFactor) { - ClippingPredictorConfig config; - config.enabled = true; - config.mode = adaptive_step_estimation() - ? ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction - : ClippingPredictorMode::kFixedStepClippingPeakPrediction; - config.window_length = kWindowLength; - config.reference_window_length = kReferenceWindowLength; - config.reference_window_delay = kReferenceWindowDelay; - config.clipping_threshold = clipping_threshold(); +class ClippingPredictorModeParameterization + : public ::testing::TestWithParam { + protected: + ClippingPredictorConfig GetConfig(float clipping_threshold_dbfs) const { + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + return {/*enabled=*/true, + /*mode=*/GetParam(), + /*window_length=*/5, + /*reference_window_length=*/5, + /*reference_window_delay=*/5, + /*clipping_threshold=*/clipping_threshold_dbfs, + /*crest_factor_margin=*/3.0f}; + } +}; + +TEST_P(ClippingPredictorModeParameterization, + CheckEstimateAfterHighCrestFactorWithNoClippingMargin) { + const ClippingPredictorConfig config = GetConfig( + /*clipping_threshold_dbfs=*/0.0f); auto predictor = CreateClippingPredictor(kNumChannels, config); - ProcessNonZeroCrestFactorAudio(kReferenceWindowLength, kNumChannels, + AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.reference_window_length, + kNumChannels, /*peak_ratio=*/0.99f, + *predictor); + CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255, + kDefaultClippedLevelStep, kMinMicLevel, + kMaxMicLevel, *predictor); + AnalyzeZeroCrestFactorAudio(config.window_length, kNumChannels, + /*peak_ratio=*/0.99f, *predictor); + // Since the clipping threshold is set to 0 dBFS, `EstimateClippedLevelStep()` + // is expected to return an unavailable value. + CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255, + kDefaultClippedLevelStep, kMinMicLevel, + kMaxMicLevel, *predictor); +} + +TEST_P(ClippingPredictorModeParameterization, + CheckEstimateAfterHighCrestFactorWithClippingMargin) { + const ClippingPredictorConfig config = + GetConfig(/*clipping_threshold_dbfs=*/-1.0f); + auto predictor = CreateClippingPredictor(kNumChannels, config); + AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/config.reference_window_length, + kNumChannels, /*peak_ratio=*/0.99f, *predictor); CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, kMaxMicLevel, *predictor); - ProcessZeroCrestFactorAudio(kWindowLength, kNumChannels, + AnalyzeZeroCrestFactorAudio(config.window_length, kNumChannels, /*peak_ratio=*/0.99f, *predictor); - if (clipping_threshold() < 20 * std::log10(0.99f)) { - if (adaptive_step_estimation()) { - CheckChannelEstimatesWithValue(kNumChannels, /*level=*/255, - kDefaultClippedLevelStep, kMinMicLevel, - kMaxMicLevel, *predictor, - /*expected=*/17); - } else { - CheckChannelEstimatesWithValue( - kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, - kMaxMicLevel, *predictor, kDefaultClippedLevelStep); - } - } else { - CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255, - kDefaultClippedLevelStep, kMinMicLevel, - kMaxMicLevel, *predictor); - } + // TODO(bugs.webrtc.org/12774): Add clarifying comment. + const float expected_step = + config.mode == ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction + ? 17 + : kDefaultClippedLevelStep; + CheckChannelEstimatesWithValue(kNumChannels, /*level=*/255, + kDefaultClippedLevelStep, kMinMicLevel, + kMaxMicLevel, *predictor, expected_step); } -INSTANTIATE_TEST_SUITE_P(GainController1ClippingPredictor, - ClippingPeakPredictorParameterization, - ::testing::Combine(::testing::Values(true, false), - ::testing::Values(-1.0f, 0.0f))); +INSTANTIATE_TEST_SUITE_P( + GainController1ClippingPredictor, + ClippingPredictorModeParameterization, + ::testing::Values( + ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction, + ClippingPredictorMode::kFixedStepClippingPeakPrediction)); TEST(ClippingEventPredictorTest, CheckEstimateAfterReset) { - ClippingPredictorConfig config; - config.enabled = true; - config.mode = ClippingPredictorMode::kClippingEventPrediction; - config.window_length = kWindowLength; - config.reference_window_length = kReferenceWindowLength; - config.reference_window_delay = kReferenceWindowDelay; - config.clipping_threshold = -1.0f; - config.crest_factor_margin = 3.0f; - auto predictor = CreateClippingPredictor(kNumChannels, config); - ProcessNonZeroCrestFactorAudio(kReferenceWindowLength, kNumChannels, + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + constexpr ClippingPredictorConfig kConfig{ + /*enabled=*/true, + /*mode=*/ClippingPredictorMode::kClippingEventPrediction, + /*window_length=*/5, + /*reference_window_length=*/5, + /*reference_window_delay=*/5, + /*clipping_threshold=*/-1.0f, + /*crest_factor_margin=*/3.0f}; + auto predictor = CreateClippingPredictor(kNumChannels, kConfig); + AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/kConfig.reference_window_length, + kNumChannels, /*peak_ratio=*/0.99f, *predictor); CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, kMaxMicLevel, *predictor); predictor->Reset(); - ProcessZeroCrestFactorAudio(kWindowLength, kNumChannels, + AnalyzeZeroCrestFactorAudio(kConfig.window_length, kNumChannels, /*peak_ratio=*/0.99f, *predictor); CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, @@ -357,22 +418,23 @@ TEST(ClippingEventPredictorTest, CheckEstimateAfterReset) { } TEST(ClippingPeakPredictorTest, CheckNoEstimateAfterReset) { - ClippingPredictorConfig config; - config.enabled = true; - config.mode = ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction; - config.window_length = kWindowLength; - config.reference_window_length = kReferenceWindowLength; - config.reference_window_delay = kReferenceWindowDelay; - config.clipping_threshold = -1.0f; - config.crest_factor_margin = 3.0f; - auto predictor = CreateClippingPredictor(kNumChannels, config); - ProcessNonZeroCrestFactorAudio(kReferenceWindowLength, kNumChannels, + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + constexpr ClippingPredictorConfig kConfig{ + /*enabled=*/true, + /*mode=*/ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction, + /*window_length=*/5, + /*reference_window_length=*/5, + /*reference_window_delay=*/5, + /*clipping_threshold=*/-1.0f}; + auto predictor = CreateClippingPredictor(kNumChannels, kConfig); + AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/kConfig.reference_window_length, + kNumChannels, /*peak_ratio=*/0.99f, *predictor); CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, kMaxMicLevel, *predictor); predictor->Reset(); - ProcessZeroCrestFactorAudio(kWindowLength, kNumChannels, + AnalyzeZeroCrestFactorAudio(kConfig.window_length, kNumChannels, /*peak_ratio=*/0.99f, *predictor); CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, @@ -380,20 +442,22 @@ TEST(ClippingPeakPredictorTest, CheckNoEstimateAfterReset) { } TEST(ClippingPeakPredictorTest, CheckAdaptiveStepEstimate) { - ClippingPredictorConfig config; - config.enabled = true; - config.mode = ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction; - config.window_length = kWindowLength; - config.reference_window_length = kReferenceWindowLength; - config.reference_window_delay = kReferenceWindowDelay; - config.clipping_threshold = -1.0f; - auto predictor = CreateClippingPredictor(kNumChannels, config); - ProcessNonZeroCrestFactorAudio(kReferenceWindowLength, kNumChannels, - /*peak_ratio=*/0.99f, *predictor); + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + constexpr ClippingPredictorConfig kConfig{ + /*enabled=*/true, + /*mode=*/ClippingPredictorMode::kAdaptiveStepClippingPeakPrediction, + /*window_length=*/5, + /*reference_window_length=*/5, + /*reference_window_delay=*/5, + /*clipping_threshold=*/-1.0f}; + auto predictor = CreateClippingPredictor(kNumChannels, kConfig); + AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/kConfig.reference_window_length, + kNumChannels, /*peak_ratio=*/0.99f, + *predictor); CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, kMaxMicLevel, *predictor); - ProcessZeroCrestFactorAudio(kWindowLength, kNumChannels, + AnalyzeZeroCrestFactorAudio(kConfig.window_length, kNumChannels, /*peak_ratio=*/0.99f, *predictor); CheckChannelEstimatesWithValue(kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, @@ -401,20 +465,22 @@ TEST(ClippingPeakPredictorTest, CheckAdaptiveStepEstimate) { } TEST(ClippingPeakPredictorTest, CheckFixedStepEstimate) { - ClippingPredictorConfig config; - config.enabled = true; - config.mode = ClippingPredictorMode::kFixedStepClippingPeakPrediction; - config.window_length = kWindowLength; - config.reference_window_length = kReferenceWindowLength; - config.reference_window_delay = kReferenceWindowDelay; - config.clipping_threshold = -1.0f; - auto predictor = CreateClippingPredictor(kNumChannels, config); - ProcessNonZeroCrestFactorAudio(kReferenceWindowLength, kNumChannels, - /*peak_ratio=*/0.99f, *predictor); + // TODO(bugs.webrtc.org/12874): Use designated initializers one fixed. + constexpr ClippingPredictorConfig kConfig{ + /*enabled=*/true, + /*mode=*/ClippingPredictorMode::kFixedStepClippingPeakPrediction, + /*window_length=*/5, + /*reference_window_length=*/5, + /*reference_window_delay=*/5, + /*clipping_threshold=*/-1.0f}; + auto predictor = CreateClippingPredictor(kNumChannels, kConfig); + AnalyzeNonZeroCrestFactorAudio(/*num_calls=*/kConfig.reference_window_length, + kNumChannels, /*peak_ratio=*/0.99f, + *predictor); CheckChannelEstimatesWithoutValue(kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel, kMaxMicLevel, *predictor); - ProcessZeroCrestFactorAudio(kWindowLength, kNumChannels, + AnalyzeZeroCrestFactorAudio(kConfig.window_length, kNumChannels, /*peak_ratio=*/0.99f, *predictor); CheckChannelEstimatesWithValue( kNumChannels, /*level=*/255, kDefaultClippedLevelStep, kMinMicLevel,