blob: e239db75c0a3cf0aec6d392b0f4c80e8259fcc2e [file] [log] [blame]
/*
* Copyright (c) 2011 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.
*/
/*
* This file contains the resampling by two functions.
* The description header can be found in signal_processing_library.h
*
*/
#include "signal_processing_library.h"
#ifdef WEBRTC_ARCH_ARM_V7A
// allpass filter coefficients.
static const WebRtc_UWord32 kResampleAllpass1[3] = {3284, 24441, 49528 << 15};
static const WebRtc_UWord32 kResampleAllpass2[3] =
{12199, 37471 << 15, 60255 << 15};
// Multiply two 32-bit values and accumulate to another input value.
// Return: state + ((diff * tbl_value) >> 16)
static __inline WebRtc_Word32 MUL_ACCUM_1(WebRtc_Word32 tbl_value,
WebRtc_Word32 diff,
WebRtc_Word32 state) {
WebRtc_Word32 result;
__asm__("smlawb %r0, %r1, %r2, %r3": "=r"(result): "r"(diff),
"r"(tbl_value), "r"(state));
return result;
}
// Multiply two 32-bit values and accumulate to another input value.
// Return: Return: state + (((diff << 1) * tbl_value) >> 32)
//
// The reason to introduce this function is that, in case we can't use smlawb
// instruction (in MUL_ACCUM_1) due to input value range, we can still use
// smmla to save some cycles.
static __inline WebRtc_Word32 MUL_ACCUM_2(WebRtc_Word32 tbl_value,
WebRtc_Word32 diff,
WebRtc_Word32 state) {
WebRtc_Word32 result;
__asm__("smmla %r0, %r1, %r2, %r3": "=r"(result): "r"(diff << 1),
"r"(tbl_value), "r"(state));
return result;
}
#else
// allpass filter coefficients.
static const WebRtc_UWord16 kResampleAllpass1[3] = {3284, 24441, 49528};
static const WebRtc_UWord16 kResampleAllpass2[3] = {12199, 37471, 60255};
// Multiply a 32-bit value with a 16-bit value and accumulate to another input:
#define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c)
#define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c)
#endif // WEBRTC_ARCH_ARM_V7A
// decimator
void WebRtcSpl_DownsampleBy2(const WebRtc_Word16* in, const WebRtc_Word16 len,
WebRtc_Word16* out, WebRtc_Word32* filtState) {
WebRtc_Word32 tmp1, tmp2, diff, in32, out32;
WebRtc_Word16 i;
register WebRtc_Word32 state0 = filtState[0];
register WebRtc_Word32 state1 = filtState[1];
register WebRtc_Word32 state2 = filtState[2];
register WebRtc_Word32 state3 = filtState[3];
register WebRtc_Word32 state4 = filtState[4];
register WebRtc_Word32 state5 = filtState[5];
register WebRtc_Word32 state6 = filtState[6];
register WebRtc_Word32 state7 = filtState[7];
for (i = (len >> 1); i > 0; i--) {
// lower allpass filter
in32 = (WebRtc_Word32)(*in++) << 10;
diff = in32 - state1;
tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0);
state0 = in32;
diff = tmp1 - state2;
tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1);
state1 = tmp1;
diff = tmp2 - state3;
state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2);
state2 = tmp2;
// upper allpass filter
in32 = (WebRtc_Word32)(*in++) << 10;
diff = in32 - state5;
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4);
state4 = in32;
diff = tmp1 - state6;
tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5);
state5 = tmp1;
diff = tmp2 - state7;
state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6);
state6 = tmp2;
// add two allpass outputs, divide by two and round
out32 = (state3 + state7 + 1024) >> 11;
// limit amplitude to prevent wrap-around, and write to output array
*out++ = WebRtcSpl_SatW32ToW16(out32);
}
filtState[0] = state0;
filtState[1] = state1;
filtState[2] = state2;
filtState[3] = state3;
filtState[4] = state4;
filtState[5] = state5;
filtState[6] = state6;
filtState[7] = state7;
}
void WebRtcSpl_UpsampleBy2(const WebRtc_Word16* in, WebRtc_Word16 len,
WebRtc_Word16* out, WebRtc_Word32* filtState) {
WebRtc_Word32 tmp1, tmp2, diff, in32, out32;
WebRtc_Word16 i;
register WebRtc_Word32 state0 = filtState[0];
register WebRtc_Word32 state1 = filtState[1];
register WebRtc_Word32 state2 = filtState[2];
register WebRtc_Word32 state3 = filtState[3];
register WebRtc_Word32 state4 = filtState[4];
register WebRtc_Word32 state5 = filtState[5];
register WebRtc_Word32 state6 = filtState[6];
register WebRtc_Word32 state7 = filtState[7];
for (i = len; i > 0; i--) {
// lower allpass filter
in32 = (WebRtc_Word32)(*in++) << 10;
diff = in32 - state1;
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0);
state0 = in32;
diff = tmp1 - state2;
tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state1);
state1 = tmp1;
diff = tmp2 - state3;
state3 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state2);
state2 = tmp2;
// round; limit amplitude to prevent wrap-around; write to output array
out32 = (state3 + 512) >> 10;
*out++ = WebRtcSpl_SatW32ToW16(out32);
// upper allpass filter
diff = in32 - state5;
tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state4);
state4 = in32;
diff = tmp1 - state6;
tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state5);
state5 = tmp1;
diff = tmp2 - state7;
state7 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state6);
state6 = tmp2;
// round; limit amplitude to prevent wrap-around; write to output array
out32 = (state7 + 512) >> 10;
*out++ = WebRtcSpl_SatW32ToW16(out32);
}
filtState[0] = state0;
filtState[1] = state1;
filtState[2] = state2;
filtState[3] = state3;
filtState[4] = state4;
filtState[5] = state5;
filtState[6] = state6;
filtState[7] = state7;
}