tor-browser

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

render_signal_analyzer.cc (5772B)


      1 /*
      2 *  Copyright (c) 2017 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/render_signal_analyzer.h"
     12 
     13 #include <algorithm>
     14 #include <array>
     15 #include <cmath>
     16 #include <cstddef>
     17 #include <optional>
     18 #include <utility>
     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/aec3/block.h"
     24 #include "modules/audio_processing/aec3/render_buffer.h"
     25 #include "rtc_base/checks.h"
     26 
     27 namespace webrtc {
     28 
     29 namespace {
     30 constexpr size_t kCounterThreshold = 5;
     31 
     32 // Identifies local bands with narrow characteristics.
     33 void IdentifySmallNarrowBandRegions(
     34    const RenderBuffer& render_buffer,
     35    const std::optional<size_t>& delay_partitions,
     36    std::array<size_t, kFftLengthBy2 - 1>* narrow_band_counters) {
     37  RTC_DCHECK(narrow_band_counters);
     38 
     39  if (!delay_partitions) {
     40    narrow_band_counters->fill(0);
     41    return;
     42  }
     43 
     44  std::array<size_t, kFftLengthBy2 - 1> channel_counters;
     45  channel_counters.fill(0);
     46  ArrayView<const std::array<float, kFftLengthBy2Plus1>> X2 =
     47      render_buffer.Spectrum(*delay_partitions);
     48  for (size_t ch = 0; ch < X2.size(); ++ch) {
     49    for (size_t k = 1; k < kFftLengthBy2; ++k) {
     50      if (X2[ch][k] > 3 * std::max(X2[ch][k - 1], X2[ch][k + 1])) {
     51        ++channel_counters[k - 1];
     52      }
     53    }
     54  }
     55  for (size_t k = 1; k < kFftLengthBy2; ++k) {
     56    (*narrow_band_counters)[k - 1] =
     57        channel_counters[k - 1] > 0 ? (*narrow_band_counters)[k - 1] + 1 : 0;
     58  }
     59 }
     60 
     61 // Identifies whether the signal has a single strong narrow-band component.
     62 void IdentifyStrongNarrowBandComponent(const RenderBuffer& render_buffer,
     63                                       int strong_peak_freeze_duration,
     64                                       std::optional<int>* narrow_peak_band,
     65                                       size_t* narrow_peak_counter) {
     66  RTC_DCHECK(narrow_peak_band);
     67  RTC_DCHECK(narrow_peak_counter);
     68  if (*narrow_peak_band &&
     69      ++(*narrow_peak_counter) >
     70          static_cast<size_t>(strong_peak_freeze_duration)) {
     71    *narrow_peak_band = std::nullopt;
     72  }
     73 
     74  const Block& x_latest = render_buffer.GetBlock(0);
     75  float max_peak_level = 0.f;
     76  for (int channel = 0; channel < x_latest.NumChannels(); ++channel) {
     77    ArrayView<const float, kFftLengthBy2Plus1> X2_latest =
     78        render_buffer.Spectrum(0)[channel];
     79 
     80    // Identify the spectral peak.
     81    const int peak_bin =
     82        static_cast<int>(std::max_element(X2_latest.begin(), X2_latest.end()) -
     83                         X2_latest.begin());
     84 
     85    // Compute the level around the peak.
     86    float non_peak_power = 0.f;
     87    for (int k = std::max(0, peak_bin - 14); k < peak_bin - 4; ++k) {
     88      non_peak_power = std::max(X2_latest[k], non_peak_power);
     89    }
     90    for (int k = peak_bin + 5;
     91         k < std::min(peak_bin + 15, static_cast<int>(kFftLengthBy2Plus1));
     92         ++k) {
     93      non_peak_power = std::max(X2_latest[k], non_peak_power);
     94    }
     95 
     96    // Assess the render signal strength.
     97    auto result0 = std::minmax_element(x_latest.begin(/*band=*/0, channel),
     98                                       x_latest.end(/*band=*/0, channel));
     99    float max_abs = std::max(fabs(*result0.first), fabs(*result0.second));
    100 
    101    if (x_latest.NumBands() > 1) {
    102      const auto result1 =
    103          std::minmax_element(x_latest.begin(/*band=*/1, channel),
    104                              x_latest.end(/*band=*/1, channel));
    105      max_abs =
    106          std::max(max_abs, static_cast<float>(std::max(
    107                                fabs(*result1.first), fabs(*result1.second))));
    108    }
    109 
    110    // Detect whether the spectral peak has as strong narrowband nature.
    111    const float peak_level = X2_latest[peak_bin];
    112    if (peak_bin > 0 && max_abs > 100 && peak_level > 100 * non_peak_power) {
    113      // Store the strongest peak across channels.
    114      if (peak_level > max_peak_level) {
    115        max_peak_level = peak_level;
    116        *narrow_peak_band = peak_bin;
    117        *narrow_peak_counter = 0;
    118      }
    119    }
    120  }
    121 }
    122 
    123 }  // namespace
    124 
    125 RenderSignalAnalyzer::RenderSignalAnalyzer(const EchoCanceller3Config& config)
    126    : strong_peak_freeze_duration_(config.filter.refined.length_blocks) {
    127  narrow_band_counters_.fill(0);
    128 }
    129 RenderSignalAnalyzer::~RenderSignalAnalyzer() = default;
    130 
    131 void RenderSignalAnalyzer::Update(
    132    const RenderBuffer& render_buffer,
    133    const std::optional<size_t>& delay_partitions) {
    134  // Identify bands of narrow nature.
    135  IdentifySmallNarrowBandRegions(render_buffer, delay_partitions,
    136                                 &narrow_band_counters_);
    137 
    138  // Identify the presence of a strong narrow band.
    139  IdentifyStrongNarrowBandComponent(render_buffer, strong_peak_freeze_duration_,
    140                                    &narrow_peak_band_, &narrow_peak_counter_);
    141 }
    142 
    143 void RenderSignalAnalyzer::MaskRegionsAroundNarrowBands(
    144    std::array<float, kFftLengthBy2Plus1>* v) const {
    145  RTC_DCHECK(v);
    146 
    147  // Set v to zero around narrow band signal regions.
    148  if (narrow_band_counters_[0] > kCounterThreshold) {
    149    (*v)[1] = (*v)[0] = 0.f;
    150  }
    151  for (size_t k = 2; k < kFftLengthBy2 - 1; ++k) {
    152    if (narrow_band_counters_[k - 1] > kCounterThreshold) {
    153      (*v)[k - 2] = (*v)[k - 1] = (*v)[k] = (*v)[k + 1] = (*v)[k + 2] = 0.f;
    154    }
    155  }
    156  if (narrow_band_counters_[kFftLengthBy2 - 2] > kCounterThreshold) {
    157    (*v)[kFftLengthBy2] = (*v)[kFftLengthBy2 - 1] = 0.f;
    158  }
    159 }
    160 
    161 }  // namespace webrtc