Files
platform-external-webrtc/webrtc/modules/audio_coding/neteq4/normal.cc
henrik.lundin@webrtc.org d94659dc27 Initial upload of NetEq4
This is the first public upload of the new NetEq, version 4.

It has been through extensive internal review during the course of
the project.

TEST=trybots

Review URL: https://webrtc-codereview.appspot.com/1073005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3425 4adac7df-926f-26a2-2b94-8c16560cd09d
2013-01-29 12:09:21 +00:00

190 lines
8.0 KiB
C++

/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/neteq4/normal.h"
#include <algorithm> // min
#include <cstring> // memset, memcpy
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
#include "webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h"
#include "webrtc/modules/audio_coding/neteq4/audio_multi_vector.h"
#include "webrtc/modules/audio_coding/neteq4/background_noise.h"
#include "webrtc/modules/audio_coding/neteq4/decoder_database.h"
#include "webrtc/modules/audio_coding/neteq4/expand.h"
#include "webrtc/modules/audio_coding/neteq4/interface/audio_decoder.h"
namespace webrtc {
int Normal::Process(const int16_t* input,
size_t length,
Modes last_mode,
int16_t* external_mute_factor_array,
AudioMultiVector<int16_t>* output) {
if (length == 0) {
// Nothing to process.
output->Clear();
return length;
}
assert(output->Empty());
// Output should be empty at this point.
output->PushBackInterleaved(input, length);
int16_t* signal = &(*output)[0][0];
const unsigned fs_mult = fs_hz_ / 8000;
assert(fs_mult > 0);
// fs_shift = log2(fs_mult), rounded down.
// Note that |fs_shift| is not "exact" for 48 kHz.
// TODO(hlundin): Investigate this further.
const int fs_shift = 30 - WebRtcSpl_NormW32(fs_mult);
// Check if last RecOut call resulted in an Expand. If so, we have to take
// care of some cross-fading and unmuting.
if (last_mode == kModeExpand) {
// Generate interpolation data using Expand.
// First, set Expand parameters to appropriate values.
expand_->SetParametersForNormalAfterExpand();
// Call Expand.
AudioMultiVector<int16_t> expanded(output->Channels());
expand_->Process(&expanded);
expand_->Reset();
for (size_t channel_ix = 0; channel_ix < output->Channels(); ++channel_ix) {
// Adjust muting factor (main muting factor times expand muting factor).
external_mute_factor_array[channel_ix] = static_cast<int16_t>(
WEBRTC_SPL_MUL_16_16_RSFT(external_mute_factor_array[channel_ix],
expand_->MuteFactor(channel_ix), 14));
int16_t* signal = &(*output)[channel_ix][0];
size_t length_per_channel = length / output->Channels();
// Find largest absolute value in new data.
int16_t decoded_max = WebRtcSpl_MaxAbsValueW16(signal,
length_per_channel);
// Adjust muting factor if needed (to BGN level).
int energy_length = std::min(static_cast<size_t>(fs_mult * 64),
length_per_channel);
int scaling = 6 + fs_shift
- WebRtcSpl_NormW32(decoded_max * decoded_max);
scaling = std::max(scaling, 0); // |scaling| should always be >= 0.
int32_t energy = WebRtcSpl_DotProductWithScale(signal, signal,
energy_length, scaling);
energy = energy / (energy_length >> scaling);
int mute_factor;
if ((energy != 0) &&
(energy > background_noise_.Energy(channel_ix))) {
// Normalize new frame energy to 15 bits.
scaling = WebRtcSpl_NormW32(energy) - 16;
// We want background_noise_.energy() / energy in Q14.
int32_t bgn_energy =
background_noise_.Energy(channel_ix) << (scaling+14);
int16_t energy_scaled = energy << scaling;
int16_t ratio = WebRtcSpl_DivW32W16(bgn_energy, energy_scaled);
mute_factor = WebRtcSpl_SqrtFloor(static_cast<int32_t>(ratio) << 14);
} else {
mute_factor = 16384; // 1.0 in Q14.
}
if (mute_factor > external_mute_factor_array[channel_ix]) {
external_mute_factor_array[channel_ix] = std::min(mute_factor, 16384);
}
// If muted increase by 0.64 for every 20 ms (NB/WB 0.0040/0.0020 in Q14).
int16_t increment = 64 / fs_mult;
for (size_t i = 0; i < length_per_channel; i++) {
// Scale with mute factor.
assert(channel_ix < output->Channels());
assert(i < output->Size());
int32_t scaled_signal = (*output)[channel_ix][i] *
external_mute_factor_array[channel_ix];
// Shift 14 with proper rounding.
(*output)[channel_ix][i] = (scaled_signal + 8192) >> 14;
// Increase mute_factor towards 16384.
external_mute_factor_array[channel_ix] =
std::min(external_mute_factor_array[channel_ix] + increment, 16384);
}
// Interpolate the expanded data into the new vector.
// (NB/WB/SWB32/SWB48 8/16/32/48 samples.)
assert(fs_shift < 3); // Will always be 0, 1, or, 2.
increment = 4 >> fs_shift;
int fraction = increment;
for (size_t i = 0; i < 8 * fs_mult; i++) {
// TODO(hlundin): Add 16 instead of 8 for correct rounding. Keeping 8
// now for legacy bit-exactness.
assert(channel_ix < output->Channels());
assert(i < output->Size());
(*output)[channel_ix][i] =
(fraction * (*output)[channel_ix][i] +
(32 - fraction) * expanded[channel_ix][i] + 8) >> 5;
fraction += increment;
}
}
} else if (last_mode == kModeRfc3389Cng) {
assert(output->Channels() == 1); // Not adapted for multi-channel yet.
static const int kCngLength = 32;
int16_t cng_output[kCngLength];
// Reset mute factor and start up fresh.
external_mute_factor_array[0] = 16384;
AudioDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder();
if (cng_decoder) {
CNG_dec_inst* cng_inst = static_cast<CNG_dec_inst*>(cng_decoder->state());
// Generate long enough for 32kHz.
if (WebRtcCng_Generate(cng_inst, cng_output, kCngLength, 0) < 0) {
// Error returned; set return vector to all zeros.
memset(cng_output, 0, sizeof(cng_output));
}
} else {
// If no CNG instance is defined, just copy from the decoded data.
// (This will result in interpolating the decoded with itself.)
memcpy(cng_output, signal, fs_mult * 8 * sizeof(int16_t));
}
// Interpolate the CNG into the new vector.
// (NB/WB/SWB32/SWB48 8/16/32/48 samples.)
assert(fs_shift < 3); // Will always be 0, 1, or, 2.
int16_t increment = 4 >> fs_shift;
int16_t fraction = increment;
for (size_t i = 0; i < 8 * fs_mult; i++) {
// TODO(hlundin): Add 16 instead of 8 for correct rounding. Keeping 8 now
// for legacy bit-exactness.
signal[i] =
(fraction * signal[i] + (32 - fraction) * cng_output[i] + 8) >> 5;
fraction += increment;
}
} else if (external_mute_factor_array[0] < 16384) {
// Previous was neither of Expand, FadeToBGN or RFC3389_CNG, but we are
// still ramping up from previous muting.
// If muted increase by 0.64 for every 20 ms (NB/WB 0.0040/0.0020 in Q14).
int16_t increment = 64 / fs_mult;
size_t length_per_channel = length / output->Channels();
for (size_t i = 0; i < length_per_channel; i++) {
for (size_t channel_ix = 0; channel_ix < output->Channels();
++channel_ix) {
// Scale with mute factor.
assert(channel_ix < output->Channels());
assert(i < output->Size());
int32_t scaled_signal = (*output)[channel_ix][i] *
external_mute_factor_array[channel_ix];
// Shift 14 with proper rounding.
(*output)[channel_ix][i] = (scaled_signal + 8192) >> 14;
// Increase mute_factor towards 16384.
external_mute_factor_array[channel_ix] =
std::min(16384, external_mute_factor_array[channel_ix] + increment);
}
}
}
return length;
}
} // namespace webrtc