diff --git a/modules/audio_processing/agc2/BUILD.gn b/modules/audio_processing/agc2/BUILD.gn index ea7fe0e9ce..af906a0238 100644 --- a/modules/audio_processing/agc2/BUILD.gn +++ b/modules/audio_processing/agc2/BUILD.gn @@ -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", diff --git a/modules/audio_processing/agc2/compute_interpolated_gain_curve.cc b/modules/audio_processing/agc2/compute_interpolated_gain_curve.cc index f395bceffa..bc92613b69 100644 --- a/modules/audio_processing/agc2/compute_interpolated_gain_curve.cc +++ b/modules/audio_processing/agc2/compute_interpolated_gain_curve.cc @@ -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 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 SampleLimiterRegion(const Limiter* limiter) { +std::vector SampleLimiterRegion(const LimiterDbGainCurve* limiter) { static_assert(kInterpolatedGainCurveBeyondKneePoints > 2, ""); struct Interval { @@ -131,7 +132,7 @@ std::vector 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); diff --git a/modules/audio_processing/agc2/fixed_gain_controller.h b/modules/audio_processing/agc2/fixed_gain_controller.h index ff6ab81172..2137764dd2 100644 --- a/modules/audio_processing/agc2/fixed_gain_controller.h +++ b/modules/audio_processing/agc2/fixed_gain_controller.h @@ -25,8 +25,8 @@ class FixedGainController { void Process(AudioFrameView 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; diff --git a/modules/audio_processing/agc2/interpolated_gain_curve_unittest.cc b/modules/audio_processing/agc2/interpolated_gain_curve_unittest.cc index dd696313ae..a8e0f2361c 100644 --- a/modules/audio_processing/agc2/interpolated_gain_curve_unittest.cc +++ b/modules/audio_processing/agc2/interpolated_gain_curve_unittest.cc @@ -9,6 +9,7 @@ */ #include +#include #include #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::value, ""); +const LimiterDbGainCurve limiter; } // namespace diff --git a/modules/audio_processing/agc2/limiter.cc b/modules/audio_processing/agc2/limiter_db_gain_curve.cc similarity index 86% rename from modules/audio_processing/agc2/limiter.cc rename to modules/audio_processing/agc2/limiter_db_gain_curve.cc index d2b9877be1..d55ed5df58 100644 --- a/modules/audio_processing/agc2/limiter.cc +++ b/modules/audio_processing/agc2/limiter_db_gain_curve.cc @@ -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 @@ -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_; } diff --git a/modules/audio_processing/agc2/limiter.h b/modules/audio_processing/agc2/limiter_db_gain_curve.h similarity index 77% rename from modules/audio_processing/agc2/limiter.h rename to modules/audio_processing/agc2/limiter_db_gain_curve.h index f350baeef1..9086e26739 100644 --- a/modules/audio_processing/agc2/limiter.h +++ b/modules/audio_processing/agc2/limiter_db_gain_curve.h @@ -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 @@ -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_ diff --git a/modules/audio_processing/agc2/limiter_unittest.cc b/modules/audio_processing/agc2/limiter_db_gain_curve_unittest.cc similarity index 92% rename from modules/audio_processing/agc2/limiter_unittest.cc rename to modules/audio_processing/agc2/limiter_db_gain_curve_unittest.cc index 7079812634..049c8d568e 100644 --- a/modules/audio_processing/agc2/limiter_unittest.cc +++ b/modules/audio_processing/agc2/limiter_db_gain_curve_unittest.cc @@ -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);