From 53a8be20f13eeb84fc2df17abcebf4fcd3b2930d Mon Sep 17 00:00:00 2001 From: "tina.legrand@webrtc.org" Date: Thu, 15 Nov 2012 08:34:38 +0000 Subject: [PATCH] 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 --- .../include/signal_processing_library.h | 12 ++--- .../signal_processing_unittest.cc | 44 +++++++++++++++++++ .../vector_scaling_operations.c | 34 +++++++------- 3 files changed, 65 insertions(+), 25 deletions(-) diff --git a/webrtc/common_audio/signal_processing/include/signal_processing_library.h b/webrtc/common_audio/signal_processing/include/signal_processing_library.h index 1738e8e9e..50a89c37a 100644 --- a/webrtc/common_audio/signal_processing/include/signal_processing_library.h +++ b/webrtc/common_audio/signal_processing/include/signal_processing_library.h @@ -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 diff --git a/webrtc/common_audio/signal_processing/signal_processing_unittest.cc b/webrtc/common_audio/signal_processing/signal_processing_unittest.cc index d5026fb88..cf7cb27fc 100644 --- a/webrtc/common_audio/signal_processing/signal_processing_unittest.cc +++ b/webrtc/common_audio/signal_processing/signal_processing_unittest.cc @@ -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]); + } +} diff --git a/webrtc/common_audio/signal_processing/vector_scaling_operations.c b/webrtc/common_audio/signal_processing/vector_scaling_operations.c index 242955cc0..c4b1df9cb 100644 --- a/webrtc/common_audio/signal_processing/vector_scaling_operations.c +++ b/webrtc/common_audio/signal_processing/vector_scaling_operations.c @@ -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,