1 /*
2 * Copyright (c) 2018 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/noise_level_estimator.h"
12
13 #include <array>
14 #include <cmath>
15 #include <functional>
16 #include <limits>
17
18 #include "api/function_view.h"
19 #include "modules/audio_processing/agc2/agc2_testing_common.h"
20 #include "modules/audio_processing/agc2/vector_float_frame.h"
21 #include "modules/audio_processing/logging/apm_data_dumper.h"
22 #include "rtc_base/gunit.h"
23
24 namespace webrtc {
25 namespace {
26
27 constexpr int kNumIterations = 200;
28 constexpr int kFramesPerSecond = 100;
29
30 // Runs the noise estimator on audio generated by 'sample_generator'
31 // for kNumIterations. Returns the last noise level estimate.
RunEstimator(rtc::FunctionView<float ()> sample_generator,NoiseLevelEstimator & estimator,int sample_rate_hz)32 float RunEstimator(rtc::FunctionView<float()> sample_generator,
33 NoiseLevelEstimator& estimator,
34 int sample_rate_hz) {
35 const int samples_per_channel =
36 rtc::CheckedDivExact(sample_rate_hz, kFramesPerSecond);
37 VectorFloatFrame signal(1, samples_per_channel, 0.0f);
38 for (int i = 0; i < kNumIterations; ++i) {
39 AudioFrameView<float> frame_view = signal.float_frame_view();
40 for (int j = 0; j < samples_per_channel; ++j) {
41 frame_view.channel(0)[j] = sample_generator();
42 }
43 estimator.Analyze(frame_view);
44 }
45 return estimator.Analyze(signal.float_frame_view());
46 }
47
48 class NoiseEstimatorParametrization : public ::testing::TestWithParam<int> {
49 protected:
sample_rate_hz() const50 int sample_rate_hz() const { return GetParam(); }
51 };
52
53 // Checks that full scale white noise maps to about -5.5 dBFS.
TEST_P(NoiseEstimatorParametrization,NoiseFloorEstimatorWithRandomNoise)54 TEST_P(NoiseEstimatorParametrization, NoiseFloorEstimatorWithRandomNoise) {
55 ApmDataDumper data_dumper(0);
56 auto estimator = CreateNoiseFloorEstimator(&data_dumper);
57
58 test::WhiteNoiseGenerator gen(/*min_amplitude=*/test::kMinS16,
59 /*max_amplitude=*/test::kMaxS16);
60 const float noise_level_dbfs =
61 RunEstimator(gen, *estimator, sample_rate_hz());
62 EXPECT_NEAR(noise_level_dbfs, -5.5f, 0.5f);
63 }
64
65 // Checks that a full scale sine wave maps to about -3 dBFS.
TEST_P(NoiseEstimatorParametrization,NoiseFloorEstimatorWithSineTone)66 TEST_P(NoiseEstimatorParametrization, NoiseFloorEstimatorWithSineTone) {
67 ApmDataDumper data_dumper(0);
68 auto estimator = CreateNoiseFloorEstimator(&data_dumper);
69
70 test::SineGenerator gen(/*amplitude=*/test::kMaxS16, /*frequency_hz=*/600.0f,
71 sample_rate_hz());
72 const float noise_level_dbfs =
73 RunEstimator(gen, *estimator, sample_rate_hz());
74 EXPECT_NEAR(noise_level_dbfs, -3.0f, 0.1f);
75 }
76
77 // Check that sufficiently spaced periodic pulses do not raise the estimated
78 // noise floor, which is determined by the amplitude of the non-pulse samples.
TEST_P(NoiseEstimatorParametrization,NoiseFloorEstimatorWithPulseTone)79 TEST_P(NoiseEstimatorParametrization, NoiseFloorEstimatorWithPulseTone) {
80 ApmDataDumper data_dumper(0);
81 auto estimator = CreateNoiseFloorEstimator(&data_dumper);
82
83 constexpr float kNoPulseAmplitude = 10.0f;
84 test::PulseGenerator gen(/*pulse_amplitude=*/test::kMaxS16, kNoPulseAmplitude,
85 /*frequency_hz=*/20.0f, sample_rate_hz());
86 const float noise_level_dbfs =
87 RunEstimator(gen, *estimator, sample_rate_hz());
88 const float expected_noise_floor_dbfs =
89 20.0f * std::log10f(kNoPulseAmplitude / test::kMaxS16);
90 EXPECT_NEAR(noise_level_dbfs, expected_noise_floor_dbfs, 0.5f);
91 }
92
93 INSTANTIATE_TEST_SUITE_P(GainController2NoiseEstimator,
94 NoiseEstimatorParametrization,
95 ::testing::Values(8000, 16000, 32000, 48000));
96
97 } // namespace
98 } // namespace webrtc
99