Mercurial > hg > vamp-plugin-sdk
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) |