Rename neteq4 folder to neteq
Keep the old neteq4/audio_decoder_unittests.isolate while waiting for
a hard-coded reference to change.
This CL effectively reverts r6257 "Rename neteq4 folder to neteq".
BUG=2996
TBR=tina.legrand@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/21629004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@6367 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_coding/neteq/background_noise.cc b/webrtc/modules/audio_coding/neteq/background_noise.cc
new file mode 100644
index 0000000..e00c4f6
--- /dev/null
+++ b/webrtc/modules/audio_coding/neteq/background_noise.cc
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/audio_coding/neteq/background_noise.h"
+
+#include <assert.h>
+#include <string.h> // memcpy
+
+#include <algorithm> // min, max
+
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/modules/audio_coding/neteq/audio_multi_vector.h"
+#include "webrtc/modules/audio_coding/neteq/post_decode_vad.h"
+
+namespace webrtc {
+
+BackgroundNoise::BackgroundNoise(size_t num_channels)
+ : num_channels_(num_channels),
+ channel_parameters_(new ChannelParameters[num_channels_]),
+ mode_(kBgnOn) {
+ Reset();
+}
+
+BackgroundNoise::~BackgroundNoise() {}
+
+void BackgroundNoise::Reset() {
+ initialized_ = false;
+ for (size_t channel = 0; channel < num_channels_; ++channel) {
+ channel_parameters_[channel].Reset();
+ }
+ // Keep _bgnMode as it is.
+}
+
+void BackgroundNoise::Update(const AudioMultiVector& input,
+ const PostDecodeVad& vad) {
+ if (vad.running() && vad.active_speech()) {
+ // Do not update the background noise parameters if we know that the signal
+ // is active speech.
+ return;
+ }
+
+ int32_t auto_correlation[kMaxLpcOrder + 1];
+ int16_t fiter_output[kMaxLpcOrder + kResidualLength];
+ int16_t reflection_coefficients[kMaxLpcOrder];
+ int16_t lpc_coefficients[kMaxLpcOrder + 1];
+
+ for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) {
+ ChannelParameters& parameters = channel_parameters_[channel_ix];
+ int16_t temp_signal_array[kVecLen + kMaxLpcOrder] = {0};
+ int16_t* temp_signal = &temp_signal_array[kMaxLpcOrder];
+ memcpy(temp_signal,
+ &input[channel_ix][input.Size() - kVecLen],
+ sizeof(int16_t) * kVecLen);
+
+ int32_t sample_energy = CalculateAutoCorrelation(temp_signal, kVecLen,
+ auto_correlation);
+
+ if ((!vad.running() &&
+ sample_energy < parameters.energy_update_threshold) ||
+ (vad.running() && !vad.active_speech())) {
+ // Generate LPC coefficients.
+ if (auto_correlation[0] > 0) {
+ // Regardless of whether the filter is actually updated or not,
+ // update energy threshold levels, since we have in fact observed
+ // a low energy signal.
+ if (sample_energy < parameters.energy_update_threshold) {
+ // Never go under 1.0 in average sample energy.
+ parameters.energy_update_threshold = std::max(sample_energy, 1);
+ parameters.low_energy_update_threshold = 0;
+ }
+
+ // Only update BGN if filter is stable, i.e., if return value from
+ // Levinson-Durbin function is 1.
+ if (WebRtcSpl_LevinsonDurbin(auto_correlation, lpc_coefficients,
+ reflection_coefficients,
+ kMaxLpcOrder) != 1) {
+ return;
+ }
+ } else {
+ // Center value in auto-correlation is not positive. Do not update.
+ return;
+ }
+
+ // Generate the CNG gain factor by looking at the energy of the residual.
+ WebRtcSpl_FilterMAFastQ12(temp_signal + kVecLen - kResidualLength,
+ fiter_output, lpc_coefficients,
+ kMaxLpcOrder + 1, kResidualLength);
+ int32_t residual_energy = WebRtcSpl_DotProductWithScale(fiter_output,
+ fiter_output,
+ kResidualLength,
+ 0);
+
+ // Check spectral flatness.
+ // Comparing the residual variance with the input signal variance tells
+ // if the spectrum is flat or not.
+ // If 20 * residual_energy >= sample_energy << 6, the spectrum is flat
+ // enough. Also ensure that the energy is non-zero.
+ if ((residual_energy * 20 >= (sample_energy << 6)) &&
+ (sample_energy > 0)) {
+ // Spectrum is flat enough; save filter parameters.
+ // |temp_signal| + |kVecLen| - |kMaxLpcOrder| points at the first of the
+ // |kMaxLpcOrder| samples in the residual signal, which will form the
+ // filter state for the next noise generation.
+ SaveParameters(channel_ix, lpc_coefficients,
+ temp_signal + kVecLen - kMaxLpcOrder, sample_energy,
+ residual_energy);
+ }
+ } else {
+ // Will only happen if post-decode VAD is disabled and |sample_energy| is
+ // not low enough. Increase the threshold for update so that it increases
+ // by a factor 4 in 4 seconds.
+ IncrementEnergyThreshold(channel_ix, sample_energy);
+ }
+ }
+ return;
+}
+
+int32_t BackgroundNoise::Energy(size_t channel) const {
+ assert(channel < num_channels_);
+ return channel_parameters_[channel].energy;
+}
+
+void BackgroundNoise::SetMuteFactor(size_t channel, int16_t value) {
+ assert(channel < num_channels_);
+ channel_parameters_[channel].mute_factor = value;
+}
+
+int16_t BackgroundNoise::MuteFactor(size_t channel) const {
+ assert(channel < num_channels_);
+ return channel_parameters_[channel].mute_factor;
+}
+
+const int16_t* BackgroundNoise::Filter(size_t channel) const {
+ assert(channel < num_channels_);
+ return channel_parameters_[channel].filter;
+}
+
+const int16_t* BackgroundNoise::FilterState(size_t channel) const {
+ assert(channel < num_channels_);
+ return channel_parameters_[channel].filter_state;
+}
+
+void BackgroundNoise::SetFilterState(size_t channel, const int16_t* input,
+ size_t length) {
+ assert(channel < num_channels_);
+ length = std::min(length, static_cast<size_t>(kMaxLpcOrder));
+ memcpy(channel_parameters_[channel].filter_state, input,
+ length * sizeof(int16_t));
+}
+
+int16_t BackgroundNoise::Scale(size_t channel) const {
+ assert(channel < num_channels_);
+ return channel_parameters_[channel].scale;
+}
+int16_t BackgroundNoise::ScaleShift(size_t channel) const {
+ assert(channel < num_channels_);
+ return channel_parameters_[channel].scale_shift;
+}
+
+int32_t BackgroundNoise::CalculateAutoCorrelation(
+ const int16_t* signal, int length, int32_t* auto_correlation) const {
+ int16_t signal_max = WebRtcSpl_MaxAbsValueW16(signal, length);
+ int correlation_scale = kLogVecLen -
+ WebRtcSpl_NormW32(signal_max * signal_max);
+ correlation_scale = std::max(0, correlation_scale);
+
+ static const int kCorrelationStep = -1;
+ WebRtcSpl_CrossCorrelation(auto_correlation, signal, signal, length,
+ kMaxLpcOrder + 1, correlation_scale,
+ kCorrelationStep);
+
+ // Number of shifts to normalize energy to energy/sample.
+ int energy_sample_shift = kLogVecLen - correlation_scale;
+ return auto_correlation[0] >> energy_sample_shift;
+}
+
+void BackgroundNoise::IncrementEnergyThreshold(size_t channel,
+ int32_t sample_energy) {
+ // TODO(hlundin): Simplify the below threshold update. What this code
+ // does is simply "threshold += (increment * threshold) >> 16", but due
+ // to the limited-width operations, it is not exactly the same. The
+ // difference should be inaudible, but bit-exactness would not be
+ // maintained.
+ assert(channel < num_channels_);
+ ChannelParameters& parameters = channel_parameters_[channel];
+ int32_t temp_energy =
+ WEBRTC_SPL_MUL_16_16_RSFT(kThresholdIncrement,
+ parameters.low_energy_update_threshold, 16);
+ temp_energy += kThresholdIncrement *
+ (parameters.energy_update_threshold & 0xFF);
+ temp_energy += (kThresholdIncrement *
+ ((parameters.energy_update_threshold>>8) & 0xFF)) << 8;
+ parameters.low_energy_update_threshold += temp_energy;
+
+ parameters.energy_update_threshold += kThresholdIncrement *
+ (parameters.energy_update_threshold>>16);
+ parameters.energy_update_threshold +=
+ parameters.low_energy_update_threshold >> 16;
+ parameters.low_energy_update_threshold =
+ parameters.low_energy_update_threshold & 0x0FFFF;
+
+ // Update maximum energy.
+ // Decrease by a factor 1/1024 each time.
+ parameters.max_energy = parameters.max_energy -
+ (parameters.max_energy >> 10);
+ if (sample_energy > parameters.max_energy) {
+ parameters.max_energy = sample_energy;
+ }
+
+ // Set |energy_update_threshold| to no less than 60 dB lower than
+ // |max_energy_|. Adding 524288 assures proper rounding.
+ int32_t energy_update_threshold = (parameters.max_energy + 524288) >> 20;
+ if (energy_update_threshold > parameters.energy_update_threshold) {
+ parameters.energy_update_threshold = energy_update_threshold;
+ }
+}
+
+void BackgroundNoise::SaveParameters(size_t channel,
+ const int16_t* lpc_coefficients,
+ const int16_t* filter_state,
+ int32_t sample_energy,
+ int32_t residual_energy) {
+ assert(channel < num_channels_);
+ ChannelParameters& parameters = channel_parameters_[channel];
+ memcpy(parameters.filter, lpc_coefficients,
+ (kMaxLpcOrder+1) * sizeof(int16_t));
+ memcpy(parameters.filter_state, filter_state,
+ kMaxLpcOrder * sizeof(int16_t));
+ // Save energy level and update energy threshold levels.
+ // Never get under 1.0 in average sample energy.
+ parameters.energy = std::max(sample_energy, 1);
+ parameters.energy_update_threshold = parameters.energy;
+ parameters.low_energy_update_threshold = 0;
+
+ // Normalize residual_energy to 29 or 30 bits before sqrt.
+ int norm_shift = WebRtcSpl_NormW32(residual_energy) - 1;
+ if (norm_shift & 0x1) {
+ norm_shift -= 1; // Even number of shifts required.
+ }
+ assert(norm_shift >= 0); // Should always be positive.
+ residual_energy = residual_energy << norm_shift;
+
+ // Calculate scale and shift factor.
+ parameters.scale = WebRtcSpl_SqrtFloor(residual_energy);
+ // Add 13 to the |scale_shift_|, since the random numbers table is in
+ // Q13.
+ // TODO(hlundin): Move the "13" to where the |scale_shift_| is used?
+ parameters.scale_shift = 13 + ((kLogResidualLength + norm_shift) / 2);
+
+ initialized_ = true;
+}
+
+} // namespace webrtc