annotate src/vamp-hostsdk/PluginInputDomainAdapter.cpp @ 301:7178510d747a

* Add include required for gcc 4.4
author cannam
date Mon, 28 Sep 2009 09:39:09 +0000
parents 5940dd0a399f
children 5cb298435765
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
cannam@233 44
cannam@233 45 /**
cannam@233 46 * If you want to compile using FFTW instead of the built-in FFT
cannam@233 47 * implementation for the PluginInputDomainAdapter, define HAVE_FFTW3
cannam@233 48 * in the Makefile.
cannam@233 49 *
cannam@233 50 * Be aware that FFTW is licensed under the GPL -- unlike this SDK,
cannam@233 51 * which is provided under a more liberal BSD license in order to
cannam@233 52 * permit use in closed source applications. The use of FFTW would
cannam@233 53 * mean that your code would need to be licensed under the GPL as
cannam@233 54 * well. Do not define this symbol unless you understand and accept
cannam@233 55 * the implications of this.
cannam@233 56 *
cannam@233 57 * Parties such as Linux distribution packagers who redistribute this
cannam@233 58 * SDK for use in other programs should _not_ define this symbol, as
cannam@233 59 * it would change the effective licensing terms under which the SDK
cannam@233 60 * was available to third party developers.
cannam@233 61 *
cannam@233 62 * The default is not to use FFTW, and to use the built-in FFT instead.
cannam@233 63 *
cannam@233 64 * Note: The FFTW code uses FFTW_MEASURE, and so will perform badly on
cannam@233 65 * its first invocation unless the host has saved and restored FFTW
cannam@233 66 * wisdom (see the FFTW documentation).
cannam@233 67 */
cannam@233 68 #ifdef HAVE_FFTW3
cannam@233 69 #include <fftw3.h>
cannam@233 70 #endif
cannam@233 71
cannam@233 72
cannam@263 73 _VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.cpp)
cannam@263 74
cannam@233 75 namespace Vamp {
cannam@233 76
cannam@233 77 namespace HostExt {
cannam@233 78
cannam@233 79 class PluginInputDomainAdapter::Impl
cannam@233 80 {
cannam@233 81 public:
cannam@233 82 Impl(Plugin *plugin, float inputSampleRate);
cannam@233 83 ~Impl();
cannam@233 84
cannam@233 85 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
cannam@288 86 void reset();
cannam@233 87
cannam@233 88 size_t getPreferredStepSize() const;
cannam@233 89 size_t getPreferredBlockSize() const;
cannam@233 90
cannam@233 91 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
cannam@288 92
cannam@288 93 void setProcessTimestampMethod(ProcessTimestampMethod m);
cannam@288 94 ProcessTimestampMethod getProcessTimestampMethod() const;
cannam@233 95
cannam@233 96 RealTime getTimestampAdjustment() const;
cannam@233 97
cannam@233 98 protected:
cannam@233 99 Plugin *m_plugin;
cannam@233 100 float m_inputSampleRate;
cannam@233 101 int m_channels;
cannam@288 102 int m_stepSize;
cannam@233 103 int m_blockSize;
cannam@233 104 float **m_freqbuf;
cannam@233 105
cannam@233 106 double *m_ri;
cannam@233 107 double *m_window;
cannam@233 108
cannam@288 109 ProcessTimestampMethod m_method;
cannam@288 110 int m_processCount;
cannam@289 111 float **m_shiftBuffers;
cannam@288 112
cannam@233 113 #ifdef HAVE_FFTW3
cannam@233 114 fftw_plan m_plan;
cannam@233 115 fftw_complex *m_cbuf;
cannam@233 116 #else
cannam@233 117 double *m_ro;
cannam@233 118 double *m_io;
cannam@233 119 void fft(unsigned int n, bool inverse,
cannam@233 120 double *ri, double *ii, double *ro, double *io);
cannam@233 121 #endif
cannam@233 122
cannam@289 123 FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp);
cannam@289 124 FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp);
cannam@289 125
cannam@233 126 size_t makeBlockSizeAcceptable(size_t) const;
cannam@233 127 };
cannam@233 128
cannam@233 129 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
cannam@233 130 PluginWrapper(plugin)
cannam@233 131 {
cannam@233 132 m_impl = new Impl(plugin, m_inputSampleRate);
cannam@233 133 }
cannam@233 134
cannam@233 135 PluginInputDomainAdapter::~PluginInputDomainAdapter()
cannam@233 136 {
cannam@233 137 delete m_impl;
cannam@233 138 }
cannam@233 139
cannam@233 140 bool
cannam@233 141 PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@233 142 {
cannam@233 143 return m_impl->initialise(channels, stepSize, blockSize);
cannam@233 144 }
cannam@233 145
cannam@288 146 void
cannam@288 147 PluginInputDomainAdapter::reset()
cannam@288 148 {
cannam@288 149 m_impl->reset();
cannam@288 150 }
cannam@288 151
cannam@233 152 Plugin::InputDomain
cannam@233 153 PluginInputDomainAdapter::getInputDomain() const
cannam@233 154 {
cannam@233 155 return TimeDomain;
cannam@233 156 }
cannam@233 157
cannam@233 158 size_t
cannam@233 159 PluginInputDomainAdapter::getPreferredStepSize() const
cannam@233 160 {
cannam@233 161 return m_impl->getPreferredStepSize();
cannam@233 162 }
cannam@233 163
cannam@233 164 size_t
cannam@233 165 PluginInputDomainAdapter::getPreferredBlockSize() const
cannam@233 166 {
cannam@233 167 return m_impl->getPreferredBlockSize();
cannam@233 168 }
cannam@233 169
cannam@233 170 Plugin::FeatureSet
cannam@233 171 PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
cannam@233 172 {
cannam@233 173 return m_impl->process(inputBuffers, timestamp);
cannam@233 174 }
cannam@233 175
cannam@288 176 void
cannam@288 177 PluginInputDomainAdapter::setProcessTimestampMethod(ProcessTimestampMethod m)
cannam@288 178 {
cannam@288 179 m_impl->setProcessTimestampMethod(m);
cannam@288 180 }
cannam@288 181
cannam@288 182 PluginInputDomainAdapter::ProcessTimestampMethod
cannam@288 183 PluginInputDomainAdapter::getProcessTimestampMethod() const
cannam@288 184 {
cannam@288 185 return m_impl->getProcessTimestampMethod();
cannam@288 186 }
cannam@288 187
cannam@233 188 RealTime
cannam@233 189 PluginInputDomainAdapter::getTimestampAdjustment() const
cannam@233 190 {
cannam@233 191 return m_impl->getTimestampAdjustment();
cannam@233 192 }
cannam@233 193
cannam@233 194
cannam@233 195 PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
cannam@233 196 m_plugin(plugin),
cannam@233 197 m_inputSampleRate(inputSampleRate),
cannam@233 198 m_channels(0),
cannam@288 199 m_stepSize(0),
cannam@233 200 m_blockSize(0),
cannam@233 201 m_freqbuf(0),
cannam@233 202 m_ri(0),
cannam@233 203 m_window(0),
cannam@288 204 m_method(ShiftTimestamp),
cannam@288 205 m_processCount(0),
cannam@289 206 m_shiftBuffers(0),
cannam@233 207 #ifdef HAVE_FFTW3
cannam@233 208 m_plan(0),
cannam@233 209 m_cbuf(0)
cannam@233 210 #else
cannam@233 211 m_ro(0),
cannam@233 212 m_io(0)
cannam@233 213 #endif
cannam@233 214 {
cannam@233 215 }
cannam@233 216
cannam@233 217 PluginInputDomainAdapter::Impl::~Impl()
cannam@233 218 {
cannam@233 219 // the adapter will delete the plugin
cannam@233 220
cannam@289 221 if (m_shiftBuffers) {
cannam@289 222 for (int c = 0; c < m_channels; ++c) {
cannam@289 223 delete[] m_shiftBuffers[c];
cannam@289 224 }
cannam@289 225 delete[] m_shiftBuffers;
cannam@289 226 }
cannam@289 227
cannam@233 228 if (m_channels > 0) {
cannam@233 229 for (int c = 0; c < m_channels; ++c) {
cannam@233 230 delete[] m_freqbuf[c];
cannam@233 231 }
cannam@233 232 delete[] m_freqbuf;
cannam@233 233 #ifdef HAVE_FFTW3
cannam@233 234 if (m_plan) {
cannam@233 235 fftw_destroy_plan(m_plan);
cannam@233 236 fftw_free(m_ri);
cannam@233 237 fftw_free(m_cbuf);
cannam@233 238 m_plan = 0;
cannam@233 239 }
cannam@233 240 #else
cannam@233 241 delete[] m_ri;
cannam@233 242 delete[] m_ro;
cannam@233 243 delete[] m_io;
cannam@233 244 #endif
cannam@233 245 delete[] m_window;
cannam@233 246 }
cannam@233 247 }
cannam@233 248
cannam@233 249 // for some visual studii apparently
cannam@233 250 #ifndef M_PI
cannam@233 251 #define M_PI 3.14159265358979232846
cannam@233 252 #endif
cannam@233 253
cannam@233 254 bool
cannam@233 255 PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@233 256 {
cannam@233 257 if (m_plugin->getInputDomain() == TimeDomain) {
cannam@233 258
cannam@288 259 m_stepSize = int(stepSize);
cannam@233 260 m_blockSize = int(blockSize);
cannam@233 261 m_channels = int(channels);
cannam@233 262
cannam@233 263 return m_plugin->initialise(channels, stepSize, blockSize);
cannam@233 264 }
cannam@233 265
cannam@233 266 if (blockSize < 2) {
cannam@283 267 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl;
cannam@233 268 return false;
cannam@233 269 }
cannam@233 270
cannam@233 271 if (blockSize & (blockSize-1)) {
cannam@283 272 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
cannam@233 273 return false;
cannam@233 274 }
cannam@233 275
cannam@233 276 if (m_channels > 0) {
cannam@233 277 for (int c = 0; c < m_channels; ++c) {
cannam@233 278 delete[] m_freqbuf[c];
cannam@233 279 }
cannam@233 280 delete[] m_freqbuf;
cannam@233 281 #ifdef HAVE_FFTW3
cannam@233 282 if (m_plan) {
cannam@233 283 fftw_destroy_plan(m_plan);
cannam@233 284 fftw_free(m_ri);
cannam@233 285 fftw_free(m_cbuf);
cannam@233 286 m_plan = 0;
cannam@233 287 }
cannam@233 288 #else
cannam@233 289 delete[] m_ri;
cannam@233 290 delete[] m_ro;
cannam@233 291 delete[] m_io;
cannam@233 292 #endif
cannam@233 293 delete[] m_window;
cannam@233 294 }
cannam@233 295
cannam@288 296 m_stepSize = int(stepSize);
cannam@233 297 m_blockSize = int(blockSize);
cannam@233 298 m_channels = int(channels);
cannam@233 299
cannam@233 300 m_freqbuf = new float *[m_channels];
cannam@233 301 for (int c = 0; c < m_channels; ++c) {
cannam@233 302 m_freqbuf[c] = new float[m_blockSize + 2];
cannam@233 303 }
cannam@233 304 m_window = new double[m_blockSize];
cannam@233 305
cannam@233 306 for (int i = 0; i < m_blockSize; ++i) {
cannam@233 307 // Hanning window
cannam@233 308 m_window[i] = (0.50 - 0.50 * cos((2.0 * M_PI * i) / m_blockSize));
cannam@233 309 }
cannam@233 310
cannam@233 311 #ifdef HAVE_FFTW3
cannam@233 312 m_ri = (double *)fftw_malloc(blockSize * sizeof(double));
cannam@233 313 m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex));
cannam@233 314 m_plan = fftw_plan_dft_r2c_1d(blockSize, m_ri, m_cbuf, FFTW_MEASURE);
cannam@233 315 #else
cannam@233 316 m_ri = new double[m_blockSize];
cannam@233 317 m_ro = new double[m_blockSize];
cannam@233 318 m_io = new double[m_blockSize];
cannam@233 319 #endif
cannam@233 320
cannam@288 321 m_processCount = 0;
cannam@288 322
cannam@233 323 return m_plugin->initialise(channels, stepSize, blockSize);
cannam@233 324 }
cannam@233 325
cannam@288 326 void
cannam@288 327 PluginInputDomainAdapter::Impl::reset()
cannam@288 328 {
cannam@288 329 m_processCount = 0;
cannam@288 330 m_plugin->reset();
cannam@288 331 }
cannam@288 332
cannam@233 333 size_t
cannam@233 334 PluginInputDomainAdapter::Impl::getPreferredStepSize() const
cannam@233 335 {
cannam@233 336 size_t step = m_plugin->getPreferredStepSize();
cannam@233 337
cannam@233 338 if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) {
cannam@233 339 step = getPreferredBlockSize() / 2;
cannam@233 340 }
cannam@233 341
cannam@233 342 return step;
cannam@233 343 }
cannam@233 344
cannam@233 345 size_t
cannam@233 346 PluginInputDomainAdapter::Impl::getPreferredBlockSize() const
cannam@233 347 {
cannam@233 348 size_t block = m_plugin->getPreferredBlockSize();
cannam@233 349
cannam@233 350 if (m_plugin->getInputDomain() == FrequencyDomain) {
cannam@233 351 if (block == 0) {
cannam@233 352 block = 1024;
cannam@233 353 } else {
cannam@233 354 block = makeBlockSizeAcceptable(block);
cannam@233 355 }
cannam@233 356 }
cannam@233 357
cannam@233 358 return block;
cannam@233 359 }
cannam@233 360
cannam@233 361 size_t
cannam@233 362 PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
cannam@233 363 {
cannam@233 364 if (blockSize < 2) {
cannam@233 365
cannam@283 366 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl
cannam@233 367 << "supported, increasing from " << blockSize << " to 2" << std::endl;
cannam@233 368 blockSize = 2;
cannam@233 369
cannam@233 370 } else if (blockSize & (blockSize-1)) {
cannam@233 371
cannam@233 372 #ifdef HAVE_FFTW3
cannam@233 373 // not an issue with FFTW
cannam@233 374 #else
cannam@233 375
cannam@233 376 // not a power of two, can't handle that with our built-in FFT
cannam@233 377 // implementation
cannam@233 378
cannam@233 379 size_t nearest = blockSize;
cannam@233 380 size_t power = 0;
cannam@233 381 while (nearest > 1) {
cannam@233 382 nearest >>= 1;
cannam@233 383 ++power;
cannam@233 384 }
cannam@233 385 nearest = 1;
cannam@233 386 while (power) {
cannam@233 387 nearest <<= 1;
cannam@233 388 --power;
cannam@233 389 }
cannam@233 390
cannam@233 391 if (blockSize - nearest > (nearest*2) - blockSize) {
cannam@233 392 nearest = nearest*2;
cannam@233 393 }
cannam@233 394
cannam@283 395 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
cannam@233 396 blockSize = nearest;
cannam@233 397
cannam@233 398 #endif
cannam@233 399 }
cannam@233 400
cannam@233 401 return blockSize;
cannam@233 402 }
cannam@233 403
cannam@233 404 RealTime
cannam@233 405 PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
cannam@233 406 {
cannam@233 407 if (m_plugin->getInputDomain() == TimeDomain) {
cannam@233 408 return RealTime::zeroTime;
cannam@298 409 } else if (m_method == ShiftData || m_method == NoShift) {
cannam@289 410 return RealTime::zeroTime;
cannam@233 411 } else {
cannam@233 412 return RealTime::frame2RealTime
cannam@233 413 (m_blockSize/2, int(m_inputSampleRate + 0.5));
cannam@233 414 }
cannam@233 415 }
cannam@233 416
cannam@288 417 void
cannam@288 418 PluginInputDomainAdapter::Impl::setProcessTimestampMethod(ProcessTimestampMethod m)
cannam@288 419 {
cannam@288 420 m_method = m;
cannam@288 421 }
cannam@288 422
cannam@288 423 PluginInputDomainAdapter::ProcessTimestampMethod
cannam@288 424 PluginInputDomainAdapter::Impl::getProcessTimestampMethod() const
cannam@288 425 {
cannam@288 426 return m_method;
cannam@288 427 }
cannam@288 428
cannam@233 429 Plugin::FeatureSet
cannam@233 430 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
cannam@233 431 RealTime timestamp)
cannam@233 432 {
cannam@233 433 if (m_plugin->getInputDomain() == TimeDomain) {
cannam@233 434 return m_plugin->process(inputBuffers, timestamp);
cannam@233 435 }
cannam@233 436
cannam@298 437 if (m_method == ShiftTimestamp || m_method == NoShift) {
cannam@289 438 return processShiftingTimestamp(inputBuffers, timestamp);
cannam@289 439 } else {
cannam@289 440 return processShiftingData(inputBuffers, timestamp);
cannam@289 441 }
cannam@289 442 }
cannam@233 443
cannam@289 444 Plugin::FeatureSet
cannam@289 445 PluginInputDomainAdapter::Impl::processShiftingTimestamp(const float *const *inputBuffers,
cannam@289 446 RealTime timestamp)
cannam@289 447 {
cannam@298 448 if (m_method == ShiftTimestamp) {
cannam@298 449 timestamp = timestamp + getTimestampAdjustment();
cannam@298 450 }
cannam@233 451
cannam@233 452 for (int c = 0; c < m_channels; ++c) {
cannam@233 453
cannam@233 454 for (int i = 0; i < m_blockSize; ++i) {
cannam@233 455 m_ri[i] = double(inputBuffers[c][i]) * m_window[i];
cannam@233 456 }
cannam@233 457
cannam@233 458 for (int i = 0; i < m_blockSize/2; ++i) {
cannam@233 459 // FFT shift
cannam@233 460 double value = m_ri[i];
cannam@233 461 m_ri[i] = m_ri[i + m_blockSize/2];
cannam@233 462 m_ri[i + m_blockSize/2] = value;
cannam@233 463 }
cannam@233 464
cannam@233 465 #ifdef HAVE_FFTW3
cannam@233 466 fftw_execute(m_plan);
cannam@233 467
cannam@233 468 for (int i = 0; i <= m_blockSize/2; ++i) {
cannam@233 469 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
cannam@233 470 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
cannam@233 471 }
cannam@233 472 #else
cannam@233 473 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
cannam@233 474
cannam@233 475 for (int i = 0; i <= m_blockSize/2; ++i) {
cannam@233 476 m_freqbuf[c][i * 2] = float(m_ro[i]);
cannam@233 477 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
cannam@233 478 }
cannam@233 479 #endif
cannam@233 480 }
cannam@233 481
cannam@289 482 return m_plugin->process(m_freqbuf, timestamp);
cannam@288 483 }
cannam@288 484
cannam@288 485 Plugin::FeatureSet
cannam@289 486 PluginInputDomainAdapter::Impl::processShiftingData(const float *const *inputBuffers,
cannam@289 487 RealTime timestamp)
cannam@288 488 {
cannam@289 489 if (m_processCount == 0) {
cannam@289 490 if (!m_shiftBuffers) {
cannam@289 491 m_shiftBuffers = new float *[m_channels];
cannam@289 492 for (int c = 0; c < m_channels; ++c) {
cannam@289 493 m_shiftBuffers[c] = new float[m_blockSize + m_blockSize/2];
cannam@289 494 }
cannam@289 495 }
cannam@289 496 for (int c = 0; c < m_channels; ++c) {
cannam@289 497 for (int i = 0; i < m_blockSize + m_blockSize/2; ++i) {
cannam@289 498 m_shiftBuffers[c][i] = 0.f;
cannam@289 499 }
cannam@289 500 }
cannam@289 501 }
cannam@289 502
cannam@289 503 for (int c = 0; c < m_channels; ++c) {
cannam@289 504 for (int i = m_stepSize; i < m_blockSize + m_blockSize/2; ++i) {
cannam@289 505 m_shiftBuffers[c][i - m_stepSize] = m_shiftBuffers[c][i];
cannam@289 506 }
cannam@289 507 for (int i = 0; i < m_blockSize; ++i) {
cannam@289 508 m_shiftBuffers[c][i + m_blockSize/2] = inputBuffers[c][i];
cannam@289 509 }
cannam@289 510 }
cannam@289 511
cannam@289 512 for (int c = 0; c < m_channels; ++c) {
cannam@289 513
cannam@289 514 for (int i = 0; i < m_blockSize; ++i) {
cannam@289 515 m_ri[i] = double(m_shiftBuffers[c][i]) * m_window[i];
cannam@289 516 }
cannam@289 517
cannam@289 518 for (int i = 0; i < m_blockSize/2; ++i) {
cannam@289 519 // FFT shift
cannam@289 520 double value = m_ri[i];
cannam@289 521 m_ri[i] = m_ri[i + m_blockSize/2];
cannam@289 522 m_ri[i + m_blockSize/2] = value;
cannam@289 523 }
cannam@289 524
cannam@289 525 #ifdef HAVE_FFTW3
cannam@289 526 fftw_execute(m_plan);
cannam@289 527
cannam@289 528 for (int i = 0; i <= m_blockSize/2; ++i) {
cannam@289 529 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
cannam@289 530 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
cannam@289 531 }
cannam@289 532 #else
cannam@289 533 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
cannam@289 534
cannam@289 535 for (int i = 0; i <= m_blockSize/2; ++i) {
cannam@289 536 m_freqbuf[c][i * 2] = float(m_ro[i]);
cannam@289 537 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
cannam@289 538 }
cannam@289 539 #endif
cannam@289 540 }
cannam@289 541
cannam@289 542 ++m_processCount;
cannam@289 543
cannam@289 544 return m_plugin->process(m_freqbuf, timestamp);
cannam@233 545 }
cannam@233 546
cannam@233 547 #ifndef HAVE_FFTW3
cannam@233 548
cannam@233 549 void
cannam@233 550 PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse,
cannam@233 551 double *ri, double *ii, double *ro, double *io)
cannam@233 552 {
cannam@233 553 if (!ri || !ro || !io) return;
cannam@233 554
cannam@233 555 unsigned int bits;
cannam@233 556 unsigned int i, j, k, m;
cannam@233 557 unsigned int blockSize, blockEnd;
cannam@233 558
cannam@233 559 double tr, ti;
cannam@233 560
cannam@233 561 if (n < 2) return;
cannam@233 562 if (n & (n-1)) return;
cannam@233 563
cannam@233 564 double angle = 2.0 * M_PI;
cannam@233 565 if (inverse) angle = -angle;
cannam@233 566
cannam@233 567 for (i = 0; ; ++i) {
cannam@233 568 if (n & (1 << i)) {
cannam@233 569 bits = i;
cannam@233 570 break;
cannam@233 571 }
cannam@233 572 }
cannam@233 573
cannam@233 574 static unsigned int tableSize = 0;
cannam@233 575 static int *table = 0;
cannam@233 576
cannam@233 577 if (tableSize != n) {
cannam@233 578
cannam@233 579 delete[] table;
cannam@233 580
cannam@233 581 table = new int[n];
cannam@233 582
cannam@233 583 for (i = 0; i < n; ++i) {
cannam@233 584
cannam@233 585 m = i;
cannam@233 586
cannam@233 587 for (j = k = 0; j < bits; ++j) {
cannam@233 588 k = (k << 1) | (m & 1);
cannam@233 589 m >>= 1;
cannam@233 590 }
cannam@233 591
cannam@233 592 table[i] = k;
cannam@233 593 }
cannam@233 594
cannam@233 595 tableSize = n;
cannam@233 596 }
cannam@233 597
cannam@233 598 if (ii) {
cannam@233 599 for (i = 0; i < n; ++i) {
cannam@233 600 ro[table[i]] = ri[i];
cannam@233 601 io[table[i]] = ii[i];
cannam@233 602 }
cannam@233 603 } else {
cannam@233 604 for (i = 0; i < n; ++i) {
cannam@233 605 ro[table[i]] = ri[i];
cannam@233 606 io[table[i]] = 0.0;
cannam@233 607 }
cannam@233 608 }
cannam@233 609
cannam@233 610 blockEnd = 1;
cannam@233 611
cannam@233 612 for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
cannam@233 613
cannam@233 614 double delta = angle / (double)blockSize;
cannam@233 615 double sm2 = -sin(-2 * delta);
cannam@233 616 double sm1 = -sin(-delta);
cannam@233 617 double cm2 = cos(-2 * delta);
cannam@233 618 double cm1 = cos(-delta);
cannam@233 619 double w = 2 * cm1;
cannam@233 620 double ar[3], ai[3];
cannam@233 621
cannam@233 622 for (i = 0; i < n; i += blockSize) {
cannam@233 623
cannam@233 624 ar[2] = cm2;
cannam@233 625 ar[1] = cm1;
cannam@233 626
cannam@233 627 ai[2] = sm2;
cannam@233 628 ai[1] = sm1;
cannam@233 629
cannam@233 630 for (j = i, m = 0; m < blockEnd; j++, m++) {
cannam@233 631
cannam@233 632 ar[0] = w * ar[1] - ar[2];
cannam@233 633 ar[2] = ar[1];
cannam@233 634 ar[1] = ar[0];
cannam@233 635
cannam@233 636 ai[0] = w * ai[1] - ai[2];
cannam@233 637 ai[2] = ai[1];
cannam@233 638 ai[1] = ai[0];
cannam@233 639
cannam@233 640 k = j + blockEnd;
cannam@233 641 tr = ar[0] * ro[k] - ai[0] * io[k];
cannam@233 642 ti = ar[0] * io[k] + ai[0] * ro[k];
cannam@233 643
cannam@233 644 ro[k] = ro[j] - tr;
cannam@233 645 io[k] = io[j] - ti;
cannam@233 646
cannam@233 647 ro[j] += tr;
cannam@233 648 io[j] += ti;
cannam@233 649 }
cannam@233 650 }
cannam@233 651
cannam@233 652 blockEnd = blockSize;
cannam@233 653 }
cannam@233 654
cannam@233 655 if (inverse) {
cannam@233 656
cannam@233 657 double denom = (double)n;
cannam@233 658
cannam@233 659 for (i = 0; i < n; i++) {
cannam@233 660 ro[i] /= denom;
cannam@233 661 io[i] /= denom;
cannam@233 662 }
cannam@233 663 }
cannam@233 664 }
cannam@233 665
cannam@233 666 #endif
cannam@233 667
cannam@233 668 }
cannam@233 669
cannam@233 670 }
cannam@233 671
cannam@263 672 _VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.cpp)
cannam@263 673