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