Line data Source code
1 : /*
2 : * Copyright (c) 2016 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 "webrtc/modules/audio_processing/level_controller/gain_selector.h"
12 :
13 : #include <math.h>
14 : #include <algorithm>
15 :
16 : #include "webrtc/base/checks.h"
17 : #include "webrtc/modules/audio_processing/include/audio_processing.h"
18 : #include "webrtc/modules/audio_processing/level_controller/level_controller_constants.h"
19 :
20 : namespace webrtc {
21 :
22 0 : GainSelector::GainSelector() {
23 0 : Initialize(AudioProcessing::kSampleRate48kHz);
24 0 : }
25 :
26 0 : void GainSelector::Initialize(int sample_rate_hz) {
27 0 : gain_ = 1.f;
28 0 : frame_length_ = rtc::CheckedDivExact(sample_rate_hz, 100);
29 0 : highly_nonstationary_signal_hold_counter_ = 0;
30 0 : }
31 :
32 : // Chooses the gain to apply by the level controller such that
33 : // 1) The level of the stationary noise does not exceed
34 : // a predefined threshold.
35 : // 2) The gain does not exceed the gain that has been found
36 : // to saturate the signal.
37 : // 3) The peak level achieves the target peak level.
38 : // 4) The gain is not below 1.
39 : // 4) The gain is 1 if the signal has been classified as stationary
40 : // for a long time.
41 : // 5) The gain is not above the maximum gain.
42 0 : float GainSelector::GetNewGain(float peak_level,
43 : float noise_energy,
44 : float saturating_gain,
45 : bool gain_jumpstart,
46 : SignalClassifier::SignalType signal_type) {
47 0 : RTC_DCHECK_LT(0.f, peak_level);
48 :
49 0 : if (signal_type == SignalClassifier::SignalType::kHighlyNonStationary ||
50 : gain_jumpstart) {
51 0 : highly_nonstationary_signal_hold_counter_ = 100;
52 : } else {
53 0 : highly_nonstationary_signal_hold_counter_ =
54 0 : std::max(0, highly_nonstationary_signal_hold_counter_ - 1);
55 : }
56 :
57 : float desired_gain;
58 0 : if (highly_nonstationary_signal_hold_counter_ > 0) {
59 : // Compute a desired gain that ensures that the peak level is amplified to
60 : // the target level.
61 0 : desired_gain = kTargetLcPeakLevel / peak_level;
62 :
63 : // Limit the desired gain so that it does not amplify the noise too much.
64 0 : float max_noise_energy = kMaxLcNoisePower * frame_length_;
65 0 : if (noise_energy * desired_gain * desired_gain > max_noise_energy) {
66 0 : RTC_DCHECK_LE(0.f, noise_energy);
67 0 : desired_gain = sqrtf(max_noise_energy / noise_energy);
68 : }
69 : } else {
70 : // If the signal has been stationary for a long while, apply a gain of 1 to
71 : // avoid amplifying pure noise.
72 0 : desired_gain = 1.0f;
73 : }
74 :
75 : // Smootly update the gain towards the desired gain.
76 0 : gain_ += 0.2f * (desired_gain - gain_);
77 :
78 : // Limit the gain to not exceed the maximum and the saturating gains, and to
79 : // ensure that the lowest possible gain is 1.
80 0 : gain_ = std::min(gain_, saturating_gain);
81 0 : gain_ = std::min(gain_, kMaxLcGain);
82 0 : gain_ = std::max(gain_, 1.f);
83 :
84 0 : return gain_;
85 : }
86 :
87 : } // namespace webrtc
|