gain_applier.cc (3461B)
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/gain_applier.h" 12 13 #include <cstddef> 14 15 #include "api/audio/audio_view.h" 16 #include "modules/audio_processing/agc2/agc2_common.h" 17 #include "rtc_base/checks.h" 18 #include "rtc_base/numerics/safe_minmax.h" 19 20 namespace webrtc { 21 namespace { 22 23 // Returns true when the gain factor is so close to 1 that it would 24 // not affect int16 samples. 25 bool GainCloseToOne(float gain_factor) { 26 return 1.f - 1.f / kMaxFloatS16Value <= gain_factor && 27 gain_factor <= 1.f + 1.f / kMaxFloatS16Value; 28 } 29 30 void ClipSignal(DeinterleavedView<float> signal) { 31 for (size_t k = 0; k < signal.num_channels(); ++k) { 32 MonoView<float> channel_view = signal[k]; 33 for (auto& sample : channel_view) { 34 sample = SafeClamp(sample, kMinFloatS16Value, kMaxFloatS16Value); 35 } 36 } 37 } 38 39 void ApplyGainWithRamping(float last_gain_linear, 40 float gain_at_end_of_frame_linear, 41 float inverse_samples_per_channel, 42 DeinterleavedView<float> float_frame) { 43 // Do not modify the signal. 44 if (last_gain_linear == gain_at_end_of_frame_linear && 45 GainCloseToOne(gain_at_end_of_frame_linear)) { 46 return; 47 } 48 49 // Gain is constant and different from 1. 50 if (last_gain_linear == gain_at_end_of_frame_linear) { 51 for (size_t k = 0; k < float_frame.num_channels(); ++k) { 52 MonoView<float> channel_view = float_frame[k]; 53 for (auto& sample : channel_view) { 54 sample *= gain_at_end_of_frame_linear; 55 } 56 } 57 return; 58 } 59 60 // The gain changes. We have to change slowly to avoid discontinuities. 61 const float increment = (gain_at_end_of_frame_linear - last_gain_linear) * 62 inverse_samples_per_channel; 63 for (size_t ch = 0; ch < float_frame.num_channels(); ++ch) { 64 float gain = last_gain_linear; 65 for (float& sample : float_frame[ch]) { 66 sample *= gain; 67 gain += increment; 68 } 69 } 70 } 71 72 } // namespace 73 74 GainApplier::GainApplier(bool hard_clip_samples, float initial_gain_factor) 75 : hard_clip_samples_(hard_clip_samples), 76 last_gain_factor_(initial_gain_factor), 77 current_gain_factor_(initial_gain_factor) {} 78 79 void GainApplier::ApplyGain(DeinterleavedView<float> signal) { 80 if (static_cast<int>(signal.samples_per_channel()) != samples_per_channel_) { 81 Initialize(signal.samples_per_channel()); 82 } 83 84 ApplyGainWithRamping(last_gain_factor_, current_gain_factor_, 85 inverse_samples_per_channel_, signal); 86 87 last_gain_factor_ = current_gain_factor_; 88 89 if (hard_clip_samples_) { 90 ClipSignal(signal); 91 } 92 } 93 94 // TODO(bugs.webrtc.org/7494): Remove once switched to gains in dB. 95 void GainApplier::SetGainFactor(float gain_factor) { 96 RTC_DCHECK_GT(gain_factor, 0.f); 97 current_gain_factor_ = gain_factor; 98 } 99 100 void GainApplier::Initialize(int samples_per_channel) { 101 RTC_DCHECK_GT(samples_per_channel, 0); 102 samples_per_channel_ = static_cast<int>(samples_per_channel); 103 inverse_samples_per_channel_ = 1.f / samples_per_channel_; 104 } 105 106 } // namespace webrtc