comparison data/fft/FFTapi.cpp @ 226:a867be73b638

* Add non-fftw3 fft alternative
author Chris Cannam
date Fri, 09 Feb 2007 11:32:34 +0000
parents
children e919a2b97c2a
comparison
equal deleted inserted replaced
225:185454896a76 226:a867be73b638
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Sonic Visualiser
5 An audio file viewer and annotation editor.
6 Centre for Digital Music, Queen Mary, University of London.
7 This file copyright 2006 Chris Cannam and QMUL.
8 FFT code from Don Cross's public domain FFT implementation.
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of the
13 License, or (at your option) any later version. See the file
14 COPYING included with this distribution for more information.
15 */
16
17 #include "FFTapi.h"
18
19 #ifndef HAVE_FFTW3F
20
21 #include <cmath>
22
23 void
24 fft(unsigned int n, bool inverse, double *ri, double *ii, double *ro, double *io)
25 {
26 if (!ri || !ro || !io) return;
27
28 unsigned int bits;
29 unsigned int i, j, k, m;
30 unsigned int blockSize, blockEnd;
31
32 double tr, ti;
33
34 if (n < 2) return;
35 if (n & (n-1)) return;
36
37 double angle = 2.0 * M_PI;
38 if (inverse) angle = -angle;
39
40 for (i = 0; ; ++i) {
41 if (n & (1 << i)) {
42 bits = i;
43 break;
44 }
45 }
46
47 static unsigned int tableSize = 0;
48 static int *table = 0;
49
50 if (tableSize != n) {
51
52 delete[] table;
53
54 table = new int[n];
55
56 for (i = 0; i < n; ++i) {
57
58 m = i;
59
60 for (j = k = 0; j < bits; ++j) {
61 k = (k << 1) | (m & 1);
62 m >>= 1;
63 }
64
65 table[i] = k;
66 }
67
68 tableSize = n;
69 }
70
71 if (ii) {
72 for (i = 0; i < n; ++i) {
73 ro[table[i]] = ri[i];
74 io[table[i]] = ii[i];
75 }
76 } else {
77 for (i = 0; i < n; ++i) {
78 ro[table[i]] = ri[i];
79 io[table[i]] = 0.0;
80 }
81 }
82
83 blockEnd = 1;
84
85 for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
86
87 double delta = angle / (double)blockSize;
88 double sm2 = -sin(-2 * delta);
89 double sm1 = -sin(-delta);
90 double cm2 = cos(-2 * delta);
91 double cm1 = cos(-delta);
92 double w = 2 * cm1;
93 double ar[3], ai[3];
94
95 for (i = 0; i < n; i += blockSize) {
96
97 ar[2] = cm2;
98 ar[1] = cm1;
99
100 ai[2] = sm2;
101 ai[1] = sm1;
102
103 for (j = i, m = 0; m < blockEnd; j++, m++) {
104
105 ar[0] = w * ar[1] - ar[2];
106 ar[2] = ar[1];
107 ar[1] = ar[0];
108
109 ai[0] = w * ai[1] - ai[2];
110 ai[2] = ai[1];
111 ai[1] = ai[0];
112
113 k = j + blockEnd;
114 tr = ar[0] * ro[k] - ai[0] * io[k];
115 ti = ar[0] * io[k] + ai[0] * ro[k];
116
117 ro[k] = ro[j] - tr;
118 io[k] = io[j] - ti;
119
120 ro[j] += tr;
121 io[j] += ti;
122 }
123 }
124
125 blockEnd = blockSize;
126 }
127
128 if (inverse) {
129
130 double denom = (double)n;
131
132 for (i = 0; i < n; i++) {
133 ro[i] /= denom;
134 io[i] /= denom;
135 }
136 }
137 }
138
139 struct fftf_plan_ {
140 int size;
141 int inverse;
142 float *real;
143 fftf_complex *cplx;
144 };
145
146 fftf_plan
147 fftf_plan_dft_r2c_1d(int n, float *in, fftf_complex *out, unsigned)
148 {
149 if (n < 2) return 0;
150 if (n & (n-1)) return 0;
151
152 fftf_plan_ *plan = new fftf_plan_;
153 plan->size = n;
154 plan->inverse = 0;
155 plan->real = in;
156 plan->cplx = out;
157 return plan;
158 }
159
160 fftf_plan
161 fftf_plan_dft_c2r_1d(int n, fftf_complex *in, float *out, unsigned)
162 {
163 if (n < 2) return 0;
164 if (n & (n-1)) return 0;
165
166 fftf_plan_ *plan = new fftf_plan_;
167 plan->size = n;
168 plan->inverse = 1;
169 plan->real = out;
170 plan->cplx = in;
171 return plan;
172 }
173
174 void
175 fftf_destroy_plan(fftf_plan p)
176 {
177 delete p;
178 }
179
180 void
181 fftf_execute(const fftf_plan p)
182 {
183 //!!! doesn't work yet for inverse transforms
184
185 float *real = p->real;
186 fftf_complex *cplx = p->cplx;
187 int n = p->size;
188 int inv = p->inverse;
189
190 double *ri = new double[n];
191 double *ro = new double[n];
192 double *io = new double[n];
193
194 double *ii = 0;
195 if (inv) ii = new double[n];
196
197 if (!inv) {
198 for (int i = 0; i < n; ++i) {
199 ri[i] = real[i];
200 }
201 } else {
202 for (int i = 0; i < n/2+1; ++i) {
203 ri[i] = cplx[i][0];
204 ii[i] = cplx[i][1];
205 if (i > 0) {
206 ri[n-i] = ri[i];
207 ii[n-i] = -ii[i];
208 }
209 }
210 }
211
212 fft(n, inv, ri, ii, ro, io);
213
214 if (!inv) {
215 for (int i = 0; i < n/2+1; ++i) {
216 cplx[i][0] = ro[i];
217 cplx[i][1] = io[i];
218 }
219 } else {
220 for (int i = 0; i < n; ++i) {
221 real[i] = ro[i];
222 }
223 }
224
225 delete[] ri;
226 delete[] ro;
227 delete[] io;
228 delete[] ii;
229 }
230
231 #endif