blob: a026b70b01f9d6e91be10fd4cefed55fb95a0179 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
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
andrew@webrtc.orgeed919d2013-05-30 16:38:36 +000018#include "webrtc/common_audio/signal_processing/complex_fft_tables.h"
pbos@webrtc.org3d8647f2013-07-16 13:32:03 +000019#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000020
21#define CFFTSFT 14
22#define CFFTRND 1
23#define CFFTRND2 16384
24
bjornv@webrtc.org132feb12011-12-01 15:40:50 +000025#define CIFFTSFT 14
26#define CIFFTRND 1
27
bjornv@webrtc.org132feb12011-12-01 15:40:50 +000028
pbos@webrtc.orgb0913072013-04-09 16:40:28 +000029int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode)
niklase@google.com470e71d2011-07-07 08:21:25 +000030{
31 int i, j, l, k, istep, n, m;
pbos@webrtc.orgb0913072013-04-09 16:40:28 +000032 int16_t wr, wi;
33 int32_t tr32, ti32, qr32, qi32;
niklase@google.com470e71d2011-07-07 08:21:25 +000034
bjornv@webrtc.org132feb12011-12-01 15:40:50 +000035 /* The 1024-value is a constant given from the size of kSinTable1024[],
niklase@google.com470e71d2011-07-07 08:21:25 +000036 * 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;
bjornv@webrtc.org132feb12011-12-01 15:40:50 +000043 k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change
niklase@google.com470e71d2011-07-07 08:21:25 +000044 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
bjornv@webrtc.org132feb12011-12-01 15:40:50 +000058 * kSinTable1024[], and should not be changed depending on the input
niklase@google.com470e71d2011-07-07 08:21:25 +000059 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
60 */
bjornv@webrtc.org132feb12011-12-01 15:40:50 +000061 wr = kSinTable1024[j + 256];
62 wi = -kSinTable1024[j];
niklase@google.com470e71d2011-07-07 08:21:25 +000063
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
pbos@webrtc.orgb0913072013-04-09 16:40:28 +000074 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);
niklase@google.com470e71d2011-07-07 08:21:25 +000080 }
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
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000100 * kSinTable1024[], and should not be changed depending on the input
niklase@google.com470e71d2011-07-07 08:21:25 +0000101 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
102 */
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000103 wr = kSinTable1024[j + 256];
104 wi = -kSinTable1024[j];
niklase@google.com470e71d2011-07-07 08:21:25 +0000105
kma@webrtc.org94771cb2012-08-28 04:09:50 +0000106#ifdef WEBRTC_ARCH_ARM_V7
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000107 int32_t wri = 0;
108 int32_t frfi_r = 0;
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000109 __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000110 "r"((int32_t)wr), "r"((int32_t)wi));
kma@google.com78dc99e2011-08-16 20:00:18 +0000111#endif
112
niklase@google.com470e71d2011-07-07 08:21:25 +0000113 for (i = m; i < n; i += istep)
114 {
115 j = i + l;
116
kma@webrtc.org94771cb2012-08-28 04:09:50 +0000117#ifdef WEBRTC_ARCH_ARM_V7
bjornv@webrtc.orgaca59392014-05-28 08:45:04 +0000118 __asm __volatile(
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000119 "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd], lsl #16\n\t"
120 "smlsd %[tr32], %[wri], %[frfi_r], %[cfftrnd]\n\t"
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000121 :[frfi_r]"+r"(frfi_r),
bjornv@webrtc.orgaca59392014-05-28 08:45:04 +0000122 [tr32]"=r"(tr32)
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000123 :[frfi_even]"r"((int32_t)frfi[2*j]),
124 [frfi_odd]"r"((int32_t)frfi[2*j +1]),
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000125 [wri]"r"(wri),
126 [cfftrnd]"r"(CFFTRND)
bjornv@webrtc.orgaca59392014-05-28 08:45:04 +0000127 );
128 __asm __volatile("smladx %0, %1, %2, %3\n\t" : "=r"(ti32) :
129 "r"(wri), "r"(frfi_r), "r"(CFFTRND));
kma@google.com78dc99e2011-08-16 20:00:18 +0000130
131#else
132 tr32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
133 - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1]) + CFFTRND;
niklase@google.com470e71d2011-07-07 08:21:25 +0000134
kma@google.com78dc99e2011-08-16 20:00:18 +0000135 ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
136 + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CFFTRND;
137#endif
138
139 tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CFFTSFT);
140 ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CFFTSFT);
niklase@google.com470e71d2011-07-07 08:21:25 +0000141
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000142 qr32 = ((int32_t)frfi[2 * i]) << CFFTSFT;
143 qi32 = ((int32_t)frfi[2 * i + 1]) << CFFTSFT;
kma@google.com78dc99e2011-08-16 20:00:18 +0000144
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000145 frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
niklase@google.com470e71d2011-07-07 08:21:25 +0000146 (qr32 - tr32 + CFFTRND2), 1 + CFFTSFT);
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000147 frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
niklase@google.com470e71d2011-07-07 08:21:25 +0000148 (qi32 - ti32 + CFFTRND2), 1 + CFFTSFT);
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000149 frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
niklase@google.com470e71d2011-07-07 08:21:25 +0000150 (qr32 + tr32 + CFFTRND2), 1 + CFFTSFT);
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000151 frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 (qi32 + ti32 + CFFTRND2), 1 + CFFTSFT);
153 }
154 }
155
156 --k;
157 l = istep;
158 }
159 }
160 return 0;
161}
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000162
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000163int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode)
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000164{
165 int i, j, l, k, istep, n, m, scale, shift;
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000166 int16_t wr, wi;
167 int32_t tr32, ti32, qr32, qi32;
168 int32_t tmp32, round2;
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000169
170 /* The 1024-value is a constant given from the size of kSinTable1024[],
171 * and should not be changed depending on the input parameter 'stages'
172 */
173 n = 1 << stages;
174 if (n > 1024)
175 return -1;
176
177 scale = 0;
178
179 l = 1;
180 k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change
181 depending on the input parameter 'stages' */
182
183 while (l < n)
184 {
185 // variable scaling, depending upon data
186 shift = 0;
187 round2 = 8192;
188
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000189 tmp32 = (int32_t)WebRtcSpl_MaxAbsValueW16(frfi, 2 * n);
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000190 if (tmp32 > 13573)
191 {
192 shift++;
193 scale++;
194 round2 <<= 1;
195 }
196 if (tmp32 > 27146)
197 {
198 shift++;
199 scale++;
200 round2 <<= 1;
201 }
202
203 istep = l << 1;
204
205 if (mode == 0)
206 {
207 // mode==0: Low-complexity and Low-accuracy mode
208 for (m = 0; m < l; ++m)
209 {
210 j = m << k;
211
212 /* The 256-value is a constant given as 1/4 of the size of
213 * kSinTable1024[], and should not be changed depending on the input
214 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
215 */
216 wr = kSinTable1024[j + 256];
217 wi = kSinTable1024[j];
218
219 for (i = m; i < n; i += istep)
220 {
221 j = i + l;
222
223 tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j], 0)
224 - WEBRTC_SPL_MUL_16_16_RSFT(wi, frfi[2 * j + 1], 0)), 15);
225
226 ti32 = WEBRTC_SPL_RSHIFT_W32(
227 (WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j + 1], 0)
228 + WEBRTC_SPL_MUL_16_16_RSFT(wi,frfi[2*j],0)), 15);
229
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000230 qr32 = (int32_t)frfi[2 * i];
231 qi32 = (int32_t)frfi[2 * i + 1];
232 frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, shift);
233 frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, shift);
234 frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, shift);
235 frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, shift);
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000236 }
237 }
238 } else
239 {
240 // mode==1: High-complexity and High-accuracy mode
241
242 for (m = 0; m < l; ++m)
243 {
244 j = m << k;
245
246 /* The 256-value is a constant given as 1/4 of the size of
247 * kSinTable1024[], and should not be changed depending on the input
248 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
249 */
250 wr = kSinTable1024[j + 256];
251 wi = kSinTable1024[j];
252
kma@webrtc.org94771cb2012-08-28 04:09:50 +0000253#ifdef WEBRTC_ARCH_ARM_V7
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000254 int32_t wri = 0;
255 int32_t frfi_r = 0;
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000256 __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000257 "r"((int32_t)wr), "r"((int32_t)wi));
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000258#endif
259
260 for (i = m; i < n; i += istep)
261 {
262 j = i + l;
263
kma@webrtc.org94771cb2012-08-28 04:09:50 +0000264#ifdef WEBRTC_ARCH_ARM_V7
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000265 __asm __volatile(
266 "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd], lsl #16\n\t"
267 "smlsd %[tr32], %[wri], %[frfi_r], %[cifftrnd]\n\t"
268 "smladx %[ti32], %[wri], %[frfi_r], %[cifftrnd]\n\t"
269 :[frfi_r]"+r"(frfi_r),
270 [tr32]"=r"(tr32),
271 [ti32]"=r"(ti32)
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000272 :[frfi_even]"r"((int32_t)frfi[2*j]),
273 [frfi_odd]"r"((int32_t)frfi[2*j +1]),
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000274 [wri]"r"(wri),
275 [cifftrnd]"r"(CIFFTRND)
276 );
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000277#else
278
279 tr32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
280 - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1]) + CIFFTRND;
281
282 ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
283 + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CIFFTRND;
284#endif
285 tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CIFFTSFT);
286 ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CIFFTSFT);
287
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000288 qr32 = ((int32_t)frfi[2 * i]) << CIFFTSFT;
289 qi32 = ((int32_t)frfi[2 * i + 1]) << CIFFTSFT;
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000290
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000291 frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32((qr32 - tr32+round2),
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000292 shift+CIFFTSFT);
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000293 frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000294 (qi32 - ti32 + round2), shift + CIFFTSFT);
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000295 frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((qr32 + tr32 + round2),
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000296 shift + CIFFTSFT);
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000297 frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000298 (qi32 + ti32 + round2), shift + CIFFTSFT);
299 }
300 }
301
302 }
303 --k;
304 l = istep;
305 }
306 return scale;
307}