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