Chris@25
|
1 <%= $:.unshift('.'); require "#{File.dirname(__FILE__)}/../src/complex.rb"; File.read "#{File.dirname(__FILE__)}/../LICENSE" %>
|
Chris@25
|
2
|
Chris@25
|
3 if (!FFT) {
|
Chris@25
|
4 var FFT = {}
|
Chris@25
|
5 }
|
Chris@25
|
6
|
Chris@25
|
7 void function (namespace) {
|
Chris@25
|
8 "use strict"
|
Chris@25
|
9
|
Chris@25
|
10 function forwardButterfly2(output, outputOffset, outputStride, input, inputOffset, inputStride, product, n, twiddle, fStride) {
|
Chris@25
|
11 var m = n / 2, q = n / product, old = product / 2
|
Chris@25
|
12
|
Chris@25
|
13 for (var i = 0; i < q; i++) {
|
Chris@25
|
14 var a0 = old * i
|
Chris@25
|
15 var a1 = a0 + m
|
Chris@25
|
16
|
Chris@25
|
17 var s0 = input[inputOffset + inputStride * a0]
|
Chris@25
|
18 var s1 = input[inputOffset + inputStride * a1]
|
Chris@25
|
19
|
Chris@25
|
20 var r0 = s0 + s1
|
Chris@25
|
21 var r1 = s0 - s1
|
Chris@25
|
22
|
Chris@25
|
23 var a0 = product * i
|
Chris@25
|
24 var a1 = a0 + product - 1
|
Chris@25
|
25
|
Chris@25
|
26 output[outputOffset + outputStride * a0] = r0
|
Chris@25
|
27 output[outputOffset + outputStride * a1] = r1
|
Chris@25
|
28 }
|
Chris@25
|
29
|
Chris@25
|
30 if (old == 1) { return }
|
Chris@25
|
31
|
Chris@25
|
32 for (var i = 0; i < old / 2; i++) {
|
Chris@25
|
33 <%= load('t1', 'twiddle', -1, 'i') %>
|
Chris@25
|
34
|
Chris@25
|
35 for (var j = 0; j < q; j++) {
|
Chris@25
|
36 var a0 = j * old + 2 * i - 1
|
Chris@25
|
37 var a1 = a0 + m
|
Chris@25
|
38
|
Chris@25
|
39 <%= load('s0', 'input', 'inputOffset', 'a0', 'inputStride') %>
|
Chris@25
|
40
|
Chris@25
|
41 <%= load('s1', 'input', 'inputOffset', 'a1', 'inputStride') %>
|
Chris@25
|
42 <%= cmul('v1', 's1', 't1') %>
|
Chris@25
|
43
|
Chris@25
|
44 <%= cadd('r0', 's0', 'v1') %>
|
Chris@25
|
45 <%= csub('r1', 's0', 'v1') %>; r1_i = -r1_i
|
Chris@25
|
46
|
Chris@25
|
47 var a0 = j * product + 2 * i - 1
|
Chris@25
|
48 var a1 = (j - 1) * product - 2 * i - 1
|
Chris@25
|
49
|
Chris@25
|
50 <%= store('r0', 'output', 'outputOffset', 'a0', 'outputStride') %>
|
Chris@25
|
51 <%= store('r1', 'output', 'outputOffset', 'a1', 'outputStride') %>
|
Chris@25
|
52 }
|
Chris@25
|
53 }
|
Chris@25
|
54
|
Chris@25
|
55 if (old % 2 == 1) { return }
|
Chris@25
|
56
|
Chris@25
|
57 for (var i = 0; i < q; i++) {
|
Chris@25
|
58 var a0 = (i + 1) * old - 1
|
Chris@25
|
59 var a1 = a0 + m
|
Chris@25
|
60
|
Chris@25
|
61 var r0_r = <%= real('input', 'inputOffset', 'a0', 'inputStride') %>
|
Chris@25
|
62 var r1_i = -<%= real('input', 'inputOffset', 'a1', 'inputStride') %>
|
Chris@25
|
63
|
Chris@25
|
64 var a0 = i * product + old - 1
|
Chris@25
|
65
|
Chris@25
|
66 <%= store('r0', 'output', 'outputOffset', 'a0', 'outputStride') %>
|
Chris@25
|
67 }
|
Chris@25
|
68 }
|
Chris@25
|
69
|
Chris@25
|
70 function forwardButterfly(output, outputOffset, outputStride, input, inputOffset, inputStride, product, n, twiddle, fStride, factor) {
|
Chris@25
|
71 var m = n / 2, q = n / product, old = product / 2
|
Chris@25
|
72
|
Chris@25
|
73 var theta = 2.0 * Math.PI / factor
|
Chris@25
|
74
|
Chris@25
|
75 var theta_r = Math.cos(theta)
|
Chris@25
|
76 var theta_i = -Math.sin(theta)
|
Chris@25
|
77
|
Chris@25
|
78 for (var i = 0; i < q; i++) {
|
Chris@25
|
79 var d_r = 1.0
|
Chris@25
|
80 var d_i = 0.0
|
Chris@25
|
81
|
Chris@25
|
82 for (var j = 0; j <= Math.floor(factor / 2); j++) {
|
Chris@25
|
83 var sum_r = 0.0
|
Chris@25
|
84 var sum_i = 0.0
|
Chris@25
|
85
|
Chris@25
|
86 var w_r = 1.0
|
Chris@25
|
87 var w_i = 0.0
|
Chris@25
|
88
|
Chris@25
|
89 if (j > 0) {
|
Chris@25
|
90 <%= cmul('t0', 'd', 'theta') %>
|
Chris@25
|
91
|
Chris@25
|
92 d_r = t0_r
|
Chris@25
|
93 d_i = t0_i
|
Chris@25
|
94 }
|
Chris@25
|
95
|
Chris@25
|
96 for (var k = 0; k < factor; k++) {
|
Chris@25
|
97 var z = <%= real('input', 'inputOffset', 'i * old + k * m', 'inputStride') %>
|
Chris@25
|
98
|
Chris@25
|
99 if (k > 0) {
|
Chris@25
|
100 <%= cmul('t0', 'd', 'w') %>
|
Chris@25
|
101
|
Chris@25
|
102 d_r = t0_r
|
Chris@25
|
103 d_i = t0_i
|
Chris@25
|
104 }
|
Chris@25
|
105
|
Chris@25
|
106 /* TODO: Use Kahan summation..? */
|
Chris@25
|
107 s_r += w_r * z
|
Chris@25
|
108 s_i += w_i * z
|
Chris@25
|
109 }
|
Chris@25
|
110
|
Chris@25
|
111 if (j == 0) {
|
Chris@25
|
112 var a0 = product * i
|
Chris@25
|
113
|
Chris@25
|
114 output[outputOffset + outputStride * a0] = sum_r
|
Chris@25
|
115 } else if (j < factor / 2) {
|
Chris@25
|
116 var a0 = product * i
|
Chris@25
|
117
|
Chris@25
|
118 output[outputOffset + outputStride * a0] = sum_r
|
Chris@25
|
119 } else if (j == factor / 2) {
|
Chris@25
|
120
|
Chris@25
|
121 }
|
Chris@25
|
122 }
|
Chris@25
|
123 for (e1 = 0; e1 <= factor - e1; e1++)
|
Chris@25
|
124 {
|
Chris@25
|
125 if (e1 == 0)
|
Chris@25
|
126 {
|
Chris@25
|
127 const size_t to0 = product * k1;
|
Chris@25
|
128 VECTOR(out,ostride,to0) = sum_real;
|
Chris@25
|
129 }
|
Chris@25
|
130 else if (e1 < factor - e1)
|
Chris@25
|
131 {
|
Chris@25
|
132 const size_t to0 = k1 * product + 2 * e1 * product_1 - 1;
|
Chris@25
|
133 VECTOR(out,ostride,to0) = sum_real;
|
Chris@25
|
134 VECTOR(out,ostride,to0 + 1) = sum_imag;
|
Chris@25
|
135 }
|
Chris@25
|
136 else if (e1 == factor - e1)
|
Chris@25
|
137 {
|
Chris@25
|
138 const size_t to0 = k1 * product + 2 * e1 * product_1 - 1;
|
Chris@25
|
139 VECTOR(out,ostride,to0) = sum_real;
|
Chris@25
|
140 }
|
Chris@25
|
141
|
Chris@25
|
142 }
|
Chris@25
|
143
|
Chris@25
|
144 }
|
Chris@25
|
145
|
Chris@25
|
146 if (old == 1) { return }
|
Chris@25
|
147
|
Chris@25
|
148 for (var i = 0; i < old / 2; i++) {
|
Chris@25
|
149
|
Chris@25
|
150 }
|
Chris@25
|
151
|
Chris@25
|
152 if (old % 2 == 1) { return }
|
Chris@25
|
153
|
Chris@25
|
154 var t_arg = Math.PI / factor
|
Chris@25
|
155
|
Chris@25
|
156 var t_r = cos(t_arg)
|
Chris@25
|
157 var t_i = -sin(t_arg)
|
Chris@25
|
158
|
Chris@25
|
159 for (var i = 0; i < q; i++) {
|
Chris@25
|
160
|
Chris@25
|
161 }
|
Chris@25
|
162 }
|
Chris@25
|
163
|
Chris@25
|
164 if (product_1 == 1)
|
Chris@25
|
165 return;
|
Chris@25
|
166
|
Chris@25
|
167 for (k = 1; k < (product_1 + 1) / 2; k++)
|
Chris@25
|
168 {
|
Chris@25
|
169 for (k1 = 0; k1 < q; k1++)
|
Chris@25
|
170 {
|
Chris@25
|
171
|
Chris@25
|
172 ATOMIC dw_real = 1.0, dw_imag = 0.0;
|
Chris@25
|
173
|
Chris@25
|
174 for (e1 = 0; e1 < factor; e1++)
|
Chris@25
|
175 {
|
Chris@25
|
176 ATOMIC sum_real = 0.0, sum_imag = 0.0;
|
Chris@25
|
177
|
Chris@25
|
178 ATOMIC w_real = 1.0, w_imag = 0.0;
|
Chris@25
|
179
|
Chris@25
|
180 if (e1 > 0)
|
Chris@25
|
181 {
|
Chris@25
|
182 const ATOMIC tmp_real = dw_real * cos_d_theta + dw_imag * sin_d_theta;
|
Chris@25
|
183 const ATOMIC tmp_imag = -dw_real * sin_d_theta + dw_imag * cos_d_theta;
|
Chris@25
|
184 dw_real = tmp_real;
|
Chris@25
|
185 dw_imag = tmp_imag;
|
Chris@25
|
186 }
|
Chris@25
|
187
|
Chris@25
|
188 for (e2 = 0; e2 < factor; e2++)
|
Chris@25
|
189 {
|
Chris@25
|
190
|
Chris@25
|
191 int tskip = (product_1 + 1) / 2 - 1;
|
Chris@25
|
192 const size_t from0 = k1 * product_1 + 2 * k + e2 * m - 1;
|
Chris@25
|
193 ATOMIC tw_real, tw_imag;
|
Chris@25
|
194 ATOMIC z_real, z_imag;
|
Chris@25
|
195
|
Chris@25
|
196 if (e2 == 0)
|
Chris@25
|
197 {
|
Chris@25
|
198 tw_real = 1.0;
|
Chris@25
|
199 tw_imag = 0.0;
|
Chris@25
|
200 }
|
Chris@25
|
201 else
|
Chris@25
|
202 {
|
Chris@25
|
203 const size_t t_index = (k - 1) + (e2 - 1) * tskip;
|
Chris@25
|
204 tw_real = GSL_REAL(twiddle[t_index]);
|
Chris@25
|
205 tw_imag = -GSL_IMAG(twiddle[t_index]);
|
Chris@25
|
206 }
|
Chris@25
|
207
|
Chris@25
|
208 {
|
Chris@25
|
209 const ATOMIC f0_real = VECTOR(in,istride,from0);
|
Chris@25
|
210 const ATOMIC f0_imag = VECTOR(in,istride,from0 + 1);
|
Chris@25
|
211
|
Chris@25
|
212 z_real = tw_real * f0_real - tw_imag * f0_imag;
|
Chris@25
|
213 z_imag = tw_real * f0_imag + tw_imag * f0_real;
|
Chris@25
|
214 }
|
Chris@25
|
215
|
Chris@25
|
216 if (e2 > 0)
|
Chris@25
|
217 {
|
Chris@25
|
218 const ATOMIC tmp_real = dw_real * w_real - dw_imag * w_imag;
|
Chris@25
|
219 const ATOMIC tmp_imag = dw_real * w_imag + dw_imag * w_real;
|
Chris@25
|
220 w_real = tmp_real;
|
Chris@25
|
221 w_imag = tmp_imag;
|
Chris@25
|
222 }
|
Chris@25
|
223
|
Chris@25
|
224 sum_real += w_real * z_real - w_imag * z_imag;
|
Chris@25
|
225 sum_imag += w_real * z_imag + w_imag * z_real;
|
Chris@25
|
226 }
|
Chris@25
|
227
|
Chris@25
|
228 if (e1 < factor - e1)
|
Chris@25
|
229 {
|
Chris@25
|
230 const size_t to0 = k1 * product - 1 + 2 * e1 * product_1 + 2 * k;
|
Chris@25
|
231 VECTOR(out,ostride,to0) = sum_real;
|
Chris@25
|
232 VECTOR(out,ostride,to0 + 1) = sum_imag;
|
Chris@25
|
233 }
|
Chris@25
|
234 else
|
Chris@25
|
235 {
|
Chris@25
|
236 const size_t to0 = k1 * product - 1 + 2 * (factor - e1) * product_1 - 2 * k;
|
Chris@25
|
237 VECTOR(out,ostride,to0) = sum_real;
|
Chris@25
|
238 VECTOR(out,ostride,to0 + 1) = -sum_imag;
|
Chris@25
|
239 }
|
Chris@25
|
240
|
Chris@25
|
241 }
|
Chris@25
|
242 }
|
Chris@25
|
243 }
|
Chris@25
|
244
|
Chris@25
|
245
|
Chris@25
|
246 if (product_1 % 2 == 1)
|
Chris@25
|
247 return;
|
Chris@25
|
248
|
Chris@25
|
249 {
|
Chris@25
|
250 double tw_arg = M_PI / ((double) factor);
|
Chris@25
|
251 ATOMIC cos_tw_arg = cos (tw_arg);
|
Chris@25
|
252 ATOMIC sin_tw_arg = -sin (tw_arg);
|
Chris@25
|
253
|
Chris@25
|
254 for (k1 = 0; k1 < q; k1++)
|
Chris@25
|
255 {
|
Chris@25
|
256 ATOMIC dw_real = 1.0, dw_imag = 0.0;
|
Chris@25
|
257
|
Chris@25
|
258 for (e1 = 0; e1 < factor; e1++)
|
Chris@25
|
259 {
|
Chris@25
|
260 ATOMIC z_real, z_imag;
|
Chris@25
|
261
|
Chris@25
|
262 ATOMIC sum_real = 0.0;
|
Chris@25
|
263 ATOMIC sum_imag = 0.0;
|
Chris@25
|
264
|
Chris@25
|
265 ATOMIC w_real = 1.0, w_imag = 0.0;
|
Chris@25
|
266 ATOMIC tw_real = 1.0, tw_imag = 0.0;
|
Chris@25
|
267
|
Chris@25
|
268 if (e1 > 0)
|
Chris@25
|
269 {
|
Chris@25
|
270 ATOMIC t_real = dw_real * cos_d_theta + dw_imag * sin_d_theta;
|
Chris@25
|
271 ATOMIC t_imag = -dw_real * sin_d_theta + dw_imag * cos_d_theta;
|
Chris@25
|
272 dw_real = t_real;
|
Chris@25
|
273 dw_imag = t_imag;
|
Chris@25
|
274 }
|
Chris@25
|
275
|
Chris@25
|
276 for (e2 = 0; e2 < factor; e2++)
|
Chris@25
|
277 {
|
Chris@25
|
278
|
Chris@25
|
279 if (e2 > 0)
|
Chris@25
|
280 {
|
Chris@25
|
281 ATOMIC tmp_real = tw_real * cos_tw_arg - tw_imag * sin_tw_arg;
|
Chris@25
|
282 ATOMIC tmp_imag = tw_real * sin_tw_arg + tw_imag * cos_tw_arg;
|
Chris@25
|
283 tw_real = tmp_real;
|
Chris@25
|
284 tw_imag = tmp_imag;
|
Chris@25
|
285 }
|
Chris@25
|
286
|
Chris@25
|
287 if (e2 > 0)
|
Chris@25
|
288 {
|
Chris@25
|
289 ATOMIC tmp_real = dw_real * w_real - dw_imag * w_imag;
|
Chris@25
|
290 ATOMIC tmp_imag = dw_real * w_imag + dw_imag * w_real;
|
Chris@25
|
291 w_real = tmp_real;
|
Chris@25
|
292 w_imag = tmp_imag;
|
Chris@25
|
293 }
|
Chris@25
|
294
|
Chris@25
|
295
|
Chris@25
|
296 {
|
Chris@25
|
297 const size_t from0 = k1 * product_1 + 2 * k + e2 * m - 1;
|
Chris@25
|
298 const ATOMIC f0_real = VECTOR(in,istride,from0);
|
Chris@25
|
299 z_real = tw_real * f0_real;
|
Chris@25
|
300 z_imag = tw_imag * f0_real;
|
Chris@25
|
301 }
|
Chris@25
|
302
|
Chris@25
|
303 sum_real += w_real * z_real - w_imag * z_imag;
|
Chris@25
|
304 sum_imag += w_real * z_imag + w_imag * z_real;
|
Chris@25
|
305 }
|
Chris@25
|
306
|
Chris@25
|
307 if (e1 + 1 < factor - e1)
|
Chris@25
|
308 {
|
Chris@25
|
309 const size_t to0 = k1 * product - 1 + 2 * e1 * product_1 + 2 * k;
|
Chris@25
|
310 VECTOR(out,ostride,to0) = sum_real;
|
Chris@25
|
311 VECTOR(out,ostride,to0 + 1) = sum_imag;
|
Chris@25
|
312 }
|
Chris@25
|
313 else if (e1 + 1 == factor - e1)
|
Chris@25
|
314 {
|
Chris@25
|
315 const size_t to0 = k1 * product - 1 + 2 * e1 * product_1 + 2 * k;
|
Chris@25
|
316 VECTOR(out,ostride,to0) = sum_real;
|
Chris@25
|
317 }
|
Chris@25
|
318 else
|
Chris@25
|
319 {
|
Chris@25
|
320 const size_t to0 = k1 * product - 1 + 2 * (factor - e1) * product_1 - 2 * k;
|
Chris@25
|
321 VECTOR(out,ostride,to0) = sum_real;
|
Chris@25
|
322 VECTOR(out,ostride,to0 + 1) = -sum_imag;
|
Chris@25
|
323 }
|
Chris@25
|
324
|
Chris@25
|
325 }
|
Chris@25
|
326 }
|
Chris@25
|
327 }
|
Chris@25
|
328 return;
|
Chris@25
|
329
|
Chris@25
|
330 function backwardButterfly2(output, outputOffset, outputStride, input, inputOffset, inputStride, product, n, twiddle, fStride) {
|
Chris@25
|
331 var m = n / 2, q = n / product, old = product / 2
|
Chris@25
|
332
|
Chris@25
|
333 for (var i = 0; i < q; i++) {
|
Chris@25
|
334 var a0 = (2 * i) * q
|
Chris@25
|
335 var a1 = (2 * i + 2) * q - 1
|
Chris@25
|
336
|
Chris@25
|
337 var s0 = input[inputOffset + inputStride * a0]
|
Chris@25
|
338 var s1 = input[inputOffset + inputStride * a1]
|
Chris@25
|
339
|
Chris@25
|
340 var r0 = s0 + s1
|
Chris@25
|
341 var r1 = s0 - s1
|
Chris@25
|
342
|
Chris@25
|
343 var a0 = q * i
|
Chris@25
|
344 var a1 = q * i + m
|
Chris@25
|
345
|
Chris@25
|
346 output[outputOffset + outputStride * a0] = r0
|
Chris@25
|
347 output[outputOffset + outputStride * a1] = r1
|
Chris@25
|
348 }
|
Chris@25
|
349
|
Chris@25
|
350 if (q == 1) { return }
|
Chris@25
|
351
|
Chris@25
|
352 for (var i = 0; i < q / 2; i++) {
|
Chris@25
|
353 <%= load('t1', 'twiddle', -1, 'i') %>
|
Chris@25
|
354
|
Chris@25
|
355 for (var j = 0; j < old; j++) {
|
Chris@25
|
356 var a0 = 2 * j * q + 2 * i - 1
|
Chris@25
|
357 var a1 = 2 * (j + 1) * q - 2 * i - 1
|
Chris@25
|
358
|
Chris@25
|
359 <%= load('s0', 'input', 'inputOffset', 'a0', 'inputStride') %>
|
Chris@25
|
360 <%= load('s1', 'input', 'inputOffset', 'a1', 'inputStride') %>
|
Chris@25
|
361
|
Chris@25
|
362 var r0_r = s0_r + s1_r
|
Chris@25
|
363 var r0_i = s0_i - s1_i
|
Chris@25
|
364
|
Chris@25
|
365 var v1_r = s0_r - s1_r
|
Chris@25
|
366 var v1_i = s0_i + s1_i
|
Chris@25
|
367
|
Chris@25
|
368 <%= cmul('r1', 'v1', 't1') %>
|
Chris@25
|
369
|
Chris@25
|
370 var a0 = j * q + 2 * i - 1
|
Chris@25
|
371 var a1 = a0 + m
|
Chris@25
|
372
|
Chris@25
|
373 <%= store('r0', 'output', 'outputOffset', 'a0', 'outputStride') %>
|
Chris@25
|
374 <%= store('r1', 'output', 'outputOffset', 'a1', 'outputStride') %>
|
Chris@25
|
375 }
|
Chris@25
|
376 }
|
Chris@25
|
377
|
Chris@25
|
378 if (q % 2 == 1) { return }
|
Chris@25
|
379
|
Chris@25
|
380 for (var i = 0; i < q; i++) {
|
Chris@25
|
381 var a0 = 2 * (i + 1) * q - 1
|
Chris@25
|
382
|
Chris@25
|
383 <%= load('r0', 'input', 'inputOffset', 'a0', 'inputStride') %>
|
Chris@25
|
384
|
Chris@25
|
385 <%= real('input', 'inputOffset', 'a0', 'inputStride') %> = 2 * r0_r
|
Chris@25
|
386 <%= imag('input', 'inputOffset', 'a1', 'inputStride') %> = -2 * r0_i
|
Chris@25
|
387 }
|
Chris@25
|
388 }
|
Chris@25
|
389
|
Chris@25
|
390 function work(output, outputOffset, outputStride, f, fOffset, fStride, inputStride, factors, state) {
|
Chris@25
|
391 var p = factors.shift()
|
Chris@25
|
392 var m = factors.shift()
|
Chris@25
|
393
|
Chris@25
|
394 if (m == 1) {
|
Chris@25
|
395 for (var i = 0; i < p * m; i++) {
|
Chris@25
|
396 <%= load('x0', 'f', 'fOffset', 'i', 'fStride * inputStride') %>
|
Chris@25
|
397 <%= store('x0', 'output', 'outputOffset', 'i', 'outputStride') %>
|
Chris@25
|
398 }
|
Chris@25
|
399 } else {
|
Chris@25
|
400 for (var i = 0; i < p; i++) {
|
Chris@25
|
401 work(output, outputOffset + outputStride * i * m, outputStride, f, fOffset + i * fStride * inputStride, fStride * p, inputStride, factors.slice(), state)
|
Chris@25
|
402 }
|
Chris@25
|
403 }
|
Chris@25
|
404
|
Chris@25
|
405 switch (p) {
|
Chris@25
|
406 case 2: butterfly2(output, outputOffset, outputStride, fStride, state, m); break
|
Chris@25
|
407 case 3: butterfly3(output, outputOffset, outputStride, fStride, state, m); break
|
Chris@25
|
408 case 4: butterfly4(output, outputOffset, outputStride, fStride, state, m); break
|
Chris@25
|
409 default: butterfly(output, outputOffset, outputStride, fStride, state, m, p); break
|
Chris@25
|
410 }
|
Chris@25
|
411 }
|
Chris@25
|
412
|
Chris@25
|
413 var real = function (n, inverse) {
|
Chris@25
|
414 var n = ~~n, inverse = !!inverse
|
Chris@25
|
415
|
Chris@25
|
416 if (n < 1) {
|
Chris@25
|
417 throw new RangeError("n is outside range, should be positive integer, was `" + n + "'")
|
Chris@25
|
418 }
|
Chris@25
|
419
|
Chris@25
|
420 var state = {
|
Chris@25
|
421 n: n,
|
Chris@25
|
422 inverse: inverse,
|
Chris@25
|
423
|
Chris@25
|
424 factors: [],
|
Chris@25
|
425 twiddle: [],
|
Chris@25
|
426 scratch: new Float64Array(n)
|
Chris@25
|
427 }
|
Chris@25
|
428
|
Chris@25
|
429 var t = new Float64Array(n)
|
Chris@25
|
430
|
Chris@25
|
431 var p = 4, v = Math.floor(Math.sqrt(n))
|
Chris@25
|
432
|
Chris@25
|
433 while (n > 1) {
|
Chris@25
|
434 while (n % p) {
|
Chris@25
|
435 switch (p) {
|
Chris@25
|
436 case 4: p = 2; break
|
Chris@25
|
437 case 2: p = 3; break
|
Chris@25
|
438 default: p += 2; break
|
Chris@25
|
439 }
|
Chris@25
|
440
|
Chris@25
|
441 if (p > v) {
|
Chris@25
|
442 p = n
|
Chris@25
|
443 }
|
Chris@25
|
444 }
|
Chris@25
|
445
|
Chris@25
|
446 n /= p
|
Chris@25
|
447
|
Chris@25
|
448 state.factors.push(p)
|
Chris@25
|
449 }
|
Chris@25
|
450
|
Chris@25
|
451 var theta = 2 * Math.PI / n, product = 1, twiddle = new Float64Array(n)
|
Chris@25
|
452
|
Chris@25
|
453 for (var i = 0, t = 0; i < state.factors.length; i++) {
|
Chris@25
|
454 var phase = theta * i, factor = state.factors[i]
|
Chris@25
|
455
|
Chris@25
|
456 var old = product, product = product * factor, q = n / product
|
Chris@25
|
457
|
Chris@25
|
458 state.twiddle.push(new Float64Array(twiddle, t))
|
Chris@25
|
459
|
Chris@25
|
460 if (inverse) {
|
Chris@25
|
461 var counter = q, multiplier = old
|
Chris@25
|
462 } else {
|
Chris@25
|
463 var counter = old, multiplier = q
|
Chris@25
|
464 }
|
Chris@25
|
465
|
Chris@25
|
466 for (var j = 1; j < factor; j++) {
|
Chris@25
|
467 var m = 0
|
Chris@25
|
468
|
Chris@25
|
469 for (var k = 1; k < counter / 2; k++, t++) {
|
Chris@25
|
470 m = (m + j * multiplier) % n
|
Chris@25
|
471
|
Chris@25
|
472 var phase = theta * m
|
Chris@25
|
473
|
Chris@25
|
474 <%= real('t', 'i') %> = Math.cos(phase)
|
Chris@25
|
475 <%= imag('t', 'i') %> = Math.sin(phase)
|
Chris@25
|
476 }
|
Chris@25
|
477 }
|
Chris@25
|
478 }
|
Chris@25
|
479
|
Chris@25
|
480 this.state = state
|
Chris@25
|
481 }
|
Chris@25
|
482
|
Chris@25
|
483 real.prototype.process = function(output, outputStride, input, inputStride) {
|
Chris@25
|
484 var outputStride = ~~outputStride, inputStride = ~~inputStride
|
Chris@25
|
485
|
Chris@25
|
486 if (outputStride < 1) {
|
Chris@25
|
487 throw new RangeError("outputStride is outside range, should be positive integer, was `" + outputStride + "'")
|
Chris@25
|
488 }
|
Chris@25
|
489
|
Chris@25
|
490 if (inputStride < 1) {
|
Chris@25
|
491 throw new RangeError("inputStride is outside range, should be positive integer, was `" + inputStride + "'")
|
Chris@25
|
492 }
|
Chris@25
|
493
|
Chris@25
|
494 var product = 1, state = 0, inverse = this.state.inverse
|
Chris@25
|
495
|
Chris@25
|
496 var n = this.state.n, factors = this.state.factors
|
Chris@25
|
497 var twiddle = this.state.twiddle, scratch = this.state.scratch
|
Chris@25
|
498
|
Chris@25
|
499 for (var i = 0; i < factors.length; i++) {
|
Chris@25
|
500 var factor = factors[i], old = product, product = product * factor
|
Chris@25
|
501
|
Chris@25
|
502 var q = n / product, fStride = Math.ceil(old / 2) - 1
|
Chris@25
|
503
|
Chris@25
|
504 if (state == 0) {
|
Chris@25
|
505 var inBuffer = input, inStride = inputStride
|
Chris@25
|
506
|
Chris@25
|
507 if (this.state.factors.length % 2 == 0) {
|
Chris@25
|
508 var outBuffer = scratch, outStride = 1, state = 1
|
Chris@25
|
509 } else {
|
Chris@25
|
510 var outBuffer = output, outStride = outputStride, state = 2
|
Chris@25
|
511 }
|
Chris@25
|
512 } else if (state == 1) {
|
Chris@25
|
513 var inBuffer = scratch, inStride = 1, outBuffer = output, outStride = outputStride, state = 2
|
Chris@25
|
514 } else if (state == 2) {
|
Chris@25
|
515 var inBuffer = output, inStride = outputStride, outBuffer = scratch, outStride = 1, state = 1
|
Chris@25
|
516 } else {
|
Chris@25
|
517 throw new RangeError("state somehow is not in the range (0 .. 2)")
|
Chris@25
|
518 }
|
Chris@25
|
519
|
Chris@25
|
520 if (inverse) {
|
Chris@25
|
521 switch (factor) {
|
Chris@25
|
522 case 2: backwardButterfly2(outBuffer, 0, outStride, inBuffer, 0, inStride, product, n, twiddle[i], fStride); break
|
Chris@25
|
523 case 3: backwardButterfly3(outBuffer, 0, outStride, inBuffer, 0, inStride, product, n, twiddle[i], fStride); break
|
Chris@25
|
524 case 4: backwardButterfly3(outBuffer, 0, outStride, inBuffer, 0, inStride, product, n, twiddle[i], fStride); break
|
Chris@25
|
525 case 5: backwardButterfly3(outBuffer, 0, outStride, inBuffer, 0, inStride, product, n, twiddle[i], fStride); break
|
Chris@25
|
526 default: backwardButterfly(outBuffer, 0, outStride, inBuffer, 0, inStride, product, n, twiddle[i], fStride, factor); break
|
Chris@25
|
527 }
|
Chris@25
|
528 } else {
|
Chris@25
|
529 switch (factor) {
|
Chris@25
|
530 case 2: forwardButterfly2(outBuffer, 0, outStride, inBuffer, 0, inStride, product, n, twiddle[i], fStride); break
|
Chris@25
|
531 case 3: forwardButterfly3(outBuffer, 0, outStride, inBuffer, 0, inStride, product, n, twiddle[i], fStride); break
|
Chris@25
|
532 case 4: forwardButterfly3(outBuffer, 0, outStride, inBuffer, 0, inStride, product, n, twiddle[i], fStride); break
|
Chris@25
|
533 case 5: forwardButterfly3(outBuffer, 0, outStride, inBuffer, 0, inStride, product, n, twiddle[i], fStride); break
|
Chris@25
|
534 default: forwardButterfly(outBuffer, 0, outStride, inBuffer, 0, inStride, product, n, twiddle[i], fStride, factor); break
|
Chris@25
|
535 }
|
Chris@25
|
536 }
|
Chris@25
|
537 }
|
Chris@25
|
538 }
|
Chris@25
|
539
|
Chris@25
|
540 namespace.real = real
|
Chris@25
|
541 }(FFT)
|