Mercurial > hg > vamp-plugin-sdk
comparison vamp-sdk/hostext/PluginBufferingAdapter.cpp @ 134:c1dce0b033cb
* Permit '-' as well as the other characters in identifiers (existing plugins
were already using this character, it's really the documentation that was
at fault)
* Fix failure to return output descriptors properly from PluginBufferingAdapter
* Fix incorrect sample rate in output descriptors for certain sample types
from PluginBufferingAdapter
* Fix incorrect timestamping on features returned from PluginBufferingAdapter
(rounding error)
author | cannam |
---|---|
date | Thu, 24 Apr 2008 10:27:02 +0000 |
parents | 92ca8e401044 |
children | af8e59f43d1d |
comparison
equal
deleted
inserted
replaced
133:92ca8e401044 | 134:c1dce0b033cb |
---|---|
225 size_t m_blockSize; | 225 size_t m_blockSize; |
226 size_t m_channels; | 226 size_t m_channels; |
227 vector<RingBuffer *> m_queue; | 227 vector<RingBuffer *> m_queue; |
228 float **m_buffers; | 228 float **m_buffers; |
229 float m_inputSampleRate; | 229 float m_inputSampleRate; |
230 RealTime m_timestamp; | 230 long m_frame; |
231 bool m_unrun; | 231 bool m_unrun; |
232 mutable OutputList m_outputs; | 232 mutable OutputList m_outputs; |
233 mutable std::map<int, bool> m_rewriteOutputTimes; | 233 mutable std::map<int, bool> m_rewriteOutputTimes; |
234 | 234 |
235 void processBlock(FeatureSet& allFeatureSets, RealTime timestamp); | 235 void processBlock(FeatureSet& allFeatureSets); |
236 }; | 236 }; |
237 | 237 |
238 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) : | 238 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) : |
239 PluginWrapper(plugin) | 239 PluginWrapper(plugin) |
240 { | 240 { |
285 m_blockSize(0), | 285 m_blockSize(0), |
286 m_channels(0), | 286 m_channels(0), |
287 m_queue(0), | 287 m_queue(0), |
288 m_buffers(0), | 288 m_buffers(0), |
289 m_inputSampleRate(inputSampleRate), | 289 m_inputSampleRate(inputSampleRate), |
290 m_timestamp(RealTime::zeroTime), | 290 m_frame(0), |
291 m_unrun(true) | 291 m_unrun(true) |
292 { | 292 { |
293 (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes | 293 (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes |
294 } | 294 } |
295 | 295 |
368 { | 368 { |
369 if (m_outputs.empty()) { | 369 if (m_outputs.empty()) { |
370 m_outputs = m_plugin->getOutputDescriptors(); | 370 m_outputs = m_plugin->getOutputDescriptors(); |
371 } | 371 } |
372 | 372 |
373 PluginBufferingAdapter::OutputList outs; | 373 PluginBufferingAdapter::OutputList outs = m_outputs; |
374 | 374 |
375 for (size_t i = 0; i < outs.size(); ++i) { | 375 for (size_t i = 0; i < outs.size(); ++i) { |
376 | 376 |
377 switch (outs[i].sampleType) { | 377 switch (outs[i].sampleType) { |
378 | 378 |
379 case OutputDescriptor::OneSamplePerStep: | 379 case OutputDescriptor::OneSamplePerStep: |
380 outs[i].sampleType = OutputDescriptor::FixedSampleRate; | 380 outs[i].sampleType = OutputDescriptor::FixedSampleRate; |
381 outs[i].sampleRate = 1.f / m_stepSize; | 381 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize; |
382 m_rewriteOutputTimes[i] = true; | 382 m_rewriteOutputTimes[i] = true; |
383 break; | 383 break; |
384 | 384 |
385 case OutputDescriptor::FixedSampleRate: | 385 case OutputDescriptor::FixedSampleRate: |
386 if (outs[i].sampleRate == 0.f) { | 386 if (outs[i].sampleRate == 0.f) { |
387 outs[i].sampleRate = 1.f / m_stepSize; | 387 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize; |
388 } | 388 } |
389 // We actually only need to rewrite output times for | 389 // We actually only need to rewrite output times for |
390 // features that don't have timestamps already, but we | 390 // features that don't have timestamps already, but we |
391 // can't tell from here whether our features will have | 391 // can't tell from here whether our features will have |
392 // timestamps or not | 392 // timestamps or not |
403 } | 403 } |
404 | 404 |
405 void | 405 void |
406 PluginBufferingAdapter::Impl::reset() | 406 PluginBufferingAdapter::Impl::reset() |
407 { | 407 { |
408 m_timestamp = RealTime::zeroTime; | 408 m_frame = 0; |
409 m_unrun = true; | 409 m_unrun = true; |
410 | 410 |
411 for (size_t i = 0; i < m_queue.size(); ++i) { | 411 for (size_t i = 0; i < m_queue.size(); ++i) { |
412 m_queue[i]->reset(); | 412 m_queue[i]->reset(); |
413 } | 413 } |
418 RealTime timestamp) | 418 RealTime timestamp) |
419 { | 419 { |
420 FeatureSet allFeatureSets; | 420 FeatureSet allFeatureSets; |
421 | 421 |
422 if (m_unrun) { | 422 if (m_unrun) { |
423 m_timestamp = timestamp; | 423 m_frame = RealTime::realTime2Frame(timestamp, |
424 int(m_inputSampleRate + 0.5)); | |
424 m_unrun = false; | 425 m_unrun = false; |
425 } | 426 } |
426 | 427 |
427 // queue the new input | 428 // queue the new input |
428 | 429 |
439 } | 440 } |
440 | 441 |
441 // process as much as we can | 442 // process as much as we can |
442 | 443 |
443 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { | 444 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { |
444 processBlock(allFeatureSets, timestamp); | 445 processBlock(allFeatureSets); |
445 } | 446 } |
446 | 447 |
447 return allFeatureSets; | 448 return allFeatureSets; |
448 } | 449 } |
449 | 450 |
452 { | 453 { |
453 FeatureSet allFeatureSets; | 454 FeatureSet allFeatureSets; |
454 | 455 |
455 // process remaining samples in queue | 456 // process remaining samples in queue |
456 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { | 457 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { |
457 processBlock(allFeatureSets, m_timestamp); | 458 processBlock(allFeatureSets); |
458 } | 459 } |
459 | 460 |
460 // pad any last samples remaining and process | 461 // pad any last samples remaining and process |
461 if (m_queue[0]->getReadSpace() > 0) { | 462 if (m_queue[0]->getReadSpace() > 0) { |
462 for (size_t i = 0; i < m_channels; ++i) { | 463 for (size_t i = 0; i < m_channels; ++i) { |
463 m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace()); | 464 m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace()); |
464 } | 465 } |
465 processBlock(allFeatureSets, m_timestamp); | 466 processBlock(allFeatureSets); |
466 } | 467 } |
467 | 468 |
468 // get remaining features | 469 // get remaining features |
469 | 470 |
470 FeatureSet featureSet = m_plugin->getRemainingFeatures(); | 471 FeatureSet featureSet = m_plugin->getRemainingFeatures(); |
479 | 480 |
480 return allFeatureSets; | 481 return allFeatureSets; |
481 } | 482 } |
482 | 483 |
483 void | 484 void |
484 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets, | 485 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets) |
485 RealTime timestamp) | |
486 { | 486 { |
487 for (size_t i = 0; i < m_channels; ++i) { | 487 for (size_t i = 0; i < m_channels; ++i) { |
488 m_queue[i]->peek(m_buffers[i], m_blockSize); | 488 m_queue[i]->peek(m_buffers[i], m_blockSize); |
489 } | 489 } |
490 | 490 |
491 FeatureSet featureSet = m_plugin->process(m_buffers, m_timestamp); | 491 long frame = m_frame; |
492 RealTime timestamp = RealTime::frame2RealTime | |
493 (frame, int(m_inputSampleRate + 0.5)); | |
494 | |
495 FeatureSet featureSet = m_plugin->process(m_buffers, timestamp); | |
492 | 496 |
493 for (FeatureSet::iterator iter = featureSet.begin(); | 497 for (FeatureSet::iterator iter = featureSet.begin(); |
494 iter != featureSet.end(); ++iter) { | 498 iter != featureSet.end(); ++iter) { |
495 | 499 |
496 int outputNo = iter->first; | 500 int outputNo = iter->first; |
497 | 501 |
498 if (m_rewriteOutputTimes[outputNo]) { | 502 if (m_rewriteOutputTimes[outputNo]) { |
499 | 503 |
500 // Make sure the timestamp is always set | |
501 | |
502 FeatureList featureList = iter->second; | 504 FeatureList featureList = iter->second; |
503 | 505 |
504 for (size_t i = 0; i < featureList.size(); ++i) { | 506 for (size_t i = 0; i < featureList.size(); ++i) { |
505 | 507 |
506 switch (m_outputs[outputNo].sampleType) { | 508 switch (m_outputs[outputNo].sampleType) { |
507 | 509 |
508 case OutputDescriptor::OneSamplePerStep: | 510 case OutputDescriptor::OneSamplePerStep: |
509 // use our internal timestamp, always | 511 // use our internal timestamp, always |
510 featureList[i].timestamp = m_timestamp; | 512 featureList[i].timestamp = timestamp; |
511 featureList[i].hasTimestamp = true; | 513 featureList[i].hasTimestamp = true; |
512 break; | 514 break; |
513 | 515 |
514 case OutputDescriptor::FixedSampleRate: | 516 case OutputDescriptor::FixedSampleRate: |
515 // use our internal timestamp if feature lacks one | 517 // use our internal timestamp if feature lacks one |
516 if (!featureList[i].hasTimestamp) { | 518 if (!featureList[i].hasTimestamp) { |
517 featureList[i].timestamp = m_timestamp; | 519 featureList[i].timestamp = timestamp; |
518 featureList[i].hasTimestamp = true; | 520 featureList[i].hasTimestamp = true; |
519 } | 521 } |
520 break; | 522 break; |
521 | 523 |
522 case OutputDescriptor::VariableSampleRate: | 524 case OutputDescriptor::VariableSampleRate: |
539 | 541 |
540 for (size_t i = 0; i < m_channels; ++i) { | 542 for (size_t i = 0; i < m_channels; ++i) { |
541 m_queue[i]->skip(m_stepSize); | 543 m_queue[i]->skip(m_stepSize); |
542 } | 544 } |
543 | 545 |
544 // fake up the timestamp each time we step forward | 546 // increment internal frame counter each time we step forward |
545 | 547 m_frame += m_stepSize; |
546 long frame = RealTime::realTime2Frame(m_timestamp, | |
547 int(m_inputSampleRate + 0.5)); | |
548 m_timestamp = RealTime::frame2RealTime(frame + m_stepSize, | |
549 int(m_inputSampleRate + 0.5)); | |
550 } | 548 } |
551 | 549 |
552 } | 550 } |
553 | 551 |
554 } | 552 } |