1 module dplug.dsp.rfft;
2 
3 /**
4 
5 FFTReal.hpp
6 By Laurent de Soras
7 
8 --- Legal stuff ---
9 
10 This program is free software. It comes without any warranty, to
11 the extent permitted by applicable law. You can redistribute it
12 and/or modify it under the terms of the Do What The Fuck You Want
13 To Public License, Version 2, as published by Sam Hocevar. See
14 http://sam.zoy.org/wtfpl/COPYING for more details.
15 
16 */
17 /**
18 * Copyright: Copyright Auburn Sounds 2016.
19 * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
20 * Authors:   Guillaume Piolat
21 * What has changed? Shuffling was added to have a similar output than the regular complex FFT.
22 */
23 import std.math: PI, sin, cos, SQRT1_2;
24 import std.complex;
25 
26 import dplug.core.math;
27 import dplug.core.alignedbuffer;
28 
29 
30 /// Performs FFT from real input, and IFFT towards real output.
31 struct RFFT(T)
32 {
33 public:
34 nothrow:
35 @nogc:
36 
37     // Over this bit depth, we use direct calculation for sin/cos
38     enum TRIGO_BD_LIMIT	= 12;
39     
40     void initialize(int length)
41     {
42         assert(length > 0);
43         assert(isPowerOfTwo(length));
44         _length = length;
45         _nbr_bits = iFloorLog2(length);
46         init_br_lut();
47         init_trigo_lut();
48         init_trigo_osc();
49         _buffer.reallocBuffer(_length);
50         _shuffledValues.reallocBuffer(_length);
51     }
52 
53     ~this()
54     {
55         _br_lut.reallocBuffer(0);
56         _trigo_lut.reallocBuffer(0);
57         _trigo_osc.reallocBuffer(0);        
58         _buffer.reallocBuffer(0); // temporary buffer
59         _shuffledValues.reallocBuffer(0);
60     }
61 
62     /**
63     * Compute the Real FFT of the array.
64     * Params:
65     *    timeData Input array (N time samples)
66     *    outputBins Destination coefficients (N/2 + 1 frequency bins)    
67     */
68     void forwardTransform(const(T)[] timeData, Complex!T[] outputBins)
69     {
70         assert(timeData.length == _length);
71         assert(outputBins.length == (_length/2)+1);
72 
73         T[] f = _shuffledValues;
74 
75         if (_nbr_bits > 2)
76         {
77             compute_fft_general(f.ptr, timeData.ptr);
78         }        
79         else if (_nbr_bits == 2) // 4-point FFT
80         {
81             f[1] = timeData[0] - timeData[2];
82             f[3] = timeData[1] - timeData[3];
83 
84             T b_0 = timeData[0] + timeData[2];
85             T b_2 = timeData[1] + timeData[3];
86 
87             f[0] = b_0 + b_2;
88             f[2] = b_0 - b_2;
89         }        
90         else if (_nbr_bits == 1) // 2-point FFT
91         {
92             f [0] = timeData[0] + timeData[1];
93             f [1] = timeData[0] - timeData[1];
94         }        
95         else
96         {
97             f[0] = timeData[0]; // 1-point FFT
98         }
99 
100         // At this point, f contains:
101         //    f destination array (frequency bins)
102         //    f[0...length(x)/2] = real values,
103         //    f[length(x)/2+1...length(x)-1] = negative imaginary values of coefficents 1...length(x)/2-1.
104         // So we have to reshuffle them to have nice complex bins.
105         int mid = _length/2;
106         outputBins[0] = Complex!T(f[0], 0);
107         for(int i = 1; i < mid; ++i)
108             outputBins[i] = Complex!T(f[i], -f[mid+i]);
109         outputBins[mid] = Complex!T(f[mid], 0); // for length 1, this still works
110     }
111 
112     /**
113     * Compute the inverse FFT of the array. Perform post-scaling.
114     *
115     * Params:
116 	*    inputBins Source arrays (N/2 + 1 frequency bins)    
117     *    timeData Destination array (N time samples).
118     *
119     * Note: 
120     *    This transform has the benefit you don't have to conjugate the "mirorred" part of the FFT.
121     *    Excess data in imaginary part of DC and Nyquist bins are ignored.
122     */
123     void reverseTransform(Complex!T[] inputBins, T[] timeData) 
124     {
125         int mid = _length/2;
126         assert(inputBins.length == mid+1); // expect _length/2+1 complex numbers, 
127         assert(timeData.length == _length);
128 
129         // On inverse transform, scale down result
130         T invMultiplier = cast(T)1 / _length;
131 
132         // Shuffle input frequency bins, and scale down.
133         T[] f = _shuffledValues;
134         for(int i = 0; i <= mid; ++i)
135             f[i] = inputBins[i].re * invMultiplier;
136         for(int i = mid+1; i < _length; ++i)
137             f[i] = -inputBins[i-mid].im * invMultiplier;
138 
139         // At this point, the format in f is:
140         //          f [0...length(x)/2] = real values
141         //          f [length(x)/2+1...length(x)-1] = negative imaginary values of coefficents 1...length(x)/2-1.
142         // Which is suitable for the RealFFT algorithm.
143 
144         if (_nbr_bits > 2) // General case
145         {
146             compute_ifft_general(f.ptr, timeData.ptr);
147         }        
148         else if (_nbr_bits == 2) // 4-point IFFT
149         {
150             const(T) b_0 = f[0] + f[2];
151             const(T) b_2 = f[0] - f[2];
152             timeData[0] = b_0 + f[1] * 2;
153             timeData[2] = b_0 - f[1] * 2;
154             timeData[1] = b_2 + f[3] * 2;
155             timeData[3] = b_2 - f[3] * 2;
156         }
157         else if (_nbr_bits == 1) // 2-point IFFT
158         {
159             timeData[0] = f[0] + f[1];
160             timeData[1] = f[0] - f[1];
161         }
162         else // 1-point IFFT
163         {
164             timeData[0] = f[0];
165         }
166     }
167 
168 private:
169 
170     int _nbr_bits;
171     int _length;
172     int[] _br_lut;
173     T[] _trigo_lut;    
174     OscSinCos!T[] _trigo_osc;
175     T[] _buffer; // temporary buffer
176     T[] _shuffledValues; // shuffled values, output of the RFFT and input of IRFFT
177 
178     // Returns: temporary buffer
179     T* use_buffer()
180     {
181         return _buffer.ptr;
182     }
183 
184     const(int)* get_br_ptr() pure const
185     {
186         return _br_lut.ptr;
187     }
188 
189     int get_trigo_level_index(int level) pure const
190     {
191         assert(level >= 3);
192         return((1 << (level - 1)) - 4);
193     }
194 
195     const(T)* get_trigo_ptr(int level) pure const
196     {
197         return (&_trigo_lut [get_trigo_level_index (level)]);
198     }
199 
200     void init_br_lut ()
201     {
202         int length = 1 << _nbr_bits;
203         _br_lut.reallocBuffer(length);
204         _br_lut[0] = 0;
205         int br_index = 0;
206         for (int cnt = 1; cnt < length; ++cnt)
207         {
208             // ++br_index (bit reversed)
209             int bit = length >> 1;
210             while (((br_index ^= bit) & bit) == 0)
211             {
212                 bit >>= 1;
213             }
214             _br_lut[cnt] = br_index;
215         }
216     }
217 
218     void init_trigo_lut()
219     {
220         if (_nbr_bits > 3)
221         {
222             int	total_len = (1 << (_nbr_bits - 1)) - 4;
223             _trigo_lut.reallocBuffer(total_len);
224 
225             for (int level = 3; level < _nbr_bits; ++level)
226             {
227                 int level_len = 1 << (level - 1);
228                 T* level_ptr = &_trigo_lut [get_trigo_level_index (level)];
229                 double mul = PI / (level_len << 1);
230                 for (int i = 0; i < level_len; ++ i)
231                 {
232                     level_ptr[i] = cast(T)(cos (i * mul));
233                 }
234             }
235         }
236     }
237 
238     void init_trigo_osc ()
239     {
240         int	nbr_osc = _nbr_bits - TRIGO_BD_LIMIT;
241         if (nbr_osc > 0)
242         {
243             _trigo_osc.reallocBuffer(nbr_osc);
244             for (int osc_cnt = 0; osc_cnt < nbr_osc; ++osc_cnt)
245             {
246                 const int		len = 1 << (TRIGO_BD_LIMIT + osc_cnt);
247                 const double	mul = (0.5 * PI) / len;
248                 _trigo_osc[osc_cnt].setStep(mul);
249             }
250         }
251     }
252 
253     // Transform in several passes
254     void compute_fft_general (T* f, const(T)* x)
255     {
256         T*		sf;
257         T*		df;
258 
259         if ((_nbr_bits & 1) != 0)
260         {
261             df = use_buffer();
262             sf = f;
263         }
264         else
265         {
266             df = f;
267             sf = use_buffer();
268         }
269 
270         compute_direct_pass_1_2 (df, x);
271         compute_direct_pass_3 (sf, df);
272 
273         for (int pass = 3; pass < _nbr_bits; ++ pass)
274         {
275             compute_direct_pass_n (df, sf, pass);
276             T* temp_ptr = df;
277             df = sf;
278             sf = temp_ptr;
279         }
280     }
281 
282     void compute_direct_pass_1_2 (T* df, const(T)* x)
283     {
284         const(int)* bit_rev_lut_ptr = get_br_ptr();
285         int				coef_index = 0;
286         do
287         {
288             const int		rev_index_0 = bit_rev_lut_ptr [coef_index];
289             const int		rev_index_1 = bit_rev_lut_ptr [coef_index + 1];
290             const int		rev_index_2 = bit_rev_lut_ptr [coef_index + 2];
291             const int		rev_index_3 = bit_rev_lut_ptr [coef_index + 3];
292 
293             T* df2 = df + coef_index;
294             df2 [1] = x [rev_index_0] - x [rev_index_1];
295             df2 [3] = x [rev_index_2] - x [rev_index_3];
296 
297             const(T)	sf_0 = x [rev_index_0] + x [rev_index_1];
298             const(T)	sf_2 = x [rev_index_2] + x [rev_index_3];
299 
300             df2 [0] = sf_0 + sf_2;
301             df2 [2] = sf_0 - sf_2;
302 
303             coef_index += 4;
304         }
305         while (coef_index < _length);
306     }
307 
308 
309 
310     void compute_direct_pass_3 (T* df, const(T)* sf)
311     {
312         alias sqrt2_2 = SQRT1_2;
313         int				coef_index = 0;
314         do
315         {
316             T			v;
317 
318             df [coef_index] = sf [coef_index] + sf [coef_index + 4];
319             df [coef_index + 4] = sf [coef_index] - sf [coef_index + 4];
320             df [coef_index + 2] = sf [coef_index + 2];
321             df [coef_index + 6] = sf [coef_index + 6];
322 
323             v = (sf [coef_index + 5] - sf [coef_index + 7]) * sqrt2_2;
324             df [coef_index + 1] = sf [coef_index + 1] + v;
325             df [coef_index + 3] = sf [coef_index + 1] - v;
326 
327             v = (sf [coef_index + 5] + sf [coef_index + 7]) * sqrt2_2;
328             df [coef_index + 5] = v + sf [coef_index + 3];
329             df [coef_index + 7] = v - sf [coef_index + 3];
330 
331             coef_index += 8;
332         }
333         while (coef_index < _length);
334     }
335 
336     void compute_direct_pass_n (T* df, const(T)* sf, int pass)
337     {
338         assert (pass >= 3);
339         assert (pass < _nbr_bits);
340 
341         if (pass <= TRIGO_BD_LIMIT)
342         {
343             compute_direct_pass_n_lut (df, sf, pass);
344         }
345         else
346         {
347             compute_direct_pass_n_osc (df, sf, pass);
348         }
349     }
350 
351 
352 
353     void compute_direct_pass_n_lut (T* df, const(T)* sf, int pass)
354     {
355         assert (pass >= 3);
356         assert (pass < _nbr_bits);
357 
358         const int		nbr_coef = 1 << pass;
359         const int		h_nbr_coef = nbr_coef >> 1;
360         const int		d_nbr_coef = nbr_coef << 1;
361         int				coef_index = 0;
362         const(T)	* cos_ptr = get_trigo_ptr (pass);
363         do
364         {
365             const(T)	* sf1r = sf + coef_index;
366             const(T)	* sf2r = sf1r + nbr_coef;
367             T			* dfr = df + coef_index;
368             T			* dfi = dfr + nbr_coef;
369 
370             // Extreme coefficients are always real
371             dfr [0] = sf1r [0] + sf2r [0];
372             dfi [0] = sf1r [0] - sf2r [0];	// dfr [nbr_coef] =
373             dfr [h_nbr_coef] = sf1r [h_nbr_coef];
374             dfi [h_nbr_coef] = sf2r [h_nbr_coef];
375 
376             // Others are conjugate complex numbers
377             const(T) * sf1i = sf1r + h_nbr_coef;
378             const(T) * sf2i = sf1i + nbr_coef;
379             for (int i = 1; i < h_nbr_coef; ++ i)
380             {
381                 const(T)	c = cos_ptr [i];					// cos (i*PI/nbr_coef);
382                 const(T)	s = cos_ptr [h_nbr_coef - i];	// sin (i*PI/nbr_coef);
383                 T	 		v;
384 
385                 v = sf2r [i] * c - sf2i [i] * s;
386                 dfr [i] = sf1r [i] + v;
387                 dfi [-i] = sf1r [i] - v;	// dfr [nbr_coef - i] =
388 
389                 v = sf2r [i] * s + sf2i [i] * c;
390                 dfi [i] = v + sf1i [i];
391                 dfi [nbr_coef - i] = v - sf1i [i];
392             }
393 
394             coef_index += d_nbr_coef;
395         }
396         while (coef_index < _length);
397     }
398 
399     void compute_direct_pass_n_osc (T* df, const(T)* sf, int pass)
400     {
401         assert (pass > TRIGO_BD_LIMIT);
402         assert (pass < _nbr_bits);
403 
404         const int		nbr_coef = 1 << pass;
405         const int		h_nbr_coef = nbr_coef >> 1;
406         const int		d_nbr_coef = nbr_coef << 1;
407         int				coef_index = 0;
408         OscSinCos!T*      osc = &_trigo_osc[pass - (TRIGO_BD_LIMIT + 1)];
409         do
410         {
411             const(T)	* sf1r = sf + coef_index;
412             const(T)	* sf2r = sf1r + nbr_coef;
413             T			* dfr = df + coef_index;
414             T			* dfi = dfr + nbr_coef;
415 
416             osc.resetPhase();
417 
418             // Extreme coefficients are always real
419             dfr [0] = sf1r [0] + sf2r [0];
420             dfi [0] = sf1r [0] - sf2r [0];	// dfr [nbr_coef] =
421             dfr [h_nbr_coef] = sf1r [h_nbr_coef];
422             dfi [h_nbr_coef] = sf2r [h_nbr_coef];
423 
424             // Others are conjugate complex numbers
425             const(T) * sf1i = sf1r + h_nbr_coef;
426             const(T) * sf2i = sf1i + nbr_coef;
427             for (int i = 1; i < h_nbr_coef; ++ i)
428             {
429                 osc.step ();
430                 const(T)	c = osc.getCos;
431                 const(T)	s = osc.getSin;
432                 T	 		v;
433 
434                 v = sf2r [i] * c - sf2i [i] * s;
435                 dfr [i] = sf1r [i] + v;
436                 dfi [-i] = sf1r [i] - v;	// dfr [nbr_coef - i] =
437 
438                 v = sf2r [i] * s + sf2i [i] * c;
439                 dfi [i] = v + sf1i [i];
440                 dfi [nbr_coef - i] = v - sf1i [i];
441             }
442 
443             coef_index += d_nbr_coef;
444         }
445         while (coef_index < _length);
446     }
447 
448     // Transform in several pass
449     void compute_ifft_general (const(T)* f, T* x)
450     {
451         T* sf = cast(T*)(f);
452         T *		df;
453         T *		df_temp;
454 
455         if (_nbr_bits & 1)
456         {
457             df = use_buffer();
458             df_temp = x;
459         }
460         else
461         {
462             df = x;
463             df_temp = use_buffer();
464         }
465 
466         for (int pass = _nbr_bits - 1; pass >= 3; -- pass)
467         {
468             compute_inverse_pass_n (df, sf, pass);
469 
470             if (pass < _nbr_bits - 1)
471             {
472                 T* temp_ptr = df;
473                 df = sf;
474                 sf = temp_ptr;
475             }
476             else
477             {
478                 sf = df;
479                 df = df_temp;
480             }
481         }
482 
483         compute_inverse_pass_3 (df, sf);
484         compute_inverse_pass_1_2 (x, df);
485     }
486 
487     void compute_inverse_pass_n (T* df, const(T)* sf, int pass)
488     {
489         assert (pass >= 3);
490         assert (pass < _nbr_bits);
491 
492         if (pass <= TRIGO_BD_LIMIT)
493         {
494             compute_inverse_pass_n_lut (df, sf, pass);
495         }
496         else
497         {
498             compute_inverse_pass_n_osc (df, sf, pass);
499         }
500     }
501 
502     void compute_inverse_pass_n_lut (T* df, const(T)* sf, int pass)
503     {
504         assert (pass >= 3);
505         assert (pass < _nbr_bits);
506 
507         const int		nbr_coef = 1 << pass;
508         const int		h_nbr_coef = nbr_coef >> 1;
509         const int		d_nbr_coef = nbr_coef << 1;
510         int				coef_index = 0;
511         const(T)* cos_ptr = get_trigo_ptr (pass);
512         do
513         {
514             const(T)	* sfr = sf + coef_index;
515             const(T)	* sfi = sfr + nbr_coef;
516             T			* df1r = df + coef_index;
517             T			* df2r = df1r + nbr_coef;
518 
519             // Extreme coefficients are always real
520             df1r [0] = sfr [0] + sfi [0];		// + sfr [nbr_coef]
521             df2r [0] = sfr [0] - sfi [0];		// - sfr [nbr_coef]
522             df1r [h_nbr_coef] = sfr [h_nbr_coef] * 2;
523             df2r [h_nbr_coef] = sfi [h_nbr_coef] * 2;
524 
525             // Others are conjugate complex numbers
526             T * 	df1i = df1r + h_nbr_coef;
527             T * 	df2i = df1i + nbr_coef;
528             for (int i = 1; i < h_nbr_coef; ++ i)
529             {
530                 df1r [i] = sfr [i] + sfi [-i];		// + sfr [nbr_coef - i]
531                 df1i [i] = sfi [i] - sfi [nbr_coef - i];
532 
533                 const(T)	c = cos_ptr [i];					// cos (i*PI/nbr_coef);
534                 const(T)	s = cos_ptr [h_nbr_coef - i];	// sin (i*PI/nbr_coef);
535                 const(T)	vr = sfr [i] - sfi [-i];		// - sfr [nbr_coef - i]
536                 const(T)	vi = sfi [i] + sfi [nbr_coef - i];
537 
538                 df2r [i] = vr * c + vi * s;
539                 df2i [i] = vi * c - vr * s;
540             }
541 
542             coef_index += d_nbr_coef;
543         }
544         while (coef_index < _length);
545     }
546 
547     void compute_inverse_pass_n_osc (T* df, const(T)* sf, int pass)
548     {
549         assert (pass > TRIGO_BD_LIMIT);
550         assert (pass < _nbr_bits);
551 
552         const int		nbr_coef = 1 << pass;
553         const int		h_nbr_coef = nbr_coef >> 1;
554         const int		d_nbr_coef = nbr_coef << 1;
555         int				coef_index = 0;
556         OscSinCos!T*    osc = &_trigo_osc[pass - (TRIGO_BD_LIMIT + 1)];
557         do
558         {
559             const(T)	* sfr = sf + coef_index;
560             const(T)	* sfi = sfr + nbr_coef;
561             T			* df1r = df + coef_index;
562             T			* df2r = df1r + nbr_coef;
563 
564             osc.resetPhase ();
565 
566             // Extreme coefficients are always real
567             df1r [0] = sfr [0] + sfi [0];		// + sfr [nbr_coef]
568             df2r [0] = sfr [0] - sfi [0];		// - sfr [nbr_coef]
569             df1r [h_nbr_coef] = sfr [h_nbr_coef] * 2;
570             df2r [h_nbr_coef] = sfi [h_nbr_coef] * 2;
571 
572             // Others are conjugate complex numbers
573             T * df1i = df1r + h_nbr_coef;
574             T * df2i = df1i + nbr_coef;
575             for (int i = 1; i < h_nbr_coef; ++ i)
576             {
577                 df1r [i] = sfr [i] + sfi [-i];		// + sfr [nbr_coef - i]
578                 df1i [i] = sfi [i] - sfi [nbr_coef - i];
579 
580                 osc.step ();
581                 const(T)	c = osc.getCos;
582                 const(T)	s = osc.getSin;
583                 const(T)	vr = sfr [i] - sfi [-i];		// - sfr [nbr_coef - i]
584                 const(T)	vi = sfi [i] + sfi [nbr_coef - i];
585 
586                 df2r [i] = vr * c + vi * s;
587                 df2i [i] = vi * c - vr * s;
588             }
589 
590             coef_index += d_nbr_coef;
591         }
592         while (coef_index < _length);
593     }
594 
595 
596 
597     void compute_inverse_pass_3 (T* df, const(T)* sf)
598     {
599         alias sqrt2_2 = SQRT1_2;
600         int				coef_index = 0;
601         do
602         {
603             df [coef_index] = sf [coef_index] + sf [coef_index + 4];
604             df [coef_index + 4] = sf [coef_index] - sf [coef_index + 4];
605             df [coef_index + 2] = sf [coef_index + 2] * 2;
606             df [coef_index + 6] = sf [coef_index + 6] * 2;
607 
608             df [coef_index + 1] = sf [coef_index + 1] + sf [coef_index + 3];
609             df [coef_index + 3] = sf [coef_index + 5] - sf [coef_index + 7];
610 
611             const(T)	vr = sf [coef_index + 1] - sf [coef_index + 3];
612             const(T)	vi = sf [coef_index + 5] + sf [coef_index + 7];
613 
614             df [coef_index + 5] = (vr + vi) * sqrt2_2;
615             df [coef_index + 7] = (vi - vr) * sqrt2_2;
616 
617             coef_index += 8;
618         }
619         while (coef_index < _length);
620     }
621 
622     void compute_inverse_pass_1_2 (T* x, const(T)* sf)
623     {
624         const(int) *	bit_rev_lut_ptr = get_br_ptr ();
625         const(T) *	sf2 = sf;
626         int				coef_index = 0;
627         do
628         {
629             {
630                 const(T)	b_0 = sf2 [0] + sf2 [2];
631                 const(T)	b_2 = sf2 [0] - sf2 [2];
632                 const(T)	b_1 = sf2 [1] * 2;
633                 const(T)	b_3 = sf2 [3] * 2;
634 
635                 x [bit_rev_lut_ptr [0]] = b_0 + b_1;
636                 x [bit_rev_lut_ptr [1]] = b_0 - b_1;
637                 x [bit_rev_lut_ptr [2]] = b_2 + b_3;
638                 x [bit_rev_lut_ptr [3]] = b_2 - b_3;
639             }
640             {
641                 const(T)	b_0 = sf2 [4] + sf2 [6];
642                 const(T)	b_2 = sf2 [4] - sf2 [6];
643                 const(T)	b_1 = sf2 [5] * 2;
644                 const(T)	b_3 = sf2 [7] * 2;
645 
646                 x [bit_rev_lut_ptr [4]] = b_0 + b_1;
647                 x [bit_rev_lut_ptr [5]] = b_0 - b_1;
648                 x [bit_rev_lut_ptr [6]] = b_2 + b_3;
649                 x [bit_rev_lut_ptr [7]] = b_2 - b_3;
650             }
651 
652             sf2 += 8;
653             coef_index += 8;
654             bit_rev_lut_ptr += 8;
655         }
656         while (coef_index < _length);
657     }
658 
659     static struct OscSinCos(T)
660     {
661     public:
662     nothrow:
663     pure:
664     @nogc:
665         void setStep(double angleRad)
666         {
667             _step_cos = cast(T)(cos(angleRad));
668             _step_sin = cast(T)(sin(angleRad));
669         }
670 
671         alias getCos = _pos_cos;
672         alias getSin = _pos_sin;
673 
674         void resetPhase()
675         {
676             _pos_cos = 1;
677             _pos_sin = 0;
678         }
679 
680         void step()
681         {
682             T old_cos = _pos_cos;
683             T old_sin = _pos_sin;
684             _pos_cos = old_cos * _step_cos - old_sin * _step_sin;
685             _pos_sin = old_cos * _step_sin + old_sin * _step_cos;
686         }
687 
688         T _pos_cos = 1;		// Current phase expressed with sin and cos. [-1 ; 1]
689         T _pos_sin = 0;		// -
690         T _step_cos = 1;		// Phase increment per step, [-1 ; 1]
691         T _step_sin = 0;		// -
692     }
693 }
694 
695 unittest
696 {
697     import std.numeric: fft, approxEqual;
698     import dplug.dsp.rfft;
699     import std.stdio; // TEMP
700     import dplug.core.random;
701 
702     auto random = defaultGlobalRNG();
703 
704     void testRFFT(T)(T[] A)
705     {
706         // Takes reference fft
707         Complex!T[] reference = fft!T(A);
708 
709         RFFT!T rfft;
710         rfft.initialize(cast(int)A.length);
711 
712         int N = cast(int)(A.length);
713         Complex!T[] B;
714         T[] C;
715         B.reallocBuffer(N/2+1);
716         C.reallocBuffer(N);
717 
718         rfft.forwardTransform(A, B);
719 
720         foreach(i; 0..N/2+1)
721         {
722             if (!approxEqual(reference[i].re, B[i].re))
723                 assert(false);
724             if (!approxEqual(reference[i].im, B[i].im))
725                 assert(false);
726         }
727         rfft.reverseTransform(B, C);
728 
729         foreach(i; 0..N)
730         {
731             if (!approxEqual(A[i].re, C[i].re))
732                 assert(false);
733             if (!approxEqual(A[i].im, C[i].im))
734                 assert(false);
735         }
736 
737         B.reallocBuffer(0);
738         C.reallocBuffer(0);
739     }
740     testRFFT!float([0.5f]);
741     testRFFT!float([1, 2]);
742     testRFFT!float([1, 13, 5, 0]);
743     testRFFT!float([1, 13, 5, 0, 2, 0, 4, 0]);
744 
745     // test larger FFTs
746     uint seed = 1;
747     for(int bit = 4; bit < 16; ++bit)
748     {
749         int size = 1 << bit;
750         double[] sequence = new double[size];
751         foreach(i; 0..size)
752             sequence[i] = nogc_uniform_float(-1.0f, 1.0f, random);
753         testRFFT!double(sequence);
754     }
755 }