Wraparound distortion in Opus

This CL solves the wraparound distortion in Opus.

In the Opus decoder-wrapper we are downsampling the signal from 48 kHz to 32 kHz. This is done in two steps, using the following functions from the signal processing library:
WebRtcSpl_Resample48khzTo32khz() and WebRtcSpl_VectorBitShiftW32ToW16

The latter does not have a saturation check, and the signal can suffer from wraparound. I've added saturation control to the function.

BUG=issue1089

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3103 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
tina.legrand@webrtc.org 2012-11-15 08:34:38 +00:00
parent 23ec30bdfc
commit 53a8be20f1
3 changed files with 65 additions and 25 deletions

View File

@ -377,11 +377,10 @@ void WebRtcSpl_VectorBitShiftW32(WebRtc_Word32* out_vector,
WebRtc_Word16 vector_length,
G_CONST WebRtc_Word32* in_vector,
WebRtc_Word16 right_shifts);
void WebRtcSpl_VectorBitShiftW32ToW16(WebRtc_Word16* out_vector,
WebRtc_Word16 vector_length,
G_CONST WebRtc_Word32* in_vector,
WebRtc_Word16 right_shifts);
void WebRtcSpl_VectorBitShiftW32ToW16(int16_t* out_vector,
int vector_length,
const int32_t* in_vector,
int right_shifts);
void WebRtcSpl_ScaleVector(G_CONST WebRtc_Word16* in_vector,
WebRtc_Word16* out_vector,
WebRtc_Word16 gain,
@ -1180,7 +1179,8 @@ void WebRtcSpl_SynthesisQMF(const WebRtc_Word16* low_band,
// WebRtcSpl_VectorBitShiftW32ToW16(...)
//
// Bit shifts all the values in a WebRtc_Word32 vector up or downwards and
// stores the result as a WebRtc_Word16 vector
// stores the result as an int16_t vector. The function will saturate the
// signal if needed, before storing in the output vector.
//
// Input:
// - vector_length : Length of vector

View File

@ -615,3 +615,47 @@ TEST_F(SplTest, FFTTest) {
//EXPECT_EQ(A[kk], B[kk]);
}
}
TEST_F(SplTest, Resample48WithSaturationTest) {
// The test resamples 3*kBlockSize number of samples to 2*kBlockSize number
// of samples.
const int kBlockSize = 16;
// Saturated input vector of 48 samples.
const int32_t kVectorSaturated[3 * kBlockSize + 7] = {
-32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768,
-32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768,
-32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768,
32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767,
32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767,
32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767,
32767, 32767, 32767, 32767, 32767, 32767, 32767
};
// All values in |out_vector| should be |kRefValue32kHz|.
const int32_t kRefValue32kHz1 = -1077493760;
const int32_t kRefValue32kHz2 = 1077493645;
// After bit shift with saturation, |out_vector_w16| is saturated.
const int16_t kRefValue16kHz1 = -32768;
const int16_t kRefValue16kHz2 = 32767;
// Vector for storing output.
int32_t out_vector[2 * kBlockSize];
int16_t out_vector_w16[2 * kBlockSize];
WebRtcSpl_Resample48khzTo32khz(kVectorSaturated, out_vector, kBlockSize);
WebRtcSpl_VectorBitShiftW32ToW16(out_vector_w16, 2 * kBlockSize, out_vector,
15);
// Comparing output values against references. The values at position
// 12-15 are skipped to account for the filter lag.
for (int i = 0; i < 12; ++i) {
EXPECT_EQ(kRefValue32kHz1, out_vector[i]);
EXPECT_EQ(kRefValue16kHz1, out_vector_w16[i]);
}
for (int i = 16; i < 2 * kBlockSize; ++i) {
EXPECT_EQ(kRefValue32kHz2, out_vector[i]);
EXPECT_EQ(kRefValue16kHz2, out_vector_w16[i]);
}
}

View File

@ -66,27 +66,23 @@ void WebRtcSpl_VectorBitShiftW32(WebRtc_Word32 *out_vector,
}
}
void WebRtcSpl_VectorBitShiftW32ToW16(WebRtc_Word16 *res,
WebRtc_Word16 length,
G_CONST WebRtc_Word32 *in,
WebRtc_Word16 right_shifts)
{
int i;
void WebRtcSpl_VectorBitShiftW32ToW16(int16_t* out, int length,
const int32_t* in, int right_shifts) {
int i;
int32_t tmp_w32;
if (right_shifts >= 0)
{
for (i = length; i > 0; i--)
{
(*res++) = (WebRtc_Word16)((*in++) >> right_shifts);
}
} else
{
WebRtc_Word16 left_shifts = -right_shifts;
for (i = length; i > 0; i--)
{
(*res++) = (WebRtc_Word16)((*in++) << left_shifts);
}
if (right_shifts >= 0) {
for (i = length; i > 0; i--) {
tmp_w32 = (*in++) >> right_shifts;
(*out++) = WebRtcSpl_SatW32ToW16(tmp_w32);
}
} else {
int16_t left_shifts = -right_shifts;
for (i = length; i > 0; i--) {
tmp_w32 = (*in++) << left_shifts;
(*out++) = WebRtcSpl_SatW32ToW16(tmp_w32);
}
}
}
void WebRtcSpl_ScaleVector(G_CONST WebRtc_Word16 *in_vector, WebRtc_Word16 *out_vector,