ooura_fft 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,307 @@
1
+ /*******************************************************************************
2
+ fft.c -- FFT
3
+
4
+ $author$
5
+ *******************************************************************************/
6
+ #include <ruby.h>
7
+ #include "ooura_fft/globals.h"
8
+ #include "ooura_fft/api.h"
9
+ #include "internal/setting/ooura_fft.h"
10
+ #include "missing/missing.h"
11
+ #include "abi/fftsg/fftsg.h"
12
+
13
+
14
+ static void InitVM_FFTMain(void);
15
+ void
16
+ InitVM_FFT(void)
17
+ {
18
+ InitVM(FFTMain);
19
+ }
20
+
21
+ int
22
+ opts_inversion_p(VALUE opts)
23
+ {
24
+ static ID kwds[1];
25
+ VALUE inversion;
26
+ if (!kwds[0]) {
27
+ kwds[0] = rb_intern_const("inversion");
28
+ }
29
+ rb_get_kwargs(opts, kwds, 0, 1, &inversion);
30
+ switch (inversion) {
31
+ case Qtrue: case Qfalse:
32
+ break;
33
+ case Qundef:
34
+ return 0;
35
+ default:
36
+ rb_raise(rb_eArgError, "true or false is expected as inversion: %+"PRIsVALUE,
37
+ inversion);
38
+ }
39
+
40
+ return inversion == Qtrue;
41
+ }
42
+
43
+ static VALUE
44
+ fft_callback(int argc, VALUE *argv, VALUE (*callback_func)(VALUE, int))
45
+ {
46
+ VALUE ary, opts = Qnil;
47
+ rb_scan_args(argc, argv, "11", &ary, &opts);
48
+ int invertible = opts_inversion_p(opts) ? -1 : 1;
49
+
50
+ Check_Type(ary, T_ARRAY);
51
+
52
+ return callback_func(ary, invertible);
53
+ }
54
+
55
+
56
+ #include "internal/solver/ooura_fft/cdft.h" // fft_cdft_inline()
57
+ /*
58
+ *
59
+ * Document-method: cdft
60
+ *
61
+ * call-seq:
62
+ * OouraFFT.cdft(ary) -> [*Complex]
63
+ * OouraFFT.cdft(ary, inversion: true) -> [*Complex]
64
+ *
65
+ * Perform FFT with the first argument +ary+ as a numerical sequence.<br>
66
+ * If the keyword argument +inversion+ is +true+, perform an inverse FFT.
67
+ *
68
+ * [Function type] Complex Discrete Fourier Transform
69
+ * [Definition]
70
+ * [case1] <tt>X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k<n</tt>
71
+ * [case2] <tt>X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k<n</tt>
72
+ * notes:: <tt>sum_j=0^n-1 is a summation from j=0 to n-1</tt>
73
+ * [+ary+ sequence type] All +Complex+
74
+ * [Array size requirement] n >= 1, n = power of 2
75
+ *
76
+ * def sinewave(amp, f0, fs, n)
77
+ * amp * Math.sin(2 * Math::PI * f0 * n / fs)
78
+ * end
79
+ *
80
+ * OouraFFT.cdft(Array.new(8){|n| sinewave(0.25, 250.0, 8000, n)})
81
+ * #=> [(1.1441462984511075+0.0i),
82
+ * #=> (-0.21410561232180816-0.3229641637954819i),
83
+ * #=> (-0.14986404592245728-0.12744889477603982i),
84
+ * #=> (-0.13944777827146557-0.05236611372238342i),
85
+ * #=> (-0.13731142541964547+0.0i),
86
+ * #=> (-0.13944777827146557+0.05236611372238342i),
87
+ * #=> (-0.14986404592245728+0.12744889477603982i),
88
+ * #=> (-0.21410561232180816+0.3229641637954819i)]
89
+ */
90
+ static VALUE
91
+ fft_cdft(int argc, VALUE *argv, VALUE unused_obj)
92
+ {
93
+ return fft_callback(argc, argv, fft_cdft_inline);
94
+ }
95
+
96
+
97
+ #include "internal/solver/ooura_fft/rdft.h" // fft_rdft_inline()
98
+ /*
99
+ * Document-method: rdft
100
+ *
101
+ * call-seq:
102
+ * OouraFFT.rdft(ary) -> [*Float]
103
+ * OouraFFT.rdft(ary, inversion: true) -> [*Float]
104
+ *
105
+ * Perform FFT with the first argument +ary+ as a numerical sequence.<br>
106
+ * If the keyword argument +inversion+ is +true+, perform an inverse FFT.
107
+ *
108
+ * [Function type] Real Discrete Fourier Transform
109
+ * [Definition]
110
+ * case1:: RDFT
111
+ * :: <tt>R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2</tt>
112
+ * :: <tt>I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0<k<n/2</tt>
113
+ * case2:: IRDFT (excluding scale)
114
+ * :: <tt>a[k] = (R[0] + R[n/2]*cos(pi*k))/2 + sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) + sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k<n</tt>
115
+ * [+ary+ sequence type] All +Float+
116
+ * [Array size requirement] n >= 2, n = power of 2
117
+ *
118
+ * def sinewave(amp, f0, fs, n)
119
+ * amp * Math.sin(2 * Math::PI * f0 * n / fs)
120
+ * end
121
+ *
122
+ * OouraFFT.rdft(Array.new(8){|n| sinewave(0.25, 250.0, 8000, n)})
123
+ * # => [1.1441462984511075,
124
+ * # => -0.13731142541964547,
125
+ * # => -0.21410561232180816,
126
+ * # => -0.3229641637954819,
127
+ * # => -0.14986404592245728,
128
+ * # => -0.12744889477603982,
129
+ * # => -0.13944777827146557,
130
+ * # => -0.052366113722383416]
131
+ */
132
+ static VALUE
133
+ fft_rdft(int argc, VALUE *argv, VALUE unused_obj)
134
+ {
135
+ return fft_callback(argc, argv, fft_rdft_inline);
136
+ }
137
+
138
+
139
+ #include "internal/solver/ooura_fft/ddct.h" // fft_ddct_inline()
140
+ /*
141
+ * Document-method: ddct
142
+ *
143
+ * call-seq:
144
+ * OouraFFT.ddct(ary) -> [*Float]
145
+ * OouraFFT.ddct(ary, inversion: true) -> [*Float]
146
+ *
147
+ * Perform FFT with the first argument +ary+ as a numerical sequence.<br>
148
+ * If the keyword argument +inversion+ is +true+, perform an inverse FFT.
149
+ *
150
+ * [Function type] Discrete Cosine Transform
151
+ * [Definition]
152
+ * case1:: IDCT (excluding scale)
153
+ * :: <tt>C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k<n</tt>
154
+ * case2:: DCT
155
+ * :: <tt>C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k<n</tt>
156
+ * [+ary+ sequence type] All +Float+
157
+ * [Array size requirement] n >= 2, n = power of 2
158
+ *
159
+ * def sinewave(amp, f0, fs, n)
160
+ * amp * Math.sin(2 * Math::PI * f0 * n / fs)
161
+ * end
162
+ *
163
+ * OouraFFT.ddct(Array.new(8){|n| sinewave(0.25, 250.0, 8000, n)})
164
+ * #=> [0.6284174365157309,
165
+ * #=> -0.6284174365157309,
166
+ * #=> 0.18707572033318604,
167
+ * #=> -0.18707572033318612,
168
+ * #=> 0.08352232973991239,
169
+ * #=> -0.08352232973991236,
170
+ * #=> 0.02486404592245728,
171
+ * #=> -0.024864045922457167]
172
+ */
173
+ static VALUE
174
+ fft_ddct(int argc, VALUE *argv, VALUE unused_obj)
175
+ {
176
+ return fft_callback(argc, argv, fft_ddct_inline);
177
+ }
178
+
179
+
180
+ #include "internal/solver/ooura_fft/ddst.h" // fft_ddst_inline()
181
+ /*
182
+ * Document-method: ddst
183
+ *
184
+ * call-seq:
185
+ * OouraFFT.ddst(ary) -> [*Float]
186
+ * OouraFFT.ddst(ary, inversion: true) -> [*Float]
187
+ *
188
+ * Perform FFT with the first argument +ary+ as a numerical sequence.<br>
189
+ * If the keyword argument +inversion+ is +true+, perform an inverse FFT.
190
+ *
191
+ * [Function type] Discrete Sine Transform
192
+ * [Definition]
193
+ * case1:: IDST (excluding scale)
194
+ * :: <tt>S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k<n</tt>
195
+ * case2:: DST
196
+ * :: <tt>S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0<k<=n</tt>
197
+ * [+ary+ sequence type] All +Float+
198
+ * [Array size requirement] n >= 2, n = power of 2
199
+ *
200
+ * def sinewave(amp, f0, fs, n)
201
+ * amp * Math.sin(2 * Math::PI * f0 * n / fs)
202
+ * end
203
+ *
204
+ * OouraFFT.ddst(Array.new(8){|n| sinewave(0.25, 250.0, 8000, n)})
205
+ * #=> [0.875,
206
+ * #=> 0.12500000000000003,
207
+ * #=> -0.12499999999999997,
208
+ * #=> 0.125,
209
+ * #=> -0.125,
210
+ * #=> 0.12500000000000006,
211
+ * #=> -0.12499999999999994,
212
+ * #=> 0.12499999999999994]
213
+
214
+ */
215
+ static VALUE
216
+ fft_ddst(int argc, VALUE *argv, VALUE unused_obj)
217
+ {
218
+ return fft_callback(argc, argv, fft_ddst_inline);
219
+ }
220
+
221
+
222
+ #include "internal/solver/ooura_fft/dfct.h" // fft_dfct_inline()
223
+ /*
224
+ * Document-method: dfct
225
+ *
226
+ * call-seq:
227
+ * OouraFFT.dfct(ary) -> [*Float]
228
+ * OouraFFT.dfct(ary, inversion: true) -> [*Float]
229
+ *
230
+ * Perform FFT with the first argument +ary+ as a numerical sequence.<br>
231
+ * If the keyword argument +inversion+ is +true+, perform an inverse FFT.
232
+ *
233
+ * [Function type] Cosine Transform of RDFT (Real Symmetric DFT)
234
+ * [Definition] <tt>C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n</tt>
235
+ * [+ary+ sequence type] All +Float+
236
+ * [Array size requirement] n >= 2, n = power of 2
237
+ *
238
+ * def sinewave(amp, f0, fs, n)
239
+ * amp * Math.sin(2 * Math::PI * f0 * n / fs)
240
+ * end
241
+ *
242
+ * OouraFFT.dfct(Array.new(8){|n| sinewave(0.25, 250.0, 8000, n)})
243
+ * #=> [1.1441462984511075,
244
+ * #=> -0.30353826116690874,
245
+ * #=> -0.21410561232180816,
246
+ * #=> 0.08422719461241164,
247
+ * #=> -0.14986404592245728,
248
+ * #=> 0.10711452157013322,
249
+ * #=> -0.13944777827146557,
250
+ * #=> 0.11219654498436385]
251
+ */
252
+ static VALUE
253
+ fft_dfct(int argc, VALUE *argv, VALUE unused_obj)
254
+ {
255
+ return fft_callback(argc, argv, fft_dfct_inline);
256
+ }
257
+
258
+
259
+ #include "internal/solver/ooura_fft/dfst.h" // fft_dfst_inline()
260
+ /*
261
+ * Document-method: dfst
262
+ *
263
+ * call-seq:
264
+ * OouraFFT.dfst(ary) -> [*Float]
265
+ * OouraFFT.dfst(ary, inversion: true) -> [*Float]
266
+ *
267
+ * Perform FFT with the first argument +ary+ as a numerical sequence.<br>
268
+ * If the keyword argument +inversion+ is +true+, perform an inverse FFT.
269
+ *
270
+ * [Function type] Sine Transform of RDFT (Real Anti-symmetric DFT)
271
+ * [Definition] <tt>S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0<k<n</tt>
272
+ * [+ary+ sequence type] All +Float+
273
+ * [Array size requirement] n >= 2, n = power of 2
274
+ *
275
+ * def sinewave(amp, f0, fs, n)
276
+ * amp * Math.sin(2 * Math::PI * f0 * n / fs)
277
+ * end
278
+ *
279
+ * OouraFFT.dfst(Array.new(8){|n| sinewave(0.25, 250.0, 8000, n)})
280
+ * #=> [0.0,
281
+ * #=> 0.8406080372841989,
282
+ * #=> -0.3229641637954819,
283
+ * #=> 0.19308574608608534,
284
+ * #=> -0.12744889477603982,
285
+ * #=> 0.08469937042371564,
286
+ * #=> -0.05236611372238342,
287
+ * #=> 0.025114880435281595]
288
+ */
289
+ static VALUE
290
+ fft_dfst(int argc, VALUE *argv, VALUE unused_obj)
291
+ {
292
+ return fft_callback(argc, argv, fft_dfst_inline);
293
+
294
+ }
295
+
296
+ static void
297
+ InitVM_FFTMain(void)
298
+ {
299
+ rb_define_module_function(rb_mOouraFFT, "cdft", fft_cdft, -1);
300
+ rb_define_module_function(rb_mOouraFFT, "rdft", fft_rdft, -1);
301
+ rb_define_module_function(rb_mOouraFFT, "ddct", fft_ddct, -1);
302
+ rb_define_module_function(rb_mOouraFFT, "ddst", fft_ddst, -1);
303
+ rb_define_module_function(rb_mOouraFFT, "dfct", fft_dfct, -1);
304
+ rb_define_module_function(rb_mOouraFFT, "dfst", fft_dfst, -1);
305
+ /* The using thread model name. Supports in Windows and POSIX. */
306
+ rb_define_const(rb_mOouraFFT, "USING_THREAD", rb_str_new_cstr((const char *)USING_THREAD));
307
+ }
@@ -0,0 +1,17 @@
1
+ #ifndef INTERNAL_SETTING_OOURAFFT_H
2
+ #define INTERNAL_SETTING_OOURAFFT_H
3
+
4
+ // Ooura's FFT Thread Use Setting
5
+ #if defined(HAVE_CREATETHREAD) && \
6
+ defined(HAVE_WAITFORSINGLEOBJECT) && \
7
+ defined(HAVE_CLOSEHANDLE)
8
+ # define USE_CDFT_WINTHREADS
9
+ # define USING_THREAD "Windows"
10
+ #elif defined(HAVE_PTHREAD_CREATE) && defined(HAVE_PTHREAD_JOIN)
11
+ # define USE_CDFT_PTHREADS
12
+ # define USING_THREAD "POSIX"
13
+ #else
14
+ # define USING_THREAD NULL
15
+ #endif
16
+
17
+ #endif /* INTERNAL_SETTING_OOURAFFT_H */
@@ -0,0 +1,52 @@
1
+ #ifndef INTERNAL_SOLVER_FFT_CDFT_H
2
+ #define INTERNAL_SOLVER_FFT_CDFT_H
3
+
4
+ static inline VALUE
5
+ fft_cdft_inline(VALUE ary, int invertible)
6
+ {
7
+ VALUE retval;
8
+ long sz = RARRAY_LEN(ary);
9
+ int *ip;
10
+ double *a, *w;
11
+
12
+ if ((INT_MAX / 2) < sz)
13
+ rb_raise(rb_eRangeError, "biggest array size");
14
+ else if (sz < 1)
15
+ rb_raise(rb_eRangeError, "unavailable array size (n >= 1, was %ld)", sz);
16
+ else if (!ispow2l(sz))
17
+ rb_raise(rb_eRangeError, "size must be 2^m");
18
+
19
+ a = ALLOC_N(double, sz*2);
20
+ ip = ALLOC_N(int, (int)(2+sqrt(sz)));
21
+ w = ALLOC_N(double, sz/2);
22
+
23
+ for (volatile long i = 0; i < sz; i++)
24
+ {
25
+ VALUE elem = rb_ary_entry(ary, i);
26
+ if (TYPE(elem) != T_COMPLEX)
27
+ elem = rb_Complex1(elem);
28
+ const double real = NUM2DBL(rb_complex_real(elem));
29
+ const double imag = NUM2DBL(rb_complex_imag(elem));
30
+ a[2*i] = real;
31
+ a[2*i+1] = imag;
32
+ }
33
+
34
+ ip[0] = 0;
35
+
36
+ cdft(2*sz, invertible, a, ip, w);
37
+
38
+ retval = rb_ary_new2(sz);
39
+
40
+ for (volatile long i = 0; i < sz; i++)
41
+ {
42
+ rb_ary_store(retval, i, rb_dbl_complex_new(a[2*i], a[2*i+1]));
43
+ }
44
+
45
+ xfree(a);
46
+ xfree(ip);
47
+ xfree(w);
48
+
49
+ return retval;
50
+ }
51
+
52
+ #endif /* INTERNAL_SOLVER_FFT_CDFT */
@@ -0,0 +1,47 @@
1
+ #ifndef INTERNAL_SOLVER_FFT_DDCT_H
2
+ #define INTERNAL_SOLVER_FFT_DDCT_H
3
+
4
+ static inline VALUE
5
+ fft_ddct_inline(VALUE ary, int invertible)
6
+ {
7
+ VALUE retval;
8
+ long sz = RARRAY_LEN(ary);
9
+ int *ip;
10
+ double *a, *w;
11
+
12
+ if (INT_MAX < sz)
13
+ rb_raise(rb_eRangeError, "biggest array size");
14
+ else if (sz < 2)
15
+ rb_raise(rb_eRangeError, "unavailable array size (n >= 2, was %ld)", sz);
16
+ else if (!ispow2l(sz))
17
+ rb_raise(rb_eRangeError, "size must be 2^m");
18
+
19
+ a = ALLOC_N(double, sz);
20
+ ip = ALLOC_N(int, (int)(2+sqrt(sz/2)));
21
+ w = ALLOC_N(double, sz*5/4);
22
+
23
+ for (volatile long i = 0; i < sz; i++)
24
+ {
25
+ VALUE elem = rb_ary_entry(ary, i);
26
+ a[i] = NUM2DBL(elem);
27
+ }
28
+
29
+ ip[0] = 0;
30
+
31
+ ddct(sz, invertible, a, ip, w);
32
+
33
+ retval = rb_ary_new2(sz);
34
+
35
+ for (volatile long i = 0; i < sz; i++)
36
+ {
37
+ rb_ary_store(retval, i, DBL2NUM(a[i]));
38
+ }
39
+
40
+ xfree(a);
41
+ xfree(ip);
42
+ xfree(w);
43
+
44
+ return retval;
45
+ }
46
+
47
+ #endif /* INTERNAL_SOLVER_FFT_DDCT */
@@ -0,0 +1,47 @@
1
+ #ifndef INTERNAL_SOLVER_FFT_DDST_H
2
+ #define INTERNAL_SOLVER_FFT_DDST_H
3
+
4
+ static inline VALUE
5
+ fft_ddst_inline(VALUE ary, int invertible)
6
+ {
7
+ VALUE retval;
8
+ long sz = RARRAY_LEN(ary);
9
+ int *ip;
10
+ double *a, *w;
11
+
12
+ if (INT_MAX < sz)
13
+ rb_raise(rb_eRangeError, "biggest array size");
14
+ else if (sz < 2)
15
+ rb_raise(rb_eRangeError, "unavailable array size (n >= 2, was %ld)", sz);
16
+ else if (!ispow2l(sz))
17
+ rb_raise(rb_eRangeError, "size must be 2^m");
18
+
19
+ a = ALLOC_N(double, sz);
20
+ ip = ALLOC_N(int, (int)(2+sqrt(sz/2)));
21
+ w = ALLOC_N(double, sz*5/4);
22
+
23
+ for (volatile long i = 0; i < sz; i++)
24
+ {
25
+ VALUE elem = rb_ary_entry(ary, i);
26
+ a[i] = NUM2DBL(elem);
27
+ }
28
+
29
+ ip[0] = 0;
30
+
31
+ ddst(sz, invertible, a, ip, w);
32
+
33
+ retval = rb_ary_new2(sz);
34
+
35
+ for (volatile long i = 0; i < sz; i++)
36
+ {
37
+ rb_ary_store(retval, i, DBL2NUM(a[i]));
38
+ }
39
+
40
+ xfree(a);
41
+ xfree(ip);
42
+ xfree(w);
43
+
44
+ return retval;
45
+ }
46
+
47
+ #endif /* INTERNAL_SOLVER_FFT_DDST */
@@ -0,0 +1,55 @@
1
+ #ifndef INTERNAL_SOLVER_FFT_DFCT_H
2
+ #define INTERNAL_SOLVER_FFT_DFCT_H
3
+
4
+ static inline VALUE
5
+ fft_dfct_inline(VALUE ary, int invertible)
6
+ {
7
+ VALUE retval;
8
+ long n = RARRAY_LEN(ary), sz = n + 1;
9
+ int *ip;
10
+ double *a, *w, *t;
11
+
12
+ if (INT_MAX < n)
13
+ rb_raise(rb_eRangeError, "biggest array size");
14
+ else if (n < 2)
15
+ rb_raise(rb_eRangeError, "unavailable array size (n >= 2, was %ld)", n);
16
+ else if (!ispow2l(n))
17
+ rb_raise(rb_eRangeError, "size must be 2^m");
18
+
19
+ a = ALLOC_N(double, sz);
20
+ ip = ALLOC_N(int, (int)(2+sqrt(n/4)));
21
+ t = ALLOC_N(double, sz/2);
22
+ w = ALLOC_N(double, n*5/8);
23
+
24
+ for (volatile long i = 0; i < n; i++)
25
+ {
26
+ VALUE elem = rb_ary_entry(ary, i);
27
+ if (invertible == -1)
28
+ a[i] = NUM2DBL(elem) * 0.5;
29
+ else
30
+ a[i] = NUM2DBL(elem);
31
+ }
32
+
33
+ ip[0] = 0;
34
+
35
+ dfct(n, a, t, ip, w);
36
+
37
+ retval = rb_ary_new2(n);
38
+
39
+ for (volatile long i = 0; i < n; i++)
40
+ {
41
+ if (invertible == -1)
42
+ rb_ary_store(retval, i, DBL2NUM(a[i] * 2.0 / n));
43
+ else
44
+ rb_ary_store(retval, i, DBL2NUM(a[i]));
45
+ }
46
+
47
+ xfree(a);
48
+ xfree(ip);
49
+ xfree(t);
50
+ xfree(w);
51
+
52
+ return retval;
53
+ }
54
+
55
+ #endif /* INTERNAL_SOLVER_FFT_DFCT */
@@ -0,0 +1,52 @@
1
+ #ifndef INTERNAL_SOLVER_FFT_DFST_H
2
+ #define INTERNAL_SOLVER_FFT_DFST_H
3
+
4
+ static inline VALUE
5
+ fft_dfst_inline(VALUE ary, int invertible)
6
+ {
7
+ VALUE retval;
8
+ long n = RARRAY_LEN(ary);
9
+ int *ip;
10
+ double *a, *w, *t;
11
+
12
+ if (INT_MAX < n)
13
+ rb_raise(rb_eRangeError, "biggest array size");
14
+ else if (n < 2)
15
+ rb_raise(rb_eRangeError, "unavailable array size (n >= 2, was %ld)", n);
16
+ else if (!ispow2l(n))
17
+ rb_raise(rb_eRangeError, "size must be 2^m");
18
+
19
+ a = ALLOC_N(double, n);
20
+ ip = ALLOC_N(int, (int)(2+sqrt(n/4)));
21
+ t = ALLOC_N(double, n/2);
22
+ w = ALLOC_N(double, n*5/8);
23
+
24
+ for (volatile long i = 0; i < n; i++)
25
+ {
26
+ VALUE elem = rb_ary_entry(ary, i);
27
+ a[i] = NUM2DBL(elem);
28
+ }
29
+
30
+ ip[0] = 0;
31
+
32
+ dfst(n, a, t, ip, w);
33
+
34
+ retval = rb_ary_new2(n);
35
+
36
+ for (volatile long i = 0; i < n; i++)
37
+ {
38
+ if (invertible == -1)
39
+ rb_ary_store(retval, i, DBL2NUM(a[i] * 2.0 / n));
40
+ else
41
+ rb_ary_store(retval, i, DBL2NUM(a[i]));
42
+ }
43
+
44
+ xfree(a);
45
+ xfree(ip);
46
+ xfree(t);
47
+ xfree(w);
48
+
49
+ return retval;
50
+ }
51
+
52
+ #endif /* INTERNAL_SOLVER_FFT_DFST */
@@ -0,0 +1,47 @@
1
+ #ifndef INTERNAL_SOLVER_FFT_RDFT_H
2
+ #define INTERNAL_SOLVER_FFT_RDFT_H
3
+
4
+ static inline VALUE
5
+ fft_rdft_inline(VALUE ary, int invertible)
6
+ {
7
+ VALUE retval;
8
+ long sz = RARRAY_LEN(ary);
9
+ int *ip;
10
+ double *a, *w;
11
+
12
+ if (INT_MAX < sz)
13
+ rb_raise(rb_eRangeError, "biggest array size");
14
+ else if (sz < 2)
15
+ rb_raise(rb_eRangeError, "unavailable array size (n >= 2, was %ld)", sz);
16
+ else if (!ispow2l(sz))
17
+ rb_raise(rb_eRangeError, "size must be 2^m");
18
+
19
+ a = ALLOC_N(double, sz);
20
+ ip = ALLOC_N(int, (int)(2+sqrt(sz/2)));
21
+ w = ALLOC_N(double, sz/2);
22
+
23
+ for (volatile long i = 0; i < sz; i++)
24
+ {
25
+ VALUE elem = rb_ary_entry(ary, i);
26
+ a[i] = NUM2DBL(elem);
27
+ }
28
+
29
+ ip[0] = 0;
30
+
31
+ rdft(sz, invertible, a, ip, w);
32
+
33
+ retval = rb_ary_new2(sz);
34
+
35
+ for (volatile long i = 0; i < sz; i++)
36
+ {
37
+ rb_ary_store(retval, i, DBL2NUM(a[i]));
38
+ }
39
+
40
+ xfree(a);
41
+ xfree(ip);
42
+ xfree(w);
43
+
44
+ return retval;
45
+ }
46
+
47
+ #endif /* INTERNAL_SOLVER_FFT_RDFT */
@@ -0,0 +1,9 @@
1
+ #include <stdbool.h>
2
+
3
+ bool
4
+ ispow2l(register long n)
5
+ {
6
+ if (n <= 0) return false;
7
+ for (; (n & 1) == 0; n >>= 1);
8
+ return n == 1;
9
+ }
@@ -0,0 +1,21 @@
1
+ #ifndef FFT_MISSING_H
2
+ #define FFT_MISSING_H
3
+
4
+ #if defined(__cplusplus)
5
+ extern "C" {
6
+ #endif
7
+
8
+ // C2X newer library
9
+ #ifdef HAVE_STDBIT_H
10
+ # include <stdbit.h>
11
+ #endif
12
+
13
+ #ifndef HAVE_ISPOW2L
14
+ extern bool ispow2l(long);
15
+ #endif
16
+
17
+ #if defined(__cplusplus)
18
+ }
19
+ #endif
20
+
21
+ #endif /* FFT_MISSING_H */
@@ -0,0 +1,13 @@
1
+ #ifndef RB_OOURAFFT_API_H_INCLUDED
2
+ #define RB_OOURAFFT_API_H_INCLUDED
3
+
4
+ #include <ruby/internal/value.h> // VALUE
5
+
6
+ VALUE rb_oourafft_cdft(VALUE, int);
7
+ VALUE rb_oourafft_rdft(VALUE, int);
8
+ VALUE rb_oourafft_ddct(VALUE, int);
9
+ VALUE rb_oourafft_ddst(VALUE, int);
10
+ VALUE rb_oourafft_dfct(VALUE, int);
11
+ VALUE rb_oourafft_dfst(VALUE, int);
12
+
13
+ #endif /* RB_OOURAFFT_API_H_INCLUDED */
@@ -0,0 +1,18 @@
1
+ #ifndef RUBY_EXT_EXTERN_H_INCLUDED
2
+ #define RUBY_EXT_EXTERN_H_INCLUDED
3
+
4
+ #if defined(__cplusplus)
5
+ extern "C" {
6
+ #endif
7
+
8
+ #ifdef USE_GLOBAL_VARIABLE
9
+ # define RUBY_EXT_EXTERN
10
+ #else
11
+ # define RUBY_EXT_EXTERN extern
12
+ #endif
13
+
14
+ #if defined(__cplusplus)
15
+ }
16
+ #endif
17
+
18
+ #endif /* RUBY_EXT_EXTERN_H_INCLUDED */
@@ -0,0 +1,9 @@
1
+ #ifndef RB_OOURAFFT_GLOBALS_H_INCLUDED
2
+ #define RB_OOURAFFT_GLOBALS_H_INCLUDED
3
+
4
+ #include <ruby/internal/value.h> // VALUE
5
+ #include "ext_extern.h"
6
+
7
+ RUBY_EXT_EXTERN VALUE rb_mOouraFFT;
8
+
9
+ #endif /* RB_OOURAFFT_GLOBALS_H_INCLUDED */