blob: dc9be474042d0eca6436896c52bb7e26d491eef1 [file] [log] [blame]
Alex Loiko1e48e802018-03-28 09:45:29 +02001/*
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/saturation_protector.h"
12
13#include <algorithm>
14
15#include "modules/audio_processing/logging/apm_data_dumper.h"
16#include "rtc_base/numerics/safe_minmax.h"
17
18namespace webrtc {
19
Alex Loiko9917c4a2018-04-04 14:16:10 +020020namespace {
21void ShiftBuffer(std::array<float, kPeakEnveloperBufferSize>* buffer_) {
22 // Move everything one element back.
23 std::copy(buffer_->begin() + 1, buffer_->end(), buffer_->begin());
24}
25} // namespace
26
27SaturationProtector::PeakEnveloper::PeakEnveloper() = default;
28
29void SaturationProtector::PeakEnveloper::Process(float frame_peak_dbfs) {
30 // Update the delayed buffer and the current superframe peak.
31 current_superframe_peak_dbfs_ =
32 std::max(current_superframe_peak_dbfs_, frame_peak_dbfs);
33 speech_time_in_estimate_ms_ += kFrameDurationMs;
34 if (speech_time_in_estimate_ms_ > kPeakEnveloperSuperFrameLengthMs) {
35 speech_time_in_estimate_ms_ = 0;
36 const bool buffer_full = elements_in_buffer_ == kPeakEnveloperBufferSize;
37 if (buffer_full) {
38 ShiftBuffer(&peak_delay_buffer_);
39 *peak_delay_buffer_.rbegin() = current_superframe_peak_dbfs_;
40 } else {
41 peak_delay_buffer_[elements_in_buffer_] = current_superframe_peak_dbfs_;
42 elements_in_buffer_++;
43 }
44 current_superframe_peak_dbfs_ = -90.f;
45 }
46}
47
48float SaturationProtector::PeakEnveloper::Query() const {
49 float result;
50 if (elements_in_buffer_ > 0) {
51 result = peak_delay_buffer_[0];
52 } else {
53 result = current_superframe_peak_dbfs_;
54 }
55 return result;
56}
57
58SaturationProtector::SaturationProtector(ApmDataDumper* apm_data_dumper)
59 : apm_data_dumper_(apm_data_dumper) {}
Alex Loiko1e48e802018-03-28 09:45:29 +020060
61void SaturationProtector::UpdateMargin(
62 const VadWithLevel::LevelAndProbability& vad_data,
Alex Loiko9917c4a2018-04-04 14:16:10 +020063 float last_speech_level_estimate) {
64 peak_enveloper_.Process(vad_data.speech_peak_dbfs);
65 const float delayed_peak_dbfs = peak_enveloper_.Query();
66 const float difference_db = delayed_peak_dbfs - last_speech_level_estimate;
67
68 if (last_margin_ < difference_db) {
69 last_margin_ = last_margin_ * kSaturationProtectorAttackConstant +
70 difference_db * (1.f - kSaturationProtectorAttackConstant);
71 } else {
72 last_margin_ = last_margin_ * kSaturationProtectorDecayConstant +
73 difference_db * (1.f - kSaturationProtectorDecayConstant);
74 }
75
76 last_margin_ = rtc::SafeClamp<float>(last_margin_, 12.f, 25.f);
77}
Alex Loiko1e48e802018-03-28 09:45:29 +020078
79float SaturationProtector::LastMargin() const {
Alex Loiko9917c4a2018-04-04 14:16:10 +020080 return last_margin_;
Alex Loiko1e48e802018-03-28 09:45:29 +020081}
Alex Loiko9917c4a2018-04-04 14:16:10 +020082
Alex Loiko4d011462018-07-02 17:00:31 +020083void SaturationProtector::Reset() {
84 peak_enveloper_ = PeakEnveloper();
85}
86
Alex Loiko9917c4a2018-04-04 14:16:10 +020087void SaturationProtector::DebugDumpEstimate() const {
88 apm_data_dumper_->DumpRaw(
89 "agc2_adaptive_saturation_protector_delayed_peak_dbfs",
90 peak_enveloper_.Query());
91 apm_data_dumper_->DumpRaw("agc2_adaptive_saturation_margin_db", last_margin_);
92}
93
Alex Loiko1e48e802018-03-28 09:45:29 +020094} // namespace webrtc