comparison src/dsp/FFT.cpp @ 120:3fa7e938e7d4

Add FFT interface code
author Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 15 May 2014 12:29:30 +0100
parents
children edbec47f4a3d
comparison
equal deleted inserted replaced
119:a38d6940f8fb 120:3fa7e938e7d4
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 /*
3 Constant-Q library
4 Copyright (c) 2013-2014 Queen Mary, University of London
5
6 Permission is hereby granted, free of charge, to any person
7 obtaining a copy of this software and associated documentation
8 files (the "Software"), to deal in the Software without
9 restriction, including without limitation the rights to use, copy,
10 modify, merge, publish, distribute, sublicense, and/or sell copies
11 of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
22 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 Except as contained in this notice, the names of the Centre for
26 Digital Music; Queen Mary, University of London; and Chris Cannam
27 shall not be used in advertising or otherwise to promote the sale,
28 use or other dealings in this Software without prior written
29 authorization.
30 */
31
32 #include "FFT.h"
33
34 #include "maths/MathUtilities.h"
35
36 #include "kiss_fft.h"
37 #include "kiss_fftr.h"
38
39 #include <cmath>
40
41 #include <iostream>
42
43 #include <stdexcept>
44
45 class FFT::D
46 {
47 public:
48 D(int n) : m_n(n) {
49 m_planf = kiss_fft_alloc(m_n, 0, NULL, NULL);
50 m_plani = kiss_fft_alloc(m_n, 1, NULL, NULL);
51 m_kin = new kiss_fft_cpx[m_n];
52 m_kout = new kiss_fft_cpx[m_n];
53 }
54
55 ~D() {
56 kiss_fft_free(m_planf);
57 kiss_fft_free(m_plani);
58 delete[] m_kin;
59 delete[] m_kout;
60 }
61
62 void process(bool inverse,
63 const double *ri,
64 const double *ii,
65 double *ro,
66 double *io) {
67
68 for (int i = 0; i < m_n; ++i) {
69 m_kin[i].r = ri[i];
70 m_kin[i].i = (ii ? ii[i] : 0.0);
71 }
72
73 if (!inverse) {
74
75 kiss_fft(m_planf, m_kin, m_kout);
76
77 for (int i = 0; i < m_n; ++i) {
78 ro[i] = m_kout[i].r;
79 io[i] = m_kout[i].i;
80 }
81
82 } else {
83
84 kiss_fft(m_plani, m_kin, m_kout);
85
86 double scale = 1.0 / m_n;
87
88 for (int i = 0; i < m_n; ++i) {
89 ro[i] = m_kout[i].r * scale;
90 io[i] = m_kout[i].i * scale;
91 }
92 }
93 }
94
95 private:
96 int m_n;
97 kiss_fft_cfg m_planf;
98 kiss_fft_cfg m_plani;
99 kiss_fft_cpx *m_kin;
100 kiss_fft_cpx *m_kout;
101 };
102
103 FFT::FFT(int n) :
104 m_d(new D(n))
105 {
106 }
107
108 FFT::~FFT()
109 {
110 delete m_d;
111 }
112
113 void
114 FFT::process(bool inverse,
115 const double *p_lpRealIn, const double *p_lpImagIn,
116 double *p_lpRealOut, double *p_lpImagOut)
117 {
118 m_d->process(inverse,
119 p_lpRealIn, p_lpImagIn,
120 p_lpRealOut, p_lpImagOut);
121 }
122
123 class FFTReal::D
124 {
125 public:
126 D(int n) : m_n(n) {
127 if (n % 2) {
128 throw std::invalid_argument
129 ("nsamples must be even in FFTReal constructor");
130 }
131 m_planf = kiss_fftr_alloc(m_n, 0, NULL, NULL);
132 m_plani = kiss_fftr_alloc(m_n, 1, NULL, NULL);
133 m_c = new kiss_fft_cpx[m_n];
134 }
135
136 ~D() {
137 kiss_fftr_free(m_planf);
138 kiss_fftr_free(m_plani);
139 delete[] m_c;
140 }
141
142 void forward(const double *ri, double *ro, double *io) {
143
144 kiss_fftr(m_planf, ri, m_c);
145
146 for (int i = 0; i <= m_n/2; ++i) {
147 ro[i] = m_c[i].r;
148 io[i] = m_c[i].i;
149 }
150
151 for (int i = 0; i + 1 < m_n/2; ++i) {
152 ro[m_n - i - 1] = ro[i + 1];
153 io[m_n - i - 1] = -io[i + 1];
154 }
155 }
156
157 void forwardMagnitude(const double *ri, double *mo) {
158
159 double *io = new double[m_n];
160
161 forward(ri, mo, io);
162
163 for (int i = 0; i < m_n; ++i) {
164 mo[i] = sqrt(mo[i] * mo[i] + io[i] * io[i]);
165 }
166
167 delete[] io;
168 }
169
170 void inverse(const double *ri, const double *ii, double *ro) {
171
172 // kiss_fftr.h says
173 // "input freqdata has nfft/2+1 complex points"
174
175 for (int i = 0; i < m_n/2 + 1; ++i) {
176 m_c[i].r = ri[i];
177 m_c[i].i = ii[i];
178 }
179
180 kiss_fftri(m_plani, m_c, ro);
181
182 double scale = 1.0 / m_n;
183
184 for (int i = 0; i < m_n; ++i) {
185 ro[i] *= scale;
186 }
187 }
188
189 private:
190 int m_n;
191 kiss_fftr_cfg m_planf;
192 kiss_fftr_cfg m_plani;
193 kiss_fft_cpx *m_c;
194 };
195
196 FFTReal::FFTReal(int n) :
197 m_d(new D(n))
198 {
199 }
200
201 FFTReal::~FFTReal()
202 {
203 delete m_d;
204 }
205
206 void
207 FFTReal::forward(const double *ri, double *ro, double *io)
208 {
209 m_d->forward(ri, ro, io);
210 }
211
212 void
213 FFTReal::forwardMagnitude(const double *ri, double *mo)
214 {
215 m_d->forwardMagnitude(ri, mo);
216 }
217
218 void
219 FFTReal::inverse(const double *ri, const double *ii, double *ro)
220 {
221 m_d->inverse(ri, ii, ro);
222 }
223
224
225