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