blob: c86045eed90cbdcf62580c34301d80df433b1d59 [file] [log] [blame]
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +00001/*
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
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000011#include "webrtc/modules/audio_coding/neteq/background_noise.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000012
13#include <assert.h>
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000014#include <string.h> // memcpy
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000015
16#include <algorithm> // min, max
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000017
18#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000019#include "webrtc/modules/audio_coding/neteq/audio_multi_vector.h"
minyue53ff70f2016-05-02 01:50:30 -070020#include "webrtc/modules/audio_coding/neteq/cross_correlation.h"
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000021#include "webrtc/modules/audio_coding/neteq/post_decode_vad.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000022
23namespace webrtc {
24
Peter Kastingdce40cf2015-08-24 14:52:23 -070025// static
26const size_t BackgroundNoise::kMaxLpcOrder;
27
pbos@webrtc.org2d1a55c2013-07-31 15:54:00 +000028BackgroundNoise::BackgroundNoise(size_t num_channels)
29 : num_channels_(num_channels),
30 channel_parameters_(new ChannelParameters[num_channels_]),
henrik.lundin@webrtc.orgea257842014-08-07 12:27:37 +000031 mode_(NetEq::kBgnOn) {
pbos@webrtc.org2d1a55c2013-07-31 15:54:00 +000032 Reset();
33}
34
35BackgroundNoise::~BackgroundNoise() {}
36
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000037void 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
henrik.lundin@webrtc.orgfd11bbf2013-09-30 20:38:44 +000045void BackgroundNoise::Update(const AudioMultiVector& input,
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000046 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 memcpy(temp_signal,
63 &input[channel_ix][input.Size() - kVecLen],
64 sizeof(int16_t) * kVecLen);
65
66 int32_t sample_energy = CalculateAutoCorrelation(temp_signal, kVecLen,
67 auto_correlation);
68
69 if ((!vad.running() &&
70 sample_energy < parameters.energy_update_threshold) ||
71 (vad.running() && !vad.active_speech())) {
72 // Generate LPC coefficients.
73 if (auto_correlation[0] > 0) {
74 // Regardless of whether the filter is actually updated or not,
75 // update energy threshold levels, since we have in fact observed
76 // a low energy signal.
77 if (sample_energy < parameters.energy_update_threshold) {
78 // Never go under 1.0 in average sample energy.
79 parameters.energy_update_threshold = std::max(sample_energy, 1);
80 parameters.low_energy_update_threshold = 0;
81 }
82
83 // Only update BGN if filter is stable, i.e., if return value from
84 // Levinson-Durbin function is 1.
85 if (WebRtcSpl_LevinsonDurbin(auto_correlation, lpc_coefficients,
86 reflection_coefficients,
87 kMaxLpcOrder) != 1) {
88 return;
89 }
90 } else {
91 // Center value in auto-correlation is not positive. Do not update.
92 return;
93 }
94
95 // Generate the CNG gain factor by looking at the energy of the residual.
96 WebRtcSpl_FilterMAFastQ12(temp_signal + kVecLen - kResidualLength,
97 fiter_output, lpc_coefficients,
98 kMaxLpcOrder + 1, kResidualLength);
99 int32_t residual_energy = WebRtcSpl_DotProductWithScale(fiter_output,
100 fiter_output,
101 kResidualLength,
102 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 20 * residual_energy >= sample_energy << 6, the spectrum is flat
108 // enough. Also ensure that the energy is non-zero.
109 if ((residual_energy * 20 >= (sample_energy << 6)) &&
110 (sample_energy > 0)) {
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 }
119 } else {
120 // Will only happen if post-decode VAD is disabled and |sample_energy| is
121 // not low enough. Increase the threshold for update so that it increases
122 // by a factor 4 in 4 seconds.
123 IncrementEnergyThreshold(channel_ix, sample_energy);
124 }
125 }
126 return;
127}
128
129int32_t BackgroundNoise::Energy(size_t channel) const {
130 assert(channel < num_channels_);
131 return channel_parameters_[channel].energy;
132}
133
134void BackgroundNoise::SetMuteFactor(size_t channel, int16_t value) {
135 assert(channel < num_channels_);
136 channel_parameters_[channel].mute_factor = value;
137}
138
139int16_t BackgroundNoise::MuteFactor(size_t channel) const {
140 assert(channel < num_channels_);
141 return channel_parameters_[channel].mute_factor;
142}
143
144const int16_t* BackgroundNoise::Filter(size_t channel) const {
145 assert(channel < num_channels_);
146 return channel_parameters_[channel].filter;
147}
148
149const int16_t* BackgroundNoise::FilterState(size_t channel) const {
150 assert(channel < num_channels_);
151 return channel_parameters_[channel].filter_state;
152}
153
154void BackgroundNoise::SetFilterState(size_t channel, const int16_t* input,
155 size_t length) {
156 assert(channel < num_channels_);
Peter Kastingdce40cf2015-08-24 14:52:23 -0700157 length = std::min(length, kMaxLpcOrder);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000158 memcpy(channel_parameters_[channel].filter_state, input,
159 length * sizeof(int16_t));
160}
161
162int16_t BackgroundNoise::Scale(size_t channel) const {
163 assert(channel < num_channels_);
164 return channel_parameters_[channel].scale;
165}
166int16_t BackgroundNoise::ScaleShift(size_t channel) const {
167 assert(channel < num_channels_);
168 return channel_parameters_[channel].scale_shift;
169}
170
171int32_t BackgroundNoise::CalculateAutoCorrelation(
Peter Kastingdce40cf2015-08-24 14:52:23 -0700172 const int16_t* signal, size_t length, int32_t* auto_correlation) const {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000173 static const int kCorrelationStep = -1;
minyue53ff70f2016-05-02 01:50:30 -0700174 const int correlation_scale =
175 CrossCorrelationWithAutoShift(signal, signal, length, kMaxLpcOrder + 1,
176 kCorrelationStep, auto_correlation);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000177
178 // Number of shifts to normalize energy to energy/sample.
179 int energy_sample_shift = kLogVecLen - correlation_scale;
180 return auto_correlation[0] >> energy_sample_shift;
181}
182
183void BackgroundNoise::IncrementEnergyThreshold(size_t channel,
184 int32_t sample_energy) {
185 // TODO(hlundin): Simplify the below threshold update. What this code
186 // does is simply "threshold += (increment * threshold) >> 16", but due
187 // to the limited-width operations, it is not exactly the same. The
188 // difference should be inaudible, but bit-exactness would not be
189 // maintained.
190 assert(channel < num_channels_);
191 ChannelParameters& parameters = channel_parameters_[channel];
192 int32_t temp_energy =
bjornv@webrtc.org600587d2015-03-09 13:30:28 +0000193 (kThresholdIncrement * parameters.low_energy_update_threshold) >> 16;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000194 temp_energy += kThresholdIncrement *
195 (parameters.energy_update_threshold & 0xFF);
196 temp_energy += (kThresholdIncrement *
197 ((parameters.energy_update_threshold>>8) & 0xFF)) << 8;
198 parameters.low_energy_update_threshold += temp_energy;
199
200 parameters.energy_update_threshold += kThresholdIncrement *
201 (parameters.energy_update_threshold>>16);
202 parameters.energy_update_threshold +=
203 parameters.low_energy_update_threshold >> 16;
204 parameters.low_energy_update_threshold =
205 parameters.low_energy_update_threshold & 0x0FFFF;
206
207 // Update maximum energy.
208 // Decrease by a factor 1/1024 each time.
209 parameters.max_energy = parameters.max_energy -
210 (parameters.max_energy >> 10);
211 if (sample_energy > parameters.max_energy) {
212 parameters.max_energy = sample_energy;
213 }
214
215 // Set |energy_update_threshold| to no less than 60 dB lower than
216 // |max_energy_|. Adding 524288 assures proper rounding.
217 int32_t energy_update_threshold = (parameters.max_energy + 524288) >> 20;
218 if (energy_update_threshold > parameters.energy_update_threshold) {
219 parameters.energy_update_threshold = energy_update_threshold;
220 }
221}
222
223void BackgroundNoise::SaveParameters(size_t channel,
224 const int16_t* lpc_coefficients,
225 const int16_t* filter_state,
226 int32_t sample_energy,
227 int32_t residual_energy) {
228 assert(channel < num_channels_);
229 ChannelParameters& parameters = channel_parameters_[channel];
230 memcpy(parameters.filter, lpc_coefficients,
231 (kMaxLpcOrder+1) * sizeof(int16_t));
232 memcpy(parameters.filter_state, filter_state,
233 kMaxLpcOrder * sizeof(int16_t));
234 // Save energy level and update energy threshold levels.
235 // Never get under 1.0 in average sample energy.
236 parameters.energy = std::max(sample_energy, 1);
237 parameters.energy_update_threshold = parameters.energy;
238 parameters.low_energy_update_threshold = 0;
239
240 // Normalize residual_energy to 29 or 30 bits before sqrt.
Peter Kastingb7e50542015-06-11 12:55:50 -0700241 int16_t norm_shift = WebRtcSpl_NormW32(residual_energy) - 1;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000242 if (norm_shift & 0x1) {
243 norm_shift -= 1; // Even number of shifts required.
244 }
Henrik Lundin3c4ef292015-08-31 10:18:28 +0200245 residual_energy = WEBRTC_SPL_SHIFT_W32(residual_energy, norm_shift);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000246
247 // Calculate scale and shift factor.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700248 parameters.scale = static_cast<int16_t>(WebRtcSpl_SqrtFloor(residual_energy));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000249 // Add 13 to the |scale_shift_|, since the random numbers table is in
250 // Q13.
251 // TODO(hlundin): Move the "13" to where the |scale_shift_| is used?
Peter Kastingb7e50542015-06-11 12:55:50 -0700252 parameters.scale_shift =
253 static_cast<int16_t>(13 + ((kLogResidualLength + norm_shift) / 2));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000254
255 initialized_ = true;
256}
257
258} // namespace webrtc