tor-browser

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

reverb_decay_estimator.cc (16291B)


      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/aec3/reverb_decay_estimator.h"
     12 
     13 #include <algorithm>
     14 #include <array>
     15 #include <cmath>
     16 #include <cstddef>
     17 #include <numeric>
     18 #include <optional>
     19 
     20 #include "api/array_view.h"
     21 #include "api/audio/echo_canceller3_config.h"
     22 #include "modules/audio_processing/aec3/aec3_common.h"
     23 #include "modules/audio_processing/logging/apm_data_dumper.h"
     24 #include "rtc_base/checks.h"
     25 
     26 namespace webrtc {
     27 
     28 namespace {
     29 
     30 constexpr int kEarlyReverbMinSizeBlocks = 3;
     31 constexpr int kBlocksPerSection = 6;
     32 // Linear regression approach assumes symmetric index around 0.
     33 constexpr float kEarlyReverbFirstPointAtLinearRegressors =
     34    -0.5f * kBlocksPerSection * kFftLengthBy2 + 0.5f;
     35 
     36 // Averages the values in a block of size kFftLengthBy2;
     37 float BlockAverage(ArrayView<const float> v, size_t block_index) {
     38  constexpr float kOneByFftLengthBy2 = 1.f / kFftLengthBy2;
     39  const int i = block_index * kFftLengthBy2;
     40  RTC_DCHECK_GE(v.size(), i + kFftLengthBy2);
     41  const float sum =
     42      std::accumulate(v.begin() + i, v.begin() + i + kFftLengthBy2, 0.f);
     43  return sum * kOneByFftLengthBy2;
     44 }
     45 
     46 // Analyzes the gain in a block.
     47 void AnalyzeBlockGain(const std::array<float, kFftLengthBy2>& h2,
     48                      float floor_gain,
     49                      float* previous_gain,
     50                      bool* block_adapting,
     51                      bool* decaying_gain) {
     52  float gain = std::max(BlockAverage(h2, 0), 1e-32f);
     53  *block_adapting =
     54      *previous_gain > 1.1f * gain || *previous_gain < 0.9f * gain;
     55  *decaying_gain = gain > floor_gain;
     56  *previous_gain = gain;
     57 }
     58 
     59 // Arithmetic sum of $2 \sum_{i=0.5}^{(N-1)/2}i^2$ calculated directly.
     60 constexpr float SymmetricArithmetricSum(int N) {
     61  return N * (N * N - 1.0f) * (1.f / 12.f);
     62 }
     63 
     64 // Returns the peak energy of an impulse response.
     65 float BlockEnergyPeak(ArrayView<const float> h, int peak_block) {
     66  RTC_DCHECK_LE((peak_block + 1) * kFftLengthBy2, h.size());
     67  RTC_DCHECK_GE(peak_block, 0);
     68  float peak_value =
     69      *std::max_element(h.begin() + peak_block * kFftLengthBy2,
     70                        h.begin() + (peak_block + 1) * kFftLengthBy2,
     71                        [](float a, float b) { return a * a < b * b; });
     72  return peak_value * peak_value;
     73 }
     74 
     75 // Returns the average energy of an impulse response block.
     76 float BlockEnergyAverage(ArrayView<const float> h, int block_index) {
     77  RTC_DCHECK_LE((block_index + 1) * kFftLengthBy2, h.size());
     78  RTC_DCHECK_GE(block_index, 0);
     79  constexpr float kOneByFftLengthBy2 = 1.f / kFftLengthBy2;
     80  const auto sum_of_squares = [](float a, float b) { return a + b * b; };
     81  return std::accumulate(h.begin() + block_index * kFftLengthBy2,
     82                         h.begin() + (block_index + 1) * kFftLengthBy2, 0.f,
     83                         sum_of_squares) *
     84         kOneByFftLengthBy2;
     85 }
     86 
     87 }  // namespace
     88 
     89 ReverbDecayEstimator::ReverbDecayEstimator(const EchoCanceller3Config& config)
     90    : filter_length_blocks_(config.filter.refined.length_blocks),
     91      filter_length_coefficients_(GetTimeDomainLength(filter_length_blocks_)),
     92      use_adaptive_echo_decay_(config.ep_strength.default_len < 0.f),
     93      early_reverb_estimator_(config.filter.refined.length_blocks -
     94                              kEarlyReverbMinSizeBlocks),
     95      late_reverb_start_(kEarlyReverbMinSizeBlocks),
     96      late_reverb_end_(kEarlyReverbMinSizeBlocks),
     97      previous_gains_(config.filter.refined.length_blocks, 0.f),
     98      decay_(std::fabs(config.ep_strength.default_len)),
     99      mild_decay_(std::fabs(config.ep_strength.nearend_len)) {
    100  RTC_DCHECK_GT(config.filter.refined.length_blocks,
    101                static_cast<size_t>(kEarlyReverbMinSizeBlocks));
    102 }
    103 
    104 ReverbDecayEstimator::~ReverbDecayEstimator() = default;
    105 
    106 void ReverbDecayEstimator::Update(ArrayView<const float> filter,
    107                                  const std::optional<float>& filter_quality,
    108                                  int filter_delay_blocks,
    109                                  bool usable_linear_filter,
    110                                  bool stationary_signal) {
    111  const int filter_size = static_cast<int>(filter.size());
    112 
    113  if (stationary_signal) {
    114    return;
    115  }
    116 
    117  bool estimation_feasible =
    118      filter_delay_blocks <=
    119      filter_length_blocks_ - kEarlyReverbMinSizeBlocks - 1;
    120  estimation_feasible =
    121      estimation_feasible && filter_size == filter_length_coefficients_;
    122  estimation_feasible = estimation_feasible && filter_delay_blocks > 0;
    123  estimation_feasible = estimation_feasible && usable_linear_filter;
    124 
    125  if (!estimation_feasible) {
    126    ResetDecayEstimation();
    127    return;
    128  }
    129 
    130  if (!use_adaptive_echo_decay_) {
    131    return;
    132  }
    133 
    134  const float new_smoothing = filter_quality ? *filter_quality * 0.2f : 0.f;
    135  smoothing_constant_ = std::max(new_smoothing, smoothing_constant_);
    136  if (smoothing_constant_ == 0.f) {
    137    return;
    138  }
    139 
    140  if (block_to_analyze_ < filter_length_blocks_) {
    141    // Analyze the filter and accumulate data for reverb estimation.
    142    AnalyzeFilter(filter);
    143    ++block_to_analyze_;
    144  } else {
    145    // When the filter is fully analyzed, estimate the reverb decay and reset
    146    // the block_to_analyze_ counter.
    147    EstimateDecay(filter, filter_delay_blocks);
    148  }
    149 }
    150 
    151 void ReverbDecayEstimator::ResetDecayEstimation() {
    152  early_reverb_estimator_.Reset();
    153  late_reverb_decay_estimator_.Reset(0);
    154  block_to_analyze_ = 0;
    155  estimation_region_candidate_size_ = 0;
    156  estimation_region_identified_ = false;
    157  smoothing_constant_ = 0.f;
    158  late_reverb_start_ = 0;
    159  late_reverb_end_ = 0;
    160 }
    161 
    162 void ReverbDecayEstimator::EstimateDecay(ArrayView<const float> filter,
    163                                         int peak_block) {
    164  auto& h = filter;
    165  RTC_DCHECK_EQ(0, h.size() % kFftLengthBy2);
    166 
    167  // Reset the block analysis counter.
    168  block_to_analyze_ =
    169      std::min(peak_block + kEarlyReverbMinSizeBlocks, filter_length_blocks_);
    170 
    171  // To estimate the reverb decay, the energy of the first filter section must
    172  // be substantially larger than the last. Also, the first filter section
    173  // energy must not deviate too much from the max peak.
    174  const float first_reverb_gain = BlockEnergyAverage(h, block_to_analyze_);
    175  const size_t h_size_blocks = h.size() >> kFftLengthBy2Log2;
    176  tail_gain_ = BlockEnergyAverage(h, h_size_blocks - 1);
    177  float peak_energy = BlockEnergyPeak(h, peak_block);
    178  const bool sufficient_reverb_decay = first_reverb_gain > 4.f * tail_gain_;
    179  const bool valid_filter =
    180      first_reverb_gain > 2.f * tail_gain_ && peak_energy < 100.f;
    181 
    182  // Estimate the size of the regions with early and late reflections.
    183  const int size_early_reverb = early_reverb_estimator_.Estimate();
    184  const int size_late_reverb =
    185      std::max(estimation_region_candidate_size_ - size_early_reverb, 0);
    186 
    187  // Only update the reverb decay estimate if the size of the identified late
    188  // reverb is sufficiently large.
    189  if (size_late_reverb >= 5) {
    190    if (valid_filter && late_reverb_decay_estimator_.EstimateAvailable()) {
    191      float decay = std::pow(
    192          2.0f, late_reverb_decay_estimator_.Estimate() * kFftLengthBy2);
    193      constexpr float kMaxDecay = 0.95f;  // ~1 sec min RT60.
    194      constexpr float kMinDecay = 0.02f;  // ~15 ms max RT60.
    195      decay = std::max(.97f * decay_, decay);
    196      decay = std::min(decay, kMaxDecay);
    197      decay = std::max(decay, kMinDecay);
    198      decay_ += smoothing_constant_ * (decay - decay_);
    199    }
    200 
    201    // Update length of decay. Must have enough data (number of sections) in
    202    // order to estimate decay rate.
    203    late_reverb_decay_estimator_.Reset(size_late_reverb * kFftLengthBy2);
    204    late_reverb_start_ =
    205        peak_block + kEarlyReverbMinSizeBlocks + size_early_reverb;
    206    late_reverb_end_ =
    207        block_to_analyze_ + estimation_region_candidate_size_ - 1;
    208  } else {
    209    late_reverb_decay_estimator_.Reset(0);
    210    late_reverb_start_ = 0;
    211    late_reverb_end_ = 0;
    212  }
    213 
    214  // Reset variables for the identification of the region for reverb decay
    215  // estimation.
    216  estimation_region_identified_ = !(valid_filter && sufficient_reverb_decay);
    217  estimation_region_candidate_size_ = 0;
    218 
    219  // Stop estimation of the decay until another good filter is received.
    220  smoothing_constant_ = 0.f;
    221 
    222  // Reset early reflections detector.
    223  early_reverb_estimator_.Reset();
    224 }
    225 
    226 void ReverbDecayEstimator::AnalyzeFilter(ArrayView<const float> filter) {
    227  auto h = ArrayView<const float>(
    228      filter.begin() + block_to_analyze_ * kFftLengthBy2, kFftLengthBy2);
    229 
    230  // Compute squared filter coeffiecients for the block to analyze_;
    231  std::array<float, kFftLengthBy2> h2;
    232  std::transform(h.begin(), h.end(), h2.begin(), [](float a) { return a * a; });
    233 
    234  // Map out the region for estimating the reverb decay.
    235  bool adapting;
    236  bool above_noise_floor;
    237  AnalyzeBlockGain(h2, tail_gain_, &previous_gains_[block_to_analyze_],
    238                   &adapting, &above_noise_floor);
    239 
    240  // Count consecutive number of "good" filter sections, where "good" means:
    241  // 1) energy is above noise floor.
    242  // 2) energy of current section has not changed too much from last check.
    243  estimation_region_identified_ =
    244      estimation_region_identified_ || adapting || !above_noise_floor;
    245  if (!estimation_region_identified_) {
    246    ++estimation_region_candidate_size_;
    247  }
    248 
    249  // Accumulate data for reverb decay estimation and for the estimation of early
    250  // reflections.
    251  if (block_to_analyze_ <= late_reverb_end_) {
    252    if (block_to_analyze_ >= late_reverb_start_) {
    253      for (float h2_k : h2) {
    254        float h2_log2 = FastApproxLog2f(h2_k + 1e-10);
    255        late_reverb_decay_estimator_.Accumulate(h2_log2);
    256        early_reverb_estimator_.Accumulate(h2_log2, smoothing_constant_);
    257      }
    258    } else {
    259      for (float h2_k : h2) {
    260        float h2_log2 = FastApproxLog2f(h2_k + 1e-10);
    261        early_reverb_estimator_.Accumulate(h2_log2, smoothing_constant_);
    262      }
    263    }
    264  }
    265 }
    266 
    267 void ReverbDecayEstimator::Dump(ApmDataDumper* data_dumper) const {
    268  data_dumper->DumpRaw("aec3_reverb_decay", decay_);
    269  data_dumper->DumpRaw("aec3_reverb_tail_energy", tail_gain_);
    270  data_dumper->DumpRaw("aec3_reverb_alpha", smoothing_constant_);
    271  data_dumper->DumpRaw("aec3_num_reverb_decay_blocks",
    272                       late_reverb_end_ - late_reverb_start_);
    273  data_dumper->DumpRaw("aec3_late_reverb_start", late_reverb_start_);
    274  data_dumper->DumpRaw("aec3_late_reverb_end", late_reverb_end_);
    275  early_reverb_estimator_.Dump(data_dumper);
    276 }
    277 
    278 void ReverbDecayEstimator::LateReverbLinearRegressor::Reset(
    279    int num_data_points) {
    280  RTC_DCHECK_LE(0, num_data_points);
    281  RTC_DCHECK_EQ(0, num_data_points % 2);
    282  const int N = num_data_points;
    283  nz_ = 0.f;
    284  // Arithmetic sum of $2 \sum_{i=0.5}^{(N-1)/2}i^2$ calculated directly.
    285  nn_ = SymmetricArithmetricSum(N);
    286  // The linear regression approach assumes symmetric index around 0.
    287  count_ = N > 0 ? -N * 0.5f + 0.5f : 0.f;
    288  N_ = N;
    289  n_ = 0;
    290 }
    291 
    292 void ReverbDecayEstimator::LateReverbLinearRegressor::Accumulate(float z) {
    293  nz_ += count_ * z;
    294  ++count_;
    295  ++n_;
    296 }
    297 
    298 float ReverbDecayEstimator::LateReverbLinearRegressor::Estimate() {
    299  RTC_DCHECK(EstimateAvailable());
    300  if (nn_ == 0.f) {
    301    RTC_DCHECK_NOTREACHED();
    302    return 0.f;
    303  }
    304  return nz_ / nn_;
    305 }
    306 
    307 ReverbDecayEstimator::EarlyReverbLengthEstimator::EarlyReverbLengthEstimator(
    308    int max_blocks)
    309    : numerators_smooth_(max_blocks - kBlocksPerSection, 0.f),
    310      numerators_(numerators_smooth_.size(), 0.f),
    311      coefficients_counter_(0) {
    312  RTC_DCHECK_LE(0, max_blocks);
    313 }
    314 
    315 ReverbDecayEstimator::EarlyReverbLengthEstimator::
    316    ~EarlyReverbLengthEstimator() = default;
    317 
    318 void ReverbDecayEstimator::EarlyReverbLengthEstimator::Reset() {
    319  coefficients_counter_ = 0;
    320  std::fill(numerators_.begin(), numerators_.end(), 0.f);
    321  block_counter_ = 0;
    322 }
    323 
    324 void ReverbDecayEstimator::EarlyReverbLengthEstimator::Accumulate(
    325    float value,
    326    float smoothing) {
    327  // Each section is composed by kBlocksPerSection blocks and each section
    328  // overlaps with the next one in (kBlocksPerSection - 1) blocks. For example,
    329  // the first section covers the blocks [0:5], the second covers the blocks
    330  // [1:6] and so on. As a result, for each value, kBlocksPerSection sections
    331  // need to be updated.
    332  int first_section_index = std::max(block_counter_ - kBlocksPerSection + 1, 0);
    333  int last_section_index =
    334      std::min(block_counter_, static_cast<int>(numerators_.size() - 1));
    335  float x_value = static_cast<float>(coefficients_counter_) +
    336                  kEarlyReverbFirstPointAtLinearRegressors;
    337  const float value_to_inc = kFftLengthBy2 * value;
    338  float value_to_add =
    339      x_value * value + (block_counter_ - last_section_index) * value_to_inc;
    340  for (int section = last_section_index; section >= first_section_index;
    341       --section, value_to_add += value_to_inc) {
    342    numerators_[section] += value_to_add;
    343  }
    344 
    345  // Check if this update was the last coefficient of the current block. In that
    346  // case, check if we are at the end of one of the sections and update the
    347  // numerator of the linear regressor that is computed in such section.
    348  if (++coefficients_counter_ == kFftLengthBy2) {
    349    if (block_counter_ >= (kBlocksPerSection - 1)) {
    350      size_t section = block_counter_ - (kBlocksPerSection - 1);
    351      RTC_DCHECK_GT(numerators_.size(), section);
    352      RTC_DCHECK_GT(numerators_smooth_.size(), section);
    353      numerators_smooth_[section] +=
    354          smoothing * (numerators_[section] - numerators_smooth_[section]);
    355      n_sections_ = section + 1;
    356    }
    357    ++block_counter_;
    358    coefficients_counter_ = 0;
    359  }
    360 }
    361 
    362 // Estimates the size in blocks of the early reverb. The estimation is done by
    363 // comparing the tilt that is estimated in each section. As an optimization
    364 // detail and due to the fact that all the linear regressors that are computed
    365 // shared the same denominator, the comparison of the tilts is done by a
    366 // comparison of the numerator of the linear regressors.
    367 int ReverbDecayEstimator::EarlyReverbLengthEstimator::Estimate() {
    368  constexpr float N = kBlocksPerSection * kFftLengthBy2;
    369  constexpr float nn = SymmetricArithmetricSum(N);
    370  // numerator_11 refers to the quantity that the linear regressor needs in the
    371  // numerator for getting a decay equal to 1.1 (which is not a decay).
    372  // log2(1.1) * nn / kFftLengthBy2.
    373  constexpr float numerator_11 = 0.13750352374993502f * nn / kFftLengthBy2;
    374  // log2(0.8) *  nn / kFftLengthBy2.
    375  constexpr float numerator_08 = -0.32192809488736229f * nn / kFftLengthBy2;
    376  constexpr int kNumSectionsToAnalyze = 9;
    377 
    378  if (n_sections_ < kNumSectionsToAnalyze) {
    379    return 0;
    380  }
    381 
    382  // Estimation of the blocks that correspond to early reverberations. The
    383  // estimation is done by analyzing the impulse response. The portions of the
    384  // impulse response whose energy is not decreasing over its coefficients are
    385  // considered to be part of the early reverberations. Furthermore, the blocks
    386  // where the energy is decreasing faster than what it does at the end of the
    387  // impulse response are also considered to be part of the early
    388  // reverberations. The estimation is limited to the first
    389  // kNumSectionsToAnalyze sections.
    390 
    391  RTC_DCHECK_LE(n_sections_, numerators_smooth_.size());
    392  const float min_numerator_tail =
    393      *std::min_element(numerators_smooth_.begin() + kNumSectionsToAnalyze,
    394                        numerators_smooth_.begin() + n_sections_);
    395  int early_reverb_size_minus_1 = 0;
    396  for (int k = 0; k < kNumSectionsToAnalyze; ++k) {
    397    if ((numerators_smooth_[k] > numerator_11) ||
    398        (numerators_smooth_[k] < numerator_08 &&
    399         numerators_smooth_[k] < 0.9f * min_numerator_tail)) {
    400      early_reverb_size_minus_1 = k;
    401    }
    402  }
    403 
    404  return early_reverb_size_minus_1 == 0 ? 0 : early_reverb_size_minus_1 + 1;
    405 }
    406 
    407 void ReverbDecayEstimator::EarlyReverbLengthEstimator::Dump(
    408    ApmDataDumper* data_dumper) const {
    409  data_dumper->DumpRaw("aec3_er_acum_numerator", numerators_smooth_);
    410 }
    411 
    412 }  // namespace webrtc