cannam@92: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@92: cannam@92: /* cannam@92: Vamp cannam@92: cannam@92: An API for audio analysis and feature extraction plugins. cannam@92: cannam@92: Centre for Digital Music, Queen Mary, University of London. cannam@92: Copyright 2006-2007 Chris Cannam and QMUL. cannam@171: This file by Mark Levy and Chris Cannam, Copyright 2007-2008 QMUL. cannam@92: cannam@92: Permission is hereby granted, free of charge, to any person cannam@92: obtaining a copy of this software and associated documentation cannam@92: files (the "Software"), to deal in the Software without cannam@92: restriction, including without limitation the rights to use, copy, cannam@92: modify, merge, publish, distribute, sublicense, and/or sell copies cannam@92: of the Software, and to permit persons to whom the Software is cannam@92: furnished to do so, subject to the following conditions: cannam@92: cannam@92: The above copyright notice and this permission notice shall be cannam@92: included in all copies or substantial portions of the Software. cannam@92: cannam@92: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, cannam@92: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF cannam@92: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND cannam@92: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR cannam@92: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF cannam@92: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION cannam@92: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cannam@92: cannam@92: Except as contained in this notice, the names of the Centre for cannam@92: Digital Music; Queen Mary, University of London; and Chris Cannam cannam@92: shall not be used in advertising or otherwise to promote the sale, cannam@92: use or other dealings in this Software without prior written cannam@92: authorization. cannam@92: */ cannam@92: cannam@92: #include cannam@92: #include cannam@92: cannam@92: #include "PluginBufferingAdapter.h" cannam@92: cannam@92: using std::vector; cannam@92: using std::map; cannam@92: cannam@92: namespace Vamp { cannam@92: cannam@92: namespace HostExt { cannam@92: cannam@92: class PluginBufferingAdapter::Impl cannam@92: { cannam@92: public: cannam@92: Impl(Plugin *plugin, float inputSampleRate); cannam@92: ~Impl(); cannam@169: cannam@169: void setPluginStepSize(size_t stepSize); cannam@169: void setPluginBlockSize(size_t blockSize); cannam@169: cannam@92: bool initialise(size_t channels, size_t stepSize, size_t blockSize); cannam@92: cannam@170: void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize); cannam@170: cannam@92: OutputList getOutputDescriptors() const; cannam@92: cannam@104: void reset(); cannam@104: cannam@92: FeatureSet process(const float *const *inputBuffers, RealTime timestamp); cannam@92: cannam@92: FeatureSet getRemainingFeatures(); cannam@92: cannam@92: protected: cannam@102: class RingBuffer cannam@102: { cannam@102: public: cannam@102: RingBuffer(int n) : cannam@102: m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { } cannam@102: virtual ~RingBuffer() { delete[] m_buffer; } cannam@102: cannam@102: int getSize() const { return m_size-1; } cannam@102: void reset() { m_writer = 0; m_reader = 0; } cannam@102: cannam@102: int getReadSpace() const { cannam@102: int writer = m_writer, reader = m_reader, space; cannam@102: if (writer > reader) space = writer - reader; cannam@102: else if (writer < reader) space = (writer + m_size) - reader; cannam@102: else space = 0; cannam@102: return space; cannam@102: } cannam@102: cannam@102: int getWriteSpace() const { cannam@102: int writer = m_writer; cannam@102: int reader = m_reader; cannam@102: int space = (reader + m_size - writer - 1); cannam@102: if (space >= m_size) space -= m_size; cannam@102: return space; cannam@102: } cannam@102: cannam@102: int peek(float *destination, int n) const { cannam@102: cannam@102: int available = getReadSpace(); cannam@102: cannam@102: if (n > available) { cannam@102: for (int i = available; i < n; ++i) { cannam@102: destination[i] = 0.f; cannam@102: } cannam@102: n = available; cannam@102: } cannam@102: if (n == 0) return n; cannam@102: cannam@102: int reader = m_reader; cannam@102: int here = m_size - reader; cannam@102: const float *const bufbase = m_buffer + reader; cannam@102: cannam@102: if (here >= n) { cannam@102: for (int i = 0; i < n; ++i) { cannam@102: destination[i] = bufbase[i]; cannam@102: } cannam@102: } else { cannam@102: for (int i = 0; i < here; ++i) { cannam@102: destination[i] = bufbase[i]; cannam@102: } cannam@102: float *const destbase = destination + here; cannam@102: const int nh = n - here; cannam@102: for (int i = 0; i < nh; ++i) { cannam@102: destbase[i] = m_buffer[i]; cannam@102: } cannam@102: } cannam@102: cannam@102: return n; cannam@102: } cannam@102: cannam@102: int skip(int n) { cannam@102: cannam@102: int available = getReadSpace(); cannam@102: if (n > available) { cannam@102: n = available; cannam@102: } cannam@102: if (n == 0) return n; cannam@102: cannam@102: int reader = m_reader; cannam@102: reader += n; cannam@102: while (reader >= m_size) reader -= m_size; cannam@102: m_reader = reader; cannam@102: return n; cannam@102: } cannam@102: cannam@102: int write(const float *source, int n) { cannam@102: cannam@102: int available = getWriteSpace(); cannam@102: if (n > available) { cannam@102: n = available; cannam@102: } cannam@102: if (n == 0) return n; cannam@102: cannam@102: int writer = m_writer; cannam@102: int here = m_size - writer; cannam@102: float *const bufbase = m_buffer + writer; cannam@102: cannam@102: if (here >= n) { cannam@102: for (int i = 0; i < n; ++i) { cannam@102: bufbase[i] = source[i]; cannam@102: } cannam@102: } else { cannam@102: for (int i = 0; i < here; ++i) { cannam@102: bufbase[i] = source[i]; cannam@102: } cannam@102: const int nh = n - here; cannam@102: const float *const srcbase = source + here; cannam@102: float *const buf = m_buffer; cannam@102: for (int i = 0; i < nh; ++i) { cannam@102: buf[i] = srcbase[i]; cannam@102: } cannam@102: } cannam@102: cannam@102: writer += n; cannam@102: while (writer >= m_size) writer -= m_size; cannam@102: m_writer = writer; cannam@102: cannam@102: return n; cannam@102: } cannam@102: cannam@102: int zero(int n) { cannam@102: cannam@102: int available = getWriteSpace(); cannam@102: if (n > available) { cannam@102: n = available; cannam@102: } cannam@102: if (n == 0) return n; cannam@102: cannam@102: int writer = m_writer; cannam@102: int here = m_size - writer; cannam@102: float *const bufbase = m_buffer + writer; cannam@102: cannam@102: if (here >= n) { cannam@102: for (int i = 0; i < n; ++i) { cannam@102: bufbase[i] = 0.f; cannam@102: } cannam@102: } else { cannam@102: for (int i = 0; i < here; ++i) { cannam@102: bufbase[i] = 0.f; cannam@102: } cannam@102: const int nh = n - here; cannam@102: for (int i = 0; i < nh; ++i) { cannam@102: m_buffer[i] = 0.f; cannam@102: } cannam@102: } cannam@102: cannam@102: writer += n; cannam@102: while (writer >= m_size) writer -= m_size; cannam@102: m_writer = writer; cannam@102: cannam@102: return n; cannam@102: } cannam@102: cannam@102: protected: cannam@102: float *m_buffer; cannam@102: int m_writer; cannam@102: int m_reader; cannam@102: int m_size; cannam@102: cannam@102: private: cannam@102: RingBuffer(const RingBuffer &); // not provided cannam@102: RingBuffer &operator=(const RingBuffer &); // not provided cannam@102: }; cannam@102: cannam@92: Plugin *m_plugin; cannam@169: size_t m_inputStepSize; // value passed to wrapper initialise() cannam@169: size_t m_inputBlockSize; // value passed to wrapper initialise() cannam@169: size_t m_setStepSize; // value passed to setPluginStepSize() cannam@169: size_t m_setBlockSize; // value passed to setPluginBlockSize() cannam@169: size_t m_stepSize; // value actually used to initialise plugin cannam@169: size_t m_blockSize; // value actually used to initialise plugin cannam@92: size_t m_channels; cannam@102: vector m_queue; cannam@102: float **m_buffers; cannam@92: float m_inputSampleRate; cannam@134: long m_frame; cannam@104: bool m_unrun; cannam@133: mutable OutputList m_outputs; cannam@133: mutable std::map m_rewriteOutputTimes; cannam@92: cannam@134: void processBlock(FeatureSet& allFeatureSets); cannam@92: }; cannam@92: cannam@92: PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) : cannam@92: PluginWrapper(plugin) cannam@92: { cannam@92: m_impl = new Impl(plugin, m_inputSampleRate); cannam@92: } cannam@92: cannam@92: PluginBufferingAdapter::~PluginBufferingAdapter() cannam@92: { cannam@92: delete m_impl; cannam@92: } cannam@169: cannam@169: size_t cannam@169: PluginBufferingAdapter::getPreferredStepSize() const cannam@169: { cannam@169: return getPreferredBlockSize(); cannam@169: } cannam@169: cannam@169: size_t cannam@169: PluginBufferingAdapter::getPreferredBlockSize() const cannam@169: { cannam@169: return PluginWrapper::getPreferredBlockSize(); cannam@169: } cannam@169: cannam@169: size_t cannam@169: PluginBufferingAdapter::getPluginPreferredStepSize() const cannam@169: { cannam@169: return PluginWrapper::getPreferredStepSize(); cannam@169: } cannam@169: cannam@169: size_t cannam@169: PluginBufferingAdapter::getPluginPreferredBlockSize() const cannam@169: { cannam@169: return PluginWrapper::getPreferredBlockSize(); cannam@169: } cannam@169: cannam@169: void cannam@169: PluginBufferingAdapter::setPluginStepSize(size_t stepSize) cannam@169: { cannam@169: m_impl->setPluginStepSize(stepSize); cannam@169: } cannam@169: cannam@169: void cannam@169: PluginBufferingAdapter::setPluginBlockSize(size_t blockSize) cannam@169: { cannam@169: m_impl->setPluginBlockSize(blockSize); cannam@169: } cannam@170: cannam@170: void cannam@170: PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize, cannam@170: size_t &blockSize) cannam@170: { cannam@170: m_impl->getActualStepAndBlockSizes(stepSize, blockSize); cannam@170: } cannam@92: cannam@92: bool cannam@92: PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) cannam@92: { cannam@92: return m_impl->initialise(channels, stepSize, blockSize); cannam@92: } cannam@92: cannam@92: PluginBufferingAdapter::OutputList cannam@92: PluginBufferingAdapter::getOutputDescriptors() const cannam@92: { cannam@92: return m_impl->getOutputDescriptors(); cannam@92: } cannam@104: cannam@104: void cannam@104: PluginBufferingAdapter::reset() cannam@104: { cannam@104: m_impl->reset(); cannam@104: } cannam@92: cannam@92: PluginBufferingAdapter::FeatureSet cannam@92: PluginBufferingAdapter::process(const float *const *inputBuffers, cannam@92: RealTime timestamp) cannam@92: { cannam@92: return m_impl->process(inputBuffers, timestamp); cannam@92: } cannam@92: cannam@92: PluginBufferingAdapter::FeatureSet cannam@92: PluginBufferingAdapter::getRemainingFeatures() cannam@92: { cannam@92: return m_impl->getRemainingFeatures(); cannam@92: } cannam@92: cannam@92: PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : cannam@92: m_plugin(plugin), cannam@92: m_inputStepSize(0), cannam@92: m_inputBlockSize(0), cannam@169: m_setStepSize(0), cannam@169: m_setBlockSize(0), cannam@92: m_stepSize(0), cannam@92: m_blockSize(0), cannam@92: m_channels(0), cannam@102: m_queue(0), cannam@92: m_buffers(0), cannam@92: m_inputSampleRate(inputSampleRate), cannam@134: m_frame(0), cannam@104: m_unrun(true) cannam@92: { cannam@133: (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes cannam@92: } cannam@92: cannam@92: PluginBufferingAdapter::Impl::~Impl() cannam@92: { cannam@92: // the adapter will delete the plugin cannam@102: cannam@102: for (size_t i = 0; i < m_channels; ++i) { cannam@102: delete m_queue[i]; cannam@102: delete[] m_buffers[i]; cannam@102: } cannam@102: delete[] m_buffers; cannam@92: } cannam@169: cannam@169: void cannam@169: PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize) cannam@92: { cannam@169: if (m_inputStepSize != 0) { cannam@169: std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl; cannam@169: return; cannam@169: } cannam@169: m_setStepSize = stepSize; cannam@92: } cannam@92: cannam@169: void cannam@169: PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize) cannam@169: { cannam@169: if (m_inputBlockSize != 0) { cannam@169: std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl; cannam@169: return; cannam@169: } cannam@169: m_setBlockSize = blockSize; cannam@169: } cannam@169: cannam@170: void cannam@170: PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize, cannam@170: size_t &blockSize) cannam@170: { cannam@170: stepSize = m_stepSize; cannam@170: blockSize = m_blockSize; cannam@170: } cannam@170: cannam@92: bool cannam@92: PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) cannam@92: { cannam@92: if (stepSize != blockSize) { cannam@92: std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl; cannam@92: return false; cannam@92: } cannam@92: cannam@92: m_channels = channels; cannam@92: m_inputStepSize = stepSize; cannam@92: m_inputBlockSize = blockSize; cannam@169: cannam@169: // if the user has requested particular step or block sizes, use cannam@169: // those; otherwise use the step and block sizes which the plugin cannam@169: // prefers cannam@169: cannam@169: m_stepSize = 0; cannam@169: m_blockSize = 0; cannam@169: cannam@169: if (m_setStepSize > 0) { cannam@169: m_stepSize = m_setStepSize; cannam@169: } cannam@169: if (m_setBlockSize > 0) { cannam@169: m_blockSize = m_setBlockSize; cannam@169: } cannam@169: cannam@169: if (m_stepSize == 0 && m_blockSize == 0) { cannam@169: m_stepSize = m_plugin->getPreferredStepSize(); cannam@169: m_blockSize = m_plugin->getPreferredBlockSize(); cannam@169: } cannam@92: cannam@169: bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain); cannam@92: cannam@92: // or sensible defaults if it has no preference cannam@92: if (m_blockSize == 0) { cannam@169: if (m_stepSize == 0) { cannam@169: m_blockSize = 1024; cannam@169: } else if (freq) { cannam@169: m_blockSize = m_stepSize * 2; cannam@169: } else { cannam@169: m_blockSize = m_stepSize; cannam@169: } cannam@169: } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above) cannam@169: if (freq) { cannam@92: m_stepSize = m_blockSize/2; cannam@92: } else { cannam@92: m_stepSize = m_blockSize; cannam@92: } cannam@92: } cannam@92: cannam@92: // current implementation breaks if step is greater than block cannam@92: if (m_stepSize > m_blockSize) { cannam@169: size_t newBlockSize; cannam@169: if (freq) { cannam@169: newBlockSize = m_stepSize * 2; cannam@169: } else { cannam@169: newBlockSize = m_stepSize; cannam@169: } cannam@169: std::cerr << "PluginBufferingAdapter::initialise: WARNING: step size " << m_stepSize << " is greater than block size " << m_blockSize << ": cannot handle this in adapter; adjusting block size to " << newBlockSize << std::endl; cannam@169: m_blockSize = newBlockSize; cannam@92: } cannam@169: cannam@169: std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize cannam@169: << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl; cannam@102: cannam@102: m_buffers = new float *[m_channels]; cannam@102: cannam@102: for (size_t i = 0; i < m_channels; ++i) { cannam@102: m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize)); cannam@102: m_buffers[i] = new float[m_blockSize]; cannam@102: } cannam@92: cannam@92: return m_plugin->initialise(m_channels, m_stepSize, m_blockSize); cannam@92: } cannam@92: cannam@92: PluginBufferingAdapter::OutputList cannam@92: PluginBufferingAdapter::Impl::getOutputDescriptors() const cannam@92: { cannam@133: if (m_outputs.empty()) { cannam@133: m_outputs = m_plugin->getOutputDescriptors(); cannam@133: } cannam@133: cannam@134: PluginBufferingAdapter::OutputList outs = m_outputs; cannam@133: cannam@92: for (size_t i = 0; i < outs.size(); ++i) { cannam@133: cannam@133: switch (outs[i].sampleType) { cannam@133: cannam@133: case OutputDescriptor::OneSamplePerStep: cannam@133: outs[i].sampleType = OutputDescriptor::FixedSampleRate; cannam@134: outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize; cannam@133: m_rewriteOutputTimes[i] = true; cannam@133: break; cannam@133: cannam@133: case OutputDescriptor::FixedSampleRate: cannam@133: if (outs[i].sampleRate == 0.f) { cannam@134: outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize; cannam@133: } cannam@133: // We actually only need to rewrite output times for cannam@133: // features that don't have timestamps already, but we cannam@133: // can't tell from here whether our features will have cannam@133: // timestamps or not cannam@133: m_rewriteOutputTimes[i] = true; cannam@133: break; cannam@133: cannam@133: case OutputDescriptor::VariableSampleRate: cannam@133: m_rewriteOutputTimes[i] = false; cannam@133: break; cannam@92: } cannam@92: } cannam@133: cannam@92: return outs; cannam@92: } cannam@92: cannam@104: void cannam@104: PluginBufferingAdapter::Impl::reset() cannam@104: { cannam@134: m_frame = 0; cannam@104: m_unrun = true; cannam@104: cannam@104: for (size_t i = 0; i < m_queue.size(); ++i) { cannam@104: m_queue[i]->reset(); cannam@104: } cannam@196: cannam@196: m_plugin->reset(); cannam@104: } cannam@104: cannam@92: PluginBufferingAdapter::FeatureSet cannam@92: PluginBufferingAdapter::Impl::process(const float *const *inputBuffers, cannam@92: RealTime timestamp) cannam@92: { cannam@169: if (m_inputStepSize == 0) { cannam@169: std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl; cannam@169: return FeatureSet(); cannam@169: } cannam@169: cannam@92: FeatureSet allFeatureSets; cannam@104: cannam@104: if (m_unrun) { cannam@134: m_frame = RealTime::realTime2Frame(timestamp, cannam@134: int(m_inputSampleRate + 0.5)); cannam@104: m_unrun = false; cannam@104: } cannam@92: cannam@92: // queue the new input cannam@92: cannam@102: for (size_t i = 0; i < m_channels; ++i) { cannam@102: int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize); cannam@102: if (written < int(m_inputBlockSize) && i == 0) { cannam@102: std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: " cannam@102: << "Buffer overflow: wrote " << written cannam@102: << " of " << m_inputBlockSize cannam@102: << " input samples (for plugin step size " cannam@102: << m_stepSize << ", block size " << m_blockSize << ")" cannam@102: << std::endl; cannam@102: } cannam@102: } cannam@92: cannam@92: // process as much as we can cannam@102: cannam@102: while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { cannam@134: processBlock(allFeatureSets); cannam@92: } cannam@92: cannam@92: return allFeatureSets; cannam@92: } cannam@92: cannam@92: PluginBufferingAdapter::FeatureSet cannam@92: PluginBufferingAdapter::Impl::getRemainingFeatures() cannam@92: { cannam@92: FeatureSet allFeatureSets; cannam@92: cannam@92: // process remaining samples in queue cannam@102: while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { cannam@134: processBlock(allFeatureSets); cannam@92: } cannam@92: cannam@92: // pad any last samples remaining and process cannam@102: if (m_queue[0]->getReadSpace() > 0) { cannam@102: for (size_t i = 0; i < m_channels; ++i) { cannam@102: m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace()); cannam@102: } cannam@134: processBlock(allFeatureSets); cannam@92: } cannam@92: cannam@92: // get remaining features cannam@102: cannam@92: FeatureSet featureSet = m_plugin->getRemainingFeatures(); cannam@102: cannam@92: for (map::iterator iter = featureSet.begin(); cannam@102: iter != featureSet.end(); ++iter) { cannam@92: FeatureList featureList = iter->second; cannam@102: for (size_t i = 0; i < featureList.size(); ++i) { cannam@102: allFeatureSets[iter->first].push_back(featureList[i]); cannam@102: } cannam@92: } cannam@92: cannam@92: return allFeatureSets; cannam@92: } cannam@92: cannam@92: void cannam@134: PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets) cannam@92: { cannam@102: for (size_t i = 0; i < m_channels; ++i) { cannam@102: m_queue[i]->peek(m_buffers[i], m_blockSize); cannam@102: } cannam@102: cannam@134: long frame = m_frame; cannam@134: RealTime timestamp = RealTime::frame2RealTime cannam@134: (frame, int(m_inputSampleRate + 0.5)); cannam@134: cannam@134: FeatureSet featureSet = m_plugin->process(m_buffers, timestamp); cannam@92: cannam@133: for (FeatureSet::iterator iter = featureSet.begin(); cannam@102: iter != featureSet.end(); ++iter) { cannam@133: cannam@133: int outputNo = iter->first; cannam@133: cannam@133: if (m_rewriteOutputTimes[outputNo]) { cannam@133: cannam@133: FeatureList featureList = iter->second; cannam@92: cannam@133: for (size_t i = 0; i < featureList.size(); ++i) { cannam@133: cannam@133: switch (m_outputs[outputNo].sampleType) { cannam@133: cannam@133: case OutputDescriptor::OneSamplePerStep: cannam@133: // use our internal timestamp, always cannam@134: featureList[i].timestamp = timestamp; cannam@133: featureList[i].hasTimestamp = true; cannam@133: break; cannam@133: cannam@133: case OutputDescriptor::FixedSampleRate: cannam@133: // use our internal timestamp if feature lacks one cannam@133: if (!featureList[i].hasTimestamp) { cannam@134: featureList[i].timestamp = timestamp; cannam@133: featureList[i].hasTimestamp = true; cannam@133: } cannam@133: break; cannam@133: cannam@133: case OutputDescriptor::VariableSampleRate: cannam@133: break; // plugin must set timestamp cannam@133: cannam@133: default: cannam@133: break; cannam@133: } cannam@92: cannam@133: allFeatureSets[outputNo].push_back(featureList[i]); cannam@92: } cannam@133: } else { cannam@133: for (size_t i = 0; i < iter->second.size(); ++i) { cannam@133: allFeatureSets[outputNo].push_back(iter->second[i]); cannam@133: } cannam@92: } cannam@92: } cannam@92: cannam@92: // step forward cannam@102: cannam@102: for (size_t i = 0; i < m_channels; ++i) { cannam@102: m_queue[i]->skip(m_stepSize); cannam@102: } cannam@92: cannam@134: // increment internal frame counter each time we step forward cannam@134: m_frame += m_stepSize; cannam@92: } cannam@92: cannam@92: } cannam@92: cannam@92: } cannam@92: cannam@92: