resample_by_2.c (6080B)
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 * This file contains the resampling by two functions. 13 * The description header can be found in signal_processing_library.h 14 * 15 */ 16 17 #include "common_audio/signal_processing/include/signal_processing_library.h" 18 19 #ifdef WEBRTC_ARCH_ARM_V7 20 21 // allpass filter coefficients. 22 static const uint32_t kResampleAllpass1[3] = {3284, 24441, 49528 << 15}; 23 static const uint32_t kResampleAllpass2[3] = {12199, 37471 << 15, 60255 << 15}; 24 25 // Multiply two 32-bit values and accumulate to another input value. 26 // Return: state + ((diff * tbl_value) >> 16) 27 28 static __inline int32_t MUL_ACCUM_1(int32_t tbl_value, 29 int32_t diff, 30 int32_t state) { 31 int32_t result; 32 __asm __volatile("smlawb %0, %1, %2, %3" 33 : "=r"(result) 34 : "r"(diff), "r"(tbl_value), "r"(state)); 35 return result; 36 } 37 38 // Multiply two 32-bit values and accumulate to another input value. 39 // Return: Return: state + (((diff << 1) * tbl_value) >> 32) 40 // 41 // The reason to introduce this function is that, in case we can't use smlawb 42 // instruction (in MUL_ACCUM_1) due to input value range, we can still use 43 // smmla to save some cycles. 44 45 static __inline int32_t MUL_ACCUM_2(int32_t tbl_value, 46 int32_t diff, 47 int32_t state) { 48 int32_t result; 49 __asm __volatile("smmla %0, %1, %2, %3" 50 : "=r"(result) 51 : "r"(diff << 1), "r"(tbl_value), "r"(state)); 52 return result; 53 } 54 55 #else 56 57 // allpass filter coefficients. 58 static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528}; 59 static const uint16_t 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_V7 66 67 // decimator 68 #if !defined(MIPS32_LE) 69 void WebRtcSpl_DownsampleBy2(const int16_t* in, 70 size_t len, 71 int16_t* out, 72 int32_t* filtState) { 73 int32_t tmp1, tmp2, diff, in32, out32; 74 size_t i; 75 76 register int32_t state0 = filtState[0]; 77 register int32_t state1 = filtState[1]; 78 register int32_t state2 = filtState[2]; 79 register int32_t state3 = filtState[3]; 80 register int32_t state4 = filtState[4]; 81 register int32_t state5 = filtState[5]; 82 register int32_t state6 = filtState[6]; 83 register int32_t state7 = filtState[7]; 84 85 for (i = (len >> 1); i > 0; i--) { 86 // lower allpass filter 87 in32 = (int32_t)(*in++) * (1 << 10); 88 diff = in32 - state1; 89 tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); 90 state0 = in32; 91 diff = tmp1 - state2; 92 tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); 93 state1 = tmp1; 94 diff = tmp2 - state3; 95 state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); 96 state2 = tmp2; 97 98 // upper allpass filter 99 in32 = (int32_t)(*in++) * (1 << 10); 100 diff = in32 - state5; 101 tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); 102 state4 = in32; 103 diff = tmp1 - state6; 104 tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); 105 state5 = tmp1; 106 diff = tmp2 - state7; 107 state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); 108 state6 = tmp2; 109 110 // add two allpass outputs, divide by two and round 111 out32 = (state3 + state7 + 1024) >> 11; 112 113 // limit amplitude to prevent wrap-around, and write to output array 114 *out++ = WebRtcSpl_SatW32ToW16(out32); 115 } 116 117 filtState[0] = state0; 118 filtState[1] = state1; 119 filtState[2] = state2; 120 filtState[3] = state3; 121 filtState[4] = state4; 122 filtState[5] = state5; 123 filtState[6] = state6; 124 filtState[7] = state7; 125 } 126 #endif // #if defined(MIPS32_LE) 127 128 void WebRtcSpl_UpsampleBy2(const int16_t* in, 129 size_t len, 130 int16_t* out, 131 int32_t* filtState) { 132 int32_t tmp1, tmp2, diff, in32, out32; 133 size_t i; 134 135 register int32_t state0 = filtState[0]; 136 register int32_t state1 = filtState[1]; 137 register int32_t state2 = filtState[2]; 138 register int32_t state3 = filtState[3]; 139 register int32_t state4 = filtState[4]; 140 register int32_t state5 = filtState[5]; 141 register int32_t state6 = filtState[6]; 142 register int32_t state7 = filtState[7]; 143 144 for (i = len; i > 0; i--) { 145 // lower allpass filter 146 in32 = (int32_t)(*in++) * (1 << 10); 147 diff = in32 - state1; 148 tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0); 149 state0 = in32; 150 diff = tmp1 - state2; 151 tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state1); 152 state1 = tmp1; 153 diff = tmp2 - state3; 154 state3 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state2); 155 state2 = tmp2; 156 157 // round; limit amplitude to prevent wrap-around; write to output array 158 out32 = (state3 + 512) >> 10; 159 *out++ = WebRtcSpl_SatW32ToW16(out32); 160 161 // upper allpass filter 162 diff = in32 - state5; 163 tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state4); 164 state4 = in32; 165 diff = tmp1 - state6; 166 tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state5); 167 state5 = tmp1; 168 diff = tmp2 - state7; 169 state7 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state6); 170 state6 = tmp2; 171 172 // round; limit amplitude to prevent wrap-around; write to output array 173 out32 = (state7 + 512) >> 10; 174 *out++ = WebRtcSpl_SatW32ToW16(out32); 175 } 176 177 filtState[0] = state0; 178 filtState[1] = state1; 179 filtState[2] = state2; 180 filtState[3] = state3; 181 filtState[4] = state4; 182 filtState[5] = state5; 183 filtState[6] = state6; 184 filtState[7] = state7; 185 }