mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00

Bug: webrtc:12338 Change-Id: I85bff694dd2ead83c939c4d1945eff82e1296001 No-Presubmit: True Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/227161 Commit-Queue: Artem Titov <titovartem@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/master@{#34690}
120 lines
4.3 KiB
C++
120 lines
4.3 KiB
C++
/*
|
|
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "modules/audio_processing/agc2/fixed_digital_level_estimator.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
#include "api/array_view.h"
|
|
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
|
#include "rtc_base/checks.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
constexpr float kInitialFilterStateLevel = 0.f;
|
|
|
|
// Instant attack.
|
|
constexpr float kAttackFilterConstant = 0.f;
|
|
// This is computed from kDecayMs by
|
|
// 10 ** (-1/20 * subframe_duration / kDecayMs).
|
|
// `subframe_duration` is |kFrameDurationMs / kSubFramesInFrame|.
|
|
// kDecayMs is defined in agc2_testing_common.h
|
|
constexpr float kDecayFilterConstant = 0.9998848773724686f;
|
|
|
|
} // namespace
|
|
|
|
FixedDigitalLevelEstimator::FixedDigitalLevelEstimator(
|
|
int sample_rate_hz,
|
|
ApmDataDumper* apm_data_dumper)
|
|
: apm_data_dumper_(apm_data_dumper),
|
|
filter_state_level_(kInitialFilterStateLevel) {
|
|
SetSampleRate(sample_rate_hz);
|
|
CheckParameterCombination();
|
|
RTC_DCHECK(apm_data_dumper_);
|
|
apm_data_dumper_->DumpRaw("agc2_level_estimator_samplerate", sample_rate_hz);
|
|
}
|
|
|
|
void FixedDigitalLevelEstimator::CheckParameterCombination() {
|
|
RTC_DCHECK_GT(samples_in_frame_, 0);
|
|
RTC_DCHECK_LE(kSubFramesInFrame, samples_in_frame_);
|
|
RTC_DCHECK_EQ(samples_in_frame_ % kSubFramesInFrame, 0);
|
|
RTC_DCHECK_GT(samples_in_sub_frame_, 1);
|
|
}
|
|
|
|
std::array<float, kSubFramesInFrame> FixedDigitalLevelEstimator::ComputeLevel(
|
|
const AudioFrameView<const float>& float_frame) {
|
|
RTC_DCHECK_GT(float_frame.num_channels(), 0);
|
|
RTC_DCHECK_EQ(float_frame.samples_per_channel(), samples_in_frame_);
|
|
|
|
// Compute max envelope without smoothing.
|
|
std::array<float, kSubFramesInFrame> envelope{};
|
|
for (size_t channel_idx = 0; channel_idx < float_frame.num_channels();
|
|
++channel_idx) {
|
|
const auto channel = float_frame.channel(channel_idx);
|
|
for (int sub_frame = 0; sub_frame < kSubFramesInFrame; ++sub_frame) {
|
|
for (int sample_in_sub_frame = 0;
|
|
sample_in_sub_frame < samples_in_sub_frame_; ++sample_in_sub_frame) {
|
|
envelope[sub_frame] =
|
|
std::max(envelope[sub_frame],
|
|
std::abs(channel[sub_frame * samples_in_sub_frame_ +
|
|
sample_in_sub_frame]));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make sure envelope increases happen one step earlier so that the
|
|
// corresponding *gain decrease* doesn't miss a sudden signal
|
|
// increase due to interpolation.
|
|
for (int sub_frame = 0; sub_frame < kSubFramesInFrame - 1; ++sub_frame) {
|
|
if (envelope[sub_frame] < envelope[sub_frame + 1]) {
|
|
envelope[sub_frame] = envelope[sub_frame + 1];
|
|
}
|
|
}
|
|
|
|
// Add attack / decay smoothing.
|
|
for (int sub_frame = 0; sub_frame < kSubFramesInFrame; ++sub_frame) {
|
|
const float envelope_value = envelope[sub_frame];
|
|
if (envelope_value > filter_state_level_) {
|
|
envelope[sub_frame] = envelope_value * (1 - kAttackFilterConstant) +
|
|
filter_state_level_ * kAttackFilterConstant;
|
|
} else {
|
|
envelope[sub_frame] = envelope_value * (1 - kDecayFilterConstant) +
|
|
filter_state_level_ * kDecayFilterConstant;
|
|
}
|
|
filter_state_level_ = envelope[sub_frame];
|
|
|
|
// Dump data for debug.
|
|
RTC_DCHECK(apm_data_dumper_);
|
|
const auto channel = float_frame.channel(0);
|
|
apm_data_dumper_->DumpRaw("agc2_level_estimator_samples",
|
|
samples_in_sub_frame_,
|
|
&channel[sub_frame * samples_in_sub_frame_]);
|
|
apm_data_dumper_->DumpRaw("agc2_level_estimator_level",
|
|
envelope[sub_frame]);
|
|
}
|
|
|
|
return envelope;
|
|
}
|
|
|
|
void FixedDigitalLevelEstimator::SetSampleRate(int sample_rate_hz) {
|
|
samples_in_frame_ =
|
|
rtc::CheckedDivExact(sample_rate_hz * kFrameDurationMs, 1000);
|
|
samples_in_sub_frame_ =
|
|
rtc::CheckedDivExact(samples_in_frame_, kSubFramesInFrame);
|
|
CheckParameterCombination();
|
|
}
|
|
|
|
void FixedDigitalLevelEstimator::Reset() {
|
|
filter_state_level_ = kInitialFilterStateLevel;
|
|
}
|
|
|
|
} // namespace webrtc
|