• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
22 namespace webrtc {
23 
BackgroundNoise(size_t num_channels)24 BackgroundNoise::BackgroundNoise(size_t num_channels)
25     : num_channels_(num_channels),
26       channel_parameters_(new ChannelParameters[num_channels_]),
27       mode_(kBgnOn) {
28   Reset();
29 }
30 
~BackgroundNoise()31 BackgroundNoise::~BackgroundNoise() {}
32 
Reset()33 void 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 
Update(const AudioMultiVector & input,const PostDecodeVad & vad)41 void 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 
Energy(size_t channel) const125 int32_t BackgroundNoise::Energy(size_t channel) const {
126   assert(channel < num_channels_);
127   return channel_parameters_[channel].energy;
128 }
129 
SetMuteFactor(size_t channel,int16_t value)130 void BackgroundNoise::SetMuteFactor(size_t channel, int16_t value) {
131   assert(channel < num_channels_);
132   channel_parameters_[channel].mute_factor = value;
133 }
134 
MuteFactor(size_t channel) const135 int16_t BackgroundNoise::MuteFactor(size_t channel) const {
136   assert(channel < num_channels_);
137   return channel_parameters_[channel].mute_factor;
138 }
139 
Filter(size_t channel) const140 const int16_t* BackgroundNoise::Filter(size_t channel) const {
141   assert(channel < num_channels_);
142   return channel_parameters_[channel].filter;
143 }
144 
FilterState(size_t channel) const145 const int16_t* BackgroundNoise::FilterState(size_t channel) const {
146   assert(channel < num_channels_);
147   return channel_parameters_[channel].filter_state;
148 }
149 
SetFilterState(size_t channel,const int16_t * input,size_t length)150 void 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 
Scale(size_t channel) const158 int16_t BackgroundNoise::Scale(size_t channel) const {
159   assert(channel < num_channels_);
160   return channel_parameters_[channel].scale;
161 }
ScaleShift(size_t channel) const162 int16_t BackgroundNoise::ScaleShift(size_t channel) const {
163   assert(channel < num_channels_);
164   return channel_parameters_[channel].scale_shift;
165 }
166 
CalculateAutoCorrelation(const int16_t * signal,int length,int32_t * auto_correlation) const167 int32_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 
IncrementEnergyThreshold(size_t channel,int32_t sample_energy)184 void 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 
SaveParameters(size_t channel,const int16_t * lpc_coefficients,const int16_t * filter_state,int32_t sample_energy,int32_t residual_energy)225 void 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