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