19a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org/*
29a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
39a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *
49a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  Use of this source code is governed by a BSD-style license
59a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  that can be found in the LICENSE file in the root of the source
69a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  tree. An additional intellectual property rights grant can be found
79a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  in the file PATENTS.  All contributing project authors may
89a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
99a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org */
109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
11e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/background_noise.h"
129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include <assert.h>
143f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <string.h>  // memcpy
159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include <algorithm>  // min, max
179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
19e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/audio_multi_vector.h"
20e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/post_decode_vad.h"
219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgnamespace webrtc {
239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
24dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.orgBackgroundNoise::BackgroundNoise(size_t num_channels)
25dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org    : num_channels_(num_channels),
26dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org      channel_parameters_(new ChannelParameters[num_channels_]),
27d8b9cd100e889aa8b4a7d8b391ebd39a1298913ehenrik.lundin@webrtc.org      mode_(NetEq::kBgnOn) {
28dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org  Reset();
29dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org}
30dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org
31dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.orgBackgroundNoise::~BackgroundNoise() {}
32dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org
339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid BackgroundNoise::Reset() {
349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  initialized_ = false;
359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  for (size_t channel = 0; channel < num_channels_; ++channel) {
369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    channel_parameters_[channel].Reset();
379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Keep _bgnMode as it is.
399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
410e9c399746f45ceaf46f12b11ba93c09cca0c2bbhenrik.lundin@webrtc.orgvoid BackgroundNoise::Update(const AudioMultiVector& input,
429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                             const PostDecodeVad& vad) {
439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (vad.running() && vad.active_speech()) {
449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Do not update the background noise parameters if we know that the signal
459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // is active speech.
469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    return;
479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int32_t auto_correlation[kMaxLpcOrder + 1];
509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t fiter_output[kMaxLpcOrder + kResidualLength];
519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t reflection_coefficients[kMaxLpcOrder];
529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t lpc_coefficients[kMaxLpcOrder + 1];
539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) {
559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    ChannelParameters& parameters = channel_parameters_[channel_ix];
569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t temp_signal_array[kVecLen + kMaxLpcOrder] = {0};
579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int16_t* temp_signal = &temp_signal_array[kMaxLpcOrder];
589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    memcpy(temp_signal,
599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           &input[channel_ix][input.Size() - kVecLen],
609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org           sizeof(int16_t) * kVecLen);
619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int32_t sample_energy = CalculateAutoCorrelation(temp_signal, kVecLen,
639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                     auto_correlation);
649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if ((!vad.running() &&
669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        sample_energy < parameters.energy_update_threshold) ||
679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        (vad.running() && !vad.active_speech())) {
689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Generate LPC coefficients.
699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if (auto_correlation[0] > 0) {
709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Regardless of whether the filter is actually updated or not,
719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // update energy threshold levels, since we have in fact observed
729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // a low energy signal.
739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        if (sample_energy < parameters.energy_update_threshold) {
749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          // Never go under 1.0 in average sample energy.
759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          parameters.energy_update_threshold = std::max(sample_energy, 1);
769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          parameters.low_energy_update_threshold = 0;
779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        }
789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Only update BGN if filter is stable, i.e., if return value from
809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Levinson-Durbin function is 1.
819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        if (WebRtcSpl_LevinsonDurbin(auto_correlation, lpc_coefficients,
829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                     reflection_coefficients,
839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                     kMaxLpcOrder) != 1) {
849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          return;
859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        }
869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      } else {
879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Center value in auto-correlation is not positive. Do not update.
889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        return;
899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Generate the CNG gain factor by looking at the energy of the residual.
929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      WebRtcSpl_FilterMAFastQ12(temp_signal + kVecLen - kResidualLength,
939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                fiter_output, lpc_coefficients,
949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                kMaxLpcOrder + 1, kResidualLength);
959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      int32_t residual_energy = WebRtcSpl_DotProductWithScale(fiter_output,
969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                              fiter_output,
979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                              kResidualLength,
989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                              0);
999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1009a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Check spectral flatness.
1019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Comparing the residual variance with the input signal variance tells
1029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // if the spectrum is flat or not.
1039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // If 20 * residual_energy >= sample_energy << 6, the spectrum is flat
1049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // enough.  Also ensure that the energy is non-zero.
1059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      if ((residual_energy * 20 >= (sample_energy << 6)) &&
1069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org          (sample_energy > 0)) {
1079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Spectrum is flat enough; save filter parameters.
1089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // |temp_signal| + |kVecLen| - |kMaxLpcOrder| points at the first of the
1099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // |kMaxLpcOrder| samples in the residual signal, which will form the
1109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // filter state for the next noise generation.
1119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        SaveParameters(channel_ix, lpc_coefficients,
1129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                       temp_signal + kVecLen - kMaxLpcOrder, sample_energy,
1139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                       residual_energy);
1149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
1159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else {
1169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Will only happen if post-decode VAD is disabled and |sample_energy| is
1179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // not low enough. Increase the threshold for update so that it increases
1189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // by a factor 4 in 4 seconds.
1199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      IncrementEnergyThreshold(channel_ix, sample_energy);
1209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
1219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
1229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return;
1239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint32_t BackgroundNoise::Energy(size_t channel) const {
1269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(channel < num_channels_);
1279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return channel_parameters_[channel].energy;
1289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid BackgroundNoise::SetMuteFactor(size_t channel, int16_t value) {
1319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(channel < num_channels_);
1329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  channel_parameters_[channel].mute_factor = value;
1339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint16_t BackgroundNoise::MuteFactor(size_t channel) const {
1369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(channel < num_channels_);
1379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return channel_parameters_[channel].mute_factor;
1389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgconst int16_t* BackgroundNoise::Filter(size_t channel) const {
1419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(channel < num_channels_);
1429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return channel_parameters_[channel].filter;
1439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgconst int16_t* BackgroundNoise::FilterState(size_t channel) const {
1469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(channel < num_channels_);
1479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return channel_parameters_[channel].filter_state;
1489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid BackgroundNoise::SetFilterState(size_t channel, const int16_t* input,
1519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                     size_t length) {
1529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(channel < num_channels_);
1539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  length = std::min(length, static_cast<size_t>(kMaxLpcOrder));
1549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  memcpy(channel_parameters_[channel].filter_state, input,
1559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org         length * sizeof(int16_t));
1569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint16_t BackgroundNoise::Scale(size_t channel) const {
1599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(channel < num_channels_);
1609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return channel_parameters_[channel].scale;
1619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint16_t BackgroundNoise::ScaleShift(size_t channel) const {
1639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(channel < num_channels_);
1649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return channel_parameters_[channel].scale_shift;
1659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint32_t BackgroundNoise::CalculateAutoCorrelation(
168045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org    const int16_t* signal, int length, int32_t* auto_correlation) const {
1699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t signal_max = WebRtcSpl_MaxAbsValueW16(signal, length);
1709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int correlation_scale = kLogVecLen -
1719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      WebRtcSpl_NormW32(signal_max * signal_max);
1729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  correlation_scale = std::max(0, correlation_scale);
1739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  static const int kCorrelationStep = -1;
175045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org  WebRtcSpl_CrossCorrelation(auto_correlation, signal, signal, length,
176045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org                             kMaxLpcOrder + 1, correlation_scale,
1779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                             kCorrelationStep);
1789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Number of shifts to normalize energy to energy/sample.
1809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int energy_sample_shift = kLogVecLen - correlation_scale;
1819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return auto_correlation[0] >> energy_sample_shift;
1829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid BackgroundNoise::IncrementEnergyThreshold(size_t channel,
1859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                               int32_t sample_energy) {
1869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // TODO(hlundin): Simplify the below threshold update. What this code
1879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // does is simply "threshold += (increment * threshold) >> 16", but due
1889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // to the limited-width operations, it is not exactly the same. The
1899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // difference should be inaudible, but bit-exactness would not be
1909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // maintained.
1919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(channel < num_channels_);
1929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  ChannelParameters& parameters = channel_parameters_[channel];
1939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int32_t temp_energy =
1949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      WEBRTC_SPL_MUL_16_16_RSFT(kThresholdIncrement,
1959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                parameters.low_energy_update_threshold, 16);
1969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  temp_energy += kThresholdIncrement *
1979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      (parameters.energy_update_threshold & 0xFF);
1989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  temp_energy += (kThresholdIncrement *
1999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      ((parameters.energy_update_threshold>>8) & 0xFF)) << 8;
2009a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  parameters.low_energy_update_threshold += temp_energy;
2019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  parameters.energy_update_threshold += kThresholdIncrement *
2039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      (parameters.energy_update_threshold>>16);
2049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  parameters.energy_update_threshold +=
2059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.low_energy_update_threshold >> 16;
2069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  parameters.low_energy_update_threshold =
2079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      parameters.low_energy_update_threshold & 0x0FFFF;
2089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Update maximum energy.
2109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Decrease by a factor 1/1024 each time.
2119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  parameters.max_energy = parameters.max_energy -
2129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      (parameters.max_energy >> 10);
2139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (sample_energy > parameters.max_energy) {
2149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    parameters.max_energy = sample_energy;
2159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
2169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Set |energy_update_threshold| to no less than 60 dB lower than
2189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // |max_energy_|. Adding 524288 assures proper rounding.
2199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int32_t energy_update_threshold = (parameters.max_energy + 524288) >> 20;
2209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (energy_update_threshold > parameters.energy_update_threshold) {
2219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    parameters.energy_update_threshold = energy_update_threshold;
2229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
2239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
2249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid BackgroundNoise::SaveParameters(size_t channel,
2269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                     const int16_t* lpc_coefficients,
2279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                     const int16_t* filter_state,
2289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                     int32_t sample_energy,
2299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                     int32_t residual_energy) {
2309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(channel < num_channels_);
2319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  ChannelParameters& parameters = channel_parameters_[channel];
2329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  memcpy(parameters.filter, lpc_coefficients,
2339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org         (kMaxLpcOrder+1) * sizeof(int16_t));
2349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  memcpy(parameters.filter_state, filter_state,
2359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org         kMaxLpcOrder * sizeof(int16_t));
2369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Save energy level and update energy threshold levels.
2379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Never get under 1.0 in average sample energy.
2389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  parameters.energy = std::max(sample_energy, 1);
2399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  parameters.energy_update_threshold = parameters.energy;
2409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  parameters.low_energy_update_threshold = 0;
2419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Normalize residual_energy to 29 or 30 bits before sqrt.
2439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int norm_shift = WebRtcSpl_NormW32(residual_energy) - 1;
2449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (norm_shift & 0x1) {
2459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    norm_shift -= 1;  // Even number of shifts required.
2469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
2479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(norm_shift >= 0);  // Should always be positive.
2489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  residual_energy = residual_energy << norm_shift;
2499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Calculate scale and shift factor.
2519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  parameters.scale = WebRtcSpl_SqrtFloor(residual_energy);
2529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Add 13 to the |scale_shift_|, since the random numbers table is in
2539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Q13.
2549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // TODO(hlundin): Move the "13" to where the |scale_shift_| is used?
2559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  parameters.scale_shift = 13 + ((kLogResidualLength + norm_shift) / 2);
2569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  initialized_ = true;
2589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
2599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
2609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}  // namespace webrtc
261