limiter.cc (5692B)
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/limiter.h" 12 13 #include <algorithm> 14 #include <array> 15 #include <cmath> 16 #include <cstddef> 17 18 #include "absl/strings/string_view.h" 19 #include "api/array_view.h" 20 #include "api/audio/audio_view.h" 21 #include "modules/audio_processing/agc2/agc2_common.h" 22 #include "modules/audio_processing/agc2/interpolated_gain_curve.h" 23 #include "modules/audio_processing/logging/apm_data_dumper.h" 24 #include "rtc_base/checks.h" 25 #include "rtc_base/numerics/safe_conversions.h" 26 #include "rtc_base/numerics/safe_minmax.h" 27 28 namespace webrtc { 29 namespace { 30 31 // This constant affects the way scaling factors are interpolated for the first 32 // sub-frame of a frame. Only in the case in which the first sub-frame has an 33 // estimated level which is greater than the that of the previous analyzed 34 // sub-frame, linear interpolation is replaced with a power function which 35 // reduces the chances of over-shooting (and hence saturation), however reducing 36 // the fixed gain effectiveness. 37 constexpr float kAttackFirstSubframeInterpolationPower = 8.0f; 38 39 void InterpolateFirstSubframe(float last_factor, 40 float current_factor, 41 ArrayView<float> subframe) { 42 const int n = dchecked_cast<int>(subframe.size()); 43 constexpr float p = kAttackFirstSubframeInterpolationPower; 44 for (int i = 0; i < n; ++i) { 45 float t = static_cast<float>(i) / n; 46 subframe[i] = 47 std::pow(1.f - t, p) * (last_factor - current_factor) + current_factor; 48 } 49 } 50 51 void ComputePerSampleSubframeFactors( 52 const std::array<float, kSubFramesInFrame + 1>& scaling_factors, 53 MonoView<float> per_sample_scaling_factors) { 54 const size_t num_subframes = scaling_factors.size() - 1; 55 const int subframe_size = CheckedDivExact( 56 SamplesPerChannel(per_sample_scaling_factors), num_subframes); 57 58 // Handle first sub-frame differently in case of attack. 59 const bool is_attack = scaling_factors[0] > scaling_factors[1]; 60 if (is_attack) { 61 InterpolateFirstSubframe( 62 scaling_factors[0], scaling_factors[1], 63 per_sample_scaling_factors.subview(0, subframe_size)); 64 } 65 66 for (size_t i = is_attack ? 1 : 0; i < num_subframes; ++i) { 67 const int subframe_start = i * subframe_size; 68 const float scaling_start = scaling_factors[i]; 69 const float scaling_end = scaling_factors[i + 1]; 70 const float scaling_diff = (scaling_end - scaling_start) / subframe_size; 71 for (int j = 0; j < subframe_size; ++j) { 72 per_sample_scaling_factors[subframe_start + j] = 73 scaling_start + scaling_diff * j; 74 } 75 } 76 } 77 78 void ScaleSamples(MonoView<const float> per_sample_scaling_factors, 79 DeinterleavedView<float> signal) { 80 const int samples_per_channel = signal.samples_per_channel(); 81 RTC_DCHECK_EQ(samples_per_channel, 82 SamplesPerChannel(per_sample_scaling_factors)); 83 for (size_t i = 0; i < signal.num_channels(); ++i) { 84 MonoView<float> channel = signal[i]; 85 for (int j = 0; j < samples_per_channel; ++j) { 86 channel[j] = SafeClamp(channel[j] * per_sample_scaling_factors[j], 87 kMinFloatS16Value, kMaxFloatS16Value); 88 } 89 } 90 } 91 } // namespace 92 93 Limiter::Limiter(ApmDataDumper* apm_data_dumper, 94 size_t samples_per_channel, 95 absl::string_view histogram_name) 96 : interp_gain_curve_(apm_data_dumper, histogram_name), 97 level_estimator_(samples_per_channel, apm_data_dumper), 98 apm_data_dumper_(apm_data_dumper) { 99 RTC_DCHECK_LE(samples_per_channel, kMaximalNumberOfSamplesPerChannel); 100 } 101 102 Limiter::~Limiter() = default; 103 104 void Limiter::Process(DeinterleavedView<float> signal) { 105 RTC_DCHECK_LE(signal.samples_per_channel(), 106 kMaximalNumberOfSamplesPerChannel); 107 108 const std::array<float, kSubFramesInFrame> level_estimate = 109 level_estimator_.ComputeLevel(signal); 110 111 RTC_DCHECK_EQ(level_estimate.size() + 1, scaling_factors_.size()); 112 scaling_factors_[0] = last_scaling_factor_; 113 std::transform(level_estimate.begin(), level_estimate.end(), 114 scaling_factors_.begin() + 1, [this](float x) { 115 return interp_gain_curve_.LookUpGainToApply(x); 116 }); 117 118 MonoView<float> per_sample_scaling_factors(&per_sample_scaling_factors_[0], 119 signal.samples_per_channel()); 120 ComputePerSampleSubframeFactors(scaling_factors_, per_sample_scaling_factors); 121 ScaleSamples(per_sample_scaling_factors, signal); 122 123 last_scaling_factor_ = scaling_factors_.back(); 124 125 // Dump data for debug. 126 apm_data_dumper_->DumpRaw("agc2_limiter_last_scaling_factor", 127 last_scaling_factor_); 128 apm_data_dumper_->DumpRaw( 129 "agc2_limiter_region", 130 static_cast<int>(interp_gain_curve_.get_stats().region)); 131 } 132 133 InterpolatedGainCurve::Stats Limiter::GetGainCurveStats() const { 134 return interp_gain_curve_.get_stats(); 135 } 136 137 void Limiter::SetSamplesPerChannel(size_t samples_per_channel) { 138 RTC_DCHECK_LE(samples_per_channel, kMaximalNumberOfSamplesPerChannel); 139 level_estimator_.SetSamplesPerChannel(samples_per_channel); 140 } 141 142 void Limiter::Reset() { 143 level_estimator_.Reset(); 144 } 145 146 float Limiter::LastAudioLevel() const { 147 return level_estimator_.LastAudioLevel(); 148 } 149 150 } // namespace webrtc