comparison vamp-sdk/hostext/PluginInputDomainAdapter.cpp @ 101:5c9f267c48c0

* Add optional support for FFTW through HAVE_FFTW3 flag. Off by default, and should be off in any distro packages, for licensing reasons.
author cannam
date Mon, 28 Jan 2008 12:34:39 +0000
parents c94c066a4897
children 2cb46126ef59
comparison
equal deleted inserted replaced
100:37348b65e792 101:5c9f267c48c0
36 36
37 #include "PluginInputDomainAdapter.h" 37 #include "PluginInputDomainAdapter.h"
38 38
39 #include <cmath> 39 #include <cmath>
40 40
41
42 /**
43 * If you want to compile using FFTW instead of the built-in FFT
44 * implementation for the PluginInputDomainAdapter, define HAVE_FFTW3
45 * in the Makefile.
46 *
47 * Remember that FFTW is licensed under the GPL (unlike this SDK, which
48 * is licensed liberally in order to permit closed-source usage), so
49 * you should not define this symbol unless your code is also under the
50 * GPL. Also, parties redistributing this SDK for use in other
51 * programs should be careful _not_ to define this symbol in order not
52 * to affect the stated license of this SDK.
53 *
54 * Note: This code uses FFTW_MEASURE, and will perform badly on its
55 * first invocation unless the host has saved and restored FFTW wisdom
56 * (see the FFTW documentation).
57 */
58 #ifdef HAVE_FFTW3
59 #include <fftw3.h>
60 #endif
61
62
41 namespace Vamp { 63 namespace Vamp {
42 64
43 namespace HostExt { 65 namespace HostExt {
44 66
45 class PluginInputDomainAdapter::Impl 67 class PluginInputDomainAdapter::Impl
56 FeatureSet process(const float *const *inputBuffers, RealTime timestamp); 78 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
57 79
58 protected: 80 protected:
59 Plugin *m_plugin; 81 Plugin *m_plugin;
60 float m_inputSampleRate; 82 float m_inputSampleRate;
61 size_t m_channels; 83 int m_channels;
62 size_t m_blockSize; 84 int m_blockSize;
63 float **m_freqbuf; 85 float **m_freqbuf;
86
64 double *m_ri; 87 double *m_ri;
88 double *m_window;
89
90 #ifdef HAVE_FFTW3
91 fftw_plan m_plan;
92 fftw_complex *m_cbuf;
93 #else
65 double *m_ro; 94 double *m_ro;
66 double *m_io; 95 double *m_io;
67
68 void fft(unsigned int n, bool inverse, 96 void fft(unsigned int n, bool inverse,
69 double *ri, double *ii, double *ro, double *io); 97 double *ri, double *ii, double *ro, double *io);
98 #endif
70 99
71 size_t makeBlockSizeAcceptable(size_t) const; 100 size_t makeBlockSizeAcceptable(size_t) const;
72 }; 101 };
73 102
74 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) : 103 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
115 PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : 144 PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
116 m_plugin(plugin), 145 m_plugin(plugin),
117 m_inputSampleRate(inputSampleRate), 146 m_inputSampleRate(inputSampleRate),
118 m_channels(0), 147 m_channels(0),
119 m_blockSize(0), 148 m_blockSize(0),
120 m_freqbuf(0) 149 m_freqbuf(0),
150 m_ri(0),
151 m_window(0),
152 #ifdef HAVE_FFTW3
153 m_plan(0),
154 m_cbuf(0)
155 #else
156 m_ro(0),
157 m_io(0)
158 #endif
121 { 159 {
122 } 160 }
123 161
124 PluginInputDomainAdapter::Impl::~Impl() 162 PluginInputDomainAdapter::Impl::~Impl()
125 { 163 {
126 // the adapter will delete the plugin 164 // the adapter will delete the plugin
127 165
128 if (m_channels > 0) { 166 if (m_channels > 0) {
129 for (size_t c = 0; c < m_channels; ++c) { 167 for (int c = 0; c < m_channels; ++c) {
130 delete[] m_freqbuf[c]; 168 delete[] m_freqbuf[c];
131 } 169 }
132 delete[] m_freqbuf; 170 delete[] m_freqbuf;
171 #ifdef HAVE_FFTW3
172 if (m_plan) {
173 fftw_destroy_plan(m_plan);
174 fftw_free(m_ri);
175 fftw_free(m_cbuf);
176 m_plan = 0;
177 }
178 #else
133 delete[] m_ri; 179 delete[] m_ri;
134 delete[] m_ro; 180 delete[] m_ro;
135 delete[] m_io; 181 delete[] m_io;
136 } 182 #endif
137 } 183 delete[] m_window;
184 }
185 }
186
187 // for some visual studii apparently
188 #ifndef M_PI
189 #define M_PI 3.14159265358979232846
190 #endif
138 191
139 bool 192 bool
140 PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) 193 PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
141 { 194 {
142 if (m_plugin->getInputDomain() == TimeDomain) { 195 if (m_plugin->getInputDomain() == TimeDomain) {
143 196
144 m_blockSize = blockSize; 197 m_blockSize = int(blockSize);
145 m_channels = channels; 198 m_channels = int(channels);
146 199
147 return m_plugin->initialise(channels, stepSize, blockSize); 200 return m_plugin->initialise(channels, stepSize, blockSize);
148 } 201 }
149 202
150 if (blockSize < 2) { 203 if (blockSize < 2) {
156 std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl; 209 std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
157 return false; 210 return false;
158 } 211 }
159 212
160 if (m_channels > 0) { 213 if (m_channels > 0) {
161 for (size_t c = 0; c < m_channels; ++c) { 214 for (int c = 0; c < m_channels; ++c) {
162 delete[] m_freqbuf[c]; 215 delete[] m_freqbuf[c];
163 } 216 }
164 delete[] m_freqbuf; 217 delete[] m_freqbuf;
218 #ifdef HAVE_FFTW3
219 if (m_plan) {
220 fftw_destroy_plan(m_plan);
221 fftw_free(m_ri);
222 fftw_free(m_cbuf);
223 m_plan = 0;
224 }
225 #else
165 delete[] m_ri; 226 delete[] m_ri;
166 delete[] m_ro; 227 delete[] m_ro;
167 delete[] m_io; 228 delete[] m_io;
168 } 229 #endif
169 230 delete[] m_window;
170 m_blockSize = blockSize; 231 }
171 m_channels = channels; 232
233 m_blockSize = int(blockSize);
234 m_channels = int(channels);
172 235
173 m_freqbuf = new float *[m_channels]; 236 m_freqbuf = new float *[m_channels];
174 for (size_t c = 0; c < m_channels; ++c) { 237 for (int c = 0; c < m_channels; ++c) {
175 m_freqbuf[c] = new float[m_blockSize + 2]; 238 m_freqbuf[c] = new float[m_blockSize + 2];
176 } 239 }
240 m_window = new double[m_blockSize];
241
242 for (int i = 0; i < m_blockSize; ++i) {
243 // Hanning window
244 m_window[i] = (0.50 - 0.50 * cos((2.0 * M_PI * i) / m_blockSize));
245 }
246
247 #ifdef HAVE_FFTW3
248 m_ri = (double *)fftw_malloc(blockSize * sizeof(double));
249 m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex));
250 m_plan = fftw_plan_dft_r2c_1d(blockSize, m_ri, m_cbuf, FFTW_MEASURE);
251 #else
177 m_ri = new double[m_blockSize]; 252 m_ri = new double[m_blockSize];
178 m_ro = new double[m_blockSize]; 253 m_ro = new double[m_blockSize];
179 m_io = new double[m_blockSize]; 254 m_io = new double[m_blockSize];
255 #endif
180 256
181 return m_plugin->initialise(channels, stepSize, blockSize); 257 return m_plugin->initialise(channels, stepSize, blockSize);
182 } 258 }
183 259
184 size_t 260 size_t
218 << "supported, increasing from " << blockSize << " to 2" << std::endl; 294 << "supported, increasing from " << blockSize << " to 2" << std::endl;
219 blockSize = 2; 295 blockSize = 2;
220 296
221 } else if (blockSize & (blockSize-1)) { 297 } else if (blockSize & (blockSize-1)) {
222 298
223 // not a power of two, can't handle that with our current fft 299 #ifdef HAVE_FFTW3
300 // not an issue with FFTW
301 #else
302
303 // not a power of two, can't handle that with our built-in FFT
224 // implementation 304 // implementation
225 305
226 size_t nearest = blockSize; 306 size_t nearest = blockSize;
227 size_t power = 0; 307 size_t power = 0;
228 while (nearest > 1) { 308 while (nearest > 1) {
239 nearest = nearest*2; 319 nearest = nearest*2;
240 } 320 }
241 321
242 std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl; 322 std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
243 blockSize = nearest; 323 blockSize = nearest;
324
325 #endif
244 } 326 }
245 327
246 return blockSize; 328 return blockSize;
247 } 329 }
248
249 // for some visual studii apparently
250 #ifndef M_PI
251 #define M_PI 3.14159265358979232846
252 #endif
253 330
254 Plugin::FeatureSet 331 Plugin::FeatureSet
255 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers, 332 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
256 RealTime timestamp) 333 RealTime timestamp)
257 { 334 {
306 timestamp = timestamp + RealTime::frame2RealTime 383 timestamp = timestamp + RealTime::frame2RealTime
307 (m_blockSize/2, int(m_inputSampleRate + 0.5)); 384 (m_blockSize/2, int(m_inputSampleRate + 0.5));
308 385
309 // std::cerr << " to " << timestamp << std::endl; 386 // std::cerr << " to " << timestamp << std::endl;
310 387
311 for (size_t c = 0; c < m_channels; ++c) { 388 for (int c = 0; c < m_channels; ++c) {
312 389
313 for (size_t i = 0; i < m_blockSize; ++i) { 390 for (int i = 0; i < m_blockSize; ++i) {
314 // Hanning window 391 m_ri[i] = double(inputBuffers[c][i]) * m_window[i];
315 m_ri[i] = double(inputBuffers[c][i]) 392 }
316 * (0.50 - 0.50 * cos((2 * M_PI * i) 393
317 / m_blockSize)); 394 for (int i = 0; i < m_blockSize/2; ++i) {
318 }
319
320 for (size_t i = 0; i < m_blockSize/2; ++i) {
321 // FFT shift 395 // FFT shift
322 double value = m_ri[i]; 396 double value = m_ri[i];
323 m_ri[i] = m_ri[i + m_blockSize/2]; 397 m_ri[i] = m_ri[i + m_blockSize/2];
324 m_ri[i + m_blockSize/2] = value; 398 m_ri[i + m_blockSize/2] = value;
325 } 399 }
326 400
401 #ifdef HAVE_FFTW3
402
403 fftw_execute(m_plan);
404
405 for (int i = 0; i <= m_blockSize/2; ++i) {
406 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
407 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
408 }
409
410 #else
411
327 fft(m_blockSize, false, m_ri, 0, m_ro, m_io); 412 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
328 413
329 for (size_t i = 0; i <= m_blockSize/2; ++i) { 414 for (int i = 0; i <= m_blockSize/2; ++i) {
330 m_freqbuf[c][i * 2] = m_ro[i]; 415 m_freqbuf[c][i * 2] = float(m_ro[i]);
331 m_freqbuf[c][i * 2 + 1] = m_io[i]; 416 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
332 } 417 }
418
419 #endif
333 } 420 }
334 421
335 return m_plugin->process(m_freqbuf, timestamp); 422 return m_plugin->process(m_freqbuf, timestamp);
336 } 423 }
424
425 #ifndef HAVE_FFTW3
337 426
338 void 427 void
339 PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse, 428 PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse,
340 double *ri, double *ii, double *ro, double *io) 429 double *ri, double *ii, double *ro, double *io)
341 { 430 {
450 io[i] /= denom; 539 io[i] /= denom;
451 } 540 }
452 } 541 }
453 } 542 }
454 543
544 #endif
545
455 } 546 }
456 547
457 } 548 }
458 549