Alex Loiko | a05ee82 | 2018-02-20 15:58:36 +0100 | [diff] [blame] | 1 | /* |
| 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 | #ifndef MODULES_AUDIO_PROCESSING_AGC2_INTERPOLATED_GAIN_CURVE_H_ |
| 12 | #define MODULES_AUDIO_PROCESSING_AGC2_INTERPOLATED_GAIN_CURVE_H_ |
| 13 | |
| 14 | #include <array> |
Alex Loiko | 03ad9b8 | 2018-08-13 17:40:43 +0200 | [diff] [blame] | 15 | #include <string> |
Alex Loiko | a05ee82 | 2018-02-20 15:58:36 +0100 | [diff] [blame] | 16 | |
| 17 | #include "modules/audio_processing/agc2/agc2_common.h" |
Steve Anton | 10542f2 | 2019-01-11 09:11:00 -0800 | [diff] [blame] | 18 | #include "rtc_base/constructor_magic.h" |
Alex Loiko | a05ee82 | 2018-02-20 15:58:36 +0100 | [diff] [blame] | 19 | #include "rtc_base/gtest_prod_util.h" |
Alex Loiko | 03ad9b8 | 2018-08-13 17:40:43 +0200 | [diff] [blame] | 20 | #include "system_wrappers/include/metrics.h" |
Alex Loiko | a05ee82 | 2018-02-20 15:58:36 +0100 | [diff] [blame] | 21 | |
| 22 | namespace webrtc { |
| 23 | |
| 24 | class ApmDataDumper; |
| 25 | |
| 26 | constexpr float kInputLevelScalingFactor = 32768.0f; |
| 27 | |
| 28 | // Defined as DbfsToLinear(kLimiterMaxInputLevelDbFs) |
| 29 | constexpr float kMaxInputLevelLinear = static_cast<float>(36766.300710566735); |
| 30 | |
| 31 | // Interpolated gain curve using under-approximation to avoid saturation. |
| 32 | // |
| 33 | // The goal of this class is allowing fast look ups to get an accurate |
| 34 | // estimates of the gain to apply given an estimated input level. |
| 35 | class InterpolatedGainCurve { |
| 36 | public: |
Alex Loiko | 6f2fcb4 | 2018-03-14 12:27:05 +0100 | [diff] [blame] | 37 | enum class GainCurveRegion { |
| 38 | kIdentity = 0, |
| 39 | kKnee = 1, |
| 40 | kLimiter = 2, |
| 41 | kSaturation = 3 |
| 42 | }; |
| 43 | |
Alex Loiko | a05ee82 | 2018-02-20 15:58:36 +0100 | [diff] [blame] | 44 | struct Stats { |
| 45 | // Region in which the output level equals the input one. |
| 46 | size_t look_ups_identity_region = 0; |
| 47 | // Smoothing between the identity and the limiter regions. |
| 48 | size_t look_ups_knee_region = 0; |
| 49 | // Limiter region in which the output and input levels are linearly related. |
| 50 | size_t look_ups_limiter_region = 0; |
| 51 | // Region in which saturation may occur since the input level is beyond the |
| 52 | // maximum expected by the limiter. |
| 53 | size_t look_ups_saturation_region = 0; |
| 54 | // True if stats have been populated. |
| 55 | bool available = false; |
Alex Loiko | 6f2fcb4 | 2018-03-14 12:27:05 +0100 | [diff] [blame] | 56 | |
| 57 | // The current region, and for how many frames the level has been |
| 58 | // in that region. |
| 59 | GainCurveRegion region = GainCurveRegion::kIdentity; |
| 60 | int64_t region_duration_frames = 0; |
Alex Loiko | a05ee82 | 2018-02-20 15:58:36 +0100 | [diff] [blame] | 61 | }; |
| 62 | |
Alex Loiko | 03ad9b8 | 2018-08-13 17:40:43 +0200 | [diff] [blame] | 63 | InterpolatedGainCurve(ApmDataDumper* apm_data_dumper, |
| 64 | std::string histogram_name_prefix); |
Alex Loiko | a05ee82 | 2018-02-20 15:58:36 +0100 | [diff] [blame] | 65 | ~InterpolatedGainCurve(); |
| 66 | |
| 67 | Stats get_stats() const { return stats_; } |
| 68 | |
| 69 | // Given a non-negative input level (linear scale), a scalar factor to apply |
| 70 | // to a sub-frame is returned. |
| 71 | // Levels above kLimiterMaxInputLevelDbFs will be reduced to 0 dBFS |
| 72 | // after applying this gain |
| 73 | float LookUpGainToApply(float input_level) const; |
| 74 | |
| 75 | private: |
| 76 | // For comparing 'approximation_params_*_' with ones computed by |
| 77 | // ComputeInterpolatedGainCurve. |
| 78 | FRIEND_TEST_ALL_PREFIXES(AutomaticGainController2InterpolatedGainCurve, |
| 79 | CheckApproximationParams); |
Alex Loiko | 03ad9b8 | 2018-08-13 17:40:43 +0200 | [diff] [blame] | 80 | |
| 81 | struct RegionLogger { |
| 82 | metrics::Histogram* identity_histogram; |
| 83 | metrics::Histogram* knee_histogram; |
| 84 | metrics::Histogram* limiter_histogram; |
| 85 | metrics::Histogram* saturation_histogram; |
| 86 | |
| 87 | RegionLogger(std::string identity_histogram_name, |
| 88 | std::string knee_histogram_name, |
| 89 | std::string limiter_histogram_name, |
| 90 | std::string saturation_histogram_name); |
| 91 | |
| 92 | ~RegionLogger(); |
| 93 | |
| 94 | void LogRegionStats(const InterpolatedGainCurve::Stats& stats) const; |
| 95 | } region_logger_; |
| 96 | |
Alex Loiko | a05ee82 | 2018-02-20 15:58:36 +0100 | [diff] [blame] | 97 | void UpdateStats(float input_level) const; |
| 98 | |
| 99 | ApmDataDumper* const apm_data_dumper_; |
| 100 | |
| 101 | static constexpr std::array<float, kInterpolatedGainCurveTotalPoints> |
| 102 | approximation_params_x_ = { |
| 103 | {30057.296875, 30148.986328125, 30240.67578125, 30424.052734375, |
| 104 | 30607.4296875, 30790.806640625, 30974.18359375, 31157.560546875, |
| 105 | 31340.939453125, 31524.31640625, 31707.693359375, 31891.0703125, |
| 106 | 32074.447265625, 32257.82421875, 32441.201171875, 32624.580078125, |
| 107 | 32807.95703125, 32991.33203125, 33174.7109375, 33358.08984375, |
| 108 | 33541.46484375, 33724.84375, 33819.53515625, 34009.5390625, |
| 109 | 34200.05859375, 34389.81640625, 34674.48828125, 35054.375, |
| 110 | 35434.86328125, 35814.81640625, 36195.16796875, 36575.03125}}; |
| 111 | static constexpr std::array<float, kInterpolatedGainCurveTotalPoints> |
| 112 | approximation_params_m_ = { |
| 113 | {-3.515235675877192989e-07, -1.050251626111275982e-06, |
| 114 | -2.085213736791047268e-06, -3.443004743530764244e-06, |
| 115 | -4.773849468620028347e-06, -6.077375928725814447e-06, |
| 116 | -7.353257842623861507e-06, -8.601219633419532329e-06, |
| 117 | -9.821013009059242904e-06, -1.101243378798244521e-05, |
| 118 | -1.217532644659513608e-05, -1.330956911260727793e-05, |
| 119 | -1.441507538402220234e-05, -1.549179251014720649e-05, |
| 120 | -1.653970684856176376e-05, -1.755882840370759368e-05, |
| 121 | -1.854918446042574942e-05, -1.951086778717581183e-05, |
| 122 | -2.044398024736437947e-05, -2.1348627342376858e-05, |
| 123 | -2.222496914328075945e-05, -2.265374678245279938e-05, |
| 124 | -2.242570917587727308e-05, -2.220122041762806475e-05, |
| 125 | -2.19802095671184361e-05, -2.176260204578284174e-05, |
| 126 | -2.133731686626560986e-05, -2.092481918225530535e-05, |
| 127 | -2.052459603874012828e-05, -2.013615448959171772e-05, |
| 128 | -1.975903069251216948e-05, -1.939277899509761482e-05}}; |
| 129 | |
| 130 | static constexpr std::array<float, kInterpolatedGainCurveTotalPoints> |
| 131 | approximation_params_q_ = { |
| 132 | {1.010565876960754395, 1.031631827354431152, 1.062929749488830566, |
| 133 | 1.104239225387573242, 1.144973039627075195, 1.185109615325927734, |
| 134 | 1.224629044532775879, 1.263512492179870605, 1.301741957664489746, |
| 135 | 1.339300632476806641, 1.376173257827758789, 1.412345528602600098, |
| 136 | 1.447803974151611328, 1.482536554336547852, 1.516532182693481445, |
| 137 | 1.549780607223510742, 1.582272171974182129, 1.613999366760253906, |
| 138 | 1.644955039024353027, 1.675132393836975098, 1.704526185989379883, |
| 139 | 1.718986630439758301, 1.711274504661560059, 1.703639745712280273, |
| 140 | 1.696081161499023438, 1.688597679138183594, 1.673851132392883301, |
| 141 | 1.659391283988952637, 1.645209431648254395, 1.631297469139099121, |
| 142 | 1.617647409439086914, 1.604251742362976074}}; |
| 143 | |
| 144 | // Stats. |
| 145 | mutable Stats stats_; |
| 146 | |
Alex Loiko | 507e8d1 | 2018-02-27 13:51:47 +0100 | [diff] [blame] | 147 | RTC_DISALLOW_COPY_AND_ASSIGN(InterpolatedGainCurve); |
Alex Loiko | a05ee82 | 2018-02-20 15:58:36 +0100 | [diff] [blame] | 148 | }; |
| 149 | |
| 150 | } // namespace webrtc |
| 151 | |
| 152 | #endif // MODULES_AUDIO_PROCESSING_AGC2_INTERPOLATED_GAIN_CURVE_H_ |