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