LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_coding/neteq - background_noise.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 114 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13