annotate src/vamp-hostsdk/PluginInputDomainAdapter.cpp @ 263:4454843ff384

* OK, we're going to have to place the host stuff in its own namespace too. Otherwise our new SV build on OSX fails to load old plugins because they pull in the host namespace PluginBase and thus report the wrong Vamp version... *sigh*
author cannam
date Thu, 20 Nov 2008 15:01:30 +0000
parents 521734d2b498
children 6c9f10b8a53a
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@233 9 Copyright 2006-2007 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@233 86
cannam@233 87 size_t getPreferredStepSize() const;
cannam@233 88 size_t getPreferredBlockSize() const;
cannam@233 89
cannam@233 90 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
cannam@233 91
cannam@233 92 RealTime getTimestampAdjustment() const;
cannam@233 93
cannam@233 94 protected:
cannam@233 95 Plugin *m_plugin;
cannam@233 96 float m_inputSampleRate;
cannam@233 97 int m_channels;
cannam@233 98 int m_blockSize;
cannam@233 99 float **m_freqbuf;
cannam@233 100
cannam@233 101 double *m_ri;
cannam@233 102 double *m_window;
cannam@233 103
cannam@233 104 #ifdef HAVE_FFTW3
cannam@233 105 fftw_plan m_plan;
cannam@233 106 fftw_complex *m_cbuf;
cannam@233 107 #else
cannam@233 108 double *m_ro;
cannam@233 109 double *m_io;
cannam@233 110 void fft(unsigned int n, bool inverse,
cannam@233 111 double *ri, double *ii, double *ro, double *io);
cannam@233 112 #endif
cannam@233 113
cannam@233 114 size_t makeBlockSizeAcceptable(size_t) const;
cannam@233 115 };
cannam@233 116
cannam@233 117 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
cannam@233 118 PluginWrapper(plugin)
cannam@233 119 {
cannam@233 120 m_impl = new Impl(plugin, m_inputSampleRate);
cannam@233 121 }
cannam@233 122
cannam@233 123 PluginInputDomainAdapter::~PluginInputDomainAdapter()
cannam@233 124 {
cannam@233 125 delete m_impl;
cannam@233 126 }
cannam@233 127
cannam@233 128 bool
cannam@233 129 PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@233 130 {
cannam@233 131 return m_impl->initialise(channels, stepSize, blockSize);
cannam@233 132 }
cannam@233 133
cannam@233 134 Plugin::InputDomain
cannam@233 135 PluginInputDomainAdapter::getInputDomain() const
cannam@233 136 {
cannam@233 137 return TimeDomain;
cannam@233 138 }
cannam@233 139
cannam@233 140 size_t
cannam@233 141 PluginInputDomainAdapter::getPreferredStepSize() const
cannam@233 142 {
cannam@233 143 return m_impl->getPreferredStepSize();
cannam@233 144 }
cannam@233 145
cannam@233 146 size_t
cannam@233 147 PluginInputDomainAdapter::getPreferredBlockSize() const
cannam@233 148 {
cannam@233 149 return m_impl->getPreferredBlockSize();
cannam@233 150 }
cannam@233 151
cannam@233 152 Plugin::FeatureSet
cannam@233 153 PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
cannam@233 154 {
cannam@233 155 return m_impl->process(inputBuffers, timestamp);
cannam@233 156 }
cannam@233 157
cannam@233 158 RealTime
cannam@233 159 PluginInputDomainAdapter::getTimestampAdjustment() const
cannam@233 160 {
cannam@233 161 return m_impl->getTimestampAdjustment();
cannam@233 162 }
cannam@233 163
cannam@233 164
cannam@233 165 PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
cannam@233 166 m_plugin(plugin),
cannam@233 167 m_inputSampleRate(inputSampleRate),
cannam@233 168 m_channels(0),
cannam@233 169 m_blockSize(0),
cannam@233 170 m_freqbuf(0),
cannam@233 171 m_ri(0),
cannam@233 172 m_window(0),
cannam@233 173 #ifdef HAVE_FFTW3
cannam@233 174 m_plan(0),
cannam@233 175 m_cbuf(0)
cannam@233 176 #else
cannam@233 177 m_ro(0),
cannam@233 178 m_io(0)
cannam@233 179 #endif
cannam@233 180 {
cannam@233 181 }
cannam@233 182
cannam@233 183 PluginInputDomainAdapter::Impl::~Impl()
cannam@233 184 {
cannam@233 185 // the adapter will delete the plugin
cannam@233 186
cannam@233 187 if (m_channels > 0) {
cannam@233 188 for (int c = 0; c < m_channels; ++c) {
cannam@233 189 delete[] m_freqbuf[c];
cannam@233 190 }
cannam@233 191 delete[] m_freqbuf;
cannam@233 192 #ifdef HAVE_FFTW3
cannam@233 193 if (m_plan) {
cannam@233 194 fftw_destroy_plan(m_plan);
cannam@233 195 fftw_free(m_ri);
cannam@233 196 fftw_free(m_cbuf);
cannam@233 197 m_plan = 0;
cannam@233 198 }
cannam@233 199 #else
cannam@233 200 delete[] m_ri;
cannam@233 201 delete[] m_ro;
cannam@233 202 delete[] m_io;
cannam@233 203 #endif
cannam@233 204 delete[] m_window;
cannam@233 205 }
cannam@233 206 }
cannam@233 207
cannam@233 208 // for some visual studii apparently
cannam@233 209 #ifndef M_PI
cannam@233 210 #define M_PI 3.14159265358979232846
cannam@233 211 #endif
cannam@233 212
cannam@233 213 bool
cannam@233 214 PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@233 215 {
cannam@233 216 if (m_plugin->getInputDomain() == TimeDomain) {
cannam@233 217
cannam@233 218 m_blockSize = int(blockSize);
cannam@233 219 m_channels = int(channels);
cannam@233 220
cannam@233 221 return m_plugin->initialise(channels, stepSize, blockSize);
cannam@233 222 }
cannam@233 223
cannam@233 224 if (blockSize < 2) {
cannam@233 225 std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not supported" << std::endl;
cannam@233 226 return false;
cannam@233 227 }
cannam@233 228
cannam@233 229 if (blockSize & (blockSize-1)) {
cannam@233 230 std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
cannam@233 231 return false;
cannam@233 232 }
cannam@233 233
cannam@233 234 if (m_channels > 0) {
cannam@233 235 for (int c = 0; c < m_channels; ++c) {
cannam@233 236 delete[] m_freqbuf[c];
cannam@233 237 }
cannam@233 238 delete[] m_freqbuf;
cannam@233 239 #ifdef HAVE_FFTW3
cannam@233 240 if (m_plan) {
cannam@233 241 fftw_destroy_plan(m_plan);
cannam@233 242 fftw_free(m_ri);
cannam@233 243 fftw_free(m_cbuf);
cannam@233 244 m_plan = 0;
cannam@233 245 }
cannam@233 246 #else
cannam@233 247 delete[] m_ri;
cannam@233 248 delete[] m_ro;
cannam@233 249 delete[] m_io;
cannam@233 250 #endif
cannam@233 251 delete[] m_window;
cannam@233 252 }
cannam@233 253
cannam@233 254 m_blockSize = int(blockSize);
cannam@233 255 m_channels = int(channels);
cannam@233 256
cannam@233 257 m_freqbuf = new float *[m_channels];
cannam@233 258 for (int c = 0; c < m_channels; ++c) {
cannam@233 259 m_freqbuf[c] = new float[m_blockSize + 2];
cannam@233 260 }
cannam@233 261 m_window = new double[m_blockSize];
cannam@233 262
cannam@233 263 for (int i = 0; i < m_blockSize; ++i) {
cannam@233 264 // Hanning window
cannam@233 265 m_window[i] = (0.50 - 0.50 * cos((2.0 * M_PI * i) / m_blockSize));
cannam@233 266 }
cannam@233 267
cannam@233 268 #ifdef HAVE_FFTW3
cannam@233 269 m_ri = (double *)fftw_malloc(blockSize * sizeof(double));
cannam@233 270 m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex));
cannam@233 271 m_plan = fftw_plan_dft_r2c_1d(blockSize, m_ri, m_cbuf, FFTW_MEASURE);
cannam@233 272 #else
cannam@233 273 m_ri = new double[m_blockSize];
cannam@233 274 m_ro = new double[m_blockSize];
cannam@233 275 m_io = new double[m_blockSize];
cannam@233 276 #endif
cannam@233 277
cannam@233 278 return m_plugin->initialise(channels, stepSize, blockSize);
cannam@233 279 }
cannam@233 280
cannam@233 281 size_t
cannam@233 282 PluginInputDomainAdapter::Impl::getPreferredStepSize() const
cannam@233 283 {
cannam@233 284 size_t step = m_plugin->getPreferredStepSize();
cannam@233 285
cannam@233 286 if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) {
cannam@233 287 step = getPreferredBlockSize() / 2;
cannam@233 288 }
cannam@233 289
cannam@233 290 return step;
cannam@233 291 }
cannam@233 292
cannam@233 293 size_t
cannam@233 294 PluginInputDomainAdapter::Impl::getPreferredBlockSize() const
cannam@233 295 {
cannam@233 296 size_t block = m_plugin->getPreferredBlockSize();
cannam@233 297
cannam@233 298 if (m_plugin->getInputDomain() == FrequencyDomain) {
cannam@233 299 if (block == 0) {
cannam@233 300 block = 1024;
cannam@233 301 } else {
cannam@233 302 block = makeBlockSizeAcceptable(block);
cannam@233 303 }
cannam@233 304 }
cannam@233 305
cannam@233 306 return block;
cannam@233 307 }
cannam@233 308
cannam@233 309 size_t
cannam@233 310 PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
cannam@233 311 {
cannam@233 312 if (blockSize < 2) {
cannam@233 313
cannam@233 314 std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not" << std::endl
cannam@233 315 << "supported, increasing from " << blockSize << " to 2" << std::endl;
cannam@233 316 blockSize = 2;
cannam@233 317
cannam@233 318 } else if (blockSize & (blockSize-1)) {
cannam@233 319
cannam@233 320 #ifdef HAVE_FFTW3
cannam@233 321 // not an issue with FFTW
cannam@233 322 #else
cannam@233 323
cannam@233 324 // not a power of two, can't handle that with our built-in FFT
cannam@233 325 // implementation
cannam@233 326
cannam@233 327 size_t nearest = blockSize;
cannam@233 328 size_t power = 0;
cannam@233 329 while (nearest > 1) {
cannam@233 330 nearest >>= 1;
cannam@233 331 ++power;
cannam@233 332 }
cannam@233 333 nearest = 1;
cannam@233 334 while (power) {
cannam@233 335 nearest <<= 1;
cannam@233 336 --power;
cannam@233 337 }
cannam@233 338
cannam@233 339 if (blockSize - nearest > (nearest*2) - blockSize) {
cannam@233 340 nearest = nearest*2;
cannam@233 341 }
cannam@233 342
cannam@233 343 std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
cannam@233 344 blockSize = nearest;
cannam@233 345
cannam@233 346 #endif
cannam@233 347 }
cannam@233 348
cannam@233 349 return blockSize;
cannam@233 350 }
cannam@233 351
cannam@233 352 RealTime
cannam@233 353 PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
cannam@233 354 {
cannam@233 355 if (m_plugin->getInputDomain() == TimeDomain) {
cannam@233 356 return RealTime::zeroTime;
cannam@233 357 } else {
cannam@233 358 return RealTime::frame2RealTime
cannam@233 359 (m_blockSize/2, int(m_inputSampleRate + 0.5));
cannam@233 360 }
cannam@233 361 }
cannam@233 362
cannam@233 363 Plugin::FeatureSet
cannam@233 364 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
cannam@233 365 RealTime timestamp)
cannam@233 366 {
cannam@233 367 if (m_plugin->getInputDomain() == TimeDomain) {
cannam@233 368 return m_plugin->process(inputBuffers, timestamp);
cannam@233 369 }
cannam@233 370
cannam@233 371 // The timestamp supplied should be (according to the Vamp::Plugin
cannam@233 372 // spec) the time of the start of the time-domain input block.
cannam@233 373 // However, we want to pass to the plugin an FFT output calculated
cannam@233 374 // from the block of samples _centred_ on that timestamp.
cannam@233 375 //
cannam@233 376 // We have two options:
cannam@233 377 //
cannam@233 378 // 1. Buffer the input, calculating the fft of the values at the
cannam@233 379 // passed-in block minus blockSize/2 rather than starting at the
cannam@233 380 // passed-in block. So each time we call process on the plugin,
cannam@233 381 // we are passing in the same timestamp as was passed to our own
cannam@233 382 // process plugin, but not (the frequency domain representation
cannam@233 383 // of) the same set of samples. Advantages: avoids confusion in
cannam@233 384 // the host by ensuring the returned values have timestamps
cannam@233 385 // comparable with that passed in to this function (in fact this
cannam@233 386 // is pretty much essential for one-value-per-block outputs);
cannam@233 387 // consistent with hosts such as SV that deal with the
cannam@233 388 // frequency-domain transform themselves. Disadvantages: means
cannam@233 389 // making the not necessarily correct assumption that the samples
cannam@233 390 // preceding the first official block are all zero (or some other
cannam@233 391 // known value).
cannam@233 392 //
cannam@233 393 // 2. Increase the passed-in timestamps by half the blocksize. So
cannam@233 394 // when we call process, we are passing in the frequency domain
cannam@233 395 // representation of the same set of samples as passed to us, but
cannam@233 396 // with a different timestamp. Advantages: simplicity; avoids
cannam@233 397 // iffy assumption mentioned above. Disadvantages: inconsistency
cannam@233 398 // with SV in cases where stepSize != blockSize/2; potential
cannam@233 399 // confusion arising from returned timestamps being calculated
cannam@233 400 // from the adjusted input timestamps rather than the original
cannam@233 401 // ones (and inaccuracy where the returned timestamp is implied,
cannam@233 402 // as in one-value-per-block).
cannam@233 403 //
cannam@233 404 // Neither way is ideal, but I don't think either is strictly
cannam@233 405 // incorrect either. I think this is just a case where the same
cannam@233 406 // plugin can legitimately produce differing results from the same
cannam@233 407 // input data, depending on how that data is packaged.
cannam@233 408 //
cannam@233 409 // We'll go for option 2, adjusting the timestamps. Note in
cannam@233 410 // particular that this means some results can differ from those
cannam@233 411 // produced by SV.
cannam@233 412
cannam@233 413 // std::cerr << "PluginInputDomainAdapter: sampleRate " << m_inputSampleRate << ", blocksize " << m_blockSize << ", adjusting time from " << timestamp;
cannam@233 414
cannam@233 415 timestamp = timestamp + getTimestampAdjustment();
cannam@233 416
cannam@233 417 // std::cerr << " to " << timestamp << std::endl;
cannam@233 418
cannam@233 419 for (int c = 0; c < m_channels; ++c) {
cannam@233 420
cannam@233 421 for (int i = 0; i < m_blockSize; ++i) {
cannam@233 422 m_ri[i] = double(inputBuffers[c][i]) * m_window[i];
cannam@233 423 }
cannam@233 424
cannam@233 425 for (int i = 0; i < m_blockSize/2; ++i) {
cannam@233 426 // FFT shift
cannam@233 427 double value = m_ri[i];
cannam@233 428 m_ri[i] = m_ri[i + m_blockSize/2];
cannam@233 429 m_ri[i + m_blockSize/2] = value;
cannam@233 430 }
cannam@233 431
cannam@233 432 #ifdef HAVE_FFTW3
cannam@233 433
cannam@233 434 fftw_execute(m_plan);
cannam@233 435
cannam@233 436 for (int i = 0; i <= m_blockSize/2; ++i) {
cannam@233 437 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
cannam@233 438 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
cannam@233 439 }
cannam@233 440
cannam@233 441 #else
cannam@233 442
cannam@233 443 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
cannam@233 444
cannam@233 445 for (int i = 0; i <= m_blockSize/2; ++i) {
cannam@233 446 m_freqbuf[c][i * 2] = float(m_ro[i]);
cannam@233 447 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
cannam@233 448 }
cannam@233 449
cannam@233 450 #endif
cannam@233 451 }
cannam@233 452
cannam@233 453 return m_plugin->process(m_freqbuf, timestamp);
cannam@233 454 }
cannam@233 455
cannam@233 456 #ifndef HAVE_FFTW3
cannam@233 457
cannam@233 458 void
cannam@233 459 PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse,
cannam@233 460 double *ri, double *ii, double *ro, double *io)
cannam@233 461 {
cannam@233 462 if (!ri || !ro || !io) return;
cannam@233 463
cannam@233 464 unsigned int bits;
cannam@233 465 unsigned int i, j, k, m;
cannam@233 466 unsigned int blockSize, blockEnd;
cannam@233 467
cannam@233 468 double tr, ti;
cannam@233 469
cannam@233 470 if (n < 2) return;
cannam@233 471 if (n & (n-1)) return;
cannam@233 472
cannam@233 473 double angle = 2.0 * M_PI;
cannam@233 474 if (inverse) angle = -angle;
cannam@233 475
cannam@233 476 for (i = 0; ; ++i) {
cannam@233 477 if (n & (1 << i)) {
cannam@233 478 bits = i;
cannam@233 479 break;
cannam@233 480 }
cannam@233 481 }
cannam@233 482
cannam@233 483 static unsigned int tableSize = 0;
cannam@233 484 static int *table = 0;
cannam@233 485
cannam@233 486 if (tableSize != n) {
cannam@233 487
cannam@233 488 delete[] table;
cannam@233 489
cannam@233 490 table = new int[n];
cannam@233 491
cannam@233 492 for (i = 0; i < n; ++i) {
cannam@233 493
cannam@233 494 m = i;
cannam@233 495
cannam@233 496 for (j = k = 0; j < bits; ++j) {
cannam@233 497 k = (k << 1) | (m & 1);
cannam@233 498 m >>= 1;
cannam@233 499 }
cannam@233 500
cannam@233 501 table[i] = k;
cannam@233 502 }
cannam@233 503
cannam@233 504 tableSize = n;
cannam@233 505 }
cannam@233 506
cannam@233 507 if (ii) {
cannam@233 508 for (i = 0; i < n; ++i) {
cannam@233 509 ro[table[i]] = ri[i];
cannam@233 510 io[table[i]] = ii[i];
cannam@233 511 }
cannam@233 512 } else {
cannam@233 513 for (i = 0; i < n; ++i) {
cannam@233 514 ro[table[i]] = ri[i];
cannam@233 515 io[table[i]] = 0.0;
cannam@233 516 }
cannam@233 517 }
cannam@233 518
cannam@233 519 blockEnd = 1;
cannam@233 520
cannam@233 521 for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
cannam@233 522
cannam@233 523 double delta = angle / (double)blockSize;
cannam@233 524 double sm2 = -sin(-2 * delta);
cannam@233 525 double sm1 = -sin(-delta);
cannam@233 526 double cm2 = cos(-2 * delta);
cannam@233 527 double cm1 = cos(-delta);
cannam@233 528 double w = 2 * cm1;
cannam@233 529 double ar[3], ai[3];
cannam@233 530
cannam@233 531 for (i = 0; i < n; i += blockSize) {
cannam@233 532
cannam@233 533 ar[2] = cm2;
cannam@233 534 ar[1] = cm1;
cannam@233 535
cannam@233 536 ai[2] = sm2;
cannam@233 537 ai[1] = sm1;
cannam@233 538
cannam@233 539 for (j = i, m = 0; m < blockEnd; j++, m++) {
cannam@233 540
cannam@233 541 ar[0] = w * ar[1] - ar[2];
cannam@233 542 ar[2] = ar[1];
cannam@233 543 ar[1] = ar[0];
cannam@233 544
cannam@233 545 ai[0] = w * ai[1] - ai[2];
cannam@233 546 ai[2] = ai[1];
cannam@233 547 ai[1] = ai[0];
cannam@233 548
cannam@233 549 k = j + blockEnd;
cannam@233 550 tr = ar[0] * ro[k] - ai[0] * io[k];
cannam@233 551 ti = ar[0] * io[k] + ai[0] * ro[k];
cannam@233 552
cannam@233 553 ro[k] = ro[j] - tr;
cannam@233 554 io[k] = io[j] - ti;
cannam@233 555
cannam@233 556 ro[j] += tr;
cannam@233 557 io[j] += ti;
cannam@233 558 }
cannam@233 559 }
cannam@233 560
cannam@233 561 blockEnd = blockSize;
cannam@233 562 }
cannam@233 563
cannam@233 564 if (inverse) {
cannam@233 565
cannam@233 566 double denom = (double)n;
cannam@233 567
cannam@233 568 for (i = 0; i < n; i++) {
cannam@233 569 ro[i] /= denom;
cannam@233 570 io[i] /= denom;
cannam@233 571 }
cannam@233 572 }
cannam@233 573 }
cannam@233 574
cannam@233 575 #endif
cannam@233 576
cannam@233 577 }
cannam@233 578
cannam@233 579 }
cannam@233 580
cannam@263 581 _VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.cpp)
cannam@263 582