blob: 1589f07404d990039ddb93fe063c41dbea5ecea5 [file] [log] [blame]
Alex Loikoa05ee822018-02-20 15:58:36 +01001/*
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
Alessio Bazzica746d46b2018-10-30 10:48:38 +010011#include "modules/audio_processing/agc2/limiter.h"
Alex Loikoa05ee822018-02-20 15:58:36 +010012
13#include <algorithm>
14#include <array>
15#include <cmath>
16
17#include "api/array_view.h"
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010018#include "modules/audio_processing/agc2/agc2_common.h"
Alex Loiko507e8d12018-02-27 13:51:47 +010019#include "modules/audio_processing/logging/apm_data_dumper.h"
Alex Loikoa05ee822018-02-20 15:58:36 +010020#include "rtc_base/checks.h"
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010021#include "rtc_base/numerics/safe_minmax.h"
Alex Loikoa05ee822018-02-20 15:58:36 +010022
23namespace webrtc {
24namespace {
25
26// This constant affects the way scaling factors are interpolated for the first
27// sub-frame of a frame. Only in the case in which the first sub-frame has an
28// estimated level which is greater than the that of the previous analyzed
29// sub-frame, linear interpolation is replaced with a power function which
30// reduces the chances of over-shooting (and hence saturation), however reducing
31// the fixed gain effectiveness.
32constexpr float kAttackFirstSubframeInterpolationPower = 8.f;
33
34void InterpolateFirstSubframe(float last_factor,
35 float current_factor,
36 rtc::ArrayView<float> subframe) {
37 const auto n = subframe.size();
38 constexpr auto p = kAttackFirstSubframeInterpolationPower;
39 for (size_t i = 0; i < n; ++i) {
40 subframe[i] = std::pow(1.f - i / n, p) * (last_factor - current_factor) +
41 current_factor;
42 }
43}
44
45void ComputePerSampleSubframeFactors(
46 const std::array<float, kSubFramesInFrame + 1>& scaling_factors,
47 size_t samples_per_channel,
48 rtc::ArrayView<float> per_sample_scaling_factors) {
49 const size_t num_subframes = scaling_factors.size() - 1;
50 const size_t subframe_size =
51 rtc::CheckedDivExact(samples_per_channel, num_subframes);
52
53 // Handle first sub-frame differently in case of attack.
54 const bool is_attack = scaling_factors[0] > scaling_factors[1];
55 if (is_attack) {
56 InterpolateFirstSubframe(
57 scaling_factors[0], scaling_factors[1],
58 rtc::ArrayView<float>(
59 per_sample_scaling_factors.subview(0, subframe_size)));
60 }
61
62 for (size_t i = is_attack ? 1 : 0; i < num_subframes; ++i) {
63 const size_t subframe_start = i * subframe_size;
64 const float scaling_start = scaling_factors[i];
65 const float scaling_end = scaling_factors[i + 1];
66 const float scaling_diff = (scaling_end - scaling_start) / subframe_size;
67 for (size_t j = 0; j < subframe_size; ++j) {
68 per_sample_scaling_factors[subframe_start + j] =
69 scaling_start + scaling_diff * j;
70 }
71 }
72}
73
74void ScaleSamples(rtc::ArrayView<const float> per_sample_scaling_factors,
75 AudioFrameView<float> signal) {
76 const size_t samples_per_channel = signal.samples_per_channel();
77 RTC_DCHECK_EQ(samples_per_channel, per_sample_scaling_factors.size());
78 for (size_t i = 0; i < signal.num_channels(); ++i) {
79 auto channel = signal.channel(i);
80 for (size_t j = 0; j < samples_per_channel; ++j) {
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010081 channel[j] = rtc::SafeClamp(channel[j] * per_sample_scaling_factors[j],
82 kMinFloatS16Value, kMaxFloatS16Value);
Alex Loikoa05ee822018-02-20 15:58:36 +010083 }
84 }
85}
86
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010087void CheckLimiterSampleRate(size_t sample_rate_hz) {
88 // Check that per_sample_scaling_factors_ is large enough.
89 RTC_DCHECK_LE(sample_rate_hz,
90 kMaximalNumberOfSamplesPerChannel * 1000 / kFrameDurationMs);
91}
92
Alex Loikoa05ee822018-02-20 15:58:36 +010093} // namespace
94
Alessio Bazzica746d46b2018-10-30 10:48:38 +010095Limiter::Limiter(size_t sample_rate_hz,
96 ApmDataDumper* apm_data_dumper,
97 std::string histogram_name)
Alex Loiko03ad9b82018-08-13 17:40:43 +020098 : interp_gain_curve_(apm_data_dumper, histogram_name),
Alex Loikoa05ee822018-02-20 15:58:36 +010099 level_estimator_(sample_rate_hz, apm_data_dumper),
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100100 apm_data_dumper_(apm_data_dumper) {
101 CheckLimiterSampleRate(sample_rate_hz);
102}
Alex Loikoa05ee822018-02-20 15:58:36 +0100103
Alessio Bazzica746d46b2018-10-30 10:48:38 +0100104Limiter::~Limiter() = default;
Alex Loikoa05ee822018-02-20 15:58:36 +0100105
Alessio Bazzica746d46b2018-10-30 10:48:38 +0100106void Limiter::Process(AudioFrameView<float> signal) {
Alex Loikoa05ee822018-02-20 15:58:36 +0100107 const auto level_estimate = level_estimator_.ComputeLevel(signal);
108
109 RTC_DCHECK_EQ(level_estimate.size() + 1, scaling_factors_.size());
110 scaling_factors_[0] = last_scaling_factor_;
111 std::transform(level_estimate.begin(), level_estimate.end(),
112 scaling_factors_.begin() + 1, [this](float x) {
113 return interp_gain_curve_.LookUpGainToApply(x);
114 });
115
116 const size_t samples_per_channel = signal.samples_per_channel();
117 RTC_DCHECK_LE(samples_per_channel, kMaximalNumberOfSamplesPerChannel);
118
119 auto per_sample_scaling_factors = rtc::ArrayView<float>(
120 &per_sample_scaling_factors_[0], samples_per_channel);
121 ComputePerSampleSubframeFactors(scaling_factors_, samples_per_channel,
122 per_sample_scaling_factors);
123 ScaleSamples(per_sample_scaling_factors, signal);
124
125 last_scaling_factor_ = scaling_factors_.back();
126
127 // Dump data for debug.
128 apm_data_dumper_->DumpRaw("agc2_gain_curve_applier_scaling_factors",
129 samples_per_channel,
130 per_sample_scaling_factors_.data());
131}
132
Alessio Bazzica746d46b2018-10-30 10:48:38 +0100133InterpolatedGainCurve::Stats Limiter::GetGainCurveStats() const {
Alex Loikoa05ee822018-02-20 15:58:36 +0100134 return interp_gain_curve_.get_stats();
135}
136
Alessio Bazzica746d46b2018-10-30 10:48:38 +0100137void Limiter::SetSampleRate(size_t sample_rate_hz) {
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100138 CheckLimiterSampleRate(sample_rate_hz);
Alex Loikoa05ee822018-02-20 15:58:36 +0100139 level_estimator_.SetSampleRate(sample_rate_hz);
Alex Loikoa05ee822018-02-20 15:58:36 +0100140}
141
Alessio Bazzica746d46b2018-10-30 10:48:38 +0100142void Limiter::Reset() {
Alessio Bazzica82ec0fa2018-08-27 14:24:16 +0200143 level_estimator_.Reset();
144}
145
Alessio Bazzica746d46b2018-10-30 10:48:38 +0100146float Limiter::LastAudioLevel() const {
Alex Loiko93e57502018-10-01 16:28:47 +0200147 return level_estimator_.LastAudioLevel();
148}
149
Alex Loikoa05ee822018-02-20 15:58:36 +0100150} // namespace webrtc