cannam@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@0
|
2
|
cannam@0
|
3 /*
|
cannam@0
|
4 QM DSP Library
|
cannam@0
|
5
|
cannam@0
|
6 Centre for Digital Music, Queen Mary, University of London.
|
cannam@0
|
7 */
|
cannam@0
|
8
|
cannam@0
|
9 #include "FFT.h"
|
cannam@55
|
10
|
cannam@55
|
11 #include "maths/MathUtilities.h"
|
cannam@55
|
12
|
Chris@129
|
13 #include "kiss_fft.h"
|
Chris@129
|
14 #include "kiss_fftr.h"
|
Chris@129
|
15
|
cannam@0
|
16 #include <cmath>
|
cannam@0
|
17
|
cannam@55
|
18 #include <iostream>
|
cannam@55
|
19
|
Chris@129
|
20 #include <stdexcept>
|
Chris@129
|
21
|
Chris@129
|
22 class FFT::D
|
Chris@129
|
23 {
|
Chris@129
|
24 public:
|
Chris@129
|
25 D(int n) : m_n(n) {
|
Chris@129
|
26 m_planf = kiss_fft_alloc(m_n, 0, NULL, NULL);
|
Chris@129
|
27 m_plani = kiss_fft_alloc(m_n, 1, NULL, NULL);
|
Chris@129
|
28 m_kin = new kiss_fft_cpx[m_n];
|
Chris@129
|
29 m_kout = new kiss_fft_cpx[m_n];
|
Chris@129
|
30 }
|
Chris@129
|
31
|
Chris@129
|
32 ~D() {
|
Chris@129
|
33 kiss_fft_free(m_planf);
|
Chris@129
|
34 kiss_fft_free(m_plani);
|
Chris@129
|
35 delete[] m_kin;
|
Chris@129
|
36 delete[] m_kout;
|
Chris@129
|
37 }
|
Chris@129
|
38
|
Chris@129
|
39 void process(bool inverse,
|
Chris@129
|
40 const double *ri,
|
Chris@129
|
41 const double *ii,
|
Chris@129
|
42 double *ro,
|
Chris@129
|
43 double *io) {
|
Chris@129
|
44
|
Chris@129
|
45 for (int i = 0; i < m_n; ++i) {
|
Chris@129
|
46 m_kin[i].r = ri[i];
|
Chris@129
|
47 m_kin[i].i = (ii ? ii[i] : 0.0);
|
Chris@129
|
48 }
|
Chris@129
|
49
|
Chris@129
|
50 if (!inverse) {
|
Chris@129
|
51
|
Chris@129
|
52 kiss_fft(m_planf, m_kin, m_kout);
|
Chris@129
|
53
|
Chris@129
|
54 for (int i = 0; i < m_n; ++i) {
|
Chris@129
|
55 ro[i] = m_kout[i].r;
|
Chris@129
|
56 io[i] = m_kout[i].i;
|
Chris@129
|
57 }
|
Chris@129
|
58
|
Chris@129
|
59 } else {
|
Chris@129
|
60
|
Chris@129
|
61 kiss_fft(m_plani, m_kin, m_kout);
|
Chris@129
|
62
|
Chris@129
|
63 double scale = 1.0 / m_n;
|
Chris@129
|
64
|
Chris@129
|
65 for (int i = 0; i < m_n; ++i) {
|
Chris@129
|
66 ro[i] = m_kout[i].r * scale;
|
Chris@129
|
67 io[i] = m_kout[i].i * scale;
|
Chris@129
|
68 }
|
Chris@129
|
69 }
|
Chris@129
|
70 }
|
Chris@129
|
71
|
Chris@129
|
72 private:
|
Chris@129
|
73 int m_n;
|
Chris@129
|
74 kiss_fft_cfg m_planf;
|
Chris@129
|
75 kiss_fft_cfg m_plani;
|
Chris@129
|
76 kiss_fft_cpx *m_kin;
|
Chris@129
|
77 kiss_fft_cpx *m_kout;
|
Chris@129
|
78 };
|
Chris@129
|
79
|
Chris@114
|
80 FFT::FFT(int n) :
|
Chris@129
|
81 m_d(new D(n))
|
cannam@0
|
82 {
|
cannam@0
|
83 }
|
cannam@0
|
84
|
cannam@0
|
85 FFT::~FFT()
|
cannam@0
|
86 {
|
Chris@129
|
87 delete m_d;
|
cannam@0
|
88 }
|
cannam@0
|
89
|
Chris@129
|
90 void
|
Chris@129
|
91 FFT::process(bool inverse,
|
Chris@129
|
92 const double *p_lpRealIn, const double *p_lpImagIn,
|
Chris@129
|
93 double *p_lpRealOut, double *p_lpImagOut)
|
Chris@129
|
94 {
|
Chris@129
|
95 m_d->process(inverse,
|
Chris@129
|
96 p_lpRealIn, p_lpImagIn,
|
Chris@129
|
97 p_lpRealOut, p_lpImagOut);
|
Chris@129
|
98 }
|
Chris@129
|
99
|
Chris@129
|
100 class FFTReal::D
|
Chris@129
|
101 {
|
Chris@129
|
102 public:
|
Chris@129
|
103 D(int n) : m_n(n) {
|
Chris@129
|
104 if (n % 2) {
|
Chris@129
|
105 throw std::invalid_argument
|
Chris@129
|
106 ("nsamples must be even in FFTReal constructor");
|
Chris@129
|
107 }
|
Chris@129
|
108 m_planf = kiss_fftr_alloc(m_n, 0, NULL, NULL);
|
Chris@129
|
109 m_plani = kiss_fftr_alloc(m_n, 1, NULL, NULL);
|
Chris@129
|
110 m_c = new kiss_fft_cpx[m_n];
|
Chris@129
|
111 }
|
Chris@129
|
112
|
Chris@129
|
113 ~D() {
|
Chris@129
|
114 kiss_fftr_free(m_planf);
|
Chris@129
|
115 kiss_fftr_free(m_plani);
|
Chris@129
|
116 delete[] m_c;
|
Chris@129
|
117 }
|
Chris@129
|
118
|
Chris@129
|
119 void forward(const double *ri, double *ro, double *io) {
|
Chris@129
|
120
|
Chris@129
|
121 kiss_fftr(m_planf, ri, m_c);
|
Chris@129
|
122
|
Chris@129
|
123 for (int i = 0; i <= m_n/2; ++i) {
|
Chris@129
|
124 ro[i] = m_c[i].r;
|
Chris@129
|
125 io[i] = m_c[i].i;
|
Chris@129
|
126 }
|
Chris@129
|
127
|
Chris@129
|
128 for (int i = 0; i + 1 < m_n/2; ++i) {
|
Chris@129
|
129 ro[m_n - i - 1] = ro[i + 1];
|
Chris@129
|
130 io[m_n - i - 1] = -io[i + 1];
|
Chris@129
|
131 }
|
Chris@129
|
132 }
|
Chris@129
|
133
|
Chris@131
|
134 void forwardMagnitude(const double *ri, double *mo) {
|
Chris@131
|
135
|
Chris@131
|
136 double *io = new double[m_n];
|
Chris@131
|
137
|
Chris@131
|
138 forward(ri, mo, io);
|
Chris@131
|
139
|
Chris@131
|
140 for (int i = 0; i < m_n; ++i) {
|
Chris@131
|
141 mo[i] = sqrt(mo[i] * mo[i] + io[i] * io[i]);
|
Chris@131
|
142 }
|
Chris@131
|
143
|
Chris@131
|
144 delete[] io;
|
Chris@131
|
145 }
|
Chris@131
|
146
|
Chris@129
|
147 void inverse(const double *ri, const double *ii, double *ro) {
|
Chris@129
|
148
|
Chris@170
|
149 // kiss_fftr.h says
|
Chris@170
|
150 // "input freqdata has nfft/2+1 complex points"
|
Chris@170
|
151
|
Chris@170
|
152 for (int i = 0; i < m_n/2 + 1; ++i) {
|
Chris@129
|
153 m_c[i].r = ri[i];
|
Chris@129
|
154 m_c[i].i = ii[i];
|
Chris@129
|
155 }
|
Chris@129
|
156
|
Chris@129
|
157 kiss_fftri(m_plani, m_c, ro);
|
Chris@129
|
158
|
Chris@129
|
159 double scale = 1.0 / m_n;
|
Chris@129
|
160
|
Chris@129
|
161 for (int i = 0; i < m_n; ++i) {
|
Chris@129
|
162 ro[i] *= scale;
|
Chris@129
|
163 }
|
Chris@129
|
164 }
|
Chris@129
|
165
|
Chris@129
|
166 private:
|
Chris@129
|
167 int m_n;
|
Chris@129
|
168 kiss_fftr_cfg m_planf;
|
Chris@129
|
169 kiss_fftr_cfg m_plani;
|
Chris@129
|
170 kiss_fft_cpx *m_c;
|
Chris@129
|
171 };
|
Chris@129
|
172
|
Chris@114
|
173 FFTReal::FFTReal(int n) :
|
Chris@129
|
174 m_d(new D(n))
|
cannam@0
|
175 {
|
cannam@64
|
176 }
|
cannam@0
|
177
|
cannam@64
|
178 FFTReal::~FFTReal()
|
cannam@64
|
179 {
|
Chris@129
|
180 delete m_d;
|
cannam@64
|
181 }
|
cannam@64
|
182
|
cannam@64
|
183 void
|
Chris@129
|
184 FFTReal::forward(const double *ri, double *ro, double *io)
|
cannam@64
|
185 {
|
Chris@129
|
186 m_d->forward(ri, ro, io);
|
cannam@64
|
187 }
|
cannam@64
|
188
|
Chris@114
|
189 void
|
Chris@131
|
190 FFTReal::forwardMagnitude(const double *ri, double *mo)
|
Chris@131
|
191 {
|
Chris@131
|
192 m_d->forwardMagnitude(ri, mo);
|
Chris@131
|
193 }
|
Chris@131
|
194
|
Chris@131
|
195 void
|
Chris@129
|
196 FFTReal::inverse(const double *ri, const double *ii, double *ro)
|
Chris@114
|
197 {
|
Chris@129
|
198 m_d->inverse(ri, ii, ro);
|
Chris@114
|
199 }
|
Chris@114
|
200
|
cannam@64
|
201
|
Chris@129
|
202
|