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:
parent
23ec30bdfc
commit
53a8be20f1
@ -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
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user