andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2013 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 | #if defined(MIPS32_LE) |
| 19 | |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 20 | #include "common_audio/signal_processing/include/signal_processing_library.h" |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 21 | |
Gordana Cmiljanovic | 5b06906 | 2017-07-18 09:41:53 | [diff] [blame] | 22 | #if !defined(MIPS_DSP_R2_LE) |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 23 | // allpass filter coefficients. |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 24 | static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528}; |
| 25 | static const uint16_t kResampleAllpass2[3] = {12199, 37471, 60255}; |
Gordana Cmiljanovic | 5b06906 | 2017-07-18 09:41:53 | [diff] [blame] | 26 | #endif |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 27 | |
| 28 | // Multiply a 32-bit value with a 16-bit value and accumulate to another input: |
| 29 | #define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) |
| 30 | #define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) |
| 31 | |
| 32 | // decimator |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 33 | void WebRtcSpl_DownsampleBy2(const int16_t* in, |
Peter Kasting | dce40cf | 2015-08-24 21:52:23 | [diff] [blame] | 34 | size_t len, |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 35 | int16_t* out, |
| 36 | int32_t* filtState) { |
| 37 | int32_t out32; |
Peter Kasting | dce40cf | 2015-08-24 21:52:23 | [diff] [blame] | 38 | size_t i, len1; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 39 | |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 40 | register int32_t state0 = filtState[0]; |
| 41 | register int32_t state1 = filtState[1]; |
| 42 | register int32_t state2 = filtState[2]; |
| 43 | register int32_t state3 = filtState[3]; |
| 44 | register int32_t state4 = filtState[4]; |
| 45 | register int32_t state5 = filtState[5]; |
| 46 | register int32_t state6 = filtState[6]; |
| 47 | register int32_t state7 = filtState[7]; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 48 | |
| 49 | #if defined(MIPS_DSP_R2_LE) |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 50 | int32_t k1Res0, k1Res1, k1Res2, k2Res0, k2Res1, k2Res2; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 51 | |
| 52 | k1Res0= 3284; |
| 53 | k1Res1= 24441; |
| 54 | k1Res2= 49528; |
| 55 | k2Res0= 12199; |
| 56 | k2Res1= 37471; |
| 57 | k2Res2= 60255; |
| 58 | len1 = (len >> 1); |
| 59 | |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 60 | const int32_t* inw = (int32_t*)in; |
| 61 | int32_t tmp11, tmp12, tmp21, tmp22; |
| 62 | int32_t in322, in321; |
| 63 | int32_t diff1, diff2; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 64 | for (i = len1; i > 0; i--) { |
| 65 | __asm__ volatile ( |
| 66 | "lh %[in321], 0(%[inw]) \n\t" |
| 67 | "lh %[in322], 2(%[inw]) \n\t" |
| 68 | |
| 69 | "sll %[in321], %[in321], 10 \n\t" |
| 70 | "sll %[in322], %[in322], 10 \n\t" |
| 71 | |
| 72 | "addiu %[inw], %[inw], 4 \n\t" |
| 73 | |
| 74 | "subu %[diff1], %[in321], %[state1] \n\t" |
| 75 | "subu %[diff2], %[in322], %[state5] \n\t" |
| 76 | |
| 77 | : [in322] "=&r" (in322), [in321] "=&r" (in321), |
| 78 | [diff1] "=&r" (diff1), [diff2] "=r" (diff2), [inw] "+r" (inw) |
| 79 | : [state1] "r" (state1), [state5] "r" (state5) |
| 80 | : "memory" |
| 81 | ); |
| 82 | |
| 83 | __asm__ volatile ( |
| 84 | "mult $ac0, %[diff1], %[k2Res0] \n\t" |
| 85 | "mult $ac1, %[diff2], %[k1Res0] \n\t" |
| 86 | |
| 87 | "extr.w %[tmp11], $ac0, 16 \n\t" |
| 88 | "extr.w %[tmp12], $ac1, 16 \n\t" |
| 89 | |
| 90 | "addu %[tmp11], %[state0], %[tmp11] \n\t" |
| 91 | "addu %[tmp12], %[state4], %[tmp12] \n\t" |
| 92 | |
| 93 | "addiu %[state0], %[in321], 0 \n\t" |
| 94 | "addiu %[state4], %[in322], 0 \n\t" |
| 95 | |
| 96 | "subu %[diff1], %[tmp11], %[state2] \n\t" |
| 97 | "subu %[diff2], %[tmp12], %[state6] \n\t" |
| 98 | |
| 99 | "mult $ac0, %[diff1], %[k2Res1] \n\t" |
| 100 | "mult $ac1, %[diff2], %[k1Res1] \n\t" |
| 101 | |
| 102 | "extr.w %[tmp21], $ac0, 16 \n\t" |
| 103 | "extr.w %[tmp22], $ac1, 16 \n\t" |
| 104 | |
| 105 | "addu %[tmp21], %[state1], %[tmp21] \n\t" |
| 106 | "addu %[tmp22], %[state5], %[tmp22] \n\t" |
| 107 | |
| 108 | "addiu %[state1], %[tmp11], 0 \n\t" |
| 109 | "addiu %[state5], %[tmp12], 0 \n\t" |
| 110 | : [tmp22] "=r" (tmp22), [tmp21] "=&r" (tmp21), |
| 111 | [tmp11] "=&r" (tmp11), [state0] "+r" (state0), |
| 112 | [state1] "+r" (state1), |
| 113 | [state2] "+r" (state2), |
| 114 | [state4] "+r" (state4), [tmp12] "=&r" (tmp12), |
| 115 | [state6] "+r" (state6), [state5] "+r" (state5) |
| 116 | : [k1Res1] "r" (k1Res1), [k2Res1] "r" (k2Res1), [k2Res0] "r" (k2Res0), |
| 117 | [diff2] "r" (diff2), [diff1] "r" (diff1), [in322] "r" (in322), |
| 118 | [in321] "r" (in321), [k1Res0] "r" (k1Res0) |
| 119 | : "hi", "lo", "$ac1hi", "$ac1lo" |
| 120 | ); |
| 121 | |
| 122 | // upper allpass filter |
| 123 | __asm__ volatile ( |
| 124 | "subu %[diff1], %[tmp21], %[state3] \n\t" |
| 125 | "subu %[diff2], %[tmp22], %[state7] \n\t" |
| 126 | |
| 127 | "mult $ac0, %[diff1], %[k2Res2] \n\t" |
| 128 | "mult $ac1, %[diff2], %[k1Res2] \n\t" |
| 129 | "extr.w %[state3], $ac0, 16 \n\t" |
| 130 | "extr.w %[state7], $ac1, 16 \n\t" |
| 131 | "addu %[state3], %[state2], %[state3] \n\t" |
| 132 | "addu %[state7], %[state6], %[state7] \n\t" |
| 133 | |
| 134 | "addiu %[state2], %[tmp21], 0 \n\t" |
| 135 | "addiu %[state6], %[tmp22], 0 \n\t" |
| 136 | |
| 137 | // add two allpass outputs, divide by two and round |
| 138 | "addu %[out32], %[state3], %[state7] \n\t" |
| 139 | "addiu %[out32], %[out32], 1024 \n\t" |
| 140 | "sra %[out32], %[out32], 11 \n\t" |
| 141 | : [state3] "+r" (state3), [state6] "+r" (state6), |
| 142 | [state2] "+r" (state2), [diff2] "=&r" (diff2), |
| 143 | [out32] "=r" (out32), [diff1] "=&r" (diff1), [state7] "+r" (state7) |
| 144 | : [tmp22] "r" (tmp22), [tmp21] "r" (tmp21), |
| 145 | [k1Res2] "r" (k1Res2), [k2Res2] "r" (k2Res2) |
| 146 | : "hi", "lo", "$ac1hi", "$ac1lo" |
| 147 | ); |
| 148 | |
| 149 | // limit amplitude to prevent wrap-around, and write to output array |
| 150 | *out++ = WebRtcSpl_SatW32ToW16(out32); |
| 151 | } |
| 152 | #else // #if defined(MIPS_DSP_R2_LE) |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 153 | int32_t tmp1, tmp2, diff; |
| 154 | int32_t in32; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 155 | len1 = (len >> 1)/4; |
| 156 | for (i = len1; i > 0; i--) { |
| 157 | // lower allpass filter |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 158 | in32 = (int32_t)(*in++) << 10; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 159 | diff = in32 - state1; |
| 160 | tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); |
| 161 | state0 = in32; |
| 162 | diff = tmp1 - state2; |
| 163 | tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); |
| 164 | state1 = tmp1; |
| 165 | diff = tmp2 - state3; |
| 166 | state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); |
| 167 | state2 = tmp2; |
| 168 | |
| 169 | // upper allpass filter |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 170 | in32 = (int32_t)(*in++) << 10; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 171 | diff = in32 - state5; |
| 172 | tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); |
| 173 | state4 = in32; |
| 174 | diff = tmp1 - state6; |
| 175 | tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); |
| 176 | state5 = tmp1; |
| 177 | diff = tmp2 - state7; |
| 178 | state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); |
| 179 | state6 = tmp2; |
| 180 | |
| 181 | // add two allpass outputs, divide by two and round |
| 182 | out32 = (state3 + state7 + 1024) >> 11; |
| 183 | |
| 184 | // limit amplitude to prevent wrap-around, and write to output array |
| 185 | *out++ = WebRtcSpl_SatW32ToW16(out32); |
| 186 | // lower allpass filter |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 187 | in32 = (int32_t)(*in++) << 10; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 188 | diff = in32 - state1; |
| 189 | tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); |
| 190 | state0 = in32; |
| 191 | diff = tmp1 - state2; |
| 192 | tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); |
| 193 | state1 = tmp1; |
| 194 | diff = tmp2 - state3; |
| 195 | state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); |
| 196 | state2 = tmp2; |
| 197 | |
| 198 | // upper allpass filter |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 199 | in32 = (int32_t)(*in++) << 10; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 200 | diff = in32 - state5; |
| 201 | tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); |
| 202 | state4 = in32; |
| 203 | diff = tmp1 - state6; |
| 204 | tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); |
| 205 | state5 = tmp1; |
| 206 | diff = tmp2 - state7; |
| 207 | state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); |
| 208 | state6 = tmp2; |
| 209 | |
| 210 | // add two allpass outputs, divide by two and round |
| 211 | out32 = (state3 + state7 + 1024) >> 11; |
| 212 | |
| 213 | // limit amplitude to prevent wrap-around, and write to output array |
| 214 | *out++ = WebRtcSpl_SatW32ToW16(out32); |
| 215 | // lower allpass filter |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 216 | in32 = (int32_t)(*in++) << 10; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 217 | diff = in32 - state1; |
| 218 | tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); |
| 219 | state0 = in32; |
| 220 | diff = tmp1 - state2; |
| 221 | tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); |
| 222 | state1 = tmp1; |
| 223 | diff = tmp2 - state3; |
| 224 | state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); |
| 225 | state2 = tmp2; |
| 226 | |
| 227 | // upper allpass filter |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 228 | in32 = (int32_t)(*in++) << 10; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 229 | diff = in32 - state5; |
| 230 | tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); |
| 231 | state4 = in32; |
| 232 | diff = tmp1 - state6; |
| 233 | tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); |
| 234 | state5 = tmp1; |
| 235 | diff = tmp2 - state7; |
| 236 | state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); |
| 237 | state6 = tmp2; |
| 238 | |
| 239 | // add two allpass outputs, divide by two and round |
| 240 | out32 = (state3 + state7 + 1024) >> 11; |
| 241 | |
| 242 | // limit amplitude to prevent wrap-around, and write to output array |
| 243 | *out++ = WebRtcSpl_SatW32ToW16(out32); |
| 244 | // lower allpass filter |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 245 | in32 = (int32_t)(*in++) << 10; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 246 | diff = in32 - state1; |
| 247 | tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); |
| 248 | state0 = in32; |
| 249 | diff = tmp1 - state2; |
| 250 | tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); |
| 251 | state1 = tmp1; |
| 252 | diff = tmp2 - state3; |
| 253 | state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); |
| 254 | state2 = tmp2; |
| 255 | |
| 256 | // upper allpass filter |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 | [diff] [blame] | 257 | in32 = (int32_t)(*in++) << 10; |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 | [diff] [blame] | 258 | diff = in32 - state5; |
| 259 | tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); |
| 260 | state4 = in32; |
| 261 | diff = tmp1 - state6; |
| 262 | tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); |
| 263 | state5 = tmp1; |
| 264 | diff = tmp2 - state7; |
| 265 | state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); |
| 266 | state6 = tmp2; |
| 267 | |
| 268 | // add two allpass outputs, divide by two and round |
| 269 | out32 = (state3 + state7 + 1024) >> 11; |
| 270 | |
| 271 | // limit amplitude to prevent wrap-around, and write to output array |
| 272 | *out++ = WebRtcSpl_SatW32ToW16(out32); |
| 273 | } |
| 274 | #endif // #if defined(MIPS_DSP_R2_LE) |
| 275 | __asm__ volatile ( |
| 276 | "sw %[state0], 0(%[filtState]) \n\t" |
| 277 | "sw %[state1], 4(%[filtState]) \n\t" |
| 278 | "sw %[state2], 8(%[filtState]) \n\t" |
| 279 | "sw %[state3], 12(%[filtState]) \n\t" |
| 280 | "sw %[state4], 16(%[filtState]) \n\t" |
| 281 | "sw %[state5], 20(%[filtState]) \n\t" |
| 282 | "sw %[state6], 24(%[filtState]) \n\t" |
| 283 | "sw %[state7], 28(%[filtState]) \n\t" |
| 284 | : |
| 285 | : [state0] "r" (state0), [state1] "r" (state1), [state2] "r" (state2), |
| 286 | [state3] "r" (state3), [state4] "r" (state4), [state5] "r" (state5), |
| 287 | [state6] "r" (state6), [state7] "r" (state7), [filtState] "r" (filtState) |
| 288 | : "memory" |
| 289 | ); |
| 290 | } |
| 291 | |
| 292 | #endif // #if defined(MIPS32_LE) |