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 "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 "common_audio/signal_processing/include/signal_processing_library.h"
19 #include "modules/audio_coding/neteq/audio_multi_vector.h"
20 #include "modules/audio_coding/neteq/cross_correlation.h"
21 #include "modules/audio_coding/neteq/post_decode_vad.h"
22 
23 namespace webrtc {
24 
25 // static
26 const size_t BackgroundNoise::kMaxLpcOrder;
27 
BackgroundNoise(size_t num_channels)28 BackgroundNoise::BackgroundNoise(size_t num_channels)
29     : num_channels_(num_channels),
30       channel_parameters_(new ChannelParameters[num_channels_]),
31       mode_(NetEq::kBgnOn) {
32   Reset();
33 }
34 
~BackgroundNoise()35 BackgroundNoise::~BackgroundNoise() {}
36 
Reset()37 void BackgroundNoise::Reset() {
38   initialized_ = false;
39   for (size_t channel = 0; channel < num_channels_; ++channel) {
40     channel_parameters_[channel].Reset();
41   }
42   // Keep _bgnMode as it is.
43 }
44 
Update(const AudioMultiVector & input,const PostDecodeVad & vad)45 void BackgroundNoise::Update(const AudioMultiVector& input,
46                              const PostDecodeVad& vad) {
47   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     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   for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) {
59     ChannelParameters& parameters = channel_parameters_[channel_ix];
60     int16_t temp_signal_array[kVecLen + kMaxLpcOrder] = {0};
61     int16_t* temp_signal = &temp_signal_array[kMaxLpcOrder];
62     input[channel_ix].CopyTo(kVecLen, input.Size() - kVecLen, temp_signal);
63     int32_t sample_energy = CalculateAutoCorrelation(temp_signal, kVecLen,
64                                                      auto_correlation);
65 
66     if ((!vad.running() &&
67         sample_energy < parameters.energy_update_threshold) ||
68         (vad.running() && !vad.active_speech())) {
69       // Generate LPC coefficients.
70       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         if (sample_energy < parameters.energy_update_threshold) {
75           // Never go under 1.0 in average sample energy.
76           parameters.energy_update_threshold = std::max(sample_energy, 1);
77           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         if (WebRtcSpl_LevinsonDurbin(auto_correlation, lpc_coefficients,
83                                      reflection_coefficients,
84                                      kMaxLpcOrder) != 1) {
85           return;
86         }
87       } else {
88         // Center value in auto-correlation is not positive. Do not update.
89         return;
90       }
91 
92       // Generate the CNG gain factor by looking at the energy of the residual.
93       WebRtcSpl_FilterMAFastQ12(temp_signal + kVecLen - kResidualLength,
94                                 fiter_output, lpc_coefficients,
95                                 kMaxLpcOrder + 1, kResidualLength);
96       int32_t residual_energy = WebRtcSpl_DotProductWithScale(fiter_output,
97                                                               fiter_output,
98                                                               kResidualLength,
99                                                               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 5 * residual_energy >= 16 * sample_energy, the spectrum is flat
105       // enough.  Also ensure that the energy is non-zero.
106       if ((sample_energy > 0) &&
107           (int64_t{5} * residual_energy >= int64_t{16} * sample_energy)) {
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                        temp_signal + kVecLen - kMaxLpcOrder, sample_energy,
114                        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       IncrementEnergyThreshold(channel_ix, sample_energy);
121     }
122   }
123   return;
124 }
125 
Energy(size_t channel) const126 int32_t BackgroundNoise::Energy(size_t channel) const {
127   assert(channel < num_channels_);
128   return channel_parameters_[channel].energy;
129 }
130 
SetMuteFactor(size_t channel,int16_t value)131 void BackgroundNoise::SetMuteFactor(size_t channel, int16_t value) {
132   assert(channel < num_channels_);
133   channel_parameters_[channel].mute_factor = value;
134 }
135 
MuteFactor(size_t channel) const136 int16_t BackgroundNoise::MuteFactor(size_t channel) const {
137   assert(channel < num_channels_);
138   return channel_parameters_[channel].mute_factor;
139 }
140 
Filter(size_t channel) const141 const int16_t* BackgroundNoise::Filter(size_t channel) const {
142   assert(channel < num_channels_);
143   return channel_parameters_[channel].filter;
144 }
145 
FilterState(size_t channel) const146 const int16_t* BackgroundNoise::FilterState(size_t channel) const {
147   assert(channel < num_channels_);
148   return channel_parameters_[channel].filter_state;
149 }
150 
SetFilterState(size_t channel,const int16_t * input,size_t length)151 void BackgroundNoise::SetFilterState(size_t channel, const int16_t* input,
152                                      size_t length) {
153   assert(channel < num_channels_);
154   length = std::min(length, kMaxLpcOrder);
155   memcpy(channel_parameters_[channel].filter_state, input,
156          length * sizeof(int16_t));
157 }
158 
Scale(size_t channel) const159 int16_t BackgroundNoise::Scale(size_t channel) const {
160   assert(channel < num_channels_);
161   return channel_parameters_[channel].scale;
162 }
ScaleShift(size_t channel) const163 int16_t BackgroundNoise::ScaleShift(size_t channel) const {
164   assert(channel < num_channels_);
165   return channel_parameters_[channel].scale_shift;
166 }
167 
CalculateAutoCorrelation(const int16_t * signal,size_t length,int32_t * auto_correlation) const168 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                                     kCorrelationStep, auto_correlation);
174 
175   // Number of shifts to normalize energy to energy/sample.
176   int energy_sample_shift = kLogVecLen - correlation_scale;
177   return auto_correlation[0] >> energy_sample_shift;
178 }
179 
IncrementEnergyThreshold(size_t channel,int32_t sample_energy)180 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   assert(channel < num_channels_);
188   ChannelParameters& parameters = channel_parameters_[channel];
189   int32_t temp_energy =
190     (kThresholdIncrement * parameters.low_energy_update_threshold) >> 16;
191   temp_energy += kThresholdIncrement *
192       (parameters.energy_update_threshold & 0xFF);
193   temp_energy += (kThresholdIncrement *
194       ((parameters.energy_update_threshold>>8) & 0xFF)) << 8;
195   parameters.low_energy_update_threshold += temp_energy;
196 
197   parameters.energy_update_threshold += kThresholdIncrement *
198       (parameters.energy_update_threshold>>16);
199   parameters.energy_update_threshold +=
200       parameters.low_energy_update_threshold >> 16;
201   parameters.low_energy_update_threshold =
202       parameters.low_energy_update_threshold & 0x0FFFF;
203 
204   // Update maximum energy.
205   // Decrease by a factor 1/1024 each time.
206   parameters.max_energy = parameters.max_energy -
207       (parameters.max_energy >> 10);
208   if (sample_energy > parameters.max_energy) {
209     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   int32_t energy_update_threshold = (parameters.max_energy + 524288) >> 20;
215   if (energy_update_threshold > parameters.energy_update_threshold) {
216     parameters.energy_update_threshold = energy_update_threshold;
217   }
218 }
219 
SaveParameters(size_t channel,const int16_t * lpc_coefficients,const int16_t * filter_state,int32_t sample_energy,int32_t residual_energy)220 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   assert(channel < num_channels_);
226   ChannelParameters& parameters = channel_parameters_[channel];
227   memcpy(parameters.filter, lpc_coefficients,
228          (kMaxLpcOrder+1) * sizeof(int16_t));
229   memcpy(parameters.filter_state, filter_state,
230          kMaxLpcOrder * sizeof(int16_t));
231   // Save energy level and update energy threshold levels.
232   // Never get under 1.0 in average sample energy.
233   parameters.energy = std::max(sample_energy, 1);
234   parameters.energy_update_threshold = parameters.energy;
235   parameters.low_energy_update_threshold = 0;
236 
237   // Normalize residual_energy to 29 or 30 bits before sqrt.
238   int16_t norm_shift = WebRtcSpl_NormW32(residual_energy) - 1;
239   if (norm_shift & 0x1) {
240     norm_shift -= 1;  // Even number of shifts required.
241   }
242   residual_energy = WEBRTC_SPL_SHIFT_W32(residual_energy, norm_shift);
243 
244   // Calculate scale and shift factor.
245   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   parameters.scale_shift =
250       static_cast<int16_t>(13 + ((kLogResidualLength + norm_shift) / 2));
251 
252   initialized_ = true;
253 }
254 
255 }  // namespace webrtc
256