niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 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 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 18 | #include "common_audio/signal_processing/include/signal_processing_library.h" |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 19 | |
kma@webrtc.org | 94771cb | 2012-08-28 04:09:50 +0000 | [diff] [blame] | 20 | #ifdef WEBRTC_ARCH_ARM_V7 |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 21 | |
| 22 | // allpass filter coefficients. |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 23 | static const uint32_t kResampleAllpass1[3] = {3284, 24441, 49528 << 15}; |
| 24 | static const uint32_t kResampleAllpass2[3] = |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 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 | |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 30 | static __inline int32_t MUL_ACCUM_1(int32_t tbl_value, |
| 31 | int32_t diff, |
| 32 | int32_t state) { |
| 33 | int32_t result; |
kma@webrtc.org | 55cd78c | 2012-11-17 00:22:46 +0000 | [diff] [blame] | 34 | __asm __volatile ("smlawb %0, %1, %2, %3": "=r"(result): "r"(diff), |
| 35 | "r"(tbl_value), "r"(state)); |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 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 | |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 46 | static __inline int32_t MUL_ACCUM_2(int32_t tbl_value, |
| 47 | int32_t diff, |
| 48 | int32_t state) { |
| 49 | int32_t result; |
kma@webrtc.org | 55cd78c | 2012-11-17 00:22:46 +0000 | [diff] [blame] | 50 | __asm __volatile ("smmla %0, %1, %2, %3": "=r"(result): "r"(diff << 1), |
| 51 | "r"(tbl_value), "r"(state)); |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 52 | return result; |
| 53 | } |
| 54 | |
| 55 | #else |
| 56 | |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 57 | // allpass filter coefficients. |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 58 | static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528}; |
| 59 | static const uint16_t kResampleAllpass2[3] = {12199, 37471, 60255}; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 60 | |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 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 | |
kma@webrtc.org | 94771cb | 2012-08-28 04:09:50 +0000 | [diff] [blame] | 65 | #endif // WEBRTC_ARCH_ARM_V7 |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 66 | |
| 67 | |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 68 | // decimator |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 +0000 | [diff] [blame] | 69 | #if !defined(MIPS32_LE) |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 70 | void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len, |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 71 | int16_t* out, int32_t* filtState) { |
| 72 | int32_t tmp1, tmp2, diff, in32, out32; |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 73 | size_t i; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 74 | |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 75 | register int32_t state0 = filtState[0]; |
| 76 | register int32_t state1 = filtState[1]; |
| 77 | register int32_t state2 = filtState[2]; |
| 78 | register int32_t state3 = filtState[3]; |
| 79 | register int32_t state4 = filtState[4]; |
| 80 | register int32_t state5 = filtState[5]; |
| 81 | register int32_t state6 = filtState[6]; |
| 82 | register int32_t state7 = filtState[7]; |
kma@google.com | 8811032 | 2011-08-08 15:40:10 +0000 | [diff] [blame] | 83 | |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 84 | for (i = (len >> 1); i > 0; i--) { |
| 85 | // lower allpass filter |
Alex Loiko | b9f5361 | 2017-10-24 09:58:00 +0200 | [diff] [blame] | 86 | in32 = (int32_t)(*in++) * (1 << 10); |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 87 | diff = in32 - state1; |
| 88 | tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); |
| 89 | state0 = in32; |
| 90 | diff = tmp1 - state2; |
| 91 | tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); |
| 92 | state1 = tmp1; |
| 93 | diff = tmp2 - state3; |
| 94 | state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); |
| 95 | state2 = tmp2; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 96 | |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 97 | // upper allpass filter |
Alex Loiko | b9f5361 | 2017-10-24 09:58:00 +0200 | [diff] [blame] | 98 | in32 = (int32_t)(*in++) * (1 << 10); |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 99 | diff = in32 - state5; |
| 100 | tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); |
| 101 | state4 = in32; |
| 102 | diff = tmp1 - state6; |
| 103 | tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); |
| 104 | state5 = tmp1; |
| 105 | diff = tmp2 - state7; |
| 106 | state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); |
| 107 | state6 = tmp2; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 108 | |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 109 | // add two allpass outputs, divide by two and round |
| 110 | out32 = (state3 + state7 + 1024) >> 11; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 111 | |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 112 | // limit amplitude to prevent wrap-around, and write to output array |
| 113 | *out++ = WebRtcSpl_SatW32ToW16(out32); |
| 114 | } |
kma@google.com | 8811032 | 2011-08-08 15:40:10 +0000 | [diff] [blame] | 115 | |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 116 | filtState[0] = state0; |
| 117 | filtState[1] = state1; |
| 118 | filtState[2] = state2; |
| 119 | filtState[3] = state3; |
| 120 | filtState[4] = state4; |
| 121 | filtState[5] = state5; |
| 122 | filtState[6] = state6; |
| 123 | filtState[7] = state7; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 124 | } |
andrew@webrtc.org | 5140e24 | 2013-02-21 20:12:21 +0000 | [diff] [blame] | 125 | #endif // #if defined(MIPS32_LE) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 126 | |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 127 | |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 128 | void WebRtcSpl_UpsampleBy2(const int16_t* in, size_t len, |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 129 | int16_t* out, int32_t* filtState) { |
| 130 | int32_t tmp1, tmp2, diff, in32, out32; |
Peter Kasting | dce40cf | 2015-08-24 14:52:23 -0700 | [diff] [blame] | 131 | size_t i; |
kma@google.com | 8811032 | 2011-08-08 15:40:10 +0000 | [diff] [blame] | 132 | |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 133 | register int32_t state0 = filtState[0]; |
| 134 | register int32_t state1 = filtState[1]; |
| 135 | register int32_t state2 = filtState[2]; |
| 136 | register int32_t state3 = filtState[3]; |
| 137 | register int32_t state4 = filtState[4]; |
| 138 | register int32_t state5 = filtState[5]; |
| 139 | register int32_t state6 = filtState[6]; |
| 140 | register int32_t state7 = filtState[7]; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 141 | |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 142 | for (i = len; i > 0; i--) { |
| 143 | // lower allpass filter |
Alex Loiko | 187c699 | 2017-10-27 16:21:31 +0200 | [diff] [blame] | 144 | in32 = (int32_t)(*in++) * (1 << 10); |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 145 | diff = in32 - state1; |
| 146 | tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0); |
| 147 | state0 = in32; |
| 148 | diff = tmp1 - state2; |
| 149 | tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state1); |
| 150 | state1 = tmp1; |
| 151 | diff = tmp2 - state3; |
| 152 | state3 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state2); |
| 153 | state2 = tmp2; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 154 | |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 155 | // round; limit amplitude to prevent wrap-around; write to output array |
| 156 | out32 = (state3 + 512) >> 10; |
| 157 | *out++ = WebRtcSpl_SatW32ToW16(out32); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 158 | |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 159 | // upper allpass filter |
| 160 | diff = in32 - state5; |
| 161 | tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state4); |
| 162 | state4 = in32; |
| 163 | diff = tmp1 - state6; |
| 164 | tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state5); |
| 165 | state5 = tmp1; |
| 166 | diff = tmp2 - state7; |
| 167 | state7 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state6); |
| 168 | state6 = tmp2; |
| 169 | |
| 170 | // round; limit amplitude to prevent wrap-around; write to output array |
| 171 | out32 = (state7 + 512) >> 10; |
| 172 | *out++ = WebRtcSpl_SatW32ToW16(out32); |
| 173 | } |
| 174 | |
| 175 | filtState[0] = state0; |
| 176 | filtState[1] = state1; |
| 177 | filtState[2] = state2; |
| 178 | filtState[3] = state3; |
| 179 | filtState[4] = state4; |
| 180 | filtState[5] = state5; |
| 181 | filtState[6] = state6; |
| 182 | filtState[7] = state7; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 183 | } |