mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-14 14:20:45 +01:00

In https://webrtc-review.googlesource.com/c/src/+/1560 we moved WebRTC from src/webrtc to src/ (in order to preserve an healthy git history). This CL takes care of fixing header guards, #include paths, etc... NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true TBR=tommi@webrtc.org Bug: chromium:611808 Change-Id: Iea91618212bee0af16aa3f05071eab8f93706578 Reviewed-on: https://webrtc-review.googlesource.com/1561 Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Henrik Kjellander <kjellander@webrtc.org> Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/master@{#19846}
160 lines
5 KiB
C++
160 lines
5 KiB
C++
/*
|
|
* Copyright (c) 2016 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/level_controller/gain_applier.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "api/array_view.h"
|
|
#include "rtc_base/checks.h"
|
|
|
|
#include "modules/audio_processing/audio_buffer.h"
|
|
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
const float kMaxSampleValue = 32767.f;
|
|
const float kMinSampleValue = -32767.f;
|
|
|
|
int CountSaturations(rtc::ArrayView<const float> in) {
|
|
return std::count_if(in.begin(), in.end(), [](const float& v) {
|
|
return v >= kMaxSampleValue || v <= kMinSampleValue;
|
|
});
|
|
}
|
|
|
|
int CountSaturations(const AudioBuffer& audio) {
|
|
int num_saturations = 0;
|
|
for (size_t k = 0; k < audio.num_channels(); ++k) {
|
|
num_saturations += CountSaturations(rtc::ArrayView<const float>(
|
|
audio.channels_const_f()[k], audio.num_frames()));
|
|
}
|
|
return num_saturations;
|
|
}
|
|
|
|
void LimitToAllowedRange(rtc::ArrayView<float> x) {
|
|
for (auto& v : x) {
|
|
v = std::max(kMinSampleValue, v);
|
|
v = std::min(kMaxSampleValue, v);
|
|
}
|
|
}
|
|
|
|
void LimitToAllowedRange(AudioBuffer* audio) {
|
|
for (size_t k = 0; k < audio->num_channels(); ++k) {
|
|
LimitToAllowedRange(
|
|
rtc::ArrayView<float>(audio->channels_f()[k], audio->num_frames()));
|
|
}
|
|
}
|
|
|
|
float ApplyIncreasingGain(float new_gain,
|
|
float old_gain,
|
|
float step_size,
|
|
rtc::ArrayView<float> x) {
|
|
RTC_DCHECK_LT(0.f, step_size);
|
|
float gain = old_gain;
|
|
for (auto& v : x) {
|
|
gain = std::min(new_gain, gain + step_size);
|
|
v *= gain;
|
|
}
|
|
return gain;
|
|
}
|
|
|
|
float ApplyDecreasingGain(float new_gain,
|
|
float old_gain,
|
|
float step_size,
|
|
rtc::ArrayView<float> x) {
|
|
RTC_DCHECK_GT(0.f, step_size);
|
|
float gain = old_gain;
|
|
for (auto& v : x) {
|
|
gain = std::max(new_gain, gain + step_size);
|
|
v *= gain;
|
|
}
|
|
return gain;
|
|
}
|
|
|
|
float ApplyConstantGain(float gain, rtc::ArrayView<float> x) {
|
|
for (auto& v : x) {
|
|
v *= gain;
|
|
}
|
|
|
|
return gain;
|
|
}
|
|
|
|
float ApplyGain(float new_gain,
|
|
float old_gain,
|
|
float increase_step_size,
|
|
float decrease_step_size,
|
|
rtc::ArrayView<float> x) {
|
|
RTC_DCHECK_LT(0.f, increase_step_size);
|
|
RTC_DCHECK_GT(0.f, decrease_step_size);
|
|
if (new_gain == old_gain) {
|
|
return ApplyConstantGain(new_gain, x);
|
|
} else if (new_gain > old_gain) {
|
|
return ApplyIncreasingGain(new_gain, old_gain, increase_step_size, x);
|
|
} else {
|
|
return ApplyDecreasingGain(new_gain, old_gain, decrease_step_size, x);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
GainApplier::GainApplier(ApmDataDumper* data_dumper)
|
|
: data_dumper_(data_dumper) {}
|
|
|
|
void GainApplier::Initialize(int sample_rate_hz) {
|
|
RTC_DCHECK(sample_rate_hz == AudioProcessing::kSampleRate8kHz ||
|
|
sample_rate_hz == AudioProcessing::kSampleRate16kHz ||
|
|
sample_rate_hz == AudioProcessing::kSampleRate32kHz ||
|
|
sample_rate_hz == AudioProcessing::kSampleRate48kHz);
|
|
const float kGainIncreaseStepSize48kHz = 0.0001f;
|
|
const float kGainDecreaseStepSize48kHz = -0.01f;
|
|
const float kGainSaturatedDecreaseStepSize48kHz = -0.05f;
|
|
|
|
last_frame_was_saturated_ = false;
|
|
old_gain_ = 1.f;
|
|
gain_increase_step_size_ =
|
|
kGainIncreaseStepSize48kHz *
|
|
(static_cast<float>(AudioProcessing::kSampleRate48kHz) / sample_rate_hz);
|
|
gain_normal_decrease_step_size_ =
|
|
kGainDecreaseStepSize48kHz *
|
|
(static_cast<float>(AudioProcessing::kSampleRate48kHz) / sample_rate_hz);
|
|
gain_saturated_decrease_step_size_ =
|
|
kGainSaturatedDecreaseStepSize48kHz *
|
|
(static_cast<float>(AudioProcessing::kSampleRate48kHz) / sample_rate_hz);
|
|
}
|
|
|
|
int GainApplier::Process(float new_gain, AudioBuffer* audio) {
|
|
RTC_CHECK_NE(0.f, gain_increase_step_size_);
|
|
RTC_CHECK_NE(0.f, gain_normal_decrease_step_size_);
|
|
RTC_CHECK_NE(0.f, gain_saturated_decrease_step_size_);
|
|
int num_saturations = 0;
|
|
if (new_gain != 1.f) {
|
|
float last_applied_gain = 1.f;
|
|
float gain_decrease_step_size = last_frame_was_saturated_
|
|
? gain_saturated_decrease_step_size_
|
|
: gain_normal_decrease_step_size_;
|
|
for (size_t k = 0; k < audio->num_channels(); ++k) {
|
|
last_applied_gain = ApplyGain(
|
|
new_gain, old_gain_, gain_increase_step_size_,
|
|
gain_decrease_step_size,
|
|
rtc::ArrayView<float>(audio->channels_f()[k], audio->num_frames()));
|
|
}
|
|
|
|
num_saturations = CountSaturations(*audio);
|
|
LimitToAllowedRange(audio);
|
|
old_gain_ = last_applied_gain;
|
|
}
|
|
|
|
data_dumper_->DumpRaw("lc_last_applied_gain", 1, &old_gain_);
|
|
|
|
return num_saturations;
|
|
}
|
|
|
|
} // namespace webrtc
|