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 "common_audio/signal_processing/include/signal_processing_library.h"
21 
22 #if !defined(MIPS_DSP_R2_LE)
23 // allpass filter coefficients.
24 static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528};
25 static const uint16_t kResampleAllpass2[3] = {12199, 37471, 60255};
26 #endif
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
WebRtcSpl_DownsampleBy2(const int16_t * in,size_t len,int16_t * out,int32_t * filtState)33 void WebRtcSpl_DownsampleBy2(const int16_t* in,
34                              size_t len,
35                              int16_t* out,
36                              int32_t* filtState) {
37   int32_t out32;
38   size_t i, len1;
39 
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];
48 
49 #if defined(MIPS_DSP_R2_LE)
50   int32_t k1Res0, k1Res1, k1Res2, k2Res0, k2Res1, k2Res2;
51 
52   k1Res0= 3284;
53   k1Res1= 24441;
54   k1Res2= 49528;
55   k2Res0= 12199;
56   k2Res1= 37471;
57   k2Res2= 60255;
58   len1 = (len >> 1);
59 
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;
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)
153   int32_t tmp1, tmp2, diff;
154   int32_t in32;
155   len1 = (len >> 1)/4;
156   for (i = len1; i > 0; i--) {
157     // lower allpass filter
158     in32 = (int32_t)(*in++) << 10;
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
170     in32 = (int32_t)(*in++) << 10;
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
187     in32 = (int32_t)(*in++) << 10;
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
199     in32 = (int32_t)(*in++) << 10;
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
216     in32 = (int32_t)(*in++) << 10;
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
228     in32 = (int32_t)(*in++) << 10;
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
245     in32 = (int32_t)(*in++) << 10;
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
257     in32 = (int32_t)(*in++) << 10;
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)
293