AGC2 Limiter class renamed.
Limiter has been renamed to LimiterDbGainCurve, which is a more correct name and will allow in a follow-up CL to reuse the Limiter name for GainCurveApplier. This is done to allow to use the limiter without instancing the fixed digital gain controller and then to fix an AGC2 issue (namely, fixed gain applied after the adaptive one). Bug: webrtc:7494 Change-Id: Icd7050e3e51b832bfbf35e5cc61109215c5b1ca6 Reviewed-on: https://webrtc-review.googlesource.com/c/106901 Commit-Queue: Alessio Bazzica <alessiob@webrtc.org> Reviewed-by: Alex Loiko <aleloi@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25322}
This commit is contained in:
parent
4842c78e93
commit
087e9bed41
@ -220,9 +220,9 @@ rtc_source_set("fixed_digital_unittests") {
|
||||
"fixed_gain_controller_unittest.cc",
|
||||
"gain_curve_applier_unittest.cc",
|
||||
"interpolated_gain_curve_unittest.cc",
|
||||
"limiter.cc",
|
||||
"limiter.h",
|
||||
"limiter_unittest.cc",
|
||||
"limiter_db_gain_curve.cc",
|
||||
"limiter_db_gain_curve.h",
|
||||
"limiter_db_gain_curve_unittest.cc",
|
||||
]
|
||||
deps = [
|
||||
":common",
|
||||
|
||||
@ -19,23 +19,24 @@
|
||||
|
||||
#include "modules/audio_processing/agc2/agc2_common.h"
|
||||
#include "modules/audio_processing/agc2/agc2_testing_common.h"
|
||||
#include "modules/audio_processing/agc2/limiter.h"
|
||||
#include "modules/audio_processing/agc2/limiter_db_gain_curve.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
std::pair<double, double> ComputeLinearApproximationParams(
|
||||
const Limiter* limiter,
|
||||
const LimiterDbGainCurve* limiter,
|
||||
const double x) {
|
||||
const double m = limiter->GetGainFirstDerivativeLinear(x);
|
||||
const double q = limiter->GetGainLinear(x) - m * x;
|
||||
return {m, q};
|
||||
}
|
||||
|
||||
double ComputeAreaUnderPiecewiseLinearApproximation(const Limiter* limiter,
|
||||
const double x0,
|
||||
const double x1) {
|
||||
double ComputeAreaUnderPiecewiseLinearApproximation(
|
||||
const LimiterDbGainCurve* limiter,
|
||||
const double x0,
|
||||
const double x1) {
|
||||
RTC_CHECK_LT(x0, x1);
|
||||
|
||||
// Linear approximation in x0 and x1.
|
||||
@ -60,7 +61,7 @@ double ComputeAreaUnderPiecewiseLinearApproximation(const Limiter* limiter,
|
||||
// Computes the approximation error in the limiter region for a given interval.
|
||||
// The error is computed as the difference between the areas beneath the limiter
|
||||
// curve to approximate and its linear under-approximation.
|
||||
double LimiterUnderApproximationNegativeError(const Limiter* limiter,
|
||||
double LimiterUnderApproximationNegativeError(const LimiterDbGainCurve* limiter,
|
||||
const double x0,
|
||||
const double x1) {
|
||||
const double area_limiter = limiter->GetGainIntegralLinear(x0, x1);
|
||||
@ -77,7 +78,7 @@ double LimiterUnderApproximationNegativeError(const Limiter* limiter,
|
||||
// are assigned by halving intervals (starting with the whole beyond-knee region
|
||||
// as a single interval). However, even if sub-optimal, this algorithm works
|
||||
// well in practice and it is efficiently implemented using priority queues.
|
||||
std::vector<double> SampleLimiterRegion(const Limiter* limiter) {
|
||||
std::vector<double> SampleLimiterRegion(const LimiterDbGainCurve* limiter) {
|
||||
static_assert(kInterpolatedGainCurveBeyondKneePoints > 2, "");
|
||||
|
||||
struct Interval {
|
||||
@ -131,7 +132,7 @@ std::vector<double> SampleLimiterRegion(const Limiter* limiter) {
|
||||
// Compute the parameters to over-approximate the knee region via linear
|
||||
// interpolation. Over-approximating is saturation-safe since the knee region is
|
||||
// convex.
|
||||
void PrecomputeKneeApproxParams(const Limiter* limiter,
|
||||
void PrecomputeKneeApproxParams(const LimiterDbGainCurve* limiter,
|
||||
test::InterpolatedParameters* parameters) {
|
||||
static_assert(kInterpolatedGainCurveKneePoints > 2, "");
|
||||
// Get |kInterpolatedGainCurveKneePoints| - 1 equally spaced points.
|
||||
@ -165,7 +166,7 @@ void PrecomputeKneeApproxParams(const Limiter* limiter,
|
||||
// interpolation and greedy sampling. Under-approximating is saturation-safe
|
||||
// since the beyond-knee region is concave.
|
||||
void PrecomputeBeyondKneeApproxParams(
|
||||
const Limiter* limiter,
|
||||
const LimiterDbGainCurve* limiter,
|
||||
test::InterpolatedParameters* parameters) {
|
||||
// Find points on which the linear pieces are tangent to the gain curve.
|
||||
const auto samples = SampleLimiterRegion(limiter);
|
||||
@ -216,7 +217,7 @@ namespace test {
|
||||
|
||||
InterpolatedParameters ComputeInterpolatedGainCurveApproximationParams() {
|
||||
InterpolatedParameters parameters;
|
||||
Limiter limiter;
|
||||
LimiterDbGainCurve limiter;
|
||||
parameters.computed_approximation_params_x.fill(0.0f);
|
||||
parameters.computed_approximation_params_m.fill(0.0f);
|
||||
parameters.computed_approximation_params_q.fill(0.0f);
|
||||
|
||||
@ -25,8 +25,8 @@ class FixedGainController {
|
||||
|
||||
void Process(AudioFrameView<float> signal);
|
||||
|
||||
// Rate and gain may be changed at any time (but not concurrently
|
||||
// with any other method call).
|
||||
// Gain and sample rate may be changed at any time (but not
|
||||
// concurrently with any other method call).
|
||||
void SetGain(float gain_to_apply_db);
|
||||
void SetSampleRate(size_t sample_rate_hz);
|
||||
float LastAudioLevel() const;
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "api/array_view.h"
|
||||
@ -16,7 +17,7 @@
|
||||
#include "modules/audio_processing/agc2/agc2_common.h"
|
||||
#include "modules/audio_processing/agc2/compute_interpolated_gain_curve.h"
|
||||
#include "modules/audio_processing/agc2/interpolated_gain_curve.h"
|
||||
#include "modules/audio_processing/agc2/limiter.h"
|
||||
#include "modules/audio_processing/agc2/limiter_db_gain_curve.h"
|
||||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/gunit.h"
|
||||
@ -27,7 +28,8 @@ namespace {
|
||||
constexpr double kLevelEpsilon = 1e-2 * kMaxAbsFloatS16Value;
|
||||
constexpr float kInterpolatedGainCurveTolerance = 1.f / 32768.f;
|
||||
ApmDataDumper apm_data_dumper(0);
|
||||
const Limiter limiter;
|
||||
static_assert(std::is_trivially_destructible<LimiterDbGainCurve>::value, "");
|
||||
const LimiterDbGainCurve limiter;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/audio_processing/agc2/limiter.h"
|
||||
#include "modules/audio_processing/agc2/limiter_db_gain_curve.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
@ -60,7 +60,7 @@ double ComputeLimiterI2(double max_input_level_db,
|
||||
|
||||
} // namespace
|
||||
|
||||
Limiter::Limiter()
|
||||
LimiterDbGainCurve::LimiterDbGainCurve()
|
||||
: max_input_level_linear_(DbfsToFloatS16(max_input_level_db_)),
|
||||
knee_start_dbfs_(ComputeKneeStart(max_input_level_db_,
|
||||
knee_smoothness_db_,
|
||||
@ -83,11 +83,11 @@ Limiter::Limiter()
|
||||
RTC_CHECK_GE(max_input_level_db_, knee_start_dbfs_ + knee_smoothness_db_);
|
||||
}
|
||||
|
||||
constexpr double Limiter::max_input_level_db_;
|
||||
constexpr double Limiter::knee_smoothness_db_;
|
||||
constexpr double Limiter::compression_ratio_;
|
||||
constexpr double LimiterDbGainCurve::max_input_level_db_;
|
||||
constexpr double LimiterDbGainCurve::knee_smoothness_db_;
|
||||
constexpr double LimiterDbGainCurve::compression_ratio_;
|
||||
|
||||
double Limiter::GetOutputLevelDbfs(double input_level_dbfs) const {
|
||||
double LimiterDbGainCurve::GetOutputLevelDbfs(double input_level_dbfs) const {
|
||||
if (input_level_dbfs < knee_start_dbfs_) {
|
||||
return input_level_dbfs;
|
||||
} else if (input_level_dbfs < limiter_start_dbfs_) {
|
||||
@ -96,7 +96,7 @@ double Limiter::GetOutputLevelDbfs(double input_level_dbfs) const {
|
||||
return GetCompressorRegionOutputLevelDbfs(input_level_dbfs);
|
||||
}
|
||||
|
||||
double Limiter::GetGainLinear(double input_level_linear) const {
|
||||
double LimiterDbGainCurve::GetGainLinear(double input_level_linear) const {
|
||||
if (input_level_linear < knee_start_linear_) {
|
||||
return 1.0;
|
||||
}
|
||||
@ -106,7 +106,7 @@ double Limiter::GetGainLinear(double input_level_linear) const {
|
||||
}
|
||||
|
||||
// Computes the first derivative of GetGainLinear() in |x|.
|
||||
double Limiter::GetGainFirstDerivativeLinear(double x) const {
|
||||
double LimiterDbGainCurve::GetGainFirstDerivativeLinear(double x) const {
|
||||
// Beyond-knee region only.
|
||||
RTC_CHECK_GE(x, limiter_start_linear_ - 1e-7 * kMaxAbsFloatS16Value);
|
||||
return gain_curve_limiter_d1_ *
|
||||
@ -114,7 +114,7 @@ double Limiter::GetGainFirstDerivativeLinear(double x) const {
|
||||
}
|
||||
|
||||
// Computes the integral of GetGainLinear() in the range [x0, x1].
|
||||
double Limiter::GetGainIntegralLinear(double x0, double x1) const {
|
||||
double LimiterDbGainCurve::GetGainIntegralLinear(double x0, double x1) const {
|
||||
RTC_CHECK_LE(x0, x1); // Valid interval.
|
||||
RTC_CHECK_GE(x0, limiter_start_linear_); // Beyond-knee region only.
|
||||
auto limiter_integral = [this](const double& x) {
|
||||
@ -123,13 +123,14 @@ double Limiter::GetGainIntegralLinear(double x0, double x1) const {
|
||||
return limiter_integral(x1) - limiter_integral(x0);
|
||||
}
|
||||
|
||||
double Limiter::GetKneeRegionOutputLevelDbfs(double input_level_dbfs) const {
|
||||
double LimiterDbGainCurve::GetKneeRegionOutputLevelDbfs(
|
||||
double input_level_dbfs) const {
|
||||
return knee_region_polynomial_[0] * input_level_dbfs * input_level_dbfs +
|
||||
knee_region_polynomial_[1] * input_level_dbfs +
|
||||
knee_region_polynomial_[2];
|
||||
}
|
||||
|
||||
double Limiter::GetCompressorRegionOutputLevelDbfs(
|
||||
double LimiterDbGainCurve::GetCompressorRegionOutputLevelDbfs(
|
||||
double input_level_dbfs) const {
|
||||
return (input_level_dbfs - max_input_level_db_) / compression_ratio_;
|
||||
}
|
||||
@ -8,8 +8,8 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_PROCESSING_AGC2_LIMITER_H_
|
||||
#define MODULES_AUDIO_PROCESSING_AGC2_LIMITER_H_
|
||||
#ifndef MODULES_AUDIO_PROCESSING_AGC2_LIMITER_DB_GAIN_CURVE_H_
|
||||
#define MODULES_AUDIO_PROCESSING_AGC2_LIMITER_DB_GAIN_CURVE_H_
|
||||
|
||||
#include <array>
|
||||
|
||||
@ -17,14 +17,16 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// A class for computing gain curve parameters. The gain curve is
|
||||
// defined by constants kLimiterMaxInputLevelDbFs, kLimiterKneeSmoothnessDb,
|
||||
// kLimiterCompressionRatio. The curve consints of one linear part,
|
||||
// one quadratic polynomial part and another linear part. The
|
||||
// constants define the parameters of the parts.
|
||||
class Limiter {
|
||||
// A class for computing a limiter gain curve (in dB scale) given a set of
|
||||
// hard-coded parameters (namely, kLimiterDbGainCurveMaxInputLevelDbFs,
|
||||
// kLimiterDbGainCurveKneeSmoothnessDb, and
|
||||
// kLimiterDbGainCurveCompressionRatio). The generated curve consists of four
|
||||
// regions: identity (linear), knee (quadratic polynomial), compression
|
||||
// (linear), saturation (linear). The aforementioned constants are used to shape
|
||||
// the different regions.
|
||||
class LimiterDbGainCurve {
|
||||
public:
|
||||
Limiter();
|
||||
LimiterDbGainCurve();
|
||||
|
||||
double max_input_level_db() const { return max_input_level_db_; }
|
||||
double max_input_level_linear() const { return max_input_level_linear_; }
|
||||
@ -71,4 +73,4 @@ class Limiter {
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_AGC2_LIMITER_H_
|
||||
#endif // MODULES_AUDIO_PROCESSING_AGC2_LIMITER_DB_GAIN_CURVE_H_
|
||||
@ -8,18 +8,18 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/audio_processing/agc2/limiter.h"
|
||||
#include "modules/audio_processing/agc2/limiter_db_gain_curve.h"
|
||||
|
||||
#include "rtc_base/gunit.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
TEST(FixedDigitalGainController2Limiter, ConstructDestruct) {
|
||||
Limiter l;
|
||||
LimiterDbGainCurve l;
|
||||
}
|
||||
|
||||
TEST(FixedDigitalGainController2Limiter, GainCurveShouldBeMonotone) {
|
||||
Limiter l;
|
||||
LimiterDbGainCurve l;
|
||||
float last_output_level = 0.f;
|
||||
bool has_last_output_level = false;
|
||||
for (float level = -90.f; level <= l.max_input_level_db(); level += 0.5f) {
|
||||
@ -34,7 +34,7 @@ TEST(FixedDigitalGainController2Limiter, GainCurveShouldBeMonotone) {
|
||||
}
|
||||
|
||||
TEST(FixedDigitalGainController2Limiter, GainCurveShouldBeContinuous) {
|
||||
Limiter l;
|
||||
LimiterDbGainCurve l;
|
||||
float last_output_level = 0.f;
|
||||
bool has_last_output_level = false;
|
||||
constexpr float kMaxDelta = 0.5f;
|
||||
@ -50,7 +50,7 @@ TEST(FixedDigitalGainController2Limiter, GainCurveShouldBeContinuous) {
|
||||
}
|
||||
|
||||
TEST(FixedDigitalGainController2Limiter, OutputGainShouldBeLessThanFullScale) {
|
||||
Limiter l;
|
||||
LimiterDbGainCurve l;
|
||||
for (float level = -90.f; level <= l.max_input_level_db(); level += 0.5f) {
|
||||
const float current_output_level = l.GetOutputLevelDbfs(level);
|
||||
EXPECT_LE(current_output_level, 0.f);
|
||||
Loading…
x
Reference in New Issue
Block a user