• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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