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 "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
19 
20 #ifdef WEBRTC_ARCH_ARM_V7
21 
22 // allpass filter coefficients.
23 static const uint32_t kResampleAllpass1[3] = {3284, 24441, 49528 << 15};
24 static const uint32_t 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 
MUL_ACCUM_1(int32_t tbl_value,int32_t diff,int32_t state)30 static __inline int32_t MUL_ACCUM_1(int32_t tbl_value,
31                                     int32_t diff,
32                                     int32_t state) {
33   int32_t result;
34   __asm __volatile ("smlawb %0, %1, %2, %3": "=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 
MUL_ACCUM_2(int32_t tbl_value,int32_t diff,int32_t state)46 static __inline int32_t MUL_ACCUM_2(int32_t tbl_value,
47                                     int32_t diff,
48                                     int32_t state) {
49   int32_t result;
50   __asm __volatile ("smmla %0, %1, %2, %3": "=r"(result): "r"(diff << 1),
51                                   "r"(tbl_value), "r"(state));
52   return result;
53 }
54 
55 #else
56 
57 // allpass filter coefficients.
58 static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528};
59 static const uint16_t 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_V7
66 
67 
68 // decimator
69 #if !defined(MIPS32_LE)
WebRtcSpl_DownsampleBy2(const int16_t * in,size_t len,int16_t * out,int32_t * filtState)70 void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len,
71                              int16_t* out, int32_t* filtState) {
72   int32_t tmp1, tmp2, diff, in32, out32;
73   size_t i;
74 
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];
83 
84   for (i = (len >> 1); i > 0; i--) {
85     // lower allpass filter
86     in32 = (int32_t)(*in++) << 10;
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;
96 
97     // upper allpass filter
98     in32 = (int32_t)(*in++) << 10;
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;
108 
109     // add two allpass outputs, divide by two and round
110     out32 = (state3 + state7 + 1024) >> 11;
111 
112     // limit amplitude to prevent wrap-around, and write to output array
113     *out++ = WebRtcSpl_SatW32ToW16(out32);
114   }
115 
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;
124 }
125 #endif  // #if defined(MIPS32_LE)
126 
127 
WebRtcSpl_UpsampleBy2(const int16_t * in,size_t len,int16_t * out,int32_t * filtState)128 void WebRtcSpl_UpsampleBy2(const int16_t* in, size_t len,
129                            int16_t* out, int32_t* filtState) {
130   int32_t tmp1, tmp2, diff, in32, out32;
131   size_t i;
132 
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];
141 
142   for (i = len; i > 0; i--) {
143     // lower allpass filter
144     in32 = (int32_t)(*in++) << 10;
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;
154 
155     // round; limit amplitude to prevent wrap-around; write to output array
156     out32 = (state3 + 512) >> 10;
157     *out++ = WebRtcSpl_SatW32ToW16(out32);
158 
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;
183 }
184