1/* 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 12/* 13 * This file contains the resampling by two functions. 14 * The description header can be found in signal_processing_library.h 15 * 16 */ 17 18#include "signal_processing_library.h" 19 20#ifdef WEBRTC_ARCH_ARM_V7A 21 22// allpass filter coefficients. 23static const WebRtc_UWord32 kResampleAllpass1[3] = {3284, 24441, 49528 << 15}; 24static const WebRtc_UWord32 kResampleAllpass2[3] = 25 {12199, 37471 << 15, 60255 << 15}; 26 27// Multiply two 32-bit values and accumulate to another input value. 28// Return: state + ((diff * tbl_value) >> 16) 29 30static __inline WebRtc_Word32 MUL_ACCUM_1(WebRtc_Word32 tbl_value, 31 WebRtc_Word32 diff, 32 WebRtc_Word32 state) { 33 WebRtc_Word32 result; 34 __asm__("smlawb %r0, %r1, %r2, %r3": "=r"(result): "r"(diff), 35 "r"(tbl_value), "r"(state)); 36 return result; 37} 38 39// Multiply two 32-bit values and accumulate to another input value. 40// Return: Return: state + (((diff << 1) * tbl_value) >> 32) 41// 42// The reason to introduce this function is that, in case we can't use smlawb 43// instruction (in MUL_ACCUM_1) due to input value range, we can still use 44// smmla to save some cycles. 45 46static __inline WebRtc_Word32 MUL_ACCUM_2(WebRtc_Word32 tbl_value, 47 WebRtc_Word32 diff, 48 WebRtc_Word32 state) { 49 WebRtc_Word32 result; 50 __asm__("smmla %r0, %r1, %r2, %r3": "=r"(result): "r"(diff << 1), 51 "r"(tbl_value), "r"(state)); 52 return result; 53} 54 55#else 56 57// allpass filter coefficients. 58static const WebRtc_UWord16 kResampleAllpass1[3] = {3284, 24441, 49528}; 59static const WebRtc_UWord16 kResampleAllpass2[3] = {12199, 37471, 60255}; 60 61// Multiply a 32-bit value with a 16-bit value and accumulate to another input: 62#define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) 63#define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) 64 65#endif // WEBRTC_ARCH_ARM_V7A 66 67 68// decimator 69void WebRtcSpl_DownsampleBy2(const WebRtc_Word16* in, const WebRtc_Word16 len, 70 WebRtc_Word16* out, WebRtc_Word32* filtState) { 71 WebRtc_Word32 tmp1, tmp2, diff, in32, out32; 72 WebRtc_Word16 i; 73 74 register WebRtc_Word32 state0 = filtState[0]; 75 register WebRtc_Word32 state1 = filtState[1]; 76 register WebRtc_Word32 state2 = filtState[2]; 77 register WebRtc_Word32 state3 = filtState[3]; 78 register WebRtc_Word32 state4 = filtState[4]; 79 register WebRtc_Word32 state5 = filtState[5]; 80 register WebRtc_Word32 state6 = filtState[6]; 81 register WebRtc_Word32 state7 = filtState[7]; 82 83 for (i = (len >> 1); i > 0; i--) { 84 // lower allpass filter 85 in32 = (WebRtc_Word32)(*in++) << 10; 86 diff = in32 - state1; 87 tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); 88 state0 = in32; 89 diff = tmp1 - state2; 90 tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); 91 state1 = tmp1; 92 diff = tmp2 - state3; 93 state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); 94 state2 = tmp2; 95 96 // upper allpass filter 97 in32 = (WebRtc_Word32)(*in++) << 10; 98 diff = in32 - state5; 99 tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); 100 state4 = in32; 101 diff = tmp1 - state6; 102 tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); 103 state5 = tmp1; 104 diff = tmp2 - state7; 105 state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); 106 state6 = tmp2; 107 108 // add two allpass outputs, divide by two and round 109 out32 = (state3 + state7 + 1024) >> 11; 110 111 // limit amplitude to prevent wrap-around, and write to output array 112 *out++ = WebRtcSpl_SatW32ToW16(out32); 113 } 114 115 filtState[0] = state0; 116 filtState[1] = state1; 117 filtState[2] = state2; 118 filtState[3] = state3; 119 filtState[4] = state4; 120 filtState[5] = state5; 121 filtState[6] = state6; 122 filtState[7] = state7; 123} 124 125 126void WebRtcSpl_UpsampleBy2(const WebRtc_Word16* in, WebRtc_Word16 len, 127 WebRtc_Word16* out, WebRtc_Word32* filtState) { 128 WebRtc_Word32 tmp1, tmp2, diff, in32, out32; 129 WebRtc_Word16 i; 130 131 register WebRtc_Word32 state0 = filtState[0]; 132 register WebRtc_Word32 state1 = filtState[1]; 133 register WebRtc_Word32 state2 = filtState[2]; 134 register WebRtc_Word32 state3 = filtState[3]; 135 register WebRtc_Word32 state4 = filtState[4]; 136 register WebRtc_Word32 state5 = filtState[5]; 137 register WebRtc_Word32 state6 = filtState[6]; 138 register WebRtc_Word32 state7 = filtState[7]; 139 140 for (i = len; i > 0; i--) { 141 // lower allpass filter 142 in32 = (WebRtc_Word32)(*in++) << 10; 143 diff = in32 - state1; 144 tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0); 145 state0 = in32; 146 diff = tmp1 - state2; 147 tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state1); 148 state1 = tmp1; 149 diff = tmp2 - state3; 150 state3 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state2); 151 state2 = tmp2; 152 153 // round; limit amplitude to prevent wrap-around; write to output array 154 out32 = (state3 + 512) >> 10; 155 *out++ = WebRtcSpl_SatW32ToW16(out32); 156 157 // upper allpass filter 158 diff = in32 - state5; 159 tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state4); 160 state4 = in32; 161 diff = tmp1 - state6; 162 tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state5); 163 state5 = tmp1; 164 diff = tmp2 - state7; 165 state7 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state6); 166 state6 = tmp2; 167 168 // round; limit amplitude to prevent wrap-around; write to output array 169 out32 = (state7 + 512) >> 10; 170 *out++ = WebRtcSpl_SatW32ToW16(out32); 171 } 172 173 filtState[0] = state0; 174 filtState[1] = state1; 175 filtState[2] = state2; 176 filtState[3] = state3; 177 filtState[4] = state4; 178 filtState[5] = state5; 179 filtState[6] = state6; 180 filtState[7] = state7; 181} 182