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 function WebRtcSpl_ComplexFFT().
14 * The description header can be found in signal_processing_library.h
15 *
16 */
17
18 #include "webrtc/common_audio/signal_processing/complex_fft_tables.h"
19 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
20
21 #define CFFTSFT 14
22 #define CFFTRND 1
23 #define CFFTRND2 16384
24
25 #define CIFFTSFT 14
26 #define CIFFTRND 1
27
28
WebRtcSpl_ComplexFFT(int16_t frfi[],int stages,int mode)29 int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode)
30 {
31 int i, j, l, k, istep, n, m;
32 int16_t wr, wi;
33 int32_t tr32, ti32, qr32, qi32;
34
35 /* The 1024-value is a constant given from the size of kSinTable1024[],
36 * and should not be changed depending on the input parameter 'stages'
37 */
38 n = 1 << stages;
39 if (n > 1024)
40 return -1;
41
42 l = 1;
43 k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change
44 depending on the input parameter 'stages' */
45
46 if (mode == 0)
47 {
48 // mode==0: Low-complexity and Low-accuracy mode
49 while (l < n)
50 {
51 istep = l << 1;
52
53 for (m = 0; m < l; ++m)
54 {
55 j = m << k;
56
57 /* The 256-value is a constant given as 1/4 of the size of
58 * kSinTable1024[], and should not be changed depending on the input
59 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
60 */
61 wr = kSinTable1024[j + 256];
62 wi = -kSinTable1024[j];
63
64 for (i = m; i < n; i += istep)
65 {
66 j = i + l;
67
68 tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
69 - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1])), 15);
70
71 ti32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
72 + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j])), 15);
73
74 qr32 = (int32_t)frfi[2 * i];
75 qi32 = (int32_t)frfi[2 * i + 1];
76 frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, 1);
77 frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, 1);
78 frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, 1);
79 frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, 1);
80 }
81 }
82
83 --k;
84 l = istep;
85
86 }
87
88 } else
89 {
90 // mode==1: High-complexity and High-accuracy mode
91 while (l < n)
92 {
93 istep = l << 1;
94
95 for (m = 0; m < l; ++m)
96 {
97 j = m << k;
98
99 /* The 256-value is a constant given as 1/4 of the size of
100 * kSinTable1024[], and should not be changed depending on the input
101 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
102 */
103 wr = kSinTable1024[j + 256];
104 wi = -kSinTable1024[j];
105
106 #ifdef WEBRTC_ARCH_ARM_V7
107 int32_t wri = 0;
108 __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
109 "r"((int32_t)wr), "r"((int32_t)wi));
110 #endif
111
112 for (i = m; i < n; i += istep)
113 {
114 j = i + l;
115
116 #ifdef WEBRTC_ARCH_ARM_V7
117 register int32_t frfi_r;
118 __asm __volatile(
119 "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd],"
120 " lsl #16\n\t"
121 "smlsd %[tr32], %[wri], %[frfi_r], %[cfftrnd]\n\t"
122 "smladx %[ti32], %[wri], %[frfi_r], %[cfftrnd]\n\t"
123 :[frfi_r]"=&r"(frfi_r),
124 [tr32]"=&r"(tr32),
125 [ti32]"=r"(ti32)
126 :[frfi_even]"r"((int32_t)frfi[2*j]),
127 [frfi_odd]"r"((int32_t)frfi[2*j +1]),
128 [wri]"r"(wri),
129 [cfftrnd]"r"(CFFTRND));
130 #else
131 tr32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
132 - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1]) + CFFTRND;
133
134 ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
135 + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CFFTRND;
136 #endif
137
138 tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CFFTSFT);
139 ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CFFTSFT);
140
141 qr32 = ((int32_t)frfi[2 * i]) << CFFTSFT;
142 qi32 = ((int32_t)frfi[2 * i + 1]) << CFFTSFT;
143
144 frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
145 (qr32 - tr32 + CFFTRND2), 1 + CFFTSFT);
146 frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
147 (qi32 - ti32 + CFFTRND2), 1 + CFFTSFT);
148 frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
149 (qr32 + tr32 + CFFTRND2), 1 + CFFTSFT);
150 frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
151 (qi32 + ti32 + CFFTRND2), 1 + CFFTSFT);
152 }
153 }
154
155 --k;
156 l = istep;
157 }
158 }
159 return 0;
160 }
161
WebRtcSpl_ComplexIFFT(int16_t frfi[],int stages,int mode)162 int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode)
163 {
164 int i, j, l, k, istep, n, m, scale, shift;
165 int16_t wr, wi;
166 int32_t tr32, ti32, qr32, qi32;
167 int32_t tmp32, round2;
168
169 /* The 1024-value is a constant given from the size of kSinTable1024[],
170 * and should not be changed depending on the input parameter 'stages'
171 */
172 n = 1 << stages;
173 if (n > 1024)
174 return -1;
175
176 scale = 0;
177
178 l = 1;
179 k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change
180 depending on the input parameter 'stages' */
181
182 while (l < n)
183 {
184 // variable scaling, depending upon data
185 shift = 0;
186 round2 = 8192;
187
188 tmp32 = (int32_t)WebRtcSpl_MaxAbsValueW16(frfi, 2 * n);
189 if (tmp32 > 13573)
190 {
191 shift++;
192 scale++;
193 round2 <<= 1;
194 }
195 if (tmp32 > 27146)
196 {
197 shift++;
198 scale++;
199 round2 <<= 1;
200 }
201
202 istep = l << 1;
203
204 if (mode == 0)
205 {
206 // mode==0: Low-complexity and Low-accuracy mode
207 for (m = 0; m < l; ++m)
208 {
209 j = m << k;
210
211 /* The 256-value is a constant given as 1/4 of the size of
212 * kSinTable1024[], and should not be changed depending on the input
213 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
214 */
215 wr = kSinTable1024[j + 256];
216 wi = kSinTable1024[j];
217
218 for (i = m; i < n; i += istep)
219 {
220 j = i + l;
221
222 tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j], 0)
223 - WEBRTC_SPL_MUL_16_16_RSFT(wi, frfi[2 * j + 1], 0)), 15);
224
225 ti32 = WEBRTC_SPL_RSHIFT_W32(
226 (WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j + 1], 0)
227 + WEBRTC_SPL_MUL_16_16_RSFT(wi,frfi[2*j],0)), 15);
228
229 qr32 = (int32_t)frfi[2 * i];
230 qi32 = (int32_t)frfi[2 * i + 1];
231 frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, shift);
232 frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, shift);
233 frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, shift);
234 frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, shift);
235 }
236 }
237 } else
238 {
239 // mode==1: High-complexity and High-accuracy mode
240
241 for (m = 0; m < l; ++m)
242 {
243 j = m << k;
244
245 /* The 256-value is a constant given as 1/4 of the size of
246 * kSinTable1024[], and should not be changed depending on the input
247 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
248 */
249 wr = kSinTable1024[j + 256];
250 wi = kSinTable1024[j];
251
252 #ifdef WEBRTC_ARCH_ARM_V7
253 int32_t wri = 0;
254 __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
255 "r"((int32_t)wr), "r"((int32_t)wi));
256 #endif
257
258 for (i = m; i < n; i += istep)
259 {
260 j = i + l;
261
262 #ifdef WEBRTC_ARCH_ARM_V7
263 register int32_t frfi_r;
264 __asm __volatile(
265 "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd], lsl #16\n\t"
266 "smlsd %[tr32], %[wri], %[frfi_r], %[cifftrnd]\n\t"
267 "smladx %[ti32], %[wri], %[frfi_r], %[cifftrnd]\n\t"
268 :[frfi_r]"=&r"(frfi_r),
269 [tr32]"=&r"(tr32),
270 [ti32]"=r"(ti32)
271 :[frfi_even]"r"((int32_t)frfi[2*j]),
272 [frfi_odd]"r"((int32_t)frfi[2*j +1]),
273 [wri]"r"(wri),
274 [cifftrnd]"r"(CIFFTRND)
275 );
276 #else
277
278 tr32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
279 - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1]) + CIFFTRND;
280
281 ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
282 + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CIFFTRND;
283 #endif
284 tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CIFFTSFT);
285 ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CIFFTSFT);
286
287 qr32 = ((int32_t)frfi[2 * i]) << CIFFTSFT;
288 qi32 = ((int32_t)frfi[2 * i + 1]) << CIFFTSFT;
289
290 frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32((qr32 - tr32+round2),
291 shift+CIFFTSFT);
292 frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
293 (qi32 - ti32 + round2), shift + CIFFTSFT);
294 frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((qr32 + tr32 + round2),
295 shift + CIFFTSFT);
296 frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
297 (qi32 + ti32 + round2), shift + CIFFTSFT);
298 }
299 }
300
301 }
302 --k;
303 l = istep;
304 }
305 return scale;
306 }
307