comparison src/vamp-hostsdk/PluginInputDomainAdapter.cpp @ 434:e979a9c4ffb6 vampipe

Switch from Cross FFT with option of FFTW build, to KissFFT only (code bundled). This is much faster than the default build and simpler than managing two options.
author Chris Cannam
date Tue, 16 Aug 2016 16:04:09 +0100
parents 9a2998401bbe
children 27c3448df198
comparison
equal deleted inserted replaced
432:8dea61e4a7be 434:e979a9c4ffb6
41 41
42 #include <cmath> 42 #include <cmath>
43 43
44 #include "Window.h" 44 #include "Window.h"
45 45
46 46 #include <stdlib.h>
47 /** 47 #include <stdio.h>
48 * If you want to compile using FFTW instead of the built-in FFT 48 #include <math.h>
49 * implementation for the PluginInputDomainAdapter, define HAVE_FFTW3 49 #include <string.h>
50 * in the Makefile. 50 #include <limits.h>
51 * 51
52 * Be aware that FFTW is licensed under the GPL -- unlike this SDK, 52 // Override C linkage for KissFFT headers. So long as we have already
53 * which is provided under a more liberal BSD license in order to 53 // included all of the other (system etc) headers KissFFT depends on,
54 * permit use in closed source applications. The use of FFTW would 54 // this should work out OK
55 * mean that your code would need to be licensed under the GPL as 55 #undef __cplusplus
56 * well. Do not define this symbol unless you understand and accept 56
57 * the implications of this. 57 namespace KissSingle {
58 * 58 #undef KISS_FFT_H
59 * Parties such as Linux distribution packagers who redistribute this 59 #undef KISS_FTR_H
60 * SDK for use in other programs should _not_ define this symbol, as 60 #undef KISS_FFT__GUTS_H
61 * it would change the effective licensing terms under which the SDK 61 #undef FIXED_POINT
62 * was available to third party developers. 62 #undef USE_SIMD
63 * 63 #undef kiss_fft_scalar
64 * The default is not to use FFTW, and to use the built-in FFT instead. 64 #define kiss_fft_scalar float
65 * 65 inline void free(void *ptr) { ::free(ptr); }
66 * Note: The FFTW code uses FFTW_MEASURE, and so will perform badly on 66 #include "../vamp-sdk/ext/kiss_fft.c"
67 * its first invocation unless the host has saved and restored FFTW 67 #include "../vamp-sdk/ext/kiss_fftr.c"
68 * wisdom (see the FFTW documentation). 68 }
69 */
70 #ifdef HAVE_FFTW3
71 #include <fftw3.h>
72 #pragma message("*** NOTE: Compiling with FFTW3 support will result in a GPL binary")
73 #else
74 #include "../vamp-sdk/FFTimpl.cpp"
75 #endif
76
77 69
78 _VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.cpp) 70 _VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.cpp)
79 71
80 namespace Vamp { 72 namespace Vamp {
81 73
108 float m_inputSampleRate; 100 float m_inputSampleRate;
109 int m_channels; 101 int m_channels;
110 int m_stepSize; 102 int m_stepSize;
111 int m_blockSize; 103 int m_blockSize;
112 float **m_freqbuf; 104 float **m_freqbuf;
113 105 float *m_ri;
114 double *m_ri;
115 106
116 WindowType m_windowType; 107 WindowType m_windowType;
117 Window<double> *m_window; 108 Window<float> *m_window;
118 109
119 ProcessTimestampMethod m_method; 110 ProcessTimestampMethod m_method;
120 int m_processCount; 111 int m_processCount;
121 float **m_shiftBuffers; 112 float **m_shiftBuffers;
122 113
123 #ifdef HAVE_FFTW3 114 KissSingle::kiss_fftr_cfg m_cfg;
124 fftw_plan m_plan; 115 KissSingle::kiss_fft_cpx *m_cbuf;
125 fftw_complex *m_cbuf;
126 #else
127 double *m_ro;
128 double *m_io;
129 #endif
130 116
131 FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp); 117 FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp);
132 FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp); 118 FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp);
133 119
134 size_t makeBlockSizeAcceptable(size_t) const; 120 size_t makeBlockSizeAcceptable(size_t) const;
135 121
136 Window<double>::WindowType convertType(WindowType t) const; 122 Window<float>::WindowType convertType(WindowType t) const;
137 }; 123 };
138 124
139 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) : 125 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
140 PluginWrapper(plugin) 126 PluginWrapper(plugin)
141 { 127 {
225 m_windowType(HanningWindow), 211 m_windowType(HanningWindow),
226 m_window(0), 212 m_window(0),
227 m_method(ShiftTimestamp), 213 m_method(ShiftTimestamp),
228 m_processCount(0), 214 m_processCount(0),
229 m_shiftBuffers(0), 215 m_shiftBuffers(0),
230 #ifdef HAVE_FFTW3 216 m_cfg(0),
231 m_plan(0),
232 m_cbuf(0) 217 m_cbuf(0)
233 #else
234 m_ro(0),
235 m_io(0)
236 #endif
237 { 218 {
238 } 219 }
239 220
240 PluginInputDomainAdapter::Impl::~Impl() 221 PluginInputDomainAdapter::Impl::~Impl()
241 { 222 {
251 if (m_channels > 0) { 232 if (m_channels > 0) {
252 for (int c = 0; c < m_channels; ++c) { 233 for (int c = 0; c < m_channels; ++c) {
253 delete[] m_freqbuf[c]; 234 delete[] m_freqbuf[c];
254 } 235 }
255 delete[] m_freqbuf; 236 delete[] m_freqbuf;
256 #ifdef HAVE_FFTW3 237 if (m_cfg) {
257 if (m_plan) { 238 KissSingle::kiss_fftr_free(m_cfg);
258 fftw_destroy_plan(m_plan); 239 delete[] m_cbuf;
259 fftw_free(m_ri); 240 m_cfg = 0;
260 fftw_free(m_cbuf); 241 }
261 m_plan = 0;
262 }
263 #else
264 delete[] m_ri;
265 delete[] m_ro;
266 delete[] m_io;
267 #endif
268
269 delete m_window; 242 delete m_window;
270 } 243 }
271 } 244 }
272 245
273 // for some visual studii apparently 246 // for some visual studii apparently
290 if (blockSize < 2) { 263 if (blockSize < 2) {
291 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl; 264 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl;
292 return false; 265 return false;
293 } 266 }
294 267
295 #ifndef HAVE_FFTW3 268 if (blockSize % 2) {
296 if (blockSize & (blockSize-1)) { 269 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: odd blocksize " << blockSize << " not supported" << std::endl;
297 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
298 return false; 270 return false;
299 } 271 }
300 #endif
301 272
302 if (m_channels > 0) { 273 if (m_channels > 0) {
303 for (int c = 0; c < m_channels; ++c) { 274 for (int c = 0; c < m_channels; ++c) {
304 delete[] m_freqbuf[c]; 275 delete[] m_freqbuf[c];
305 } 276 }
306 delete[] m_freqbuf; 277 delete[] m_freqbuf;
307 #ifdef HAVE_FFTW3 278 if (m_cfg) {
308 if (m_plan) { 279 KissSingle::kiss_fftr_free(m_cfg);
309 fftw_destroy_plan(m_plan); 280 delete[] m_cbuf;
310 fftw_free(m_ri); 281 m_cfg = 0;
311 fftw_free(m_cbuf); 282 }
312 m_plan = 0;
313 }
314 #else
315 delete[] m_ri;
316 delete[] m_ro;
317 delete[] m_io;
318 #endif
319 delete m_window; 283 delete m_window;
320 } 284 }
321 285
322 m_stepSize = int(stepSize); 286 m_stepSize = int(stepSize);
323 m_blockSize = int(blockSize); 287 m_blockSize = int(blockSize);
326 m_freqbuf = new float *[m_channels]; 290 m_freqbuf = new float *[m_channels];
327 for (int c = 0; c < m_channels; ++c) { 291 for (int c = 0; c < m_channels; ++c) {
328 m_freqbuf[c] = new float[m_blockSize + 2]; 292 m_freqbuf[c] = new float[m_blockSize + 2];
329 } 293 }
330 294
331 m_window = new Window<double>(convertType(m_windowType), m_blockSize); 295 m_window = new Window<float>(convertType(m_windowType), m_blockSize);
332 296
333 #ifdef HAVE_FFTW3 297 m_cfg = KissSingle::kiss_fftr_alloc(blockSize, false, 0, 0);
334 m_ri = (double *)fftw_malloc(blockSize * sizeof(double)); 298 m_cbuf = new KissSingle::kiss_fft_cpx[blockSize/2+1];
335 m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex));
336 m_plan = fftw_plan_dft_r2c_1d(int(blockSize), m_ri, m_cbuf, FFTW_MEASURE);
337 #else
338 m_ri = new double[m_blockSize];
339 m_ro = new double[m_blockSize];
340 m_io = new double[m_blockSize];
341 #endif
342 299
343 m_processCount = 0; 300 m_processCount = 0;
344 301
345 return m_plugin->initialise(channels, stepSize, blockSize); 302 return m_plugin->initialise(channels, stepSize, blockSize);
346 } 303 }
386 if (blockSize < 2) { 343 if (blockSize < 2) {
387 344
388 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl 345 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl
389 << "supported, increasing from " << blockSize << " to 2" << std::endl; 346 << "supported, increasing from " << blockSize << " to 2" << std::endl;
390 blockSize = 2; 347 blockSize = 2;
348
349 } else if (blockSize % 2) {
391 350
392 } else if (blockSize & (blockSize-1)) { 351 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: odd blocksize not" << std::endl
393 352 << "supported, increasing from " << blockSize << " to " << (blockSize+1) << std::endl;
394 #ifdef HAVE_FFTW3 353 blockSize = blockSize+1;
395 // not an issue with FFTW
396 #else
397
398 // not a power of two, can't handle that with our built-in FFT
399 // implementation
400
401 size_t nearest = blockSize;
402 size_t power = 0;
403 while (nearest > 1) {
404 nearest >>= 1;
405 ++power;
406 }
407 nearest = 1;
408 while (power) {
409 nearest <<= 1;
410 --power;
411 }
412
413 if (blockSize - nearest > (nearest*2) - blockSize) {
414 nearest = nearest*2;
415 }
416
417 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
418 blockSize = nearest;
419
420 #endif
421 } 354 }
422 355
423 return blockSize; 356 return blockSize;
424 } 357 }
425 358
453 { 386 {
454 if (m_windowType == t) return; 387 if (m_windowType == t) return;
455 m_windowType = t; 388 m_windowType = t;
456 if (m_window) { 389 if (m_window) {
457 delete m_window; 390 delete m_window;
458 m_window = new Window<double>(convertType(m_windowType), m_blockSize); 391 m_window = new Window<float>(convertType(m_windowType), m_blockSize);
459 } 392 }
460 } 393 }
461 394
462 PluginInputDomainAdapter::WindowType 395 PluginInputDomainAdapter::WindowType
463 PluginInputDomainAdapter::Impl::getWindowType() const 396 PluginInputDomainAdapter::Impl::getWindowType() const
464 { 397 {
465 return m_windowType; 398 return m_windowType;
466 } 399 }
467 400
468 Window<double>::WindowType 401 Window<float>::WindowType
469 PluginInputDomainAdapter::Impl::convertType(WindowType t) const 402 PluginInputDomainAdapter::Impl::convertType(WindowType t) const
470 { 403 {
471 switch (t) { 404 switch (t) {
472 case RectangularWindow: 405 case RectangularWindow:
473 return Window<double>::RectangularWindow; 406 return Window<float>::RectangularWindow;
474 case BartlettWindow: 407 case BartlettWindow:
475 return Window<double>::BartlettWindow; 408 return Window<float>::BartlettWindow;
476 case HammingWindow: 409 case HammingWindow:
477 return Window<double>::HammingWindow; 410 return Window<float>::HammingWindow;
478 case HanningWindow: 411 case HanningWindow:
479 return Window<double>::HanningWindow; 412 return Window<float>::HanningWindow;
480 case BlackmanWindow: 413 case BlackmanWindow:
481 return Window<double>::BlackmanWindow; 414 return Window<float>::BlackmanWindow;
482 case NuttallWindow: 415 case NuttallWindow:
483 return Window<double>::NuttallWindow; 416 return Window<float>::NuttallWindow;
484 case BlackmanHarrisWindow: 417 case BlackmanHarrisWindow:
485 return Window<double>::BlackmanHarrisWindow; 418 return Window<float>::BlackmanHarrisWindow;
486 default: 419 default:
487 return Window<double>::HanningWindow; 420 return Window<float>::HanningWindow;
488 } 421 }
489 } 422 }
490 423
491 Plugin::FeatureSet 424 Plugin::FeatureSet
492 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers, 425 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
527 460
528 m_window->cut(inputBuffers[c], m_ri); 461 m_window->cut(inputBuffers[c], m_ri);
529 462
530 for (int i = 0; i < m_blockSize/2; ++i) { 463 for (int i = 0; i < m_blockSize/2; ++i) {
531 // FFT shift 464 // FFT shift
532 double value = m_ri[i]; 465 float value = m_ri[i];
533 m_ri[i] = m_ri[i + m_blockSize/2]; 466 m_ri[i] = m_ri[i + m_blockSize/2];
534 m_ri[i + m_blockSize/2] = value; 467 m_ri[i + m_blockSize/2] = value;
535 } 468 }
536 469
537 #ifdef HAVE_FFTW3 470 KissSingle::kiss_fftr(m_cfg, m_ri, m_cbuf);
538 fftw_execute(m_plan); 471
539
540 for (int i = 0; i <= m_blockSize/2; ++i) { 472 for (int i = 0; i <= m_blockSize/2; ++i) {
541 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]); 473 m_freqbuf[c][i * 2] = m_cbuf[i].r;
542 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]); 474 m_freqbuf[c][i * 2 + 1] = m_cbuf[i].i;
543 } 475 }
544 #else
545 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
546
547 for (int i = 0; i <= m_blockSize/2; ++i) {
548 m_freqbuf[c][i * 2] = float(m_ro[i]);
549 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
550 }
551 #endif
552 } 476 }
553 477
554 return m_plugin->process(m_freqbuf, timestamp); 478 return m_plugin->process(m_freqbuf, timestamp);
555 } 479 }
556 480
585 509
586 m_window->cut(m_shiftBuffers[c], m_ri); 510 m_window->cut(m_shiftBuffers[c], m_ri);
587 511
588 for (int i = 0; i < m_blockSize/2; ++i) { 512 for (int i = 0; i < m_blockSize/2; ++i) {
589 // FFT shift 513 // FFT shift
590 double value = m_ri[i]; 514 float value = m_ri[i];
591 m_ri[i] = m_ri[i + m_blockSize/2]; 515 m_ri[i] = m_ri[i + m_blockSize/2];
592 m_ri[i + m_blockSize/2] = value; 516 m_ri[i + m_blockSize/2] = value;
593 } 517 }
594 518
595 #ifdef HAVE_FFTW3 519 KissSingle::kiss_fftr(m_cfg, m_ri, m_cbuf);
596 fftw_execute(m_plan); 520
597
598 for (int i = 0; i <= m_blockSize/2; ++i) { 521 for (int i = 0; i <= m_blockSize/2; ++i) {
599 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]); 522 m_freqbuf[c][i * 2] = m_cbuf[i].r;
600 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]); 523 m_freqbuf[c][i * 2 + 1] = m_cbuf[i].i;
601 } 524 }
602 #else
603 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
604
605 for (int i = 0; i <= m_blockSize/2; ++i) {
606 m_freqbuf[c][i * 2] = float(m_ro[i]);
607 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
608 }
609 #endif
610 } 525 }
611 526
612 ++m_processCount; 527 ++m_processCount;
613 528
614 return m_plugin->process(m_freqbuf, timestamp); 529 return m_plugin->process(m_freqbuf, timestamp);
615 } 530 }
616 531
617 #ifndef HAVE_FFTW3
618
619 #endif
620
621 } 532 }
622 533
623 } 534 }
624 535
625 _VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.cpp) 536 _VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.cpp)