tor-browser

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

background_noise.cc (12095B)


      1 /*
      2 *  Copyright (c) 2012 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_coding/neteq/background_noise.h"
     12 
     13 #include <algorithm>  // min, max
     14 #include <cstdint>
     15 #include <cstring>  // memcpy
     16 
     17 #include "api/array_view.h"
     18 #include "common_audio/signal_processing/dot_product_with_scale.h"
     19 #include "common_audio/signal_processing/include/signal_processing_library.h"
     20 #include "common_audio/signal_processing/include/spl_inl.h"
     21 #include "modules/audio_coding/neteq/audio_multi_vector.h"
     22 #include "modules/audio_coding/neteq/cross_correlation.h"
     23 #include "rtc_base/checks.h"
     24 
     25 namespace webrtc {
     26 namespace {
     27 
     28 constexpr size_t kMaxSampleRate = 48000;
     29 
     30 }  // namespace
     31 
     32 BackgroundNoise::BackgroundNoise(size_t num_channels)
     33    : num_channels_(num_channels),
     34      channel_parameters_(new ChannelParameters[num_channels_]) {
     35  Reset();
     36 }
     37 
     38 BackgroundNoise::~BackgroundNoise() {}
     39 
     40 void BackgroundNoise::Reset() {
     41  initialized_ = false;
     42  for (size_t channel = 0; channel < num_channels_; ++channel) {
     43    channel_parameters_[channel].Reset();
     44  }
     45 }
     46 
     47 bool BackgroundNoise::Update(const AudioMultiVector& sync_buffer) {
     48  bool filter_params_saved = false;
     49 
     50  int32_t auto_correlation[kMaxLpcOrder + 1];
     51  int16_t filter_output[kMaxLpcOrder + kResidualLength];
     52  int16_t reflection_coefficients[kMaxLpcOrder];
     53  int16_t lpc_coefficients[kMaxLpcOrder + 1];
     54 
     55  for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) {
     56    ChannelParameters& parameters = channel_parameters_[channel_ix];
     57    int16_t temp_signal_array[kVecLen + kMaxLpcOrder] = {0};
     58    int16_t* temp_signal = &temp_signal_array[kMaxLpcOrder];
     59    RTC_DCHECK_GE(sync_buffer.Size(), kVecLen);
     60    sync_buffer[channel_ix].CopyTo(kVecLen, sync_buffer.Size() - kVecLen,
     61                                   temp_signal);
     62    int32_t sample_energy =
     63        CalculateAutoCorrelation(temp_signal, kVecLen, auto_correlation);
     64 
     65    if (sample_energy < parameters.energy_update_threshold) {
     66      // Generate LPC coefficients.
     67      if (auto_correlation[0] <= 0) {
     68        // Center value in auto-correlation is not positive. Do not update.
     69        return filter_params_saved;
     70      }
     71 
     72      // Regardless of whether the filter is actually updated or not,
     73      // update energy threshold levels, since we have in fact observed
     74      // a low energy signal.
     75      if (sample_energy < parameters.energy_update_threshold) {
     76        // Never go under 1.0 in average sample energy.
     77        parameters.energy_update_threshold = std::max(sample_energy, 1);
     78        parameters.low_energy_update_threshold = 0;
     79      }
     80 
     81      // Only update BGN if filter is stable, i.e., if return value from
     82      // Levinson-Durbin function is 1.
     83      if (WebRtcSpl_LevinsonDurbin(auto_correlation, lpc_coefficients,
     84                                   reflection_coefficients,
     85                                   kMaxLpcOrder) != 1) {
     86        return filter_params_saved;
     87      }
     88 
     89      // Generate the CNG gain factor by looking at the energy of the residual.
     90      WebRtcSpl_FilterMAFastQ12(temp_signal + kVecLen - kResidualLength,
     91                                filter_output, lpc_coefficients,
     92                                kMaxLpcOrder + 1, kResidualLength);
     93      int32_t residual_energy = WebRtcSpl_DotProductWithScale(
     94          filter_output, filter_output, kResidualLength, 0);
     95 
     96      // Check spectral flatness.
     97      // Comparing the residual variance with the input signal variance tells
     98      // if the spectrum is flat or not.
     99      // If 5 * residual_energy >= 16 * sample_energy, the spectrum is flat
    100      // enough.  Also ensure that the energy is non-zero.
    101      if ((sample_energy > 0) &&
    102          (int64_t{5} * residual_energy >= int64_t{16} * sample_energy)) {
    103        // Spectrum is flat enough; save filter parameters.
    104        // `temp_signal` + `kVecLen` - `kMaxLpcOrder` points at the first of the
    105        // `kMaxLpcOrder` samples in the residual signal, which will form the
    106        // filter state for the next noise generation.
    107        SaveParameters(channel_ix, lpc_coefficients,
    108                       temp_signal + kVecLen - kMaxLpcOrder, sample_energy,
    109                       residual_energy);
    110        filter_params_saved = true;
    111      }
    112    } else {
    113      // Will only happen if `sample_energy` is not low enough. Increase the
    114      // threshold for update so that it increases by a factor 4 in 4 seconds.
    115      IncrementEnergyThreshold(channel_ix, sample_energy);
    116    }
    117  }
    118  return filter_params_saved;
    119 }
    120 
    121 void BackgroundNoise::GenerateBackgroundNoise(
    122    ArrayView<const int16_t> random_vector,
    123    size_t channel,
    124    int /* mute_slope */,
    125    bool /* too_many_expands */,
    126    size_t num_noise_samples,
    127    int16_t* buffer) {
    128  constexpr size_t kNoiseLpcOrder = kMaxLpcOrder;
    129  int16_t scaled_random_vector[kMaxSampleRate / 8000 * 125];
    130  RTC_DCHECK_LE(num_noise_samples, (kMaxSampleRate / 8000 * 125));
    131  RTC_DCHECK_GE(random_vector.size(), num_noise_samples);
    132  int16_t* noise_samples = &buffer[kNoiseLpcOrder];
    133  if (initialized()) {
    134    // Use background noise parameters.
    135    memcpy(noise_samples - kNoiseLpcOrder, FilterState(channel),
    136           sizeof(int16_t) * kNoiseLpcOrder);
    137 
    138    int dc_offset = 0;
    139    if (ScaleShift(channel) > 1) {
    140      dc_offset = 1 << (ScaleShift(channel) - 1);
    141    }
    142 
    143    // Scale random vector to correct energy level.
    144    WebRtcSpl_AffineTransformVector(scaled_random_vector, random_vector.data(),
    145                                    Scale(channel), dc_offset,
    146                                    ScaleShift(channel), num_noise_samples);
    147 
    148    WebRtcSpl_FilterARFastQ12(scaled_random_vector, noise_samples,
    149                              Filter(channel), kNoiseLpcOrder + 1,
    150                              num_noise_samples);
    151 
    152    SetFilterState(
    153        channel,
    154        {&(noise_samples[num_noise_samples - kNoiseLpcOrder]), kNoiseLpcOrder});
    155 
    156    // Unmute the background noise.
    157    int16_t bgn_mute_factor = MuteFactor(channel);
    158    if (bgn_mute_factor < 16384) {
    159      WebRtcSpl_AffineTransformVector(noise_samples, noise_samples,
    160                                      bgn_mute_factor, 8192, 14,
    161                                      num_noise_samples);
    162    }
    163    // Update mute_factor in BackgroundNoise class.
    164    SetMuteFactor(channel, bgn_mute_factor);
    165  } else {
    166    // BGN parameters have not been initialized; use zero noise.
    167    memset(noise_samples, 0, sizeof(int16_t) * num_noise_samples);
    168  }
    169 }
    170 
    171 int32_t BackgroundNoise::Energy(size_t channel) const {
    172  RTC_DCHECK_LT(channel, num_channels_);
    173  return channel_parameters_[channel].energy;
    174 }
    175 
    176 void BackgroundNoise::SetMuteFactor(size_t channel, int16_t value) {
    177  RTC_DCHECK_LT(channel, num_channels_);
    178  channel_parameters_[channel].mute_factor = value;
    179 }
    180 
    181 int16_t BackgroundNoise::MuteFactor(size_t channel) const {
    182  RTC_DCHECK_LT(channel, num_channels_);
    183  return channel_parameters_[channel].mute_factor;
    184 }
    185 
    186 const int16_t* BackgroundNoise::Filter(size_t channel) const {
    187  RTC_DCHECK_LT(channel, num_channels_);
    188  return channel_parameters_[channel].filter;
    189 }
    190 
    191 const int16_t* BackgroundNoise::FilterState(size_t channel) const {
    192  RTC_DCHECK_LT(channel, num_channels_);
    193  return channel_parameters_[channel].filter_state;
    194 }
    195 
    196 void BackgroundNoise::SetFilterState(size_t channel,
    197                                     ArrayView<const int16_t> input) {
    198  RTC_DCHECK_LT(channel, num_channels_);
    199  size_t length = std::min(input.size(), kMaxLpcOrder);
    200  memcpy(channel_parameters_[channel].filter_state, input.data(),
    201         length * sizeof(int16_t));
    202 }
    203 
    204 int16_t BackgroundNoise::Scale(size_t channel) const {
    205  RTC_DCHECK_LT(channel, num_channels_);
    206  return channel_parameters_[channel].scale;
    207 }
    208 int16_t BackgroundNoise::ScaleShift(size_t channel) const {
    209  RTC_DCHECK_LT(channel, num_channels_);
    210  return channel_parameters_[channel].scale_shift;
    211 }
    212 
    213 int32_t BackgroundNoise::CalculateAutoCorrelation(
    214    const int16_t* signal,
    215    size_t length,
    216    int32_t* auto_correlation) const {
    217  static const int kCorrelationStep = -1;
    218  const int correlation_scale =
    219      CrossCorrelationWithAutoShift(signal, signal, length, kMaxLpcOrder + 1,
    220                                    kCorrelationStep, auto_correlation);
    221 
    222  // Number of shifts to normalize energy to energy/sample.
    223  int energy_sample_shift = kLogVecLen - correlation_scale;
    224  return auto_correlation[0] >> energy_sample_shift;
    225 }
    226 
    227 void BackgroundNoise::IncrementEnergyThreshold(size_t channel,
    228                                               int32_t sample_energy) {
    229  // TODO(hlundin): Simplify the below threshold update. What this code
    230  // does is simply "threshold += (increment * threshold) >> 16", but due
    231  // to the limited-width operations, it is not exactly the same. The
    232  // difference should be inaudible, but bit-exactness would not be
    233  // maintained.
    234  RTC_DCHECK_LT(channel, num_channels_);
    235  ChannelParameters& parameters = channel_parameters_[channel];
    236  int32_t temp_energy =
    237      (kThresholdIncrement * parameters.low_energy_update_threshold) >> 16;
    238  temp_energy +=
    239      kThresholdIncrement * (parameters.energy_update_threshold & 0xFF);
    240  temp_energy +=
    241      (kThresholdIncrement * ((parameters.energy_update_threshold >> 8) & 0xFF))
    242      << 8;
    243  parameters.low_energy_update_threshold += temp_energy;
    244 
    245  parameters.energy_update_threshold +=
    246      kThresholdIncrement * (parameters.energy_update_threshold >> 16);
    247  parameters.energy_update_threshold +=
    248      parameters.low_energy_update_threshold >> 16;
    249  parameters.low_energy_update_threshold =
    250      parameters.low_energy_update_threshold & 0x0FFFF;
    251 
    252  // Update maximum energy.
    253  // Decrease by a factor 1/1024 each time.
    254  parameters.max_energy = parameters.max_energy - (parameters.max_energy >> 10);
    255  if (sample_energy > parameters.max_energy) {
    256    parameters.max_energy = sample_energy;
    257  }
    258 
    259  // Set `energy_update_threshold` to no less than 60 dB lower than
    260  // `max_energy_`. Adding 524288 assures proper rounding.
    261  int32_t energy_update_threshold = (parameters.max_energy + 524288) >> 20;
    262  if (energy_update_threshold > parameters.energy_update_threshold) {
    263    parameters.energy_update_threshold = energy_update_threshold;
    264  }
    265 }
    266 
    267 void BackgroundNoise::SaveParameters(size_t channel,
    268                                     const int16_t* lpc_coefficients,
    269                                     const int16_t* filter_state,
    270                                     int32_t sample_energy,
    271                                     int32_t residual_energy) {
    272  RTC_DCHECK_LT(channel, num_channels_);
    273  ChannelParameters& parameters = channel_parameters_[channel];
    274  memcpy(parameters.filter, lpc_coefficients,
    275         (kMaxLpcOrder + 1) * sizeof(int16_t));
    276  memcpy(parameters.filter_state, filter_state, kMaxLpcOrder * sizeof(int16_t));
    277  // Save energy level and update energy threshold levels.
    278  // Never get under 1.0 in average sample energy.
    279  parameters.energy = std::max(sample_energy, 1);
    280  parameters.energy_update_threshold = parameters.energy;
    281  parameters.low_energy_update_threshold = 0;
    282 
    283  // Normalize residual_energy to 29 or 30 bits before sqrt.
    284  int16_t norm_shift = WebRtcSpl_NormW32(residual_energy) - 1;
    285  if (norm_shift & 0x1) {
    286    norm_shift -= 1;  // Even number of shifts required.
    287  }
    288  residual_energy = WEBRTC_SPL_SHIFT_W32(residual_energy, norm_shift);
    289 
    290  // Calculate scale and shift factor.
    291  parameters.scale = static_cast<int16_t>(WebRtcSpl_SqrtFloor(residual_energy));
    292  // Add 13 to the `scale_shift_`, since the random numbers table is in
    293  // Q13.
    294  // TODO(hlundin): Move the "13" to where the `scale_shift_` is used?
    295  parameters.scale_shift =
    296      static_cast<int16_t>(13 + ((kLogResidualLength + norm_shift) / 2));
    297 
    298  initialized_ = true;
    299 }
    300 
    301 }  // namespace webrtc