xoreos  0.0.5
fft.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 /* Based on the (I)FFT code in FFmpeg (<https://ffmpeg.org/)>, which
26  * is released under the terms of version 2 or later of the GNU Lesser
27  * General Public License.
28  *
29  * The original copyright note in libavcodec/fft_template.c reads as follows:
30  *
31  * FFT/IFFT transforms
32  * Copyright (c) 2008 Loren Merritt
33  * Copyright (c) 2002 Fabrice Bellard
34  * Partly based on libdjbfft by D. J. Bernstein
35  *
36  * This file is part of FFmpeg.
37  *
38  * FFmpeg is free software; you can redistribute it and/or
39  * modify it under the terms of the GNU Lesser General Public
40  * License as published by the Free Software Foundation; either
41  * version 2.1 of the License, or (at your option) any later version.
42  *
43  * FFmpeg is distributed in the hope that it will be useful,
44  * but WITHOUT ANY WARRANTY; without even the implied warranty of
45  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
46  * Lesser General Public License for more details.
47  *
48  * You should have received a copy of the GNU Lesser General Public
49  * License along with FFmpeg; if not, write to the Free Software
50  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
51  */
52 
53 #include <cassert>
54 #include <cstring>
55 
56 #include "src/common/maths.h"
58 #include "src/common/util.h"
59 #include "src/common/fft.h"
60 
61 namespace Common {
62 
63 FFT::FFT(int bits, bool inverse) : _bits(bits), _inverse(inverse) {
64  assert((_bits >= 2) && (_bits <= 16));
65 
66  int n = 1 << bits;
67 
68  _tmpBuf.reset(new Complex[n]);
69  _expTab.reset(new Complex[n / 2]);
70  _revTab.reset(new uint16[n]);
71 
72  for (int i = 0; i < n; i++)
73  _revTab[-splitRadixPermutation(i, n, _inverse) & (n - 1)] = i;
74 }
75 
77 }
78 
79 const uint16 *FFT::getRevTab() const {
80  return _revTab.get();
81 }
82 
84  int np = 1 << _bits;
85 
86  if (_tmpBuf) {
87  for (int j = 0; j < np; j++)
88  _tmpBuf[_revTab[j]] = z[j];
89 
90  std::memcpy(z, _tmpBuf.get(), np * sizeof(Complex));
91 
92  return;
93  }
94 
95  // Reverse
96  for (int j = 0; j < np; j++) {
97  int k = _revTab[j];
98 
99  if (k < j)
100  SWAP(z[k], z[j]);
101  }
102 }
103 
104 int FFT::splitRadixPermutation(int i, int n, bool inverse) {
105  if (n <= 2)
106  return i & 1;
107 
108  int m = n >> 1;
109 
110  if (!(i & m))
111  return splitRadixPermutation(i, m, inverse) * 2;
112 
113  m >>= 1;
114 
115  if (inverse == !(i & m))
116  return splitRadixPermutation(i, m, inverse) * 4 + 1;
117 
118  return splitRadixPermutation(i, m, inverse) * 4 - 1;
119 }
120 
121 #define sqrthalf (float)M_SQRT1_2
122 
123 #define BF(x,y,a,b) {\
124  x = a - b;\
125  y = a + b;\
126 }
127 
128 #define BUTTERFLIES(a0,a1,a2,a3) {\
129  BF(t3, t5, t5, t1);\
130  BF(a2.re, a0.re, a0.re, t5);\
131  BF(a3.im, a1.im, a1.im, t3);\
132  BF(t4, t6, t2, t6);\
133  BF(a3.re, a1.re, a1.re, t4);\
134  BF(a2.im, a0.im, a0.im, t6);\
135 }
136 
137 // force loading all the inputs before storing any.
138 // this is slightly slower for small data, but avoids store->load aliasing
139 // for addresses separated by large powers of 2.
140 #define BUTTERFLIES_BIG(a0,a1,a2,a3) {\
141  float r0=a0.re, i0=a0.im, r1=a1.re, i1=a1.im;\
142  BF(t3, t5, t5, t1);\
143  BF(a2.re, a0.re, r0, t5);\
144  BF(a3.im, a1.im, i1, t3);\
145  BF(t4, t6, t2, t6);\
146  BF(a3.re, a1.re, r1, t4);\
147  BF(a2.im, a0.im, i0, t6);\
148 }
149 
150 #define TRANSFORM(a0,a1,a2,a3,wre,wim) {\
151  t1 = a2.re * wre + a2.im * wim;\
152  t2 = a2.im * wre - a2.re * wim;\
153  t5 = a3.re * wre - a3.im * wim;\
154  t6 = a3.im * wre + a3.re * wim;\
155  BUTTERFLIES(a0,a1,a2,a3)\
156 }
157 
158 #define TRANSFORM_ZERO(a0,a1,a2,a3) {\
159  t1 = a2.re;\
160  t2 = a2.im;\
161  t5 = a3.re;\
162  t6 = a3.im;\
163  BUTTERFLIES(a0,a1,a2,a3)\
164 }
165 
166 /* z[0...8n-1], w[1...2n-1] */
167 #define PASS(name)\
168 static void name(Complex *z, const float *wre, unsigned int n)\
169 {\
170  float t1, t2, t3, t4, t5, t6;\
171  int o1 = 2*n;\
172  int o2 = 4*n;\
173  int o3 = 6*n;\
174  const float *wim = wre+o1;\
175  n--;\
176 \
177  TRANSFORM_ZERO(z[0],z[o1],z[o2],z[o3]);\
178  TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\
179  do {\
180  z += 2;\
181  wre += 2;\
182  wim -= 2;\
183  TRANSFORM(z[0],z[o1],z[o2],z[o3],wre[0],wim[0]);\
184  TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\
185  } while (--n);\
186 }
187 
189 #undef BUTTERFLIES
190 #define BUTTERFLIES BUTTERFLIES_BIG
192 
193 #define DECL_FFT(t,n,n2,n4)\
194 static void fft##n(Complex *z)\
195 {\
196  fft##n2(z);\
197  fft##n4(z+n4*2);\
198  fft##n4(z+n4*3);\
199  pass(z,getCosineTable(t),n4/2);\
200 }
201 
202 static void fft4(Complex *z)
203 {
204  float t1, t2, t3, t4, t5, t6, t7, t8;
205 
206  BF(t3, t1, z[0].re, z[1].re);
207  BF(t8, t6, z[3].re, z[2].re);
208  BF(z[2].re, z[0].re, t1, t6);
209  BF(t4, t2, z[0].im, z[1].im);
210  BF(t7, t5, z[2].im, z[3].im);
211  BF(z[3].im, z[1].im, t4, t8);
212  BF(z[3].re, z[1].re, t3, t7);
213  BF(z[2].im, z[0].im, t2, t5);
214 }
215 
216 static void fft8(Complex *z)
217 {
218  float t1, t2, t3, t4, t5, t6, t7, t8;
219 
220  fft4(z);
221 
222  BF(t1, z[5].re, z[4].re, -z[5].re);
223  BF(t2, z[5].im, z[4].im, -z[5].im);
224  BF(t3, z[7].re, z[6].re, -z[7].re);
225  BF(t4, z[7].im, z[6].im, -z[7].im);
226  BF(t8, t1, t3, t1);
227  BF(t7, t2, t2, t4);
228  BF(z[4].re, z[0].re, z[0].re, t1);
229  BF(z[4].im, z[0].im, z[0].im, t2);
230  BF(z[6].re, z[2].re, z[2].re, t7);
231  BF(z[6].im, z[2].im, z[2].im, t8);
232 
233  TRANSFORM(z[1],z[3],z[5],z[7],sqrthalf,sqrthalf);
234 }
235 
236 static void fft16(Complex *z)
237 {
238  float t1, t2, t3, t4, t5, t6;
239 
240  fft8(z);
241  fft4(z+8);
242  fft4(z+12);
243 
244  const float * const cosTable = getCosineTable(4);
245 
246  TRANSFORM_ZERO(z[0],z[4],z[8],z[12]);
247  TRANSFORM(z[2],z[6],z[10],z[14],sqrthalf,sqrthalf);
248  TRANSFORM(z[1],z[5],z[9],z[13],cosTable[1],cosTable[3]);
249  TRANSFORM(z[3],z[7],z[11],z[15],cosTable[3],cosTable[1]);
250 }
251 
252 DECL_FFT(5, 32,16,8)
253 DECL_FFT(6, 64,32,16)
254 DECL_FFT(7, 128,64,32)
255 DECL_FFT(8, 256,128,64)
256 DECL_FFT(9, 512,256,128)
257 #define pass pass_big
258 DECL_FFT(10, 1024,512,256)
259 DECL_FFT(11, 2048,1024,512)
260 DECL_FFT(12, 4096,2048,1024)
261 DECL_FFT(13, 8192,4096,2048)
262 DECL_FFT(14, 16384,8192,4096)
263 DECL_FFT(15, 32768,16384,8192)
264 DECL_FFT(16, 65536,32768,16384)
265 
266 static void (* const fft_dispatch[])(Complex*) = {
269 };
270 
271 void FFT::calc(Complex *z) {
272  fft_dispatch[_bits - 2](z);
273 }
274 
275 } // End of namespace Common
~FFT()
Definition: fft.cpp:76
A complex number.
Definition: maths.h:61
static void fft4(Complex *z)
Definition: fft.cpp:202
static void pass(Complex *z, const float *wre, unsigned int n)
Definition: fft.cpp:188
Definition: 2dafile.h:39
static void fft8(Complex *z)
Definition: fft.cpp:216
ScopedArray< Complex > _expTab
Definition: fft.h:89
const uint16 * getRevTab() const
Definition: fft.cpp:79
static void fft64(Complex *z)
Definition: fft.cpp:253
void reset(PointerType o=0)
Resets the pointer with the new value.
Definition: scopedptr.h:87
Mathematical helpers.
static void fft128(Complex *z)
Definition: fft.cpp:254
static void(*const fft_dispatch[])(Complex *)
Definition: fft.cpp:266
#define sqrthalf
Definition: fft.cpp:121
uint16_t uint16
Definition: types.h:202
Utility templates and functions.
#define TRANSFORM(a0, a1, a2, a3, wre, wim)
Definition: fft.cpp:150
#define TRANSFORM_ZERO(a0, a1, a2, a3)
Definition: fft.cpp:158
static void fft8192(Complex *z)
Definition: fft.cpp:261
static void fft2048(Complex *z)
Definition: fft.cpp:259
static void fft32(Complex *z)
Definition: fft.cpp:252
ScopedArray< uint16 > _revTab
Definition: fft.h:87
void permute(Complex *z)
Do the permutation needed BEFORE calling calc().
Definition: fft.cpp:83
void calc(Complex *z)
Do a complex FFT.
Definition: fft.cpp:271
static void fft32768(Complex *z)
Definition: fft.cpp:263
#define BF(x, y, a, b)
Definition: fft.cpp:123
static void fft65536(Complex *z)
Definition: fft.cpp:264
ScopedArray< Complex > _tmpBuf
Definition: fft.h:90
PointerType get() const
Returns the plain pointer value.
Definition: scopedptr.h:96
FFT(int bits, bool inverse)
Definition: fft.cpp:63
#define PASS(name)
Definition: fft.cpp:167
bool _inverse
Definition: fft.h:85
static void fft512(Complex *z)
Definition: fft.cpp:256
static void fft1024(Complex *z)
Definition: fft.cpp:258
static glm::mat4 inverse(const glm::mat4 &m)
Definition: graphics.cpp:1363
static int splitRadixPermutation(int i, int n, bool inverse)
Definition: fft.cpp:104
int _bits
Definition: fft.h:84
static void fft256(Complex *z)
Definition: fft.cpp:255
const float * getCosineTable(int bits)
static void fft16(Complex *z)
Definition: fft.cpp:236
#define DECL_FFT(t, n, n2, n4)
Definition: fft.cpp:193
(Inverse) Fast Fourier Transform.
static void fft16384(Complex *z)
Definition: fft.cpp:262
static void fft4096(Complex *z)
Definition: fft.cpp:260
Static cosine tables.
void SWAP(T &a, T &b)
Template method which swaps the values of its two parameters.
Definition: util.h:78
static void pass_big(Complex *z, const float *wre, unsigned int n)
Definition: fft.cpp:191