tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

interpolated_gain_curve.cc (7311B)


      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 #include "modules/audio_processing/agc2/interpolated_gain_curve.h"
     12 
     13 #include <algorithm>
     14 #include <array>
     15 #include <cstddef>
     16 #include <iterator>
     17 
     18 #include "absl/strings/string_view.h"
     19 #include "modules/audio_processing/agc2/agc2_common.h"
     20 #include "modules/audio_processing/logging/apm_data_dumper.h"
     21 #include "rtc_base/checks.h"
     22 #include "rtc_base/strings/string_builder.h"
     23 #include "system_wrappers/include/metrics.h"
     24 
     25 namespace webrtc {
     26 
     27 InterpolatedGainCurve::InterpolatedGainCurve(
     28    ApmDataDumper* apm_data_dumper,
     29    absl::string_view histogram_name_prefix)
     30    : region_logger_(
     31          (StringBuilder("WebRTC.Audio.")
     32           << histogram_name_prefix << ".FixedDigitalGainCurveRegion.Identity")
     33              .str(),
     34          (StringBuilder("WebRTC.Audio.")
     35           << histogram_name_prefix << ".FixedDigitalGainCurveRegion.Knee")
     36              .str(),
     37          (StringBuilder("WebRTC.Audio.")
     38           << histogram_name_prefix << ".FixedDigitalGainCurveRegion.Limiter")
     39              .str(),
     40          (StringBuilder("WebRTC.Audio.")
     41           << histogram_name_prefix
     42           << ".FixedDigitalGainCurveRegion.Saturation")
     43              .str()),
     44      apm_data_dumper_(apm_data_dumper) {}
     45 
     46 InterpolatedGainCurve::~InterpolatedGainCurve() {
     47  if (stats_.available) {
     48    RTC_DCHECK(apm_data_dumper_);
     49    apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_identity",
     50                              stats_.look_ups_identity_region);
     51    apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_knee",
     52                              stats_.look_ups_knee_region);
     53    apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_limiter",
     54                              stats_.look_ups_limiter_region);
     55    apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_saturation",
     56                              stats_.look_ups_saturation_region);
     57    region_logger_.LogRegionStats(stats_);
     58  }
     59 }
     60 
     61 InterpolatedGainCurve::RegionLogger::RegionLogger(
     62    absl::string_view identity_histogram_name,
     63    absl::string_view knee_histogram_name,
     64    absl::string_view limiter_histogram_name,
     65    absl::string_view saturation_histogram_name)
     66    : identity_histogram(
     67          metrics::HistogramFactoryGetCounts(identity_histogram_name,
     68                                             1,
     69                                             10000,
     70                                             50)),
     71      knee_histogram(metrics::HistogramFactoryGetCounts(knee_histogram_name,
     72                                                        1,
     73                                                        10000,
     74                                                        50)),
     75      limiter_histogram(
     76          metrics::HistogramFactoryGetCounts(limiter_histogram_name,
     77                                             1,
     78                                             10000,
     79                                             50)),
     80      saturation_histogram(
     81          metrics::HistogramFactoryGetCounts(saturation_histogram_name,
     82                                             1,
     83                                             10000,
     84                                             50)) {}
     85 
     86 InterpolatedGainCurve::RegionLogger::~RegionLogger() = default;
     87 
     88 void InterpolatedGainCurve::RegionLogger::LogRegionStats(
     89    const InterpolatedGainCurve::Stats& stats) const {
     90  using Region = InterpolatedGainCurve::GainCurveRegion;
     91  const int duration_s =
     92      stats.region_duration_frames / (1000 / kFrameDurationMs);
     93 
     94  switch (stats.region) {
     95    case Region::kIdentity: {
     96      if (identity_histogram) {
     97        metrics::HistogramAdd(identity_histogram, duration_s);
     98      }
     99      break;
    100    }
    101    case Region::kKnee: {
    102      if (knee_histogram) {
    103        metrics::HistogramAdd(knee_histogram, duration_s);
    104      }
    105      break;
    106    }
    107    case Region::kLimiter: {
    108      if (limiter_histogram) {
    109        metrics::HistogramAdd(limiter_histogram, duration_s);
    110      }
    111      break;
    112    }
    113    case Region::kSaturation: {
    114      if (saturation_histogram) {
    115        metrics::HistogramAdd(saturation_histogram, duration_s);
    116      }
    117      break;
    118    }
    119    default: {
    120      RTC_DCHECK_NOTREACHED();
    121    }
    122  }
    123 }
    124 
    125 void InterpolatedGainCurve::UpdateStats(float input_level) const {
    126  stats_.available = true;
    127 
    128  GainCurveRegion region;
    129 
    130  if (input_level < approximation_params_x_[0]) {
    131    stats_.look_ups_identity_region++;
    132    region = GainCurveRegion::kIdentity;
    133  } else if (input_level <
    134             approximation_params_x_[kInterpolatedGainCurveKneePoints - 1]) {
    135    stats_.look_ups_knee_region++;
    136    region = GainCurveRegion::kKnee;
    137  } else if (input_level < kMaxInputLevelLinear) {
    138    stats_.look_ups_limiter_region++;
    139    region = GainCurveRegion::kLimiter;
    140  } else {
    141    stats_.look_ups_saturation_region++;
    142    region = GainCurveRegion::kSaturation;
    143  }
    144 
    145  if (region == stats_.region) {
    146    ++stats_.region_duration_frames;
    147  } else {
    148    region_logger_.LogRegionStats(stats_);
    149 
    150    stats_.region_duration_frames = 0;
    151    stats_.region = region;
    152  }
    153 }
    154 
    155 // Looks up a gain to apply given a non-negative input level.
    156 // The cost of this operation depends on the region in which `input_level`
    157 // falls.
    158 // For the identity and the saturation regions the cost is O(1).
    159 // For the other regions, namely knee and limiter, the cost is
    160 // O(2 + log2(`LightkInterpolatedGainCurveTotalPoints`), plus O(1) for the
    161 // linear interpolation (one product and one sum).
    162 float InterpolatedGainCurve::LookUpGainToApply(float input_level) const {
    163  UpdateStats(input_level);
    164 
    165  if (input_level <= approximation_params_x_[0]) {
    166    // Identity region.
    167    return 1.0f;
    168  }
    169 
    170  if (input_level >= kMaxInputLevelLinear) {
    171    // Saturating lower bound. The saturing samples exactly hit the clipping
    172    // level. This method achieves has the lowest harmonic distorsion, but it
    173    // may reduce the amplitude of the non-saturating samples too much.
    174    return 32768.f / input_level;
    175  }
    176 
    177  // Knee and limiter regions; find the linear piece index. Spelling
    178  // out the complete type was the only way to silence both the clang
    179  // plugin and the windows compilers.
    180  std::array<float, kInterpolatedGainCurveTotalPoints>::const_iterator it =
    181      std::lower_bound(approximation_params_x_.begin(),
    182                       approximation_params_x_.end(), input_level);
    183  const size_t index = std::distance(approximation_params_x_.begin(), it) - 1;
    184  RTC_DCHECK_LE(0, index);
    185  RTC_DCHECK_LT(index, approximation_params_m_.size());
    186  RTC_DCHECK_LE(approximation_params_x_[index], input_level);
    187  if (index < approximation_params_m_.size() - 1) {
    188    RTC_DCHECK_LE(input_level, approximation_params_x_[index + 1]);
    189  }
    190 
    191  // Piece-wise linear interploation.
    192  const float gain = approximation_params_m_[index] * input_level +
    193                     approximation_params_q_[index];
    194  RTC_DCHECK_LE(0.f, gain);
    195  return gain;
    196 }
    197 
    198 }  // namespace webrtc