comparison src/vamp-hostsdk/PluginInputDomainAdapter.cpp @ 289:3e5ab1c7ea8c

* Implementation of ShiftData process method
author cannam
date Wed, 16 Sep 2009 11:27:15 +0000
parents 283e15f6e548
children c97e70ed5abc
comparison
equal deleted inserted replaced
288:283e15f6e548 289:3e5ab1c7ea8c
106 double *m_ri; 106 double *m_ri;
107 double *m_window; 107 double *m_window;
108 108
109 ProcessTimestampMethod m_method; 109 ProcessTimestampMethod m_method;
110 int m_processCount; 110 int m_processCount;
111 FeatureSet prepadProcess(const float *const *inputBuffers, 111 float **m_shiftBuffers;
112 RealTime timestamp); 112 // FeatureSet prepadProcess(const float *const *inputBuffers,
113 // RealTime timestamp);
113 114
114 #ifdef HAVE_FFTW3 115 #ifdef HAVE_FFTW3
115 fftw_plan m_plan; 116 fftw_plan m_plan;
116 fftw_complex *m_cbuf; 117 fftw_complex *m_cbuf;
117 #else 118 #else
118 double *m_ro; 119 double *m_ro;
119 double *m_io; 120 double *m_io;
120 void fft(unsigned int n, bool inverse, 121 void fft(unsigned int n, bool inverse,
121 double *ri, double *ii, double *ro, double *io); 122 double *ri, double *ii, double *ro, double *io);
122 #endif 123 #endif
124
125 FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp);
126 FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp);
123 127
124 size_t makeBlockSizeAcceptable(size_t) const; 128 size_t makeBlockSizeAcceptable(size_t) const;
125 }; 129 };
126 130
127 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) : 131 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
199 m_freqbuf(0), 203 m_freqbuf(0),
200 m_ri(0), 204 m_ri(0),
201 m_window(0), 205 m_window(0),
202 m_method(ShiftTimestamp), 206 m_method(ShiftTimestamp),
203 m_processCount(0), 207 m_processCount(0),
208 m_shiftBuffers(0),
204 #ifdef HAVE_FFTW3 209 #ifdef HAVE_FFTW3
205 m_plan(0), 210 m_plan(0),
206 m_cbuf(0) 211 m_cbuf(0)
207 #else 212 #else
208 m_ro(0), 213 m_ro(0),
212 } 217 }
213 218
214 PluginInputDomainAdapter::Impl::~Impl() 219 PluginInputDomainAdapter::Impl::~Impl()
215 { 220 {
216 // the adapter will delete the plugin 221 // the adapter will delete the plugin
222
223 if (m_shiftBuffers) {
224 for (int c = 0; c < m_channels; ++c) {
225 delete[] m_shiftBuffers[c];
226 }
227 delete[] m_shiftBuffers;
228 }
217 229
218 if (m_channels > 0) { 230 if (m_channels > 0) {
219 for (int c = 0; c < m_channels; ++c) { 231 for (int c = 0; c < m_channels; ++c) {
220 delete[] m_freqbuf[c]; 232 delete[] m_freqbuf[c];
221 } 233 }
394 RealTime 406 RealTime
395 PluginInputDomainAdapter::Impl::getTimestampAdjustment() const 407 PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
396 { 408 {
397 if (m_plugin->getInputDomain() == TimeDomain) { 409 if (m_plugin->getInputDomain() == TimeDomain) {
398 return RealTime::zeroTime; 410 return RealTime::zeroTime;
411 } else if (m_method == ShiftData) {
412 return RealTime::zeroTime;
399 } else { 413 } else {
400 return RealTime::frame2RealTime 414 return RealTime::frame2RealTime
401 (m_blockSize/2, int(m_inputSampleRate + 0.5)); 415 (m_blockSize/2, int(m_inputSampleRate + 0.5));
402 } 416 }
403 } 417 }
420 { 434 {
421 if (m_plugin->getInputDomain() == TimeDomain) { 435 if (m_plugin->getInputDomain() == TimeDomain) {
422 return m_plugin->process(inputBuffers, timestamp); 436 return m_plugin->process(inputBuffers, timestamp);
423 } 437 }
424 438
425 // The timestamp supplied should be (according to the Vamp::Plugin
426 // spec) the time of the start of the time-domain input block.
427 // However, we want to pass to the plugin an FFT output calculated
428 // from the block of samples _centred_ on that timestamp.
429 //
430 // We have two options:
431 //
432 // 1. Buffer the input, calculating the fft of the values at the
433 // passed-in block minus blockSize/2 rather than starting at the
434 // passed-in block. So each time we call process on the plugin,
435 // we are passing in the same timestamp as was passed to our own
436 // process plugin, but not (the frequency domain representation
437 // of) the same set of samples. Advantages: avoids confusion in
438 // the host by ensuring the returned values have timestamps
439 // comparable with that passed in to this function (in fact this
440 // is pretty much essential for one-value-per-block outputs);
441 // consistent with hosts such as SV that deal with the
442 // frequency-domain transform themselves. Disadvantages: means
443 // making the not necessarily correct assumption that the samples
444 // preceding the first official block are all zero (or some other
445 // known value).
446 //
447 // 2. Increase the passed-in timestamps by half the blocksize. So
448 // when we call process, we are passing in the frequency domain
449 // representation of the same set of samples as passed to us, but
450 // with a different timestamp. Advantages: simplicity; avoids
451 // iffy assumption mentioned above. Disadvantages: inconsistency
452 // with SV in cases where stepSize != blockSize/2; potential
453 // confusion arising from returned timestamps being calculated
454 // from the adjusted input timestamps rather than the original
455 // ones (and inaccuracy where the returned timestamp is implied,
456 // as in one-value-per-block).
457 //
458 // Neither way is ideal, but I don't think either is strictly
459 // incorrect either. I think this is just a case where the same
460 // plugin can legitimately produce differing results from the same
461 // input data, depending on how that data is packaged.
462 //
463 // We'll go for option 2, adjusting the timestamps. Note in
464 // particular that this means some results can differ from those
465 // produced by SV.
466
467 // std::cerr << "PluginInputDomainAdapter: sampleRate " << m_inputSampleRate << ", blocksize " << m_blockSize << ", adjusting time from " << timestamp;
468
469 //!!! update the above comment for ProcessTimestampMethod
470
471 FeatureSet fs;
472 if (m_method == ShiftTimestamp) { 439 if (m_method == ShiftTimestamp) {
473 timestamp = timestamp + getTimestampAdjustment(); 440 return processShiftingTimestamp(inputBuffers, timestamp);
474 } else if (m_processCount == 0) { 441 } else {
475 fs = prepadProcess(inputBuffers, timestamp); 442 return processShiftingData(inputBuffers, timestamp);
476 } 443 }
477 ++m_processCount; 444 }
478 445
479 // std::cerr << " to " << timestamp << std::endl; 446 Plugin::FeatureSet
447 PluginInputDomainAdapter::Impl::processShiftingTimestamp(const float *const *inputBuffers,
448 RealTime timestamp)
449 {
450 timestamp = timestamp + getTimestampAdjustment();
480 451
481 for (int c = 0; c < m_channels; ++c) { 452 for (int c = 0; c < m_channels; ++c) {
482 453
483 for (int i = 0; i < m_blockSize; ++i) { 454 for (int i = 0; i < m_blockSize; ++i) {
484 m_ri[i] = double(inputBuffers[c][i]) * m_window[i]; 455 m_ri[i] = double(inputBuffers[c][i]) * m_window[i];
490 m_ri[i] = m_ri[i + m_blockSize/2]; 461 m_ri[i] = m_ri[i + m_blockSize/2];
491 m_ri[i + m_blockSize/2] = value; 462 m_ri[i + m_blockSize/2] = value;
492 } 463 }
493 464
494 #ifdef HAVE_FFTW3 465 #ifdef HAVE_FFTW3
495
496 fftw_execute(m_plan); 466 fftw_execute(m_plan);
497 467
498 for (int i = 0; i <= m_blockSize/2; ++i) { 468 for (int i = 0; i <= m_blockSize/2; ++i) {
499 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]); 469 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
500 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]); 470 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
501 } 471 }
502 472 #else
503 #else
504
505 fft(m_blockSize, false, m_ri, 0, m_ro, m_io); 473 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
506 474
507 for (int i = 0; i <= m_blockSize/2; ++i) { 475 for (int i = 0; i <= m_blockSize/2; ++i) {
508 m_freqbuf[c][i * 2] = float(m_ro[i]); 476 m_freqbuf[c][i * 2] = float(m_ro[i]);
509 m_freqbuf[c][i * 2 + 1] = float(m_io[i]); 477 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
510 } 478 }
511 479 #endif
512 #endif 480 }
513 } 481
514 482 return m_plugin->process(m_freqbuf, timestamp);
515 FeatureSet pfs(m_plugin->process(m_freqbuf, timestamp)); 483 }
516 484
517 if (!fs.empty()) { // add any prepad results back in 485 Plugin::FeatureSet
518 for (FeatureSet::const_iterator i = pfs.begin(); i != pfs.end(); ++i) { 486 PluginInputDomainAdapter::Impl::processShiftingData(const float *const *inputBuffers,
519 for (FeatureList::const_iterator j = i->second.begin(); 487 RealTime timestamp)
520 j != i->second.end(); ++j) { 488 {
521 fs[i->first].push_back(*j); 489 if (m_processCount == 0) {
490 if (!m_shiftBuffers) {
491 m_shiftBuffers = new float *[m_channels];
492 for (int c = 0; c < m_channels; ++c) {
493 m_shiftBuffers[c] = new float[m_blockSize + m_blockSize/2];
522 } 494 }
523 } 495 }
524 pfs = fs; 496 for (int c = 0; c < m_channels; ++c) {
525 } 497 for (int i = 0; i < m_blockSize + m_blockSize/2; ++i) {
526 498 m_shiftBuffers[c][i] = 0.f;
527 return pfs; 499 }
528 } 500 }
529 501 }
530 Plugin::FeatureSet 502
531 PluginInputDomainAdapter::Impl::prepadProcess(const float *const *inputBuffers, 503 for (int c = 0; c < m_channels; ++c) {
532 RealTime timestamp) 504 for (int i = m_stepSize; i < m_blockSize + m_blockSize/2; ++i) {
533 { 505 m_shiftBuffers[c][i - m_stepSize] = m_shiftBuffers[c][i];
534 FeatureSet fs; 506 }
535 //!!! 507 for (int i = 0; i < m_blockSize; ++i) {
536 return fs; 508 m_shiftBuffers[c][i + m_blockSize/2] = inputBuffers[c][i];
509 }
510 }
511
512 for (int c = 0; c < m_channels; ++c) {
513
514 for (int i = 0; i < m_blockSize; ++i) {
515 m_ri[i] = double(m_shiftBuffers[c][i]) * m_window[i];
516 }
517
518 for (int i = 0; i < m_blockSize/2; ++i) {
519 // FFT shift
520 double value = m_ri[i];
521 m_ri[i] = m_ri[i + m_blockSize/2];
522 m_ri[i + m_blockSize/2] = value;
523 }
524
525 #ifdef HAVE_FFTW3
526 fftw_execute(m_plan);
527
528 for (int i = 0; i <= m_blockSize/2; ++i) {
529 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
530 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
531 }
532 #else
533 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
534
535 for (int i = 0; i <= m_blockSize/2; ++i) {
536 m_freqbuf[c][i * 2] = float(m_ro[i]);
537 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
538 }
539 #endif
540 }
541
542 ++m_processCount;
543
544 return m_plugin->process(m_freqbuf, timestamp);
537 } 545 }
538 546
539 #ifndef HAVE_FFTW3 547 #ifndef HAVE_FFTW3
540 548
541 void 549 void