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