ooura_fft 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 */