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/fixed_digital_level_estimator.h"
12
13 #include <algorithm>
14 #include <cmath>
15
16 #include "api/array_view.h"
17 #include "modules/audio_processing/logging/apm_data_dumper.h"
18 #include "rtc_base/checks.h"
19
20 namespace webrtc {
21 namespace {
22
23 constexpr float kInitialFilterStateLevel = 0.f;
24
25 } // namespace
26
FixedDigitalLevelEstimator(size_t sample_rate_hz,ApmDataDumper * apm_data_dumper)27 FixedDigitalLevelEstimator::FixedDigitalLevelEstimator(
28 size_t sample_rate_hz,
29 ApmDataDumper* apm_data_dumper)
30 : apm_data_dumper_(apm_data_dumper),
31 filter_state_level_(kInitialFilterStateLevel) {
32 SetSampleRate(sample_rate_hz);
33 CheckParameterCombination();
34 RTC_DCHECK(apm_data_dumper_);
35 apm_data_dumper_->DumpRaw("agc2_level_estimator_samplerate", sample_rate_hz);
36 }
37
CheckParameterCombination()38 void FixedDigitalLevelEstimator::CheckParameterCombination() {
39 RTC_DCHECK_GT(samples_in_frame_, 0);
40 RTC_DCHECK_LE(kSubFramesInFrame, samples_in_frame_);
41 RTC_DCHECK_EQ(samples_in_frame_ % kSubFramesInFrame, 0);
42 RTC_DCHECK_GT(samples_in_sub_frame_, 1);
43 }
44
ComputeLevel(const AudioFrameView<const float> & float_frame)45 std::array<float, kSubFramesInFrame> FixedDigitalLevelEstimator::ComputeLevel(
46 const AudioFrameView<const float>& float_frame) {
47 RTC_DCHECK_GT(float_frame.num_channels(), 0);
48 RTC_DCHECK_EQ(float_frame.samples_per_channel(), samples_in_frame_);
49
50 // Compute max envelope without smoothing.
51 std::array<float, kSubFramesInFrame> envelope{};
52 for (size_t channel_idx = 0; channel_idx < float_frame.num_channels();
53 ++channel_idx) {
54 const auto channel = float_frame.channel(channel_idx);
55 for (size_t sub_frame = 0; sub_frame < kSubFramesInFrame; ++sub_frame) {
56 for (size_t sample_in_sub_frame = 0;
57 sample_in_sub_frame < samples_in_sub_frame_; ++sample_in_sub_frame) {
58 envelope[sub_frame] =
59 std::max(envelope[sub_frame],
60 std::abs(channel[sub_frame * samples_in_sub_frame_ +
61 sample_in_sub_frame]));
62 }
63 }
64 }
65
66 // Make sure envelope increases happen one step earlier so that the
67 // corresponding *gain decrease* doesn't miss a sudden signal
68 // increase due to interpolation.
69 for (size_t sub_frame = 0; sub_frame < kSubFramesInFrame - 1; ++sub_frame) {
70 if (envelope[sub_frame] < envelope[sub_frame + 1]) {
71 envelope[sub_frame] = envelope[sub_frame + 1];
72 }
73 }
74
75 // Add attack / decay smoothing.
76 for (size_t sub_frame = 0; sub_frame < kSubFramesInFrame; ++sub_frame) {
77 const float envelope_value = envelope[sub_frame];
78 if (envelope_value > filter_state_level_) {
79 envelope[sub_frame] = envelope_value * (1 - kAttackFilterConstant) +
80 filter_state_level_ * kAttackFilterConstant;
81 } else {
82 envelope[sub_frame] = envelope_value * (1 - kDecayFilterConstant) +
83 filter_state_level_ * kDecayFilterConstant;
84 }
85 filter_state_level_ = envelope[sub_frame];
86
87 // Dump data for debug.
88 RTC_DCHECK(apm_data_dumper_);
89 const auto channel = float_frame.channel(0);
90 apm_data_dumper_->DumpRaw("agc2_level_estimator_samples",
91 samples_in_sub_frame_,
92 &channel[sub_frame * samples_in_sub_frame_]);
93 apm_data_dumper_->DumpRaw("agc2_level_estimator_level",
94 envelope[sub_frame]);
95 }
96
97 return envelope;
98 }
99
SetSampleRate(size_t sample_rate_hz)100 void FixedDigitalLevelEstimator::SetSampleRate(size_t sample_rate_hz) {
101 samples_in_frame_ = rtc::CheckedDivExact(sample_rate_hz * kFrameDurationMs,
102 static_cast<size_t>(1000));
103 samples_in_sub_frame_ =
104 rtc::CheckedDivExact(samples_in_frame_, kSubFramesInFrame);
105 CheckParameterCombination();
106 }
107
Reset()108 void FixedDigitalLevelEstimator::Reset() {
109 filter_state_level_ = kInitialFilterStateLevel;
110 }
111
112 } // namespace webrtc
113