blob: aaeda52ad9794132287d0fdcd70b7571548dd3ba [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
bjornv@webrtc.orgf5670952014-10-29 10:29:16 +000068 tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15;
niklase@google.com470e71d2011-07-07 08:21:25 +000069
bjornv@webrtc.orgf5670952014-10-29 10:29:16 +000070 ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15;
niklase@google.com470e71d2011-07-07 08:21:25 +000071
pbos@webrtc.orgb0913072013-04-09 16:40:28 +000072 qr32 = (int32_t)frfi[2 * i];
73 qi32 = (int32_t)frfi[2 * i + 1];
bjornv@webrtc.orgf5670952014-10-29 10:29:16 +000074 frfi[2 * j] = (int16_t)((qr32 - tr32) >> 1);
75 frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> 1);
76 frfi[2 * i] = (int16_t)((qr32 + tr32) >> 1);
77 frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> 1);
niklase@google.com470e71d2011-07-07 08:21:25 +000078 }
79 }
80
81 --k;
82 l = istep;
83
84 }
85
86 } else
87 {
88 // mode==1: High-complexity and High-accuracy mode
89 while (l < n)
90 {
91 istep = l << 1;
92
93 for (m = 0; m < l; ++m)
94 {
95 j = m << k;
96
97 /* The 256-value is a constant given as 1/4 of the size of
bjornv@webrtc.org132feb12011-12-01 15:40:50 +000098 * kSinTable1024[], and should not be changed depending on the input
niklase@google.com470e71d2011-07-07 08:21:25 +000099 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
100 */
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000101 wr = kSinTable1024[j + 256];
102 wi = -kSinTable1024[j];
niklase@google.com470e71d2011-07-07 08:21:25 +0000103
kma@webrtc.org94771cb2012-08-28 04:09:50 +0000104#ifdef WEBRTC_ARCH_ARM_V7
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000105 int32_t wri = 0;
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000106 __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000107 "r"((int32_t)wr), "r"((int32_t)wi));
kma@google.com78dc99e2011-08-16 20:00:18 +0000108#endif
109
niklase@google.com470e71d2011-07-07 08:21:25 +0000110 for (i = m; i < n; i += istep)
111 {
112 j = i + l;
113
kma@webrtc.org94771cb2012-08-28 04:09:50 +0000114#ifdef WEBRTC_ARCH_ARM_V7
bjornv@webrtc.orgaafd7a82014-06-05 08:53:51 +0000115 register int32_t frfi_r;
116 __asm __volatile(
117 "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd],"
118 " lsl #16\n\t"
119 "smlsd %[tr32], %[wri], %[frfi_r], %[cfftrnd]\n\t"
120 "smladx %[ti32], %[wri], %[frfi_r], %[cfftrnd]\n\t"
121 :[frfi_r]"=&r"(frfi_r),
122 [tr32]"=&r"(tr32),
123 [ti32]"=r"(ti32)
124 :[frfi_even]"r"((int32_t)frfi[2*j]),
125 [frfi_odd]"r"((int32_t)frfi[2*j +1]),
126 [wri]"r"(wri),
127 [cfftrnd]"r"(CFFTRND));
kma@google.com78dc99e2011-08-16 20:00:18 +0000128#else
Bjorn Volckeraffcfb22015-04-24 08:12:07 +0200129 tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CFFTRND;
niklase@google.com470e71d2011-07-07 08:21:25 +0000130
Bjorn Volckeraffcfb22015-04-24 08:12:07 +0200131 ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CFFTRND;
kma@google.com78dc99e2011-08-16 20:00:18 +0000132#endif
133
bjornv@webrtc.orgf5670952014-10-29 10:29:16 +0000134 tr32 >>= 15 - CFFTSFT;
135 ti32 >>= 15 - CFFTSFT;
niklase@google.com470e71d2011-07-07 08:21:25 +0000136
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000137 qr32 = ((int32_t)frfi[2 * i]) << CFFTSFT;
138 qi32 = ((int32_t)frfi[2 * i + 1]) << CFFTSFT;
kma@google.com78dc99e2011-08-16 20:00:18 +0000139
bjornv@webrtc.orgf5670952014-10-29 10:29:16 +0000140 frfi[2 * j] = (int16_t)(
141 (qr32 - tr32 + CFFTRND2) >> (1 + CFFTSFT));
142 frfi[2 * j + 1] = (int16_t)(
143 (qi32 - ti32 + CFFTRND2) >> (1 + CFFTSFT));
144 frfi[2 * i] = (int16_t)(
145 (qr32 + tr32 + CFFTRND2) >> (1 + CFFTSFT));
146 frfi[2 * i + 1] = (int16_t)(
147 (qi32 + ti32 + CFFTRND2) >> (1 + CFFTSFT));
niklase@google.com470e71d2011-07-07 08:21:25 +0000148 }
149 }
150
151 --k;
152 l = istep;
153 }
154 }
155 return 0;
156}
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000157
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000158int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode)
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000159{
160 int i, j, l, k, istep, n, m, scale, shift;
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000161 int16_t wr, wi;
162 int32_t tr32, ti32, qr32, qi32;
163 int32_t tmp32, round2;
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000164
165 /* The 1024-value is a constant given from the size of kSinTable1024[],
166 * and should not be changed depending on the input parameter 'stages'
167 */
168 n = 1 << stages;
169 if (n > 1024)
170 return -1;
171
172 scale = 0;
173
174 l = 1;
175 k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change
176 depending on the input parameter 'stages' */
177
178 while (l < n)
179 {
180 // variable scaling, depending upon data
181 shift = 0;
182 round2 = 8192;
183
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000184 tmp32 = (int32_t)WebRtcSpl_MaxAbsValueW16(frfi, 2 * n);
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000185 if (tmp32 > 13573)
186 {
187 shift++;
188 scale++;
189 round2 <<= 1;
190 }
191 if (tmp32 > 27146)
192 {
193 shift++;
194 scale++;
195 round2 <<= 1;
196 }
197
198 istep = l << 1;
199
200 if (mode == 0)
201 {
202 // mode==0: Low-complexity and Low-accuracy mode
203 for (m = 0; m < l; ++m)
204 {
205 j = m << k;
206
207 /* The 256-value is a constant given as 1/4 of the size of
208 * kSinTable1024[], and should not be changed depending on the input
209 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
210 */
211 wr = kSinTable1024[j + 256];
212 wi = kSinTable1024[j];
213
214 for (i = m; i < n; i += istep)
215 {
216 j = i + l;
217
bjornv@webrtc.orgf5670952014-10-29 10:29:16 +0000218 tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15;
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000219
bjornv@webrtc.orgf5670952014-10-29 10:29:16 +0000220 ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15;
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000221
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000222 qr32 = (int32_t)frfi[2 * i];
223 qi32 = (int32_t)frfi[2 * i + 1];
bjornv@webrtc.orgf5670952014-10-29 10:29:16 +0000224 frfi[2 * j] = (int16_t)((qr32 - tr32) >> shift);
225 frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> shift);
226 frfi[2 * i] = (int16_t)((qr32 + tr32) >> shift);
227 frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> shift);
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000228 }
229 }
230 } else
231 {
232 // mode==1: High-complexity and High-accuracy mode
233
234 for (m = 0; m < l; ++m)
235 {
236 j = m << k;
237
238 /* The 256-value is a constant given as 1/4 of the size of
239 * kSinTable1024[], and should not be changed depending on the input
240 * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
241 */
242 wr = kSinTable1024[j + 256];
243 wi = kSinTable1024[j];
244
kma@webrtc.org94771cb2012-08-28 04:09:50 +0000245#ifdef WEBRTC_ARCH_ARM_V7
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000246 int32_t wri = 0;
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000247 __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000248 "r"((int32_t)wr), "r"((int32_t)wi));
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000249#endif
250
251 for (i = m; i < n; i += istep)
252 {
253 j = i + l;
254
kma@webrtc.org94771cb2012-08-28 04:09:50 +0000255#ifdef WEBRTC_ARCH_ARM_V7
bjornv@webrtc.orgaafd7a82014-06-05 08:53:51 +0000256 register int32_t frfi_r;
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000257 __asm __volatile(
258 "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd], lsl #16\n\t"
259 "smlsd %[tr32], %[wri], %[frfi_r], %[cifftrnd]\n\t"
260 "smladx %[ti32], %[wri], %[frfi_r], %[cifftrnd]\n\t"
bjornv@webrtc.orgaafd7a82014-06-05 08:53:51 +0000261 :[frfi_r]"=&r"(frfi_r),
262 [tr32]"=&r"(tr32),
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000263 [ti32]"=r"(ti32)
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000264 :[frfi_even]"r"((int32_t)frfi[2*j]),
265 [frfi_odd]"r"((int32_t)frfi[2*j +1]),
kma@webrtc.org7d6f1132013-03-01 23:01:14 +0000266 [wri]"r"(wri),
267 [cifftrnd]"r"(CIFFTRND)
268 );
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000269#else
270
Bjorn Volckeraffcfb22015-04-24 08:12:07 +0200271 tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CIFFTRND;
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000272
Bjorn Volckeraffcfb22015-04-24 08:12:07 +0200273 ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CIFFTRND;
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000274#endif
bjornv@webrtc.orgf5670952014-10-29 10:29:16 +0000275 tr32 >>= 15 - CIFFTSFT;
276 ti32 >>= 15 - CIFFTSFT;
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000277
pbos@webrtc.orgb0913072013-04-09 16:40:28 +0000278 qr32 = ((int32_t)frfi[2 * i]) << CIFFTSFT;
279 qi32 = ((int32_t)frfi[2 * i + 1]) << CIFFTSFT;
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000280
bjornv@webrtc.orgf5670952014-10-29 10:29:16 +0000281 frfi[2 * j] = (int16_t)(
282 (qr32 - tr32 + round2) >> (shift + CIFFTSFT));
283 frfi[2 * j + 1] = (int16_t)(
284 (qi32 - ti32 + round2) >> (shift + CIFFTSFT));
285 frfi[2 * i] = (int16_t)(
286 (qr32 + tr32 + round2) >> (shift + CIFFTSFT));
287 frfi[2 * i + 1] = (int16_t)(
288 (qi32 + ti32 + round2) >> (shift + CIFFTSFT));
bjornv@webrtc.org132feb12011-12-01 15:40:50 +0000289 }
290 }
291
292 }
293 --k;
294 l = istep;
295 }
296 return scale;
297}