annotate src/vamp-hostsdk/PluginInputDomainAdapter.cpp @ 323:b070230a1fc8

Added tag vamp-plugin-sdk-v2.3 for changeset 71b69f569f52
author Chris Cannam
date Wed, 28 Sep 2011 16:36:32 +0100
parents 7920b9519fd9
children 50df48a51c97
rev   line source
cannam@233 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@233 2
cannam@233 3 /*
cannam@233 4 Vamp
cannam@233 5
cannam@233 6 An API for audio analysis and feature extraction plugins.
cannam@233 7
cannam@233 8 Centre for Digital Music, Queen Mary, University of London.
cannam@290 9 Copyright 2006-2009 Chris Cannam and QMUL.
cannam@233 10
cannam@233 11 This file is based in part on Don Cross's public domain FFT
cannam@233 12 implementation.
cannam@233 13
cannam@233 14 Permission is hereby granted, free of charge, to any person
cannam@233 15 obtaining a copy of this software and associated documentation
cannam@233 16 files (the "Software"), to deal in the Software without
cannam@233 17 restriction, including without limitation the rights to use, copy,
cannam@233 18 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@233 19 of the Software, and to permit persons to whom the Software is
cannam@233 20 furnished to do so, subject to the following conditions:
cannam@233 21
cannam@233 22 The above copyright notice and this permission notice shall be
cannam@233 23 included in all copies or substantial portions of the Software.
cannam@233 24
cannam@233 25 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@233 26 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@233 27 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@233 28 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@233 29 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@233 30 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@233 31 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@233 32
cannam@233 33 Except as contained in this notice, the names of the Centre for
cannam@233 34 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@233 35 shall not be used in advertising or otherwise to promote the sale,
cannam@233 36 use or other dealings in this Software without prior written
cannam@233 37 authorization.
cannam@233 38 */
cannam@233 39
cannam@233 40 #include <vamp-hostsdk/PluginInputDomainAdapter.h>
cannam@233 41
cannam@233 42 #include <cmath>
cannam@233 43
Chris@317 44 #include "Window.h"
Chris@317 45
cannam@233 46
cannam@233 47 /**
cannam@233 48 * If you want to compile using FFTW instead of the built-in FFT
cannam@233 49 * implementation for the PluginInputDomainAdapter, define HAVE_FFTW3
cannam@233 50 * in the Makefile.
cannam@233 51 *
cannam@233 52 * Be aware that FFTW is licensed under the GPL -- unlike this SDK,
cannam@233 53 * which is provided under a more liberal BSD license in order to
cannam@233 54 * permit use in closed source applications. The use of FFTW would
cannam@233 55 * mean that your code would need to be licensed under the GPL as
cannam@233 56 * well. Do not define this symbol unless you understand and accept
cannam@233 57 * the implications of this.
cannam@233 58 *
cannam@233 59 * Parties such as Linux distribution packagers who redistribute this
cannam@233 60 * SDK for use in other programs should _not_ define this symbol, as
cannam@233 61 * it would change the effective licensing terms under which the SDK
cannam@233 62 * was available to third party developers.
cannam@233 63 *
cannam@233 64 * The default is not to use FFTW, and to use the built-in FFT instead.
cannam@233 65 *
cannam@233 66 * Note: The FFTW code uses FFTW_MEASURE, and so will perform badly on
cannam@233 67 * its first invocation unless the host has saved and restored FFTW
cannam@233 68 * wisdom (see the FFTW documentation).
cannam@233 69 */
cannam@233 70 #ifdef HAVE_FFTW3
cannam@233 71 #include <fftw3.h>
cannam@233 72 #endif
cannam@233 73
cannam@233 74
cannam@263 75 _VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.cpp)
cannam@263 76
cannam@233 77 namespace Vamp {
cannam@233 78
cannam@233 79 namespace HostExt {
cannam@233 80
cannam@233 81 class PluginInputDomainAdapter::Impl
cannam@233 82 {
cannam@233 83 public:
cannam@233 84 Impl(Plugin *plugin, float inputSampleRate);
cannam@233 85 ~Impl();
cannam@233 86
cannam@233 87 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
cannam@288 88 void reset();
cannam@233 89
cannam@233 90 size_t getPreferredStepSize() const;
cannam@233 91 size_t getPreferredBlockSize() const;
cannam@233 92
cannam@233 93 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
cannam@288 94
cannam@288 95 void setProcessTimestampMethod(ProcessTimestampMethod m);
cannam@288 96 ProcessTimestampMethod getProcessTimestampMethod() const;
cannam@233 97
cannam@233 98 RealTime getTimestampAdjustment() const;
cannam@233 99
Chris@317 100 WindowType getWindowType() const;
Chris@317 101 void setWindowType(WindowType type);
Chris@317 102
cannam@233 103 protected:
cannam@233 104 Plugin *m_plugin;
cannam@233 105 float m_inputSampleRate;
cannam@233 106 int m_channels;
cannam@288 107 int m_stepSize;
cannam@233 108 int m_blockSize;
cannam@233 109 float **m_freqbuf;
cannam@233 110
cannam@233 111 double *m_ri;
Chris@317 112
Chris@317 113 WindowType m_windowType;
Chris@317 114 Window<double> *m_window;
cannam@233 115
cannam@288 116 ProcessTimestampMethod m_method;
cannam@288 117 int m_processCount;
cannam@289 118 float **m_shiftBuffers;
cannam@288 119
cannam@233 120 #ifdef HAVE_FFTW3
cannam@233 121 fftw_plan m_plan;
cannam@233 122 fftw_complex *m_cbuf;
cannam@233 123 #else
cannam@233 124 double *m_ro;
cannam@233 125 double *m_io;
cannam@233 126 void fft(unsigned int n, bool inverse,
cannam@233 127 double *ri, double *ii, double *ro, double *io);
cannam@233 128 #endif
cannam@233 129
cannam@289 130 FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp);
cannam@289 131 FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp);
cannam@289 132
cannam@233 133 size_t makeBlockSizeAcceptable(size_t) const;
Chris@317 134
Chris@317 135 Window<double>::WindowType convertType(WindowType t) const;
cannam@233 136 };
cannam@233 137
cannam@233 138 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
cannam@233 139 PluginWrapper(plugin)
cannam@233 140 {
cannam@233 141 m_impl = new Impl(plugin, m_inputSampleRate);
cannam@233 142 }
cannam@233 143
cannam@233 144 PluginInputDomainAdapter::~PluginInputDomainAdapter()
cannam@233 145 {
cannam@233 146 delete m_impl;
cannam@233 147 }
cannam@233 148
cannam@233 149 bool
cannam@233 150 PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@233 151 {
cannam@233 152 return m_impl->initialise(channels, stepSize, blockSize);
cannam@233 153 }
cannam@233 154
cannam@288 155 void
cannam@288 156 PluginInputDomainAdapter::reset()
cannam@288 157 {
cannam@288 158 m_impl->reset();
cannam@288 159 }
cannam@288 160
cannam@233 161 Plugin::InputDomain
cannam@233 162 PluginInputDomainAdapter::getInputDomain() const
cannam@233 163 {
cannam@233 164 return TimeDomain;
cannam@233 165 }
cannam@233 166
cannam@233 167 size_t
cannam@233 168 PluginInputDomainAdapter::getPreferredStepSize() const
cannam@233 169 {
cannam@233 170 return m_impl->getPreferredStepSize();
cannam@233 171 }
cannam@233 172
cannam@233 173 size_t
cannam@233 174 PluginInputDomainAdapter::getPreferredBlockSize() const
cannam@233 175 {
cannam@233 176 return m_impl->getPreferredBlockSize();
cannam@233 177 }
cannam@233 178
cannam@233 179 Plugin::FeatureSet
cannam@233 180 PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
cannam@233 181 {
cannam@233 182 return m_impl->process(inputBuffers, timestamp);
cannam@233 183 }
cannam@233 184
cannam@288 185 void
cannam@288 186 PluginInputDomainAdapter::setProcessTimestampMethod(ProcessTimestampMethod m)
cannam@288 187 {
cannam@288 188 m_impl->setProcessTimestampMethod(m);
cannam@288 189 }
cannam@288 190
cannam@288 191 PluginInputDomainAdapter::ProcessTimestampMethod
cannam@288 192 PluginInputDomainAdapter::getProcessTimestampMethod() const
cannam@288 193 {
cannam@288 194 return m_impl->getProcessTimestampMethod();
cannam@288 195 }
cannam@288 196
cannam@233 197 RealTime
cannam@233 198 PluginInputDomainAdapter::getTimestampAdjustment() const
cannam@233 199 {
cannam@233 200 return m_impl->getTimestampAdjustment();
cannam@233 201 }
cannam@233 202
Chris@317 203 PluginInputDomainAdapter::WindowType
Chris@317 204 PluginInputDomainAdapter::getWindowType() const
Chris@317 205 {
Chris@317 206 return m_impl->getWindowType();
Chris@317 207 }
Chris@317 208
Chris@317 209 void
Chris@317 210 PluginInputDomainAdapter::setWindowType(WindowType w)
Chris@317 211 {
Chris@317 212 m_impl->setWindowType(w);
Chris@317 213 }
Chris@317 214
cannam@233 215
cannam@233 216 PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
cannam@233 217 m_plugin(plugin),
cannam@233 218 m_inputSampleRate(inputSampleRate),
cannam@233 219 m_channels(0),
cannam@288 220 m_stepSize(0),
cannam@233 221 m_blockSize(0),
cannam@233 222 m_freqbuf(0),
cannam@233 223 m_ri(0),
Chris@317 224 m_windowType(HanningWindow),
cannam@233 225 m_window(0),
cannam@288 226 m_method(ShiftTimestamp),
cannam@288 227 m_processCount(0),
cannam@289 228 m_shiftBuffers(0),
cannam@233 229 #ifdef HAVE_FFTW3
cannam@233 230 m_plan(0),
cannam@233 231 m_cbuf(0)
cannam@233 232 #else
cannam@233 233 m_ro(0),
cannam@233 234 m_io(0)
cannam@233 235 #endif
cannam@233 236 {
cannam@233 237 }
cannam@233 238
cannam@233 239 PluginInputDomainAdapter::Impl::~Impl()
cannam@233 240 {
cannam@233 241 // the adapter will delete the plugin
cannam@233 242
cannam@289 243 if (m_shiftBuffers) {
cannam@289 244 for (int c = 0; c < m_channels; ++c) {
cannam@289 245 delete[] m_shiftBuffers[c];
cannam@289 246 }
cannam@289 247 delete[] m_shiftBuffers;
cannam@289 248 }
cannam@289 249
cannam@233 250 if (m_channels > 0) {
cannam@233 251 for (int c = 0; c < m_channels; ++c) {
cannam@233 252 delete[] m_freqbuf[c];
cannam@233 253 }
cannam@233 254 delete[] m_freqbuf;
cannam@233 255 #ifdef HAVE_FFTW3
cannam@233 256 if (m_plan) {
cannam@233 257 fftw_destroy_plan(m_plan);
cannam@233 258 fftw_free(m_ri);
cannam@233 259 fftw_free(m_cbuf);
cannam@233 260 m_plan = 0;
cannam@233 261 }
cannam@233 262 #else
cannam@233 263 delete[] m_ri;
cannam@233 264 delete[] m_ro;
cannam@233 265 delete[] m_io;
cannam@233 266 #endif
Chris@317 267
Chris@317 268 delete m_window;
cannam@233 269 }
cannam@233 270 }
cannam@233 271
cannam@233 272 // for some visual studii apparently
cannam@233 273 #ifndef M_PI
cannam@233 274 #define M_PI 3.14159265358979232846
cannam@233 275 #endif
cannam@233 276
cannam@233 277 bool
cannam@233 278 PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@233 279 {
cannam@233 280 if (m_plugin->getInputDomain() == TimeDomain) {
cannam@233 281
cannam@288 282 m_stepSize = int(stepSize);
cannam@233 283 m_blockSize = int(blockSize);
cannam@233 284 m_channels = int(channels);
cannam@233 285
cannam@233 286 return m_plugin->initialise(channels, stepSize, blockSize);
cannam@233 287 }
cannam@233 288
cannam@233 289 if (blockSize < 2) {
cannam@283 290 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl;
cannam@233 291 return false;
cannam@233 292 }
cannam@233 293
cannam@233 294 if (blockSize & (blockSize-1)) {
cannam@283 295 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
cannam@233 296 return false;
cannam@233 297 }
cannam@233 298
cannam@233 299 if (m_channels > 0) {
cannam@233 300 for (int c = 0; c < m_channels; ++c) {
cannam@233 301 delete[] m_freqbuf[c];
cannam@233 302 }
cannam@233 303 delete[] m_freqbuf;
cannam@233 304 #ifdef HAVE_FFTW3
cannam@233 305 if (m_plan) {
cannam@233 306 fftw_destroy_plan(m_plan);
cannam@233 307 fftw_free(m_ri);
cannam@233 308 fftw_free(m_cbuf);
cannam@233 309 m_plan = 0;
cannam@233 310 }
cannam@233 311 #else
cannam@233 312 delete[] m_ri;
cannam@233 313 delete[] m_ro;
cannam@233 314 delete[] m_io;
cannam@233 315 #endif
Chris@317 316 delete m_window;
cannam@233 317 }
cannam@233 318
cannam@288 319 m_stepSize = int(stepSize);
cannam@233 320 m_blockSize = int(blockSize);
cannam@233 321 m_channels = int(channels);
cannam@233 322
cannam@233 323 m_freqbuf = new float *[m_channels];
cannam@233 324 for (int c = 0; c < m_channels; ++c) {
cannam@233 325 m_freqbuf[c] = new float[m_blockSize + 2];
cannam@233 326 }
cannam@233 327
Chris@317 328 m_window = new Window<double>(convertType(m_windowType), m_blockSize);
cannam@233 329
cannam@233 330 #ifdef HAVE_FFTW3
cannam@233 331 m_ri = (double *)fftw_malloc(blockSize * sizeof(double));
cannam@233 332 m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex));
cannam@233 333 m_plan = fftw_plan_dft_r2c_1d(blockSize, m_ri, m_cbuf, FFTW_MEASURE);
cannam@233 334 #else
cannam@233 335 m_ri = new double[m_blockSize];
cannam@233 336 m_ro = new double[m_blockSize];
cannam@233 337 m_io = new double[m_blockSize];
cannam@233 338 #endif
cannam@233 339
cannam@288 340 m_processCount = 0;
cannam@288 341
cannam@233 342 return m_plugin->initialise(channels, stepSize, blockSize);
cannam@233 343 }
cannam@233 344
cannam@288 345 void
cannam@288 346 PluginInputDomainAdapter::Impl::reset()
cannam@288 347 {
cannam@288 348 m_processCount = 0;
cannam@288 349 m_plugin->reset();
cannam@288 350 }
cannam@288 351
cannam@233 352 size_t
cannam@233 353 PluginInputDomainAdapter::Impl::getPreferredStepSize() const
cannam@233 354 {
cannam@233 355 size_t step = m_plugin->getPreferredStepSize();
cannam@233 356
cannam@233 357 if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) {
cannam@233 358 step = getPreferredBlockSize() / 2;
cannam@233 359 }
cannam@233 360
cannam@233 361 return step;
cannam@233 362 }
cannam@233 363
cannam@233 364 size_t
cannam@233 365 PluginInputDomainAdapter::Impl::getPreferredBlockSize() const
cannam@233 366 {
cannam@233 367 size_t block = m_plugin->getPreferredBlockSize();
cannam@233 368
cannam@233 369 if (m_plugin->getInputDomain() == FrequencyDomain) {
cannam@233 370 if (block == 0) {
cannam@233 371 block = 1024;
cannam@233 372 } else {
cannam@233 373 block = makeBlockSizeAcceptable(block);
cannam@233 374 }
cannam@233 375 }
cannam@233 376
cannam@233 377 return block;
cannam@233 378 }
cannam@233 379
cannam@233 380 size_t
cannam@233 381 PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
cannam@233 382 {
cannam@233 383 if (blockSize < 2) {
cannam@233 384
cannam@283 385 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl
cannam@233 386 << "supported, increasing from " << blockSize << " to 2" << std::endl;
cannam@233 387 blockSize = 2;
cannam@233 388
cannam@233 389 } else if (blockSize & (blockSize-1)) {
cannam@233 390
cannam@233 391 #ifdef HAVE_FFTW3
cannam@233 392 // not an issue with FFTW
cannam@233 393 #else
cannam@233 394
cannam@233 395 // not a power of two, can't handle that with our built-in FFT
cannam@233 396 // implementation
cannam@233 397
cannam@233 398 size_t nearest = blockSize;
cannam@233 399 size_t power = 0;
cannam@233 400 while (nearest > 1) {
cannam@233 401 nearest >>= 1;
cannam@233 402 ++power;
cannam@233 403 }
cannam@233 404 nearest = 1;
cannam@233 405 while (power) {
cannam@233 406 nearest <<= 1;
cannam@233 407 --power;
cannam@233 408 }
cannam@233 409
cannam@233 410 if (blockSize - nearest > (nearest*2) - blockSize) {
cannam@233 411 nearest = nearest*2;
cannam@233 412 }
cannam@233 413
cannam@283 414 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
cannam@233 415 blockSize = nearest;
cannam@233 416
cannam@233 417 #endif
cannam@233 418 }
cannam@233 419
cannam@233 420 return blockSize;
cannam@233 421 }
cannam@233 422
cannam@233 423 RealTime
cannam@233 424 PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
cannam@233 425 {
cannam@233 426 if (m_plugin->getInputDomain() == TimeDomain) {
cannam@233 427 return RealTime::zeroTime;
cannam@298 428 } else if (m_method == ShiftData || m_method == NoShift) {
cannam@289 429 return RealTime::zeroTime;
cannam@233 430 } else {
cannam@233 431 return RealTime::frame2RealTime
cannam@233 432 (m_blockSize/2, int(m_inputSampleRate + 0.5));
cannam@233 433 }
cannam@233 434 }
cannam@233 435
cannam@288 436 void
cannam@288 437 PluginInputDomainAdapter::Impl::setProcessTimestampMethod(ProcessTimestampMethod m)
cannam@288 438 {
cannam@288 439 m_method = m;
cannam@288 440 }
cannam@288 441
cannam@288 442 PluginInputDomainAdapter::ProcessTimestampMethod
cannam@288 443 PluginInputDomainAdapter::Impl::getProcessTimestampMethod() const
cannam@288 444 {
cannam@288 445 return m_method;
cannam@288 446 }
cannam@288 447
Chris@317 448 void
Chris@317 449 PluginInputDomainAdapter::Impl::setWindowType(WindowType t)
Chris@317 450 {
Chris@317 451 if (m_windowType == t) return;
Chris@317 452 m_windowType = t;
Chris@317 453 if (m_window) {
Chris@317 454 delete m_window;
Chris@317 455 m_window = new Window<double>(convertType(m_windowType), m_blockSize);
Chris@317 456 }
Chris@317 457 }
Chris@317 458
Chris@317 459 PluginInputDomainAdapter::WindowType
Chris@317 460 PluginInputDomainAdapter::Impl::getWindowType() const
Chris@317 461 {
Chris@317 462 return m_windowType;
Chris@317 463 }
Chris@317 464
Chris@317 465 Window<double>::WindowType
Chris@317 466 PluginInputDomainAdapter::Impl::convertType(WindowType t) const
Chris@317 467 {
Chris@317 468 switch (t) {
Chris@317 469 case RectangularWindow:
Chris@317 470 return Window<double>::RectangularWindow;
Chris@317 471 case BartlettWindow:
Chris@317 472 return Window<double>::BartlettWindow;
Chris@317 473 case HammingWindow:
Chris@317 474 return Window<double>::HammingWindow;
Chris@317 475 case HanningWindow:
Chris@317 476 return Window<double>::HanningWindow;
Chris@317 477 case BlackmanWindow:
Chris@317 478 return Window<double>::BlackmanWindow;
Chris@317 479 case NuttallWindow:
Chris@317 480 return Window<double>::NuttallWindow;
Chris@317 481 case BlackmanHarrisWindow:
Chris@317 482 return Window<double>::BlackmanHarrisWindow;
Chris@319 483 default:
Chris@319 484 return Window<double>::HanningWindow;
Chris@317 485 }
Chris@317 486 }
Chris@317 487
cannam@233 488 Plugin::FeatureSet
cannam@233 489 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
cannam@233 490 RealTime timestamp)
cannam@233 491 {
cannam@233 492 if (m_plugin->getInputDomain() == TimeDomain) {
cannam@233 493 return m_plugin->process(inputBuffers, timestamp);
cannam@233 494 }
cannam@233 495
cannam@298 496 if (m_method == ShiftTimestamp || m_method == NoShift) {
cannam@289 497 return processShiftingTimestamp(inputBuffers, timestamp);
cannam@289 498 } else {
cannam@289 499 return processShiftingData(inputBuffers, timestamp);
cannam@289 500 }
cannam@289 501 }
cannam@233 502
cannam@289 503 Plugin::FeatureSet
cannam@289 504 PluginInputDomainAdapter::Impl::processShiftingTimestamp(const float *const *inputBuffers,
cannam@289 505 RealTime timestamp)
cannam@289 506 {
cannam@298 507 if (m_method == ShiftTimestamp) {
cannam@298 508 timestamp = timestamp + getTimestampAdjustment();
cannam@298 509 }
cannam@233 510
cannam@233 511 for (int c = 0; c < m_channels; ++c) {
cannam@233 512
Chris@317 513 m_window->cut(inputBuffers[c], m_ri);
cannam@233 514
cannam@233 515 for (int i = 0; i < m_blockSize/2; ++i) {
cannam@233 516 // FFT shift
cannam@233 517 double value = m_ri[i];
cannam@233 518 m_ri[i] = m_ri[i + m_blockSize/2];
cannam@233 519 m_ri[i + m_blockSize/2] = value;
cannam@233 520 }
cannam@233 521
cannam@233 522 #ifdef HAVE_FFTW3
cannam@233 523 fftw_execute(m_plan);
cannam@233 524
cannam@233 525 for (int i = 0; i <= m_blockSize/2; ++i) {
cannam@233 526 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
cannam@233 527 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
cannam@233 528 }
cannam@233 529 #else
cannam@233 530 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
cannam@233 531
cannam@233 532 for (int i = 0; i <= m_blockSize/2; ++i) {
cannam@233 533 m_freqbuf[c][i * 2] = float(m_ro[i]);
cannam@233 534 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
cannam@233 535 }
cannam@233 536 #endif
cannam@233 537 }
cannam@233 538
cannam@289 539 return m_plugin->process(m_freqbuf, timestamp);
cannam@288 540 }
cannam@288 541
cannam@288 542 Plugin::FeatureSet
cannam@289 543 PluginInputDomainAdapter::Impl::processShiftingData(const float *const *inputBuffers,
cannam@289 544 RealTime timestamp)
cannam@288 545 {
cannam@289 546 if (m_processCount == 0) {
cannam@289 547 if (!m_shiftBuffers) {
cannam@289 548 m_shiftBuffers = new float *[m_channels];
cannam@289 549 for (int c = 0; c < m_channels; ++c) {
cannam@289 550 m_shiftBuffers[c] = new float[m_blockSize + m_blockSize/2];
cannam@289 551 }
cannam@289 552 }
cannam@289 553 for (int c = 0; c < m_channels; ++c) {
cannam@289 554 for (int i = 0; i < m_blockSize + m_blockSize/2; ++i) {
cannam@289 555 m_shiftBuffers[c][i] = 0.f;
cannam@289 556 }
cannam@289 557 }
cannam@289 558 }
cannam@289 559
cannam@289 560 for (int c = 0; c < m_channels; ++c) {
cannam@289 561 for (int i = m_stepSize; i < m_blockSize + m_blockSize/2; ++i) {
cannam@289 562 m_shiftBuffers[c][i - m_stepSize] = m_shiftBuffers[c][i];
cannam@289 563 }
cannam@289 564 for (int i = 0; i < m_blockSize; ++i) {
cannam@289 565 m_shiftBuffers[c][i + m_blockSize/2] = inputBuffers[c][i];
cannam@289 566 }
cannam@289 567 }
cannam@289 568
cannam@289 569 for (int c = 0; c < m_channels; ++c) {
cannam@289 570
Chris@317 571 m_window->cut(m_shiftBuffers[c], m_ri);
cannam@289 572
cannam@289 573 for (int i = 0; i < m_blockSize/2; ++i) {
cannam@289 574 // FFT shift
cannam@289 575 double value = m_ri[i];
cannam@289 576 m_ri[i] = m_ri[i + m_blockSize/2];
cannam@289 577 m_ri[i + m_blockSize/2] = value;
cannam@289 578 }
cannam@289 579
cannam@289 580 #ifdef HAVE_FFTW3
cannam@289 581 fftw_execute(m_plan);
cannam@289 582
cannam@289 583 for (int i = 0; i <= m_blockSize/2; ++i) {
cannam@289 584 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
cannam@289 585 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
cannam@289 586 }
cannam@289 587 #else
cannam@289 588 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
cannam@289 589
cannam@289 590 for (int i = 0; i <= m_blockSize/2; ++i) {
cannam@289 591 m_freqbuf[c][i * 2] = float(m_ro[i]);
cannam@289 592 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
cannam@289 593 }
cannam@289 594 #endif
cannam@289 595 }
cannam@289 596
cannam@289 597 ++m_processCount;
cannam@289 598
cannam@289 599 return m_plugin->process(m_freqbuf, timestamp);
cannam@233 600 }
cannam@233 601
cannam@233 602 #ifndef HAVE_FFTW3
cannam@233 603
cannam@233 604 void
cannam@233 605 PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse,
cannam@233 606 double *ri, double *ii, double *ro, double *io)
cannam@233 607 {
cannam@233 608 if (!ri || !ro || !io) return;
cannam@233 609
cannam@233 610 unsigned int bits;
cannam@233 611 unsigned int i, j, k, m;
cannam@233 612 unsigned int blockSize, blockEnd;
cannam@233 613
cannam@233 614 double tr, ti;
cannam@233 615
cannam@233 616 if (n < 2) return;
cannam@233 617 if (n & (n-1)) return;
cannam@233 618
cannam@233 619 double angle = 2.0 * M_PI;
cannam@233 620 if (inverse) angle = -angle;
cannam@233 621
cannam@233 622 for (i = 0; ; ++i) {
cannam@233 623 if (n & (1 << i)) {
cannam@233 624 bits = i;
cannam@233 625 break;
cannam@233 626 }
cannam@233 627 }
cannam@233 628
cannam@233 629 static unsigned int tableSize = 0;
cannam@233 630 static int *table = 0;
cannam@233 631
cannam@233 632 if (tableSize != n) {
cannam@233 633
cannam@233 634 delete[] table;
cannam@233 635
cannam@233 636 table = new int[n];
cannam@233 637
cannam@233 638 for (i = 0; i < n; ++i) {
cannam@233 639
cannam@233 640 m = i;
cannam@233 641
cannam@233 642 for (j = k = 0; j < bits; ++j) {
cannam@233 643 k = (k << 1) | (m & 1);
cannam@233 644 m >>= 1;
cannam@233 645 }
cannam@233 646
cannam@233 647 table[i] = k;
cannam@233 648 }
cannam@233 649
cannam@233 650 tableSize = n;
cannam@233 651 }
cannam@233 652
cannam@233 653 if (ii) {
cannam@233 654 for (i = 0; i < n; ++i) {
cannam@233 655 ro[table[i]] = ri[i];
cannam@233 656 io[table[i]] = ii[i];
cannam@233 657 }
cannam@233 658 } else {
cannam@233 659 for (i = 0; i < n; ++i) {
cannam@233 660 ro[table[i]] = ri[i];
cannam@233 661 io[table[i]] = 0.0;
cannam@233 662 }
cannam@233 663 }
cannam@233 664
cannam@233 665 blockEnd = 1;
cannam@233 666
cannam@233 667 for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
cannam@233 668
cannam@233 669 double delta = angle / (double)blockSize;
cannam@233 670 double sm2 = -sin(-2 * delta);
cannam@233 671 double sm1 = -sin(-delta);
cannam@233 672 double cm2 = cos(-2 * delta);
cannam@233 673 double cm1 = cos(-delta);
cannam@233 674 double w = 2 * cm1;
cannam@233 675 double ar[3], ai[3];
cannam@233 676
cannam@233 677 for (i = 0; i < n; i += blockSize) {
cannam@233 678
cannam@233 679 ar[2] = cm2;
cannam@233 680 ar[1] = cm1;
cannam@233 681
cannam@233 682 ai[2] = sm2;
cannam@233 683 ai[1] = sm1;
cannam@233 684
cannam@233 685 for (j = i, m = 0; m < blockEnd; j++, m++) {
cannam@233 686
cannam@233 687 ar[0] = w * ar[1] - ar[2];
cannam@233 688 ar[2] = ar[1];
cannam@233 689 ar[1] = ar[0];
cannam@233 690
cannam@233 691 ai[0] = w * ai[1] - ai[2];
cannam@233 692 ai[2] = ai[1];
cannam@233 693 ai[1] = ai[0];
cannam@233 694
cannam@233 695 k = j + blockEnd;
cannam@233 696 tr = ar[0] * ro[k] - ai[0] * io[k];
cannam@233 697 ti = ar[0] * io[k] + ai[0] * ro[k];
cannam@233 698
cannam@233 699 ro[k] = ro[j] - tr;
cannam@233 700 io[k] = io[j] - ti;
cannam@233 701
cannam@233 702 ro[j] += tr;
cannam@233 703 io[j] += ti;
cannam@233 704 }
cannam@233 705 }
cannam@233 706
cannam@233 707 blockEnd = blockSize;
cannam@233 708 }
cannam@233 709
cannam@233 710 if (inverse) {
cannam@233 711
cannam@233 712 double denom = (double)n;
cannam@233 713
cannam@233 714 for (i = 0; i < n; i++) {
cannam@233 715 ro[i] /= denom;
cannam@233 716 io[i] /= denom;
cannam@233 717 }
cannam@233 718 }
cannam@233 719 }
cannam@233 720
cannam@233 721 #endif
cannam@233 722
cannam@233 723 }
cannam@233 724
cannam@233 725 }
cannam@233 726
cannam@263 727 _VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.cpp)
cannam@263 728