rearrange and update VAMP tree to match VAMP 2.0

git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@4898 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-03-26 14:10:25 +00:00
parent cb5cb2e7b0
commit c2429bdcd6
31 changed files with 4132 additions and 239 deletions

View file

@ -5,18 +5,17 @@ import os.path
import glob
vampsdk_files = Split ("""
vamp-sdk/PluginAdapter.cpp
vamp-sdk/RealTime.cpp
src/vamp-sdk/PluginAdapter.cpp
src/vamp-sdk/RealTime.cpp
""")
vamphostsdk_files = Split ("""
vamp-sdk/PluginHostAdapter.cpp
vamp-sdk/hostext/PluginBufferingAdapter.cpp
vamp-sdk/hostext/PluginChannelAdapter.cpp
vamp-sdk/hostext/PluginInputDomainAdapter.cpp
vamp-sdk/hostext/PluginLoader.cpp
vamp-sdk/hostext/PluginWrapper.cpp
vamp-sdk/RealTime.cpp
src/vamp-hostsdk/PluginHostAdapter.cpp
src/vamp-hostsdk/PluginBufferingAdapter.cpp
src/vamp-hostsdk/PluginChannelAdapter.cpp
src/vamp-hostsdk/PluginInputDomainAdapter.cpp
src/vamp-hostsdk/PluginLoader.cpp
src/vamp-hostsdk/PluginWrapper.cpp
""")
Import('env install_prefix libraries')
@ -43,4 +42,4 @@ env.Alias('tarball', env.Distribute (env['DISTTREE'],
vamphostsdk_files +
glob.glob('vamp/*.h') +
glob.glob('vamp-sdk/*.h') +
glob.glob('vamp-sdk/hostext/*.h')))
glob.glob('vamp-hostsdk/*.h')))

View file

@ -7,7 +7,7 @@
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL.
This file by Mark Levy and Chris Cannam.
This file by Mark Levy and Chris Cannam, Copyright 2007-2008 QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
@ -38,11 +38,13 @@
#include <vector>
#include <map>
#include "PluginBufferingAdapter.h"
#include <vamp-hostsdk/PluginBufferingAdapter.h>
using std::vector;
using std::map;
_VAMP_SDK_HOSTSPACE_BEGIN(PluginBufferingAdapter.cpp)
namespace Vamp {
namespace HostExt {
@ -52,11 +54,19 @@ class PluginBufferingAdapter::Impl
public:
Impl(Plugin *plugin, float inputSampleRate);
~Impl();
void setPluginStepSize(size_t stepSize);
void setPluginBlockSize(size_t blockSize);
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
OutputList getOutputDescriptors() const;
void setParameter(std::string, float);
void selectProgram(std::string);
void reset();
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
@ -219,19 +229,22 @@ protected:
};
Plugin *m_plugin;
size_t m_inputStepSize;
size_t m_inputBlockSize;
size_t m_stepSize;
size_t m_blockSize;
size_t m_inputStepSize; // value passed to wrapper initialise()
size_t m_inputBlockSize; // value passed to wrapper initialise()
size_t m_setStepSize; // value passed to setPluginStepSize()
size_t m_setBlockSize; // value passed to setPluginBlockSize()
size_t m_stepSize; // value actually used to initialise plugin
size_t m_blockSize; // value actually used to initialise plugin
size_t m_channels;
vector<RingBuffer *> m_queue;
float **m_buffers;
float m_inputSampleRate;
RealTime m_timestamp;
long m_frame;
bool m_unrun;
OutputList m_outputs;
mutable OutputList m_outputs;
mutable std::map<int, bool> m_rewriteOutputTimes;
void processBlock(FeatureSet& allFeatureSets, RealTime timestamp);
void processBlock(FeatureSet& allFeatureSets);
};
PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
@ -244,6 +257,49 @@ PluginBufferingAdapter::~PluginBufferingAdapter()
{
delete m_impl;
}
size_t
PluginBufferingAdapter::getPreferredStepSize() const
{
return getPreferredBlockSize();
}
size_t
PluginBufferingAdapter::getPreferredBlockSize() const
{
return PluginWrapper::getPreferredBlockSize();
}
size_t
PluginBufferingAdapter::getPluginPreferredStepSize() const
{
return PluginWrapper::getPreferredStepSize();
}
size_t
PluginBufferingAdapter::getPluginPreferredBlockSize() const
{
return PluginWrapper::getPreferredBlockSize();
}
void
PluginBufferingAdapter::setPluginStepSize(size_t stepSize)
{
m_impl->setPluginStepSize(stepSize);
}
void
PluginBufferingAdapter::setPluginBlockSize(size_t blockSize)
{
m_impl->setPluginBlockSize(blockSize);
}
void
PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize,
size_t &blockSize)
{
m_impl->getActualStepAndBlockSizes(stepSize, blockSize);
}
bool
PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
@ -257,6 +313,18 @@ PluginBufferingAdapter::getOutputDescriptors() const
return m_impl->getOutputDescriptors();
}
void
PluginBufferingAdapter::setParameter(std::string name, float value)
{
m_impl->setParameter(name, value);
}
void
PluginBufferingAdapter::selectProgram(std::string name)
{
m_impl->selectProgram(name);
}
void
PluginBufferingAdapter::reset()
{
@ -280,16 +348,18 @@ PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
m_plugin(plugin),
m_inputStepSize(0),
m_inputBlockSize(0),
m_setStepSize(0),
m_setBlockSize(0),
m_stepSize(0),
m_blockSize(0),
m_channels(0),
m_queue(0),
m_buffers(0),
m_inputSampleRate(inputSampleRate),
m_timestamp(RealTime::zeroTime),
m_frame(0),
m_unrun(true)
{
m_outputs = plugin->getOutputDescriptors();
(void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
}
PluginBufferingAdapter::Impl::~Impl()
@ -302,13 +372,35 @@ PluginBufferingAdapter::Impl::~Impl()
}
delete[] m_buffers;
}
size_t
PluginBufferingAdapter::getPreferredStepSize() const
void
PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize)
{
return getPreferredBlockSize();
if (m_inputStepSize != 0) {
std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl;
return;
}
m_setStepSize = stepSize;
}
void
PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize)
{
if (m_inputBlockSize != 0) {
std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl;
return;
}
m_setBlockSize = blockSize;
}
void
PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize,
size_t &blockSize)
{
stepSize = m_stepSize;
blockSize = m_blockSize;
}
bool
PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
@ -320,37 +412,64 @@ PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_
m_channels = channels;
m_inputStepSize = stepSize;
m_inputBlockSize = blockSize;
// if the user has requested particular step or block sizes, use
// those; otherwise use the step and block sizes which the plugin
// prefers
m_stepSize = 0;
m_blockSize = 0;
if (m_setStepSize > 0) {
m_stepSize = m_setStepSize;
}
if (m_setBlockSize > 0) {
m_blockSize = m_setBlockSize;
}
if (m_stepSize == 0 && m_blockSize == 0) {
m_stepSize = m_plugin->getPreferredStepSize();
m_blockSize = m_plugin->getPreferredBlockSize();
}
// use the step and block sizes which the plugin prefers
m_stepSize = m_plugin->getPreferredStepSize();
m_blockSize = m_plugin->getPreferredBlockSize();
bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain);
// or sensible defaults if it has no preference
if (m_blockSize == 0) {
m_blockSize = 1024;
}
if (m_stepSize == 0) {
if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
m_stepSize = m_blockSize/2;
} else {
m_stepSize = m_blockSize;
}
} else if (m_stepSize > m_blockSize) {
if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
if (m_stepSize == 0) {
m_blockSize = 1024;
if (freq) {
m_stepSize = m_blockSize / 2;
} else {
m_stepSize = m_blockSize;
}
} else if (freq) {
m_blockSize = m_stepSize * 2;
} else {
m_blockSize = m_stepSize;
}
} else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above)
if (freq) {
m_stepSize = m_blockSize/2;
} else {
m_stepSize = m_blockSize;
}
}
// std::cerr << "PluginBufferingAdapter::initialise: stepSize " << m_inputStepSize << " -> " << m_stepSize
// << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
// current implementation breaks if step is greater than block
if (m_stepSize > m_blockSize) {
std::cerr << "PluginBufferingAdapter::initialise: plugin's preferred stepSize greater than blockSize, giving up!" << std::endl;
return false;
size_t newBlockSize;
if (freq) {
newBlockSize = m_stepSize * 2;
} else {
newBlockSize = m_stepSize;
}
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;
m_blockSize = newBlockSize;
}
// std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize
// << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
m_buffers = new float *[m_channels];
@ -359,41 +478,108 @@ PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_
m_buffers[i] = new float[m_blockSize];
}
return m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
bool success = m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
// std::cerr << "PluginBufferingAdapter::initialise: success = " << success << std::endl;
if (success) {
// Re-query outputs; properties such as bin count may have
// changed on initialise
m_outputs.clear();
(void)getOutputDescriptors();
}
return success;
}
PluginBufferingAdapter::OutputList
PluginBufferingAdapter::Impl::getOutputDescriptors() const
{
OutputList outs = m_plugin->getOutputDescriptors();
for (size_t i = 0; i < outs.size(); ++i) {
if (outs[i].sampleType == OutputDescriptor::OneSamplePerStep) {
outs[i].sampleRate = 1.f / m_stepSize;
}
outs[i].sampleType = OutputDescriptor::VariableSampleRate;
if (m_outputs.empty()) {
// std::cerr << "PluginBufferingAdapter::getOutputDescriptors: querying anew" << std::endl;
m_outputs = m_plugin->getOutputDescriptors();
}
PluginBufferingAdapter::OutputList outs = m_outputs;
for (size_t i = 0; i < outs.size(); ++i) {
switch (outs[i].sampleType) {
case OutputDescriptor::OneSamplePerStep:
outs[i].sampleType = OutputDescriptor::FixedSampleRate;
outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
m_rewriteOutputTimes[i] = true;
break;
case OutputDescriptor::FixedSampleRate:
if (outs[i].sampleRate == 0.f) {
outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
}
// We actually only need to rewrite output times for
// features that don't have timestamps already, but we
// can't tell from here whether our features will have
// timestamps or not
m_rewriteOutputTimes[i] = true;
break;
case OutputDescriptor::VariableSampleRate:
m_rewriteOutputTimes[i] = false;
break;
}
}
return outs;
}
void
PluginBufferingAdapter::Impl::setParameter(std::string name, float value)
{
m_plugin->setParameter(name, value);
// Re-query outputs; properties such as bin count may have changed
m_outputs.clear();
(void)getOutputDescriptors();
}
void
PluginBufferingAdapter::Impl::selectProgram(std::string name)
{
m_plugin->selectProgram(name);
// Re-query outputs; properties such as bin count may have changed
m_outputs.clear();
(void)getOutputDescriptors();
}
void
PluginBufferingAdapter::Impl::reset()
{
m_timestamp = RealTime::zeroTime;
m_frame = 0;
m_unrun = true;
for (size_t i = 0; i < m_queue.size(); ++i) {
m_queue[i]->reset();
}
m_plugin->reset();
}
PluginBufferingAdapter::FeatureSet
PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
RealTime timestamp)
{
if (m_inputStepSize == 0) {
std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl;
return FeatureSet();
}
FeatureSet allFeatureSets;
if (m_unrun) {
m_timestamp = timestamp;
m_frame = RealTime::realTime2Frame(timestamp,
int(m_inputSampleRate + 0.5));
m_unrun = false;
}
@ -414,7 +600,7 @@ PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
// process as much as we can
while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
processBlock(allFeatureSets, timestamp);
processBlock(allFeatureSets);
}
return allFeatureSets;
@ -427,7 +613,7 @@ PluginBufferingAdapter::Impl::getRemainingFeatures()
// process remaining samples in queue
while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
processBlock(allFeatureSets, m_timestamp);
processBlock(allFeatureSets);
}
// pad any last samples remaining and process
@ -435,7 +621,7 @@ PluginBufferingAdapter::Impl::getRemainingFeatures()
for (size_t i = 0; i < m_channels; ++i) {
m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
}
processBlock(allFeatureSets, m_timestamp);
processBlock(allFeatureSets);
}
// get remaining features
@ -454,44 +640,58 @@ PluginBufferingAdapter::Impl::getRemainingFeatures()
}
void
PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets,
RealTime timestamp)
PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
{
for (size_t i = 0; i < m_channels; ++i) {
m_queue[i]->peek(m_buffers[i], m_blockSize);
}
FeatureSet featureSet = m_plugin->process(m_buffers, m_timestamp);
long frame = m_frame;
RealTime timestamp = RealTime::frame2RealTime
(frame, int(m_inputSampleRate + 0.5));
FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
for (map<int, FeatureList>::iterator iter = featureSet.begin();
for (FeatureSet::iterator iter = featureSet.begin();
iter != featureSet.end(); ++iter) {
FeatureList featureList = iter->second;
int outputNo = iter->first;
if (m_rewriteOutputTimes[outputNo]) {
FeatureList featureList = iter->second;
for (size_t i = 0; i < featureList.size(); ++i) {
for (size_t i = 0; i < featureList.size(); ++i) {
switch (m_outputs[outputNo].sampleType) {
case OutputDescriptor::OneSamplePerStep:
// use our internal timestamp, always
featureList[i].timestamp = timestamp;
featureList[i].hasTimestamp = true;
break;
case OutputDescriptor::FixedSampleRate:
// use our internal timestamp if feature lacks one
if (!featureList[i].hasTimestamp) {
featureList[i].timestamp = timestamp;
featureList[i].hasTimestamp = true;
}
break;
case OutputDescriptor::VariableSampleRate:
break; // plugin must set timestamp
default:
break;
}
// make sure the timestamp is set
switch (m_outputs[outputNo].sampleType) {
case OutputDescriptor::OneSamplePerStep:
// use our internal timestamp - OK????
featureList[i].timestamp = m_timestamp;
break;
case OutputDescriptor::FixedSampleRate:
// use our internal timestamp
featureList[i].timestamp = m_timestamp;
break;
case OutputDescriptor::VariableSampleRate:
break; // plugin must set timestamp
default:
break;
allFeatureSets[outputNo].push_back(featureList[i]);
}
} else {
for (size_t i = 0; i < iter->second.size(); ++i) {
allFeatureSets[outputNo].push_back(iter->second[i]);
}
allFeatureSets[outputNo].push_back(featureList[i]);
}
}
@ -501,16 +701,12 @@ PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets,
m_queue[i]->skip(m_stepSize);
}
// fake up the timestamp each time we step forward
long frame = RealTime::realTime2Frame(m_timestamp,
int(m_inputSampleRate + 0.5));
m_timestamp = RealTime::frame2RealTime(frame + m_stepSize,
int(m_inputSampleRate + 0.5));
// increment internal frame counter each time we step forward
m_frame += m_stepSize;
}
}
}
_VAMP_SDK_HOSTSPACE_END(PluginBufferingAdapter.cpp)

View file

@ -34,7 +34,9 @@
authorization.
*/
#include "PluginChannelAdapter.h"
#include <vamp-hostsdk/PluginChannelAdapter.h>
_VAMP_SDK_HOSTSPACE_BEGIN(PluginChannelAdapter.cpp)
namespace Vamp {
@ -49,6 +51,7 @@ public:
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet processInterleaved(const float *inputBuffers, RealTime timestamp);
protected:
Plugin *m_plugin;
@ -56,6 +59,7 @@ protected:
size_t m_inputChannels;
size_t m_pluginChannels;
float **m_buffer;
float **m_deinterleave;
const float **m_forwardPtrs;
};
@ -83,12 +87,20 @@ PluginChannelAdapter::process(const float *const *inputBuffers,
return m_impl->process(inputBuffers, timestamp);
}
PluginChannelAdapter::FeatureSet
PluginChannelAdapter::processInterleaved(const float *inputBuffers,
RealTime timestamp)
{
return m_impl->processInterleaved(inputBuffers, timestamp);
}
PluginChannelAdapter::Impl::Impl(Plugin *plugin) :
m_plugin(plugin),
m_blockSize(0),
m_inputChannels(0),
m_pluginChannels(0),
m_buffer(0),
m_deinterleave(0),
m_forwardPtrs(0)
{
}
@ -109,6 +121,14 @@ PluginChannelAdapter::Impl::~Impl()
m_buffer = 0;
}
if (m_deinterleave) {
for (size_t i = 0; i < m_inputChannels; ++i) {
delete[] m_deinterleave[i];
}
delete[] m_deinterleave;
m_deinterleave = 0;
}
if (m_forwardPtrs) {
delete[] m_forwardPtrs;
m_forwardPtrs = 0;
@ -143,7 +163,7 @@ PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t
m_pluginChannels = minch;
// std::cerr << "PluginChannelAdapter::initialise: expanding " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
// std::cerr << "PluginChannelAdapter::initialise: expanding " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
} else if (m_inputChannels > maxch) {
@ -155,24 +175,44 @@ PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t
m_buffer = new float *[1];
m_buffer[0] = new float[blockSize];
// std::cerr << "PluginChannelAdapter::initialise: mixing " << m_inputChannels << " to mono for plugin" << std::endl;
// std::cerr << "PluginChannelAdapter::initialise: mixing " << m_inputChannels << " to mono for plugin" << std::endl;
} else {
// std::cerr << "PluginChannelAdapter::initialise: reducing " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
// std::cerr << "PluginChannelAdapter::initialise: reducing " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
}
m_pluginChannels = maxch;
} else {
// std::cerr << "PluginChannelAdapter::initialise: accepting given number of channels (" << m_inputChannels << ")" << std::endl;
// std::cerr << "PluginChannelAdapter::initialise: accepting given number of channels (" << m_inputChannels << ")" << std::endl;
m_pluginChannels = m_inputChannels;
}
return m_plugin->initialise(m_pluginChannels, stepSize, blockSize);
}
PluginChannelAdapter::FeatureSet
PluginChannelAdapter::Impl::processInterleaved(const float *inputBuffers,
RealTime timestamp)
{
if (!m_deinterleave) {
m_deinterleave = new float *[m_inputChannels];
for (size_t i = 0; i < m_inputChannels; ++i) {
m_deinterleave[i] = new float[m_blockSize];
}
}
for (size_t i = 0; i < m_inputChannels; ++i) {
for (size_t j = 0; j < m_blockSize; ++j) {
m_deinterleave[i][j] = inputBuffers[j * m_inputChannels + i];
}
}
return process(m_deinterleave, timestamp);
}
PluginChannelAdapter::FeatureSet
PluginChannelAdapter::Impl::process(const float *const *inputBuffers,
RealTime timestamp)
@ -225,4 +265,6 @@ PluginChannelAdapter::Impl::process(const float *const *inputBuffers,
}
_VAMP_SDK_HOSTSPACE_END(PluginChannelAdapter.cpp)

View file

@ -0,0 +1,456 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include <vamp-hostsdk/PluginHostAdapter.h>
#include <cstdlib>
#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 0 )
#error Incorrect Vamp SDK header included (not the expected 2.0 SDK)
#endif
_VAMP_SDK_HOSTSPACE_BEGIN(PluginHostAdapter.cpp)
namespace Vamp
{
PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor,
float inputSampleRate) :
Plugin(inputSampleRate),
m_descriptor(descriptor)
{
// std::cerr << "PluginHostAdapter::PluginHostAdapter (plugin = " << descriptor->name << ")" << std::endl;
m_handle = m_descriptor->instantiate(m_descriptor, inputSampleRate);
if (!m_handle) {
// std::cerr << "WARNING: PluginHostAdapter: Plugin instantiation failed for plugin " << m_descriptor->name << std::endl;
}
}
PluginHostAdapter::~PluginHostAdapter()
{
// std::cerr << "PluginHostAdapter::~PluginHostAdapter (plugin = " << m_descriptor->name << ")" << std::endl;
if (m_handle) m_descriptor->cleanup(m_handle);
}
std::vector<std::string>
PluginHostAdapter::getPluginPath()
{
std::vector<std::string> path;
std::string envPath;
char *cpath = getenv("VAMP_PATH");
if (cpath) envPath = cpath;
#ifdef _WIN32
#define PATH_SEPARATOR ';'
#define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins"
#else
#define PATH_SEPARATOR ':'
#ifdef __APPLE__
#define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"
#else
#define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"
#endif
#endif
if (envPath == "") {
envPath = DEFAULT_VAMP_PATH;
char *chome = getenv("HOME");
if (chome) {
std::string home(chome);
std::string::size_type f;
while ((f = envPath.find("$HOME")) != std::string::npos &&
f < envPath.length()) {
envPath.replace(f, 5, home);
}
}
#ifdef _WIN32
char *cpfiles = getenv("ProgramFiles");
if (!cpfiles) cpfiles = (char *)"C:\\Program Files";
std::string pfiles(cpfiles);
std::string::size_type f;
while ((f = envPath.find("%ProgramFiles%")) != std::string::npos &&
f < envPath.length()) {
envPath.replace(f, 14, pfiles);
}
#endif
}
std::string::size_type index = 0, newindex = 0;
while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) {
path.push_back(envPath.substr(index, newindex - index));
index = newindex + 1;
}
path.push_back(envPath.substr(index));
return path;
}
bool
PluginHostAdapter::initialise(size_t channels,
size_t stepSize,
size_t blockSize)
{
if (!m_handle) return false;
return m_descriptor->initialise(m_handle, channels, stepSize, blockSize) ?
true : false;
}
void
PluginHostAdapter::reset()
{
if (!m_handle) {
// std::cerr << "PluginHostAdapter::reset: no handle" << std::endl;
return;
}
// std::cerr << "PluginHostAdapter::reset(" << m_handle << ")" << std::endl;
m_descriptor->reset(m_handle);
}
PluginHostAdapter::InputDomain
PluginHostAdapter::getInputDomain() const
{
if (m_descriptor->inputDomain == vampFrequencyDomain) {
return FrequencyDomain;
} else {
return TimeDomain;
}
}
unsigned int
PluginHostAdapter::getVampApiVersion() const
{
return m_descriptor->vampApiVersion;
}
std::string
PluginHostAdapter::getIdentifier() const
{
return m_descriptor->identifier;
}
std::string
PluginHostAdapter::getName() const
{
return m_descriptor->name;
}
std::string
PluginHostAdapter::getDescription() const
{
return m_descriptor->description;
}
std::string
PluginHostAdapter::getMaker() const
{
return m_descriptor->maker;
}
int
PluginHostAdapter::getPluginVersion() const
{
return m_descriptor->pluginVersion;
}
std::string
PluginHostAdapter::getCopyright() const
{
return m_descriptor->copyright;
}
PluginHostAdapter::ParameterList
PluginHostAdapter::getParameterDescriptors() const
{
ParameterList list;
for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
const VampParameterDescriptor *spd = m_descriptor->parameters[i];
ParameterDescriptor pd;
pd.identifier = spd->identifier;
pd.name = spd->name;
pd.description = spd->description;
pd.unit = spd->unit;
pd.minValue = spd->minValue;
pd.maxValue = spd->maxValue;
pd.defaultValue = spd->defaultValue;
pd.isQuantized = spd->isQuantized;
pd.quantizeStep = spd->quantizeStep;
if (pd.isQuantized && spd->valueNames) {
for (unsigned int j = 0; spd->valueNames[j]; ++j) {
pd.valueNames.push_back(spd->valueNames[j]);
}
}
list.push_back(pd);
}
return list;
}
float
PluginHostAdapter::getParameter(std::string param) const
{
if (!m_handle) return 0.0;
for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
if (param == m_descriptor->parameters[i]->identifier) {
return m_descriptor->getParameter(m_handle, i);
}
}
return 0.0;
}
void
PluginHostAdapter::setParameter(std::string param,
float value)
{
if (!m_handle) return;
for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
if (param == m_descriptor->parameters[i]->identifier) {
m_descriptor->setParameter(m_handle, i, value);
return;
}
}
}
PluginHostAdapter::ProgramList
PluginHostAdapter::getPrograms() const
{
ProgramList list;
for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
list.push_back(m_descriptor->programs[i]);
}
return list;
}
std::string
PluginHostAdapter::getCurrentProgram() const
{
if (!m_handle) return "";
int pn = m_descriptor->getCurrentProgram(m_handle);
return m_descriptor->programs[pn];
}
void
PluginHostAdapter::selectProgram(std::string program)
{
if (!m_handle) return;
for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
if (program == m_descriptor->programs[i]) {
m_descriptor->selectProgram(m_handle, i);
return;
}
}
}
size_t
PluginHostAdapter::getPreferredStepSize() const
{
if (!m_handle) return 0;
return m_descriptor->getPreferredStepSize(m_handle);
}
size_t
PluginHostAdapter::getPreferredBlockSize() const
{
if (!m_handle) return 0;
return m_descriptor->getPreferredBlockSize(m_handle);
}
size_t
PluginHostAdapter::getMinChannelCount() const
{
if (!m_handle) return 0;
return m_descriptor->getMinChannelCount(m_handle);
}
size_t
PluginHostAdapter::getMaxChannelCount() const
{
if (!m_handle) return 0;
return m_descriptor->getMaxChannelCount(m_handle);
}
PluginHostAdapter::OutputList
PluginHostAdapter::getOutputDescriptors() const
{
OutputList list;
if (!m_handle) {
// std::cerr << "PluginHostAdapter::getOutputDescriptors: no handle " << std::endl;
return list;
}
unsigned int count = m_descriptor->getOutputCount(m_handle);
for (unsigned int i = 0; i < count; ++i) {
VampOutputDescriptor *sd = m_descriptor->getOutputDescriptor(m_handle, i);
OutputDescriptor d;
d.identifier = sd->identifier;
d.name = sd->name;
d.description = sd->description;
d.unit = sd->unit;
d.hasFixedBinCount = sd->hasFixedBinCount;
d.binCount = sd->binCount;
if (d.hasFixedBinCount && sd->binNames) {
for (unsigned int j = 0; j < sd->binCount; ++j) {
d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : "");
}
}
d.hasKnownExtents = sd->hasKnownExtents;
d.minValue = sd->minValue;
d.maxValue = sd->maxValue;
d.isQuantized = sd->isQuantized;
d.quantizeStep = sd->quantizeStep;
switch (sd->sampleType) {
case vampOneSamplePerStep:
d.sampleType = OutputDescriptor::OneSamplePerStep; break;
case vampFixedSampleRate:
d.sampleType = OutputDescriptor::FixedSampleRate; break;
case vampVariableSampleRate:
d.sampleType = OutputDescriptor::VariableSampleRate; break;
}
d.sampleRate = sd->sampleRate;
if (m_descriptor->vampApiVersion >= 2) {
d.hasDuration = sd->hasDuration;
} else {
d.hasDuration = false;
}
list.push_back(d);
m_descriptor->releaseOutputDescriptor(sd);
}
return list;
}
PluginHostAdapter::FeatureSet
PluginHostAdapter::process(const float *const *inputBuffers,
RealTime timestamp)
{
FeatureSet fs;
if (!m_handle) return fs;
int sec = timestamp.sec;
int nsec = timestamp.nsec;
VampFeatureList *features = m_descriptor->process(m_handle,
inputBuffers,
sec, nsec);
convertFeatures(features, fs);
m_descriptor->releaseFeatureSet(features);
return fs;
}
PluginHostAdapter::FeatureSet
PluginHostAdapter::getRemainingFeatures()
{
FeatureSet fs;
if (!m_handle) return fs;
VampFeatureList *features = m_descriptor->getRemainingFeatures(m_handle);
convertFeatures(features, fs);
m_descriptor->releaseFeatureSet(features);
return fs;
}
void
PluginHostAdapter::convertFeatures(VampFeatureList *features,
FeatureSet &fs)
{
if (!features) return;
unsigned int outputs = m_descriptor->getOutputCount(m_handle);
for (unsigned int i = 0; i < outputs; ++i) {
VampFeatureList &list = features[i];
if (list.featureCount > 0) {
Feature feature;
feature.values.reserve(list.features[0].v1.valueCount);
for (unsigned int j = 0; j < list.featureCount; ++j) {
feature.hasTimestamp = list.features[j].v1.hasTimestamp;
feature.timestamp = RealTime(list.features[j].v1.sec,
list.features[j].v1.nsec);
feature.hasDuration = false;
if (m_descriptor->vampApiVersion >= 2) {
unsigned int j2 = j + list.featureCount;
feature.hasDuration = list.features[j2].v2.hasDuration;
feature.duration = RealTime(list.features[j2].v2.durationSec,
list.features[j2].v2.durationNsec);
}
for (unsigned int k = 0; k < list.features[j].v1.valueCount; ++k) {
feature.values.push_back(list.features[j].v1.values[k]);
}
if (list.features[j].v1.label) {
feature.label = list.features[j].v1.label;
}
fs[i].push_back(feature);
if (list.features[j].v1.valueCount > 0) {
feature.values.clear();
}
if (list.features[j].v1.label) {
feature.label = "";
}
}
}
}
}
}
_VAMP_SDK_HOSTSPACE_END(PluginHostAdapter.cpp)

View file

@ -37,10 +37,11 @@
authorization.
*/
#include "PluginInputDomainAdapter.h"
#include <vamp-hostsdk/PluginInputDomainAdapter.h>
#include <cmath>
/**
* If you want to compile using FFTW instead of the built-in FFT
* implementation for the PluginInputDomainAdapter, define HAVE_FFTW3
@ -68,6 +69,9 @@
#include <fftw3.h>
#endif
_VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.cpp)
namespace Vamp {
namespace HostExt {
@ -84,6 +88,8 @@ public:
size_t getPreferredBlockSize() const;
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
RealTime getTimestampAdjustment() const;
protected:
Plugin *m_plugin;
@ -149,6 +155,13 @@ PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime tim
return m_impl->process(inputBuffers, timestamp);
}
RealTime
PluginInputDomainAdapter::getTimestampAdjustment() const
{
return m_impl->getTimestampAdjustment();
}
PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
m_plugin(plugin),
m_inputSampleRate(inputSampleRate),
@ -336,6 +349,17 @@ PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
return blockSize;
}
RealTime
PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
{
if (m_plugin->getInputDomain() == TimeDomain) {
return RealTime::zeroTime;
} else {
return RealTime::frame2RealTime
(m_blockSize/2, int(m_inputSampleRate + 0.5));
}
}
Plugin::FeatureSet
PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
RealTime timestamp)
@ -388,8 +412,7 @@ PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
// std::cerr << "PluginInputDomainAdapter: sampleRate " << m_inputSampleRate << ", blocksize " << m_blockSize << ", adjusting time from " << timestamp;
timestamp = timestamp + RealTime::frame2RealTime
(m_blockSize/2, int(m_inputSampleRate + 0.5));
timestamp = timestamp + getTimestampAdjustment();
// std::cerr << " to " << timestamp << std::endl;
@ -555,3 +578,5 @@ PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse,
}
_VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.cpp)

View file

@ -34,16 +34,15 @@
authorization.
*/
#include "vamp-sdk/PluginHostAdapter.h"
#include "PluginLoader.h"
#include "PluginInputDomainAdapter.h"
#include "PluginChannelAdapter.h"
#include "PluginBufferingAdapter.h"
#include <vamp-hostsdk/PluginHostAdapter.h>
#include <vamp-hostsdk/PluginLoader.h>
#include <vamp-hostsdk/PluginInputDomainAdapter.h>
#include <vamp-hostsdk/PluginChannelAdapter.h>
#include <vamp-hostsdk/PluginBufferingAdapter.h>
#include <string>
#include <cstring>
#include <fstream>
#include <cctype> // tolower
#include <cstring>
#ifdef _WIN32
@ -67,6 +66,8 @@
using namespace std;
_VAMP_SDK_HOSTSPACE_BEGIN(PluginLoader.cpp)
namespace Vamp {
namespace HostExt {
@ -518,7 +519,7 @@ PluginLoader::Impl::loadLibrary(string path)
<< path << "\"" << endl;
}
#else
handle = dlopen(path.c_str(), RTLD_LAZY);
handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (!handle) {
cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
<< path << "\": " << dlerror() << endl;
@ -586,8 +587,6 @@ PluginLoader::Impl::listFiles(string dir, string extension)
struct dirent *e = 0;
while ((e = readdir(d))) {
if (!(e->d_type & DT_REG) && (e->d_type != DT_UNKNOWN)) continue;
if (!e->d_name) continue;
size_t len = strlen(e->d_name);
@ -637,3 +636,6 @@ PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
}
}
_VAMP_SDK_HOSTSPACE_END(PluginLoader.cpp)

View file

@ -0,0 +1,952 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2008 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include <vamp-hostsdk/PluginSummarisingAdapter.h>
#include <map>
#include <algorithm>
#include <cmath>
#include <climits>
//#define DEBUG_PLUGIN_SUMMARISING_ADAPTER 1
//#define DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT 1
_VAMP_SDK_HOSTSPACE_BEGIN(PluginSummarisingAdapter.cpp)
namespace Vamp {
namespace HostExt {
class PluginSummarisingAdapter::Impl
{
public:
Impl(Plugin *plugin, float inputSampleRate);
~Impl();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures();
void setSummarySegmentBoundaries(const SegmentBoundaries &);
FeatureList getSummaryForOutput(int output,
SummaryType type,
AveragingMethod avg);
FeatureSet getSummaryForAllOutputs(SummaryType type,
AveragingMethod avg);
protected:
Plugin *m_plugin;
float m_inputSampleRate;
size_t m_stepSize;
size_t m_blockSize;
SegmentBoundaries m_boundaries;
typedef std::vector<float> ValueList;
struct Result { // smaller than Feature
RealTime time;
RealTime duration;
ValueList values; // bin number -> value
};
typedef std::vector<Result> ResultList;
struct OutputAccumulator {
int bins;
ResultList results;
OutputAccumulator() : bins(0) { }
};
typedef std::map<int, OutputAccumulator> OutputAccumulatorMap;
OutputAccumulatorMap m_accumulators; // output number -> accumulator
typedef std::map<RealTime, OutputAccumulator> SegmentAccumulatorMap;
typedef std::map<int, SegmentAccumulatorMap> OutputSegmentAccumulatorMap;
OutputSegmentAccumulatorMap m_segmentedAccumulators; // output -> segmented
typedef std::map<int, RealTime> OutputTimestampMap;
OutputTimestampMap m_prevTimestamps; // output number -> timestamp
OutputTimestampMap m_prevDurations; // output number -> durations
struct OutputBinSummary {
int count;
// extents
double minimum;
double maximum;
double sum;
// sample-average results
double median;
double mode;
double variance;
// continuous-time average results
double median_c;
double mode_c;
double mean_c;
double variance_c;
};
typedef std::map<int, OutputBinSummary> OutputSummary;
typedef std::map<RealTime, OutputSummary> SummarySegmentMap;
typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap;
OutputSummarySegmentMap m_summaries;
bool m_reduced;
RealTime m_endTime;
void accumulate(const FeatureSet &fs, RealTime, bool final);
void accumulate(int output, const Feature &f, RealTime, bool final);
void accumulateFinalDurations();
void findSegmentBounds(RealTime t, RealTime &start, RealTime &end);
void segment();
void reduce();
std::string getSummaryLabel(SummaryType type, AveragingMethod avg);
};
static RealTime INVALID_DURATION(INT_MIN, INT_MIN);
PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) :
PluginWrapper(plugin)
{
m_impl = new Impl(plugin, m_inputSampleRate);
}
PluginSummarisingAdapter::~PluginSummarisingAdapter()
{
delete m_impl;
}
bool
PluginSummarisingAdapter::initialise(size_t channels,
size_t stepSize, size_t blockSize)
{
return
PluginWrapper::initialise(channels, stepSize, blockSize) &&
m_impl->initialise(channels, stepSize, blockSize);
}
void
PluginSummarisingAdapter::reset()
{
m_impl->reset();
}
Plugin::FeatureSet
PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp)
{
return m_impl->process(inputBuffers, timestamp);
}
Plugin::FeatureSet
PluginSummarisingAdapter::getRemainingFeatures()
{
return m_impl->getRemainingFeatures();
}
void
PluginSummarisingAdapter::setSummarySegmentBoundaries(const SegmentBoundaries &b)
{
m_impl->setSummarySegmentBoundaries(b);
}
Plugin::FeatureList
PluginSummarisingAdapter::getSummaryForOutput(int output,
SummaryType type,
AveragingMethod avg)
{
return m_impl->getSummaryForOutput(output, type, avg);
}
Plugin::FeatureSet
PluginSummarisingAdapter::getSummaryForAllOutputs(SummaryType type,
AveragingMethod avg)
{
return m_impl->getSummaryForAllOutputs(type, avg);
}
PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
m_plugin(plugin),
m_inputSampleRate(inputSampleRate),
m_reduced(false)
{
}
PluginSummarisingAdapter::Impl::~Impl()
{
}
bool
PluginSummarisingAdapter::Impl::initialise(size_t channels,
size_t stepSize, size_t blockSize)
{
m_stepSize = stepSize;
m_blockSize = blockSize;
return true;
}
void
PluginSummarisingAdapter::Impl::reset()
{
m_accumulators.clear();
m_segmentedAccumulators.clear();
m_prevTimestamps.clear();
m_prevDurations.clear();
m_summaries.clear();
m_reduced = false;
m_endTime = RealTime();
m_plugin->reset();
}
Plugin::FeatureSet
PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers,
RealTime timestamp)
{
if (m_reduced) {
std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
}
FeatureSet fs = m_plugin->process(inputBuffers, timestamp);
accumulate(fs, timestamp, false);
m_endTime = timestamp +
RealTime::frame2RealTime(m_stepSize, int(m_inputSampleRate + 0.5));
return fs;
}
Plugin::FeatureSet
PluginSummarisingAdapter::Impl::getRemainingFeatures()
{
if (m_reduced) {
std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
}
FeatureSet fs = m_plugin->getRemainingFeatures();
accumulate(fs, m_endTime, true);
return fs;
}
void
PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b)
{
m_boundaries = b;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "PluginSummarisingAdapter::setSummarySegmentBoundaries: boundaries are:" << std::endl;
for (SegmentBoundaries::const_iterator i = m_boundaries.begin();
i != m_boundaries.end(); ++i) {
std::cerr << *i << " ";
}
std::cerr << std::endl;
#endif
}
Plugin::FeatureList
PluginSummarisingAdapter::Impl::getSummaryForOutput(int output,
SummaryType type,
AveragingMethod avg)
{
if (!m_reduced) {
accumulateFinalDurations();
segment();
reduce();
m_reduced = true;
}
bool continuous = (avg == ContinuousTimeAverage);
FeatureList fl;
for (SummarySegmentMap::const_iterator i = m_summaries[output].begin();
i != m_summaries[output].end(); ++i) {
Feature f;
f.hasTimestamp = true;
f.timestamp = i->first;
f.hasDuration = true;
SummarySegmentMap::const_iterator ii = i;
if (++ii == m_summaries[output].end()) {
f.duration = m_endTime - f.timestamp;
} else {
f.duration = ii->first - f.timestamp;
}
f.label = getSummaryLabel(type, avg);
for (OutputSummary::const_iterator j = i->second.begin();
j != i->second.end(); ++j) {
// these will be ordered by bin number, and no bin numbers
// will be missing except at the end (because of the way
// the accumulators were initially filled in accumulate())
const OutputBinSummary &summary = j->second;
double result = 0.f;
switch (type) {
case Minimum:
result = summary.minimum;
break;
case Maximum:
result = summary.maximum;
break;
case Mean:
if (continuous) {
result = summary.mean_c;
} else if (summary.count) {
result = summary.sum / summary.count;
}
break;
case Median:
if (continuous) result = summary.median_c;
else result = summary.median;
break;
case Mode:
if (continuous) result = summary.mode_c;
else result = summary.mode;
break;
case Sum:
result = summary.sum;
break;
case Variance:
if (continuous) result = summary.variance_c;
else result = summary.variance;
break;
case StandardDeviation:
if (continuous) result = sqrtf(summary.variance_c);
else result = sqrtf(summary.variance);
break;
case Count:
result = summary.count;
break;
case UnknownSummaryType:
break;
default:
break;
}
f.values.push_back(result);
}
fl.push_back(f);
}
return fl;
}
Plugin::FeatureSet
PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type,
AveragingMethod avg)
{
if (!m_reduced) {
accumulateFinalDurations();
segment();
reduce();
m_reduced = true;
}
FeatureSet fs;
for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin();
i != m_summaries.end(); ++i) {
fs[i->first] = getSummaryForOutput(i->first, type, avg);
}
return fs;
}
void
PluginSummarisingAdapter::Impl::accumulate(const FeatureSet &fs,
RealTime timestamp,
bool final)
{
for (FeatureSet::const_iterator i = fs.begin(); i != fs.end(); ++i) {
for (FeatureList::const_iterator j = i->second.begin();
j != i->second.end(); ++j) {
if (j->hasTimestamp) {
accumulate(i->first, *j, j->timestamp, final);
} else {
//!!! is this correct?
accumulate(i->first, *j, timestamp, final);
}
}
}
}
std::string
PluginSummarisingAdapter::Impl::getSummaryLabel(SummaryType type,
AveragingMethod avg)
{
std::string label;
std::string avglabel;
if (avg == SampleAverage) avglabel = ", sample average";
else avglabel = ", continuous-time average";
switch (type) {
case Minimum: label = "(minimum value)"; break;
case Maximum: label = "(maximum value)"; break;
case Mean: label = "(mean value" + avglabel + ")"; break;
case Median: label = "(median value" + avglabel + ")"; break;
case Mode: label = "(modal value" + avglabel + ")"; break;
case Sum: label = "(sum)"; break;
case Variance: label = "(variance" + avglabel + ")"; break;
case StandardDeviation: label = "(standard deviation" + avglabel + ")"; break;
case Count: label = "(count)"; break;
case UnknownSummaryType: label = "(unknown summary)"; break;
}
return label;
}
void
PluginSummarisingAdapter::Impl::accumulate(int output,
const Feature &f,
RealTime timestamp,
bool final)
{
// What should happen if a feature's duration spans a segment
// boundary? I think we probably want to chop it, and pretend
// that it appears in both. A very long feature (e.g. key, if the
// whole audio is in a single key) might span many or all
// segments, and we want that to be reflected in the results
// (e.g. it is the modal key in all of those segments, not just
// the first). This is actually quite complicated to do.
// If features spanning a boundary should be chopped, then we need
// to have per-segment accumulators (and the feature value goes
// into both -- with a separate phase to split the accumulator up
// into segments).
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << ", final " << final << std::endl;
#endif
// At each process step, accumulate() is called once for each
// feature on each output within that process's returned feature
// list, and with the timestamp passed in being that of the start
// of the process block.
// At the end (in getRemainingFeatures), accumulate() is called
// once for each feature on each output within the feature list
// returned by getRemainingFeatures, and with the timestamp being
// the same as the last process block and final set to true.
// (What if getRemainingFeatures doesn't return any features? We
// still need to ensure that the final duration is written. Need
// a separate function to close the durations.)
// At each call, we pull out the value for the feature and stuff
// it into the accumulator's appropriate values array; and we
// calculate the duration for the _previous_ feature, or pull it
// from the prevDurations array if the previous feature had a
// duration in its structure, and stuff that into the
// accumulator's appropriate durations array.
if (m_prevDurations.find(output) != m_prevDurations.end()) {
// Not the first time accumulate has been called for this
// output -- there has been a previous feature
RealTime prevDuration;
// Note that m_prevDurations[output] only contains the
// duration field that was contained in the previous feature.
// If it didn't have an explicit duration,
// m_prevDurations[output] should be INVALID_DURATION and we
// will have to calculate the duration from the previous and
// current timestamps.
if (m_prevDurations[output] != INVALID_DURATION) {
prevDuration = m_prevDurations[output];
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "Previous duration from previous feature: " << prevDuration << std::endl;
#endif
} else {
prevDuration = timestamp - m_prevTimestamps[output];
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "Previous duration from diff: " << timestamp << " - "
<< m_prevTimestamps[output] << std::endl;
#endif
}
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "output " << output << ": ";
std::cerr << "Pushing previous duration as " << prevDuration << std::endl;
#endif
m_accumulators[output].results
[m_accumulators[output].results.size() - 1]
.duration = prevDuration;
}
if (f.hasDuration) m_prevDurations[output] = f.duration;
else m_prevDurations[output] = INVALID_DURATION;
m_prevTimestamps[output] = timestamp;
if (f.hasDuration) {
RealTime et = timestamp;
et = et + f.duration;
if (et > m_endTime) m_endTime = et;
}
Result result;
result.time = timestamp;
result.duration = INVALID_DURATION;
if (int(f.values.size()) > m_accumulators[output].bins) {
m_accumulators[output].bins = f.values.size();
}
for (int i = 0; i < int(f.values.size()); ++i) {
result.values.push_back(f.values[i]);
}
m_accumulators[output].results.push_back(result);
}
void
PluginSummarisingAdapter::Impl::accumulateFinalDurations()
{
for (OutputTimestampMap::iterator i = m_prevTimestamps.begin();
i != m_prevTimestamps.end(); ++i) {
int output = i->first;
int acount = m_accumulators[output].results.size();
if (acount == 0) continue;
RealTime prevTimestamp = i->second;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "output " << output << ": ";
#endif
if (m_prevDurations.find(output) != m_prevDurations.end() &&
m_prevDurations[output] != INVALID_DURATION) {
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "Pushing final duration from feature as " << m_prevDurations[output] << std::endl;
#endif
m_accumulators[output].results[acount - 1].duration =
m_prevDurations[output];
} else {
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "Pushing final duration from diff as " << m_endTime << " - " << m_prevTimestamps[output] << std::endl;
#endif
m_accumulators[output].results[acount - 1].duration =
m_endTime - m_prevTimestamps[output];
}
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "so duration for result no " << acount-1 << " is "
<< m_accumulators[output].results[acount-1].duration
<< std::endl;
#endif
}
}
void
PluginSummarisingAdapter::Impl::findSegmentBounds(RealTime t,
RealTime &start,
RealTime &end)
{
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "findSegmentBounds: t = " << t << std::endl;
#endif
SegmentBoundaries::const_iterator i = std::upper_bound
(m_boundaries.begin(), m_boundaries.end(), t);
start = RealTime::zeroTime;
end = m_endTime;
if (i != m_boundaries.end()) {
end = *i;
}
if (i != m_boundaries.begin()) {
start = *--i;
}
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "findSegmentBounds: " << t << " is in segment " << start << " -> " << end << std::endl;
#endif
}
void
PluginSummarisingAdapter::Impl::segment()
{
SegmentBoundaries::iterator boundaryitr = m_boundaries.begin();
RealTime segmentStart = RealTime::zeroTime;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "segment: starting" << std::endl;
#endif
for (OutputAccumulatorMap::iterator i = m_accumulators.begin();
i != m_accumulators.end(); ++i) {
int output = i->first;
OutputAccumulator &source = i->second;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "segment: total results for output " << output << " = "
<< source.results.size() << std::endl;
#endif
// This is basically nonsense if the results have no values
// (i.e. their times and counts are the only things of
// interest)... but perhaps it's the user's problem if they
// ask for segmentation (or any summary at all) in that case
for (int n = 0; n < int(source.results.size()); ++n) {
// This result spans source.results[n].time to
// source.results[n].time + source.results[n].duration.
// We need to dispose it into segments appropriately
RealTime resultStart = source.results[n].time;
RealTime resultEnd = resultStart + source.results[n].duration;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "output: " << output << ", result start = " << resultStart << ", end = " << resultEnd << std::endl;
#endif
RealTime segmentStart = RealTime::zeroTime;
RealTime segmentEnd = resultEnd - RealTime(1, 0);
RealTime prevSegmentStart = segmentStart - RealTime(1, 0);
while (segmentEnd < resultEnd) {
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "segment end " << segmentEnd << " < result end "
<< resultEnd << " (with result start " << resultStart << ")" << std::endl;
#endif
findSegmentBounds(resultStart, segmentStart, segmentEnd);
if (segmentStart == prevSegmentStart) {
// This can happen when we reach the end of the
// input, if a feature's end time overruns the
// input audio end time
break;
}
prevSegmentStart = segmentStart;
RealTime chunkStart = resultStart;
if (chunkStart < segmentStart) chunkStart = segmentStart;
RealTime chunkEnd = resultEnd;
if (chunkEnd > segmentEnd) chunkEnd = segmentEnd;
m_segmentedAccumulators[output][segmentStart].bins = source.bins;
Result chunk;
chunk.time = chunkStart;
chunk.duration = chunkEnd - chunkStart;
chunk.values = source.results[n].values;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "chunk for segment " << segmentStart << ": from " << chunk.time << ", duration " << chunk.duration << std::endl;
#endif
m_segmentedAccumulators[output][segmentStart].results
.push_back(chunk);
resultStart = chunkEnd;
}
}
}
}
struct ValueDurationFloatPair
{
float value;
float duration;
ValueDurationFloatPair() : value(0), duration(0) { }
ValueDurationFloatPair(float v, float d) : value(v), duration(d) { }
ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) {
value = p.value;
duration = p.duration;
return *this;
}
bool operator<(const ValueDurationFloatPair &p) const {
return value < p.value;
}
};
static double toSec(const RealTime &r)
{
return r.sec + double(r.nsec) / 1000000000.0;
}
void
PluginSummarisingAdapter::Impl::reduce()
{
for (OutputSegmentAccumulatorMap::iterator i =
m_segmentedAccumulators.begin();
i != m_segmentedAccumulators.end(); ++i) {
int output = i->first;
SegmentAccumulatorMap &segments = i->second;
for (SegmentAccumulatorMap::iterator j = segments.begin();
j != segments.end(); ++j) {
RealTime segmentStart = j->first;
OutputAccumulator &accumulator = j->second;
int sz = accumulator.results.size();
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "reduce: segment starting at " << segmentStart
<< " on output " << output << " has " << sz << " result(s)" << std::endl;
#endif
double totalDuration = 0.0;
//!!! is this right?
if (sz > 0) {
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "last time = " << accumulator.results[sz-1].time
<< ", duration = " << accumulator.results[sz-1].duration
<< " (step = " << m_stepSize << ", block = " << m_blockSize << ")"
<< std::endl;
#endif
totalDuration = toSec((accumulator.results[sz-1].time +
accumulator.results[sz-1].duration) -
segmentStart);
}
for (int bin = 0; bin < accumulator.bins; ++bin) {
// work on all values over time for a single bin
OutputBinSummary summary;
summary.count = sz;
summary.minimum = 0.f;
summary.maximum = 0.f;
summary.median = 0.f;
summary.mode = 0.f;
summary.sum = 0.f;
summary.variance = 0.f;
summary.median_c = 0.f;
summary.mode_c = 0.f;
summary.mean_c = 0.f;
summary.variance_c = 0.f;
if (sz == 0) continue;
std::vector<ValueDurationFloatPair> valvec;
for (int k = 0; k < sz; ++k) {
while (int(accumulator.results[k].values.size()) <
accumulator.bins) {
accumulator.results[k].values.push_back(0.f);
}
}
for (int k = 0; k < sz; ++k) {
float value = accumulator.results[k].values[bin];
valvec.push_back(ValueDurationFloatPair
(value,
toSec(accumulator.results[k].duration)));
}
std::sort(valvec.begin(), valvec.end());
summary.minimum = valvec[0].value;
summary.maximum = valvec[sz-1].value;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "total duration = " << totalDuration << std::endl;
#endif
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
/*
std::cerr << "value vector for medians:" << std::endl;
for (int k = 0; k < sz; ++k) {
std::cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") ";
}
std::cerr << std::endl;
*/
#endif
if (sz % 2 == 1) {
summary.median = valvec[sz/2].value;
} else {
summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2;
}
double duracc = 0.0;
summary.median_c = valvec[sz-1].value;
for (int k = 0; k < sz; ++k) {
duracc += valvec[k].duration;
if (duracc > totalDuration/2) {
summary.median_c = valvec[k].value;
break;
}
}
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "median_c = " << summary.median_c << std::endl;
std::cerr << "median = " << summary.median << std::endl;
#endif
std::map<float, int> distribution;
for (int k = 0; k < sz; ++k) {
summary.sum += accumulator.results[k].values[bin];
distribution[accumulator.results[k].values[bin]] += 1;
}
int md = 0;
for (std::map<float, int>::iterator di = distribution.begin();
di != distribution.end(); ++di) {
if (di->second > md) {
md = di->second;
summary.mode = di->first;
}
}
distribution.clear();
std::map<float, double> distribution_c;
for (int k = 0; k < sz; ++k) {
distribution_c[accumulator.results[k].values[bin]]
+= toSec(accumulator.results[k].duration);
}
double mrd = 0.0;
for (std::map<float, double>::iterator di = distribution_c.begin();
di != distribution_c.end(); ++di) {
if (di->second > mrd) {
mrd = di->second;
summary.mode_c = di->first;
}
}
distribution_c.clear();
if (totalDuration > 0.0) {
double sum_c = 0.0;
for (int k = 0; k < sz; ++k) {
double value = accumulator.results[k].values[bin]
* toSec(accumulator.results[k].duration);
sum_c += value;
}
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "mean_c = " << sum_c << " / " << totalDuration << " = "
<< sum_c / totalDuration << " (sz = " << sz << ")" << std::endl;
#endif
summary.mean_c = sum_c / totalDuration;
for (int k = 0; k < sz; ++k) {
double value = accumulator.results[k].values[bin];
// * toSec(accumulator.results[k].duration);
summary.variance_c +=
(value - summary.mean_c) * (value - summary.mean_c)
* toSec(accumulator.results[k].duration);
}
// summary.variance_c /= summary.count;
summary.variance_c /= totalDuration;
}
double mean = summary.sum / summary.count;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "mean = " << summary.sum << " / " << summary.count << " = "
<< summary.sum / summary.count << std::endl;
#endif
for (int k = 0; k < sz; ++k) {
float value = accumulator.results[k].values[bin];
summary.variance += (value - mean) * (value - mean);
}
summary.variance /= summary.count;
m_summaries[output][segmentStart][bin] = summary;
}
}
}
m_segmentedAccumulators.clear();
m_accumulators.clear();
}
}
}
_VAMP_SDK_HOSTSPACE_END(PluginSummarisingAdapter.cpp)

View file

@ -34,7 +34,9 @@
authorization.
*/
#include "PluginWrapper.h"
#include <vamp-hostsdk/PluginWrapper.h>
_VAMP_SDK_HOSTSPACE_BEGIN(PluginWrapper.cpp)
namespace Vamp {
@ -199,3 +201,4 @@ PluginWrapper::getRemainingFeatures()
}
_VAMP_SDK_HOSTSPACE_END(PluginWrapper.cpp)

View file

@ -0,0 +1,39 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include <vamp-hostsdk/RealTime.h>
#include "../vamp-sdk/RealTime.cpp"

View file

@ -0,0 +1,914 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include <vamp-sdk/PluginAdapter.h>
#include <cstring>
#include <cstdlib>
#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 0 )
#error Incorrect Vamp SDK header included (not the expected 2.0 SDK)
#endif
//#define DEBUG_PLUGIN_ADAPTER 1
_VAMP_SDK_PLUGSPACE_BEGIN(PluginAdapter.cpp)
namespace Vamp {
class PluginAdapterBase::Impl
{
public:
Impl(PluginAdapterBase *);
~Impl();
const VampPluginDescriptor *getDescriptor();
protected:
PluginAdapterBase *m_base;
static VampPluginHandle vampInstantiate(const VampPluginDescriptor *desc,
float inputSampleRate);
static void vampCleanup(VampPluginHandle handle);
static int vampInitialise(VampPluginHandle handle, unsigned int channels,
unsigned int stepSize, unsigned int blockSize);
static void vampReset(VampPluginHandle handle);
static float vampGetParameter(VampPluginHandle handle, int param);
static void vampSetParameter(VampPluginHandle handle, int param, float value);
static unsigned int vampGetCurrentProgram(VampPluginHandle handle);
static void vampSelectProgram(VampPluginHandle handle, unsigned int program);
static unsigned int vampGetPreferredStepSize(VampPluginHandle handle);
static unsigned int vampGetPreferredBlockSize(VampPluginHandle handle);
static unsigned int vampGetMinChannelCount(VampPluginHandle handle);
static unsigned int vampGetMaxChannelCount(VampPluginHandle handle);
static unsigned int vampGetOutputCount(VampPluginHandle handle);
static VampOutputDescriptor *vampGetOutputDescriptor(VampPluginHandle handle,
unsigned int i);
static void vampReleaseOutputDescriptor(VampOutputDescriptor *desc);
static VampFeatureList *vampProcess(VampPluginHandle handle,
const float *const *inputBuffers,
int sec,
int nsec);
static VampFeatureList *vampGetRemainingFeatures(VampPluginHandle handle);
static void vampReleaseFeatureSet(VampFeatureList *fs);
void checkOutputMap(Plugin *plugin);
void markOutputsChanged(Plugin *plugin);
void cleanup(Plugin *plugin);
unsigned int getOutputCount(Plugin *plugin);
VampOutputDescriptor *getOutputDescriptor(Plugin *plugin,
unsigned int i);
VampFeatureList *process(Plugin *plugin,
const float *const *inputBuffers,
int sec, int nsec);
VampFeatureList *getRemainingFeatures(Plugin *plugin);
VampFeatureList *convertFeatures(Plugin *plugin,
const Plugin::FeatureSet &features);
// maps both plugins and descriptors to adapters
typedef std::map<const void *, Impl *> AdapterMap;
static AdapterMap *m_adapterMap;
static Impl *lookupAdapter(VampPluginHandle);
bool m_populated;
VampPluginDescriptor m_descriptor;
Plugin::ParameterList m_parameters;
Plugin::ProgramList m_programs;
typedef std::map<Plugin *, Plugin::OutputList *> OutputMap;
OutputMap m_pluginOutputs;
std::map<Plugin *, VampFeatureList *> m_fs;
std::map<Plugin *, std::vector<size_t> > m_fsizes;
std::map<Plugin *, std::vector<std::vector<size_t> > > m_fvsizes;
void resizeFS(Plugin *plugin, int n);
void resizeFL(Plugin *plugin, int n, size_t sz);
void resizeFV(Plugin *plugin, int n, int j, size_t sz);
};
PluginAdapterBase::PluginAdapterBase()
{
m_impl = new Impl(this);
}
PluginAdapterBase::~PluginAdapterBase()
{
delete m_impl;
}
const VampPluginDescriptor *
PluginAdapterBase::getDescriptor()
{
return m_impl->getDescriptor();
}
PluginAdapterBase::Impl::Impl(PluginAdapterBase *base) :
m_base(base),
m_populated(false)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl[" << this << "]::Impl" << std::endl;
#endif
}
const VampPluginDescriptor *
PluginAdapterBase::Impl::getDescriptor()
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl[" << this << "]::getDescriptor" << std::endl;
#endif
if (m_populated) return &m_descriptor;
Plugin *plugin = m_base->createPlugin(48000);
if (plugin->getVampApiVersion() != VAMP_API_VERSION) {
std::cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: "
<< "API version " << plugin->getVampApiVersion()
<< " for\nplugin \"" << plugin->getIdentifier() << "\" "
<< "differs from version "
<< VAMP_API_VERSION << " for adapter.\n"
<< "This plugin is probably linked against a different version of the Vamp SDK\n"
<< "from the version it was compiled with. It will need to be re-linked correctly\n"
<< "before it can be used." << std::endl;
delete plugin;
return 0;
}
m_parameters = plugin->getParameterDescriptors();
m_programs = plugin->getPrograms();
m_descriptor.vampApiVersion = plugin->getVampApiVersion();
m_descriptor.identifier = strdup(plugin->getIdentifier().c_str());
m_descriptor.name = strdup(plugin->getName().c_str());
m_descriptor.description = strdup(plugin->getDescription().c_str());
m_descriptor.maker = strdup(plugin->getMaker().c_str());
m_descriptor.pluginVersion = plugin->getPluginVersion();
m_descriptor.copyright = strdup(plugin->getCopyright().c_str());
m_descriptor.parameterCount = m_parameters.size();
m_descriptor.parameters = (const VampParameterDescriptor **)
malloc(m_parameters.size() * sizeof(VampParameterDescriptor));
unsigned int i;
for (i = 0; i < m_parameters.size(); ++i) {
VampParameterDescriptor *desc = (VampParameterDescriptor *)
malloc(sizeof(VampParameterDescriptor));
desc->identifier = strdup(m_parameters[i].identifier.c_str());
desc->name = strdup(m_parameters[i].name.c_str());
desc->description = strdup(m_parameters[i].description.c_str());
desc->unit = strdup(m_parameters[i].unit.c_str());
desc->minValue = m_parameters[i].minValue;
desc->maxValue = m_parameters[i].maxValue;
desc->defaultValue = m_parameters[i].defaultValue;
desc->isQuantized = m_parameters[i].isQuantized;
desc->quantizeStep = m_parameters[i].quantizeStep;
desc->valueNames = 0;
if (desc->isQuantized && !m_parameters[i].valueNames.empty()) {
desc->valueNames = (const char **)
malloc((m_parameters[i].valueNames.size()+1) * sizeof(char *));
for (unsigned int j = 0; j < m_parameters[i].valueNames.size(); ++j) {
desc->valueNames[j] = strdup(m_parameters[i].valueNames[j].c_str());
}
desc->valueNames[m_parameters[i].valueNames.size()] = 0;
}
m_descriptor.parameters[i] = desc;
}
m_descriptor.programCount = m_programs.size();
m_descriptor.programs = (const char **)
malloc(m_programs.size() * sizeof(const char *));
for (i = 0; i < m_programs.size(); ++i) {
m_descriptor.programs[i] = strdup(m_programs[i].c_str());
}
if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
m_descriptor.inputDomain = vampFrequencyDomain;
} else {
m_descriptor.inputDomain = vampTimeDomain;
}
m_descriptor.instantiate = vampInstantiate;
m_descriptor.cleanup = vampCleanup;
m_descriptor.initialise = vampInitialise;
m_descriptor.reset = vampReset;
m_descriptor.getParameter = vampGetParameter;
m_descriptor.setParameter = vampSetParameter;
m_descriptor.getCurrentProgram = vampGetCurrentProgram;
m_descriptor.selectProgram = vampSelectProgram;
m_descriptor.getPreferredStepSize = vampGetPreferredStepSize;
m_descriptor.getPreferredBlockSize = vampGetPreferredBlockSize;
m_descriptor.getMinChannelCount = vampGetMinChannelCount;
m_descriptor.getMaxChannelCount = vampGetMaxChannelCount;
m_descriptor.getOutputCount = vampGetOutputCount;
m_descriptor.getOutputDescriptor = vampGetOutputDescriptor;
m_descriptor.releaseOutputDescriptor = vampReleaseOutputDescriptor;
m_descriptor.process = vampProcess;
m_descriptor.getRemainingFeatures = vampGetRemainingFeatures;
m_descriptor.releaseFeatureSet = vampReleaseFeatureSet;
if (!m_adapterMap) {
m_adapterMap = new AdapterMap;
}
(*m_adapterMap)[&m_descriptor] = this;
delete plugin;
m_populated = true;
return &m_descriptor;
}
PluginAdapterBase::Impl::~Impl()
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl[" << this << "]::~Impl" << std::endl;
#endif
if (!m_populated) return;
free((void *)m_descriptor.identifier);
free((void *)m_descriptor.name);
free((void *)m_descriptor.description);
free((void *)m_descriptor.maker);
free((void *)m_descriptor.copyright);
for (unsigned int i = 0; i < m_descriptor.parameterCount; ++i) {
const VampParameterDescriptor *desc = m_descriptor.parameters[i];
free((void *)desc->identifier);
free((void *)desc->name);
free((void *)desc->description);
free((void *)desc->unit);
if (desc->valueNames) {
for (unsigned int j = 0; desc->valueNames[j]; ++j) {
free((void *)desc->valueNames[j]);
}
free((void *)desc->valueNames);
}
}
free((void *)m_descriptor.parameters);
for (unsigned int i = 0; i < m_descriptor.programCount; ++i) {
free((void *)m_descriptor.programs[i]);
}
free((void *)m_descriptor.programs);
if (m_adapterMap) {
m_adapterMap->erase(&m_descriptor);
if (m_adapterMap->empty()) {
delete m_adapterMap;
m_adapterMap = 0;
}
}
}
PluginAdapterBase::Impl *
PluginAdapterBase::Impl::lookupAdapter(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::lookupAdapter(" << handle << ")" << std::endl;
#endif
if (!m_adapterMap) return 0;
AdapterMap::const_iterator i = m_adapterMap->find(handle);
if (i == m_adapterMap->end()) return 0;
return i->second;
}
VampPluginHandle
PluginAdapterBase::Impl::vampInstantiate(const VampPluginDescriptor *desc,
float inputSampleRate)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << ")" << std::endl;
#endif
if (!m_adapterMap) {
m_adapterMap = new AdapterMap();
}
if (m_adapterMap->find(desc) == m_adapterMap->end()) {
std::cerr << "WARNING: PluginAdapterBase::Impl::vampInstantiate: Descriptor " << desc << " not in adapter map" << std::endl;
return 0;
}
Impl *adapter = (*m_adapterMap)[desc];
if (desc != &adapter->m_descriptor) return 0;
Plugin *plugin = adapter->m_base->createPlugin(inputSampleRate);
if (plugin) {
(*m_adapterMap)[plugin] = adapter;
}
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << "): returning handle " << plugin << std::endl;
#endif
return plugin;
}
void
PluginAdapterBase::Impl::vampCleanup(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampCleanup(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) {
delete ((Plugin *)handle);
return;
}
adapter->cleanup(((Plugin *)handle));
}
int
PluginAdapterBase::Impl::vampInitialise(VampPluginHandle handle,
unsigned int channels,
unsigned int stepSize,
unsigned int blockSize)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0;
bool result = ((Plugin *)handle)->initialise(channels, stepSize, blockSize);
adapter->markOutputsChanged((Plugin *)handle);
return result ? 1 : 0;
}
void
PluginAdapterBase::Impl::vampReset(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampReset(" << handle << ")" << std::endl;
#endif
((Plugin *)handle)->reset();
}
float
PluginAdapterBase::Impl::vampGetParameter(VampPluginHandle handle,
int param)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetParameter(" << handle << ", " << param << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0.0;
Plugin::ParameterList &list = adapter->m_parameters;
return ((Plugin *)handle)->getParameter(list[param].identifier);
}
void
PluginAdapterBase::Impl::vampSetParameter(VampPluginHandle handle,
int param, float value)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return;
Plugin::ParameterList &list = adapter->m_parameters;
((Plugin *)handle)->setParameter(list[param].identifier, value);
adapter->markOutputsChanged((Plugin *)handle);
}
unsigned int
PluginAdapterBase::Impl::vampGetCurrentProgram(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetCurrentProgram(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0;
Plugin::ProgramList &list = adapter->m_programs;
std::string program = ((Plugin *)handle)->getCurrentProgram();
for (unsigned int i = 0; i < list.size(); ++i) {
if (list[i] == program) return i;
}
return 0;
}
void
PluginAdapterBase::Impl::vampSelectProgram(VampPluginHandle handle,
unsigned int program)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return;
Plugin::ProgramList &list = adapter->m_programs;
((Plugin *)handle)->selectProgram(list[program]);
adapter->markOutputsChanged((Plugin *)handle);
}
unsigned int
PluginAdapterBase::Impl::vampGetPreferredStepSize(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetPreferredStepSize(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getPreferredStepSize();
}
unsigned int
PluginAdapterBase::Impl::vampGetPreferredBlockSize(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetPreferredBlockSize(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getPreferredBlockSize();
}
unsigned int
PluginAdapterBase::Impl::vampGetMinChannelCount(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetMinChannelCount(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getMinChannelCount();
}
unsigned int
PluginAdapterBase::Impl::vampGetMaxChannelCount(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetMaxChannelCount(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getMaxChannelCount();
}
unsigned int
PluginAdapterBase::Impl::vampGetOutputCount(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetOutputCount(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
// std::cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << std::endl;
if (!adapter) return 0;
return adapter->getOutputCount((Plugin *)handle);
}
VampOutputDescriptor *
PluginAdapterBase::Impl::vampGetOutputDescriptor(VampPluginHandle handle,
unsigned int i)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetOutputDescriptor(" << handle << ", " << i << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
// std::cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << std::endl;
if (!adapter) return 0;
return adapter->getOutputDescriptor((Plugin *)handle, i);
}
void
PluginAdapterBase::Impl::vampReleaseOutputDescriptor(VampOutputDescriptor *desc)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampReleaseOutputDescriptor(" << desc << ")" << std::endl;
#endif
if (desc->identifier) free((void *)desc->identifier);
if (desc->name) free((void *)desc->name);
if (desc->description) free((void *)desc->description);
if (desc->unit) free((void *)desc->unit);
if (desc->hasFixedBinCount && desc->binNames) {
for (unsigned int i = 0; i < desc->binCount; ++i) {
if (desc->binNames[i]) {
free((void *)desc->binNames[i]);
}
}
}
if (desc->binNames) free((void *)desc->binNames);
free((void *)desc);
}
VampFeatureList *
PluginAdapterBase::Impl::vampProcess(VampPluginHandle handle,
const float *const *inputBuffers,
int sec,
int nsec)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0;
return adapter->process((Plugin *)handle, inputBuffers, sec, nsec);
}
VampFeatureList *
PluginAdapterBase::Impl::vampGetRemainingFeatures(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetRemainingFeatures(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0;
return adapter->getRemainingFeatures((Plugin *)handle);
}
void
PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *fs)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << std::endl;
#endif
}
void
PluginAdapterBase::Impl::cleanup(Plugin *plugin)
{
if (m_fs.find(plugin) != m_fs.end()) {
size_t outputCount = 0;
if (m_pluginOutputs[plugin]) {
outputCount = m_pluginOutputs[plugin]->size();
}
VampFeatureList *list = m_fs[plugin];
for (unsigned int i = 0; i < outputCount; ++i) {
for (unsigned int j = 0; j < m_fsizes[plugin][i]; ++j) {
if (list[i].features[j].v1.label) {
free(list[i].features[j].v1.label);
}
if (list[i].features[j].v1.values) {
free(list[i].features[j].v1.values);
}
}
if (list[i].features) free(list[i].features);
}
m_fs.erase(plugin);
m_fsizes.erase(plugin);
m_fvsizes.erase(plugin);
}
if (m_pluginOutputs.find(plugin) != m_pluginOutputs.end()) {
delete m_pluginOutputs[plugin];
m_pluginOutputs.erase(plugin);
}
if (m_adapterMap) {
m_adapterMap->erase(plugin);
if (m_adapterMap->empty()) {
delete m_adapterMap;
m_adapterMap = 0;
}
}
delete ((Plugin *)plugin);
}
void
PluginAdapterBase::Impl::checkOutputMap(Plugin *plugin)
{
OutputMap::iterator i = m_pluginOutputs.find(plugin);
if (i == m_pluginOutputs.end() || !i->second) {
m_pluginOutputs[plugin] = new Plugin::OutputList
(plugin->getOutputDescriptors());
// std::cerr << "PluginAdapterBase::Impl::checkOutputMap: Have " << m_pluginOutputs[plugin]->size() << " outputs for plugin " << plugin->getIdentifier() << std::endl;
}
}
void
PluginAdapterBase::Impl::markOutputsChanged(Plugin *plugin)
{
OutputMap::iterator i = m_pluginOutputs.find(plugin);
// std::cerr << "PluginAdapterBase::Impl::markOutputsChanged" << std::endl;
if (i != m_pluginOutputs.end()) {
Plugin::OutputList *list = i->second;
m_pluginOutputs.erase(i);
delete list;
}
}
unsigned int
PluginAdapterBase::Impl::getOutputCount(Plugin *plugin)
{
checkOutputMap(plugin);
return m_pluginOutputs[plugin]->size();
}
VampOutputDescriptor *
PluginAdapterBase::Impl::getOutputDescriptor(Plugin *plugin,
unsigned int i)
{
checkOutputMap(plugin);
Plugin::OutputDescriptor &od =
(*m_pluginOutputs[plugin])[i];
VampOutputDescriptor *desc = (VampOutputDescriptor *)
malloc(sizeof(VampOutputDescriptor));
desc->identifier = strdup(od.identifier.c_str());
desc->name = strdup(od.name.c_str());
desc->description = strdup(od.description.c_str());
desc->unit = strdup(od.unit.c_str());
desc->hasFixedBinCount = od.hasFixedBinCount;
desc->binCount = od.binCount;
if (od.hasFixedBinCount && od.binCount > 0
// We would like to do "&& !od.binNames.empty()" here -- but we
// can't, because it will crash older versions of the host adapter
// which try to copy the names across whenever the bin count is
// non-zero, regardless of whether they exist or not
) {
desc->binNames = (const char **)
malloc(od.binCount * sizeof(const char *));
for (unsigned int i = 0; i < od.binCount; ++i) {
if (i < od.binNames.size()) {
desc->binNames[i] = strdup(od.binNames[i].c_str());
} else {
desc->binNames[i] = 0;
}
}
} else {
desc->binNames = 0;
}
desc->hasKnownExtents = od.hasKnownExtents;
desc->minValue = od.minValue;
desc->maxValue = od.maxValue;
desc->isQuantized = od.isQuantized;
desc->quantizeStep = od.quantizeStep;
switch (od.sampleType) {
case Plugin::OutputDescriptor::OneSamplePerStep:
desc->sampleType = vampOneSamplePerStep; break;
case Plugin::OutputDescriptor::FixedSampleRate:
desc->sampleType = vampFixedSampleRate; break;
case Plugin::OutputDescriptor::VariableSampleRate:
desc->sampleType = vampVariableSampleRate; break;
}
desc->sampleRate = od.sampleRate;
desc->hasDuration = od.hasDuration;
return desc;
}
VampFeatureList *
PluginAdapterBase::Impl::process(Plugin *plugin,
const float *const *inputBuffers,
int sec, int nsec)
{
// std::cerr << "PluginAdapterBase::Impl::process" << std::endl;
RealTime rt(sec, nsec);
checkOutputMap(plugin);
return convertFeatures(plugin, plugin->process(inputBuffers, rt));
}
VampFeatureList *
PluginAdapterBase::Impl::getRemainingFeatures(Plugin *plugin)
{
// std::cerr << "PluginAdapterBase::Impl::getRemainingFeatures" << std::endl;
checkOutputMap(plugin);
return convertFeatures(plugin, plugin->getRemainingFeatures());
}
VampFeatureList *
PluginAdapterBase::Impl::convertFeatures(Plugin *plugin,
const Plugin::FeatureSet &features)
{
int lastN = -1;
int outputCount = 0;
if (m_pluginOutputs[plugin]) outputCount = m_pluginOutputs[plugin]->size();
resizeFS(plugin, outputCount);
VampFeatureList *fs = m_fs[plugin];
// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: sizeof(Feature) == " << sizeof(Plugin::Feature) << ", sizeof(VampFeature) == " << sizeof(VampFeature) << ", sizeof(VampFeatureList) == " << sizeof(VampFeatureList) << std::endl;
for (Plugin::FeatureSet::const_iterator fi = features.begin();
fi != features.end(); ++fi) {
int n = fi->first;
// std::cerr << "PluginAdapterBase::Impl::convertFeatures: n = " << n << std::endl;
if (n >= int(outputCount)) {
std::cerr << "WARNING: PluginAdapterBase::Impl::convertFeatures: Too many outputs from plugin (" << n+1 << ", only should be " << outputCount << ")" << std::endl;
continue;
}
if (n > lastN + 1) {
for (int i = lastN + 1; i < n; ++i) {
fs[i].featureCount = 0;
}
}
const Plugin::FeatureList &fl = fi->second;
size_t sz = fl.size();
if (sz > m_fsizes[plugin][n]) resizeFL(plugin, n, sz);
fs[n].featureCount = sz;
for (size_t j = 0; j < sz; ++j) {
// std::cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << std::endl;
VampFeature *feature = &fs[n].features[j].v1;
feature->hasTimestamp = fl[j].hasTimestamp;
feature->sec = fl[j].timestamp.sec;
feature->nsec = fl[j].timestamp.nsec;
feature->valueCount = fl[j].values.size();
VampFeatureV2 *v2 = &fs[n].features[j + sz].v2;
v2->hasDuration = fl[j].hasDuration;
v2->durationSec = fl[j].duration.sec;
v2->durationNsec = fl[j].duration.nsec;
if (feature->label) free(feature->label);
if (fl[j].label.empty()) {
feature->label = 0;
} else {
feature->label = strdup(fl[j].label.c_str());
}
if (feature->valueCount > m_fvsizes[plugin][n][j]) {
resizeFV(plugin, n, j, feature->valueCount);
}
for (unsigned int k = 0; k < feature->valueCount; ++k) {
// std::cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << std::endl;
feature->values[k] = fl[j].values[k];
}
}
lastN = n;
}
if (lastN == -1) return 0;
if (int(outputCount) > lastN + 1) {
for (int i = lastN + 1; i < int(outputCount); ++i) {
fs[i].featureCount = 0;
}
}
// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: have " << outputCount << " outputs" << std::endl;
// for (int i = 0; i < outputCount; ++i) {
// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: output " << i << " has " << fs[i].featureCount << " features" << std::endl;
// }
return fs;
}
void
PluginAdapterBase::Impl::resizeFS(Plugin *plugin, int n)
{
// std::cerr << "PluginAdapterBase::Impl::resizeFS(" << plugin << ", " << n << ")" << std::endl;
int i = m_fsizes[plugin].size();
if (i >= n) return;
// std::cerr << "resizing from " << i << std::endl;
m_fs[plugin] = (VampFeatureList *)realloc
(m_fs[plugin], n * sizeof(VampFeatureList));
while (i < n) {
m_fs[plugin][i].featureCount = 0;
m_fs[plugin][i].features = 0;
m_fsizes[plugin].push_back(0);
m_fvsizes[plugin].push_back(std::vector<size_t>());
i++;
}
}
void
PluginAdapterBase::Impl::resizeFL(Plugin *plugin, int n, size_t sz)
{
// std::cerr << "PluginAdapterBase::Impl::resizeFL(" << plugin << ", " << n << ", "
// << sz << ")" << std::endl;
size_t i = m_fsizes[plugin][n];
if (i >= sz) return;
// std::cerr << "resizing from " << i << std::endl;
m_fs[plugin][n].features = (VampFeatureUnion *)realloc
(m_fs[plugin][n].features, 2 * sz * sizeof(VampFeatureUnion));
while (m_fsizes[plugin][n] < sz) {
m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.hasTimestamp = 0;
m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.valueCount = 0;
m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.values = 0;
m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.label = 0;
m_fs[plugin][n].features[m_fsizes[plugin][n] + sz].v2.hasDuration = 0;
m_fvsizes[plugin][n].push_back(0);
m_fsizes[plugin][n]++;
}
}
void
PluginAdapterBase::Impl::resizeFV(Plugin *plugin, int n, int j, size_t sz)
{
// std::cerr << "PluginAdapterBase::Impl::resizeFV(" << plugin << ", " << n << ", "
// << j << ", " << sz << ")" << std::endl;
size_t i = m_fvsizes[plugin][n][j];
if (i >= sz) return;
// std::cerr << "resizing from " << i << std::endl;
m_fs[plugin][n].features[j].v1.values = (float *)realloc
(m_fs[plugin][n].features[j].v1.values, sz * sizeof(float));
m_fvsizes[plugin][n][j] = sz;
}
PluginAdapterBase::Impl::AdapterMap *
PluginAdapterBase::Impl::m_adapterMap = 0;
}
_VAMP_SDK_PLUGSPACE_END(PluginAdapter.cpp)

View file

@ -0,0 +1,252 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
/*
This is a modified version of a source file from the
Rosegarden MIDI and audio sequencer and notation editor.
This file copyright 2000-2006 Chris Cannam.
Relicensed by the author as detailed above.
*/
#include <iostream>
#if (__GNUC__ < 3)
#include <strstream>
#define stringstream strstream
#else
#include <sstream>
#endif
using std::cerr;
using std::endl;
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <vamp-sdk/RealTime.h>
_VAMP_SDK_PLUGSPACE_BEGIN(RealTime.cpp)
namespace Vamp {
// A RealTime consists of two ints that must be at least 32 bits each.
// A signed 32-bit int can store values exceeding +/- 2 billion. This
// means we can safely use our lower int for nanoseconds, as there are
// 1 billion nanoseconds in a second and we need to handle double that
// because of the implementations of addition etc that we use.
//
// The maximum valid RealTime on a 32-bit system is somewhere around
// 68 years: 999999999 nanoseconds longer than the classic Unix epoch.
#define ONE_BILLION 1000000000
RealTime::RealTime(int s, int n) :
sec(s), nsec(n)
{
if (sec == 0) {
while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
} else if (sec < 0) {
while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
while (nsec > 0) { nsec -= ONE_BILLION; ++sec; }
} else {
while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
while (nsec < 0) { nsec += ONE_BILLION; --sec; }
}
}
RealTime
RealTime::fromSeconds(double sec)
{
return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5));
}
RealTime
RealTime::fromMilliseconds(int msec)
{
return RealTime(msec / 1000, (msec % 1000) * 1000000);
}
#ifndef _WIN32
RealTime
RealTime::fromTimeval(const struct timeval &tv)
{
return RealTime(tv.tv_sec, tv.tv_usec * 1000);
}
#endif
std::ostream &operator<<(std::ostream &out, const RealTime &rt)
{
if (rt < RealTime::zeroTime) {
out << "-";
} else {
out << " ";
}
int s = (rt.sec < 0 ? -rt.sec : rt.sec);
int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec);
out << s << ".";
int nn(n);
if (nn == 0) out << "00000000";
else while (nn < (ONE_BILLION / 10)) {
out << "0";
nn *= 10;
}
out << n << "R";
return out;
}
std::string
RealTime::toString() const
{
std::stringstream out;
out << *this;
#if (__GNUC__ < 3)
out << std::ends;
#endif
std::string s = out.str();
// remove trailing R
return s.substr(0, s.length() - 1);
}
std::string
RealTime::toText(bool fixedDp) const
{
if (*this < RealTime::zeroTime) return "-" + (-*this).toText();
std::stringstream out;
if (sec >= 3600) {
out << (sec / 3600) << ":";
}
if (sec >= 60) {
out << (sec % 3600) / 60 << ":";
}
if (sec >= 10) {
out << ((sec % 60) / 10);
}
out << (sec % 10);
int ms = msec();
if (ms != 0) {
out << ".";
out << (ms / 100);
ms = ms % 100;
if (ms != 0) {
out << (ms / 10);
ms = ms % 10;
} else if (fixedDp) {
out << "0";
}
if (ms != 0) {
out << ms;
} else if (fixedDp) {
out << "0";
}
} else if (fixedDp) {
out << ".000";
}
#if (__GNUC__ < 3)
out << std::ends;
#endif
std::string s = out.str();
return s;
}
RealTime
RealTime::operator/(int d) const
{
int secdiv = sec / d;
int secrem = sec % d;
double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d;
return RealTime(secdiv, int(nsecdiv + 0.5));
}
double
RealTime::operator/(const RealTime &r) const
{
double lTotal = double(sec) * ONE_BILLION + double(nsec);
double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec);
if (rTotal == 0) return 0.0;
else return lTotal/rTotal;
}
long
RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate)
{
if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
double s = time.sec + double(time.nsec + 1) / 1000000000.0;
return long(s * sampleRate);
}
RealTime
RealTime::frame2RealTime(long frame, unsigned int sampleRate)
{
if (frame < 0) return -frame2RealTime(-frame, sampleRate);
RealTime rt;
rt.sec = frame / long(sampleRate);
frame -= rt.sec * long(sampleRate);
rt.nsec = (int)(((double(frame) * 1000000.0) / sampleRate) * 1000.0);
return rt;
}
const RealTime RealTime::zeroTime(0,0);
}
_VAMP_SDK_PLUGSPACE_END(RealTime.cpp)

View file

@ -0,0 +1,47 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_HOSTSDK_PLUGIN_H_
#define _VAMP_HOSTSDK_PLUGIN_H_
// Do not include vamp-sdk/Plugin.h directly from host code. Always
// use this header instead.
#include "hostguard.h"
#include <vamp-sdk/Plugin.h>
#endif

View file

@ -0,0 +1,47 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_HOSTSDK_PLUGIN_BASE_H_
#define _VAMP_HOSTSDK_PLUGIN_BASE_H_
// Do not include vamp-sdk/PluginBase.h directly from host code.
// Always use this header instead.
#include "hostguard.h"
#include <vamp-sdk/PluginBase.h>
#endif

View file

@ -0,0 +1,194 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL.
This file by Mark Levy and Chris Cannam, Copyright 2007-2008 QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
#define _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
#include "hostguard.h"
#include "PluginWrapper.h"
_VAMP_SDK_HOSTSPACE_BEGIN(PluginBufferingAdapter.h)
namespace Vamp {
namespace HostExt {
/**
* \class PluginBufferingAdapter PluginBufferingAdapter.h <vamp-hostsdk/PluginBufferingAdapter.h>
*
* PluginBufferingAdapter is a Vamp plugin adapter that allows plugins
* to be used by a host supplying an audio stream in non-overlapping
* buffers of arbitrary size.
*
* A host using PluginBufferingAdapter may ignore the preferred step
* and block size reported by the plugin, and still expect the plugin
* to run. The value of blockSize and stepSize passed to initialise
* should be the size of the buffer which the host will supply; the
* stepSize should be equal to the blockSize.
*
* If the internal step size used for the plugin differs from that
* supplied by the host, the adapter will modify the sample type and
* rate specifications for the plugin outputs appropriately, and set
* timestamps on the output features for outputs that formerly used a
* different sample rate specification. This is necessary in order to
* obtain correct time stamping.
*
* In other respects, the PluginBufferingAdapter behaves identically
* to the plugin that it wraps. The wrapped plugin will be deleted
* when the wrapper is deleted.
*/
class PluginBufferingAdapter : public PluginWrapper
{
public:
/**
* Construct a PluginBufferingAdapter wrapping the given plugin.
* The adapter takes ownership of the plugin, which will be
* deleted when the adapter is deleted.
*/
PluginBufferingAdapter(Plugin *plugin);
virtual ~PluginBufferingAdapter();
/**
* Return the preferred step size for this adapter.
*
* Because of the way this adapter works, its preferred step size
* will always be the same as its preferred block size. This may
* or may not be the same as the preferred step size of the
* underlying plugin, which may be obtained by calling
* getPluginPreferredStepSize().
*/
size_t getPreferredStepSize() const;
/**
* Return the preferred block size for this adapter.
*
* This may or may not be the same as the preferred block size of
* the underlying plugin, which may be obtained by calling
* getPluginPreferredBlockSize().
*
* Note that this adapter may be initialised with any block size,
* not just its supposedly preferred one.
*/
size_t getPreferredBlockSize() const;
/**
* Initialise the adapter (and therefore the plugin) for the given
* number of channels. Initialise the adapter for the given step
* and block size, which must be equal.
*
* The step and block size used for the underlying plugin will
* depend on its preferences, or any values previously passed to
* setPluginStepSize and setPluginBlockSize.
*/
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
/**
* Return the preferred step size of the plugin wrapped by this
* adapter.
*
* This is included mainly for informational purposes. This value
* is not likely to be a valid step size for the adapter itself,
* and it is not usually of any use in interpreting the results
* (because the adapter re-writes OneSamplePerStep outputs to
* FixedSampleRate so that the hop size no longer needs to be
* known beforehand in order to interpret them).
*/
size_t getPluginPreferredStepSize() const;
/**
* Return the preferred block size of the plugin wrapped by this
* adapter.
*
* This is included mainly for informational purposes.
*/
size_t getPluginPreferredBlockSize() const;
/**
* Set the step size that will be used for the underlying plugin
* when initialise() is called. If this is not set, the plugin's
* own preferred step size will be used. You will not usually
* need to call this function. If you do call it, it must be
* before the first call to initialise().
*/
void setPluginStepSize(size_t stepSize);
/**
* Set the block size that will be used for the underlying plugin
* when initialise() is called. If this is not set, the plugin's
* own preferred block size will be used. You will not usually
* need to call this function. If you do call it, it must be
* before the first call to initialise().
*/
void setPluginBlockSize(size_t blockSize);
/**
* Return the step and block sizes that were actually used when
* initialising the underlying plugin.
*
* This is included mainly for informational purposes. You will
* not usually need to call this function. If this is called
* before initialise(), it will return 0 for both values. If it
* is called after a failed call to initialise(), it will return
* the values that were used in the failed call to the plugin's
* initialise() function.
*/
void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
void setParameter(std::string, float);
void selectProgram(std::string);
OutputList getOutputDescriptors() const;
void reset();
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures();
protected:
class Impl;
Impl *m_impl;
};
}
}
_VAMP_SDK_HOSTSPACE_END(PluginBufferingAdapter.h)
#endif

View file

@ -37,14 +37,17 @@
#ifndef _VAMP_PLUGIN_CHANNEL_ADAPTER_H_
#define _VAMP_PLUGIN_CHANNEL_ADAPTER_H_
#include "hostguard.h"
#include "PluginWrapper.h"
_VAMP_SDK_HOSTSPACE_BEGIN(PluginChannelAdapter.h)
namespace Vamp {
namespace HostExt {
/**
* \class PluginChannelAdapter PluginChannelAdapter.h <vamp-sdk/hostext/PluginChannelAdapter.h>
* \class PluginChannelAdapter PluginChannelAdapter.h <vamp-hostsdk/PluginChannelAdapter.h>
*
* PluginChannelAdapter is a Vamp plugin adapter that implements a
* policy for management of plugins that expect a different number of
@ -109,13 +112,29 @@ namespace HostExt {
class PluginChannelAdapter : public PluginWrapper
{
public:
PluginChannelAdapter(Plugin *plugin); // I take ownership of plugin
/**
* Construct a PluginChannelAdapter wrapping the given plugin.
* The adapter takes ownership of the plugin, which will be
* deleted when the adapter is deleted.
*/
PluginChannelAdapter(Plugin *plugin);
virtual ~PluginChannelAdapter();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
/**
* Call process(), providing interleaved audio data with the
* number of channels passed to initialise(). The adapter will
* de-interleave into temporary buffers as appropriate before
* calling process().
*
* \note This function was introduced in version 1.4 of the Vamp
* plugin SDK.
*/
FeatureSet processInterleaved(const float *inputBuffer, RealTime timestamp);
protected:
class Impl;
Impl *m_impl;
@ -125,4 +144,6 @@ protected:
}
_VAMP_SDK_HOSTSPACE_END(PluginChannelAdapter.h)
#endif

View file

@ -0,0 +1,123 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_HOST_ADAPTER_H_
#define _VAMP_PLUGIN_HOST_ADAPTER_H_
#include "hostguard.h"
#include "Plugin.h"
#include <vamp/vamp.h>
#include <vector>
_VAMP_SDK_HOSTSPACE_BEGIN(PluginHostAdapter.h)
namespace Vamp {
/**
* \class PluginHostAdapter PluginHostAdapter.h <vamp-hostsdk/PluginHostAdapter.h>
*
* PluginHostAdapter is a wrapper class that a Vamp host can use to
* make the C-language VampPluginDescriptor object appear as a C++
* Vamp::Plugin object.
*
* The Vamp API is defined in vamp/vamp.h as a C API. The C++ objects
* used for convenience by plugins and hosts actually communicate
* using the C low-level API, but the details of this communication
* are handled seamlessly by the Vamp SDK implementation provided the
* plugin and host use the proper C++ wrapper objects.
*
* See also PluginAdapter, the plugin-side wrapper that makes a C++
* plugin object available using the C query API.
*/
class PluginHostAdapter : public Plugin
{
public:
PluginHostAdapter(const VampPluginDescriptor *descriptor,
float inputSampleRate);
virtual ~PluginHostAdapter();
static std::vector<std::string> getPluginPath();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
InputDomain getInputDomain() const;
unsigned int getVampApiVersion() const;
std::string getIdentifier() const;
std::string getName() const;
std::string getDescription() const;
std::string getMaker() const;
int getPluginVersion() const;
std::string getCopyright() const;
ParameterList getParameterDescriptors() const;
float getParameter(std::string) const;
void setParameter(std::string, float);
ProgramList getPrograms() const;
std::string getCurrentProgram() const;
void selectProgram(std::string);
size_t getPreferredStepSize() const;
size_t getPreferredBlockSize() const;
size_t getMinChannelCount() const;
size_t getMaxChannelCount() const;
OutputList getOutputDescriptors() const;
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures();
protected:
void convertFeatures(VampFeatureList *, FeatureSet &);
const VampPluginDescriptor *m_descriptor;
VampPluginHandle m_handle;
};
}
_VAMP_SDK_HOSTSPACE_END(PluginHostAdapter.h)
#endif

View file

@ -37,14 +37,17 @@
#ifndef _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_
#define _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_
#include "hostguard.h"
#include "PluginWrapper.h"
_VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.h)
namespace Vamp {
namespace HostExt {
/**
* \class PluginInputDomainAdapter PluginInputDomainAdapter.h <vamp-sdk/hostext/PluginInputDomainAdapter.h>
* \class PluginInputDomainAdapter PluginInputDomainAdapter.h <vamp-hostsdk/PluginInputDomainAdapter.h>
*
* PluginInputDomainAdapter is a Vamp plugin adapter that converts
* time-domain input into frequency-domain input for plugins that need
@ -79,7 +82,12 @@ namespace HostExt {
class PluginInputDomainAdapter : public PluginWrapper
{
public:
PluginInputDomainAdapter(Plugin *plugin); // I take ownership of plugin
/**
* Construct a PluginInputDomainAdapter wrapping the given plugin.
* The adapter takes ownership of the plugin, which will be
* deleted when the adapter is deleted.
*/
PluginInputDomainAdapter(Plugin *plugin);
virtual ~PluginInputDomainAdapter();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
@ -91,6 +99,29 @@ public:
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
/**
* Return the amount by which the timestamps supplied to process()
* are being incremented when they are passed to the plugin's own
* process() implementation.
*
* The Vamp API mandates that the timestamp passed to the plugin
* for time-domain input should be the time of the first sample in
* the block, but the timestamp passed for frequency-domain input
* should be the timestamp of the centre of the block.
*
* The PluginInputDomainAdapter adjusts its timestamps properly so
* that the plugin receives correct times, but in some
* circumstances (such as for establishing the correct timing of
* implicitly-timed features, i.e. features without their own
* timestamps) the host may need to be aware that this adjustment
* is taking place.
*
* If the plugin requires time-domain input, this function will
* return zero. The result of calling this function before
* initialise() has been called is undefined.
*/
RealTime getTimestampAdjustment() const;
protected:
class Impl;
Impl *m_impl;
@ -100,4 +131,6 @@ protected:
}
_VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.h)
#endif

View file

@ -41,8 +41,11 @@
#include <string>
#include <map>
#include "hostguard.h"
#include "PluginWrapper.h"
_VAMP_SDK_HOSTSPACE_BEGIN(PluginLoader.h)
namespace Vamp {
class Plugin;
@ -50,7 +53,7 @@ class Plugin;
namespace HostExt {
/**
* \class PluginLoader PluginLoader.h <vamp-sdk/hostext/PluginLoader.h>
* \class PluginLoader PluginLoader.h <vamp-hostsdk/PluginLoader.h>
*
* Vamp::HostExt::PluginLoader is a convenience class for discovering
* and loading Vamp plugins using the typical plugin-path, library
@ -234,5 +237,7 @@ protected:
}
_VAMP_SDK_HOSTSPACE_END(PluginLoader.h)
#endif

View file

@ -0,0 +1,197 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2008 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_SUMMARISING_ADAPTER_H_
#define _VAMP_PLUGIN_SUMMARISING_ADAPTER_H_
#include "hostguard.h"
#include "PluginWrapper.h"
#include <set>
_VAMP_SDK_HOSTSPACE_BEGIN(PluginSummarisingAdapter.h)
namespace Vamp {
namespace HostExt {
/**
* \class PluginSummarisingAdapter PluginSummarisingAdapter.h <vamp-hostsdk/PluginSummarisingAdapter.h>
*
* PluginSummarisingAdapter is a Vamp plugin adapter that provides
* summarisation methods such as mean and median averages of output
* features, for use in any context where an available plugin produces
* individual values but the result that is actually needed is some
* sort of aggregate.
*
* To make use of PluginSummarisingAdapter, the host should configure,
* initialise and run the plugin through the adapter interface just as
* normal. Then, after the process and getRemainingFeatures methods
* have been properly called and processing is complete, the host may
* call getSummaryForOutput or getSummaryForAllOutputs to obtain
* summarised features: averages, maximum values, etc, depending on
* the SummaryType passed to the function.
*
* By default PluginSummarisingAdapter calculates a single summary of
* each output's feature across the whole duration of processed audio.
* A host needing summaries of sub-segments of the whole audio may
* call setSummarySegmentBoundaries before retrieving the summaries,
* providing a list of times such that one summary will be provided
* for each segment between two consecutive times.
*
* PluginSummarisingAdapter is straightforward rather than fast. It
* calculates all of the summary types for all outputs always, and
* then returns only the ones that are requested. It is designed on
* the basis that, for most features, summarising and storing
* summarised results is far cheaper than calculating the results in
* the first place. If this is not true for your particular feature,
* PluginSummarisingAdapter may not be the best approach for you.
*
* \note This class was introduced in version 2.0 of the Vamp plugin SDK.
*/
class PluginSummarisingAdapter : public PluginWrapper
{
public:
/**
* Construct a PluginSummarisingAdapter wrapping the given plugin.
* The adapter takes ownership of the plugin, which will be
* deleted when the adapter is deleted.
*/
PluginSummarisingAdapter(Plugin *plugin);
virtual ~PluginSummarisingAdapter();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures();
typedef std::set<RealTime> SegmentBoundaries;
/**
* Specify a series of segment boundaries, such that one summary
* will be returned for each of the contiguous intra-boundary
* segments. This function must be called before
* getSummaryForOutput or getSummaryForAllOutputs.
*
* Note that you cannot retrieve results with multiple different
* segmentations by repeatedly calling this function followed by
* one of the getSummary functions. The summaries are all
* calculated at the first call to any getSummary function, and
* once the summaries have been calculated, they remain
* calculated.
*/
void setSummarySegmentBoundaries(const SegmentBoundaries &);
enum SummaryType {
Minimum = 0,
Maximum = 1,
Mean = 2,
Median = 3,
Mode = 4,
Sum = 5,
Variance = 6,
StandardDeviation = 7,
Count = 8,
UnknownSummaryType = 999
};
/**
* AveragingMethod indicates how the adapter should handle
* average-based summaries of features whose results are not
* equally spaced in time.
*
* If SampleAverage is specified, summary types based on averages
* will be calculated by treating each result individually without
* regard to its time: for example, the mean will be the sum of
* all values divided by the number of values.
*
* If ContinuousTimeAverage is specified, each feature will be
* considered to have a duration, either as specified in the
* feature's duration field, or until the following feature: thus,
* for example, the mean will be the sum of the products of values
* and durations, divided by the total duration.
*
* Although SampleAverage is useful for many types of feature,
* ContinuousTimeAverage is essential for some situations, for
* example finding the result that spans the largest proportion of
* the input given a feature that emits a new result only when the
* value changes (the modal value integrated over time).
*/
enum AveragingMethod {
SampleAverage = 0,
ContinuousTimeAverage = 1,
};
/**
* Return summaries of the features that were returned on the
* given output, using the given SummaryType and AveragingMethod.
*
* The plugin must have been fully run (process() and
* getRemainingFeatures() calls all made as appropriate) before
* this function is called.
*/
FeatureList getSummaryForOutput(int output,
SummaryType type,
AveragingMethod method = SampleAverage);
/**
* Return summaries of the features that were returned on all of
* the plugin's outputs, using the given SummaryType and
* AveragingMethod.
*
* The plugin must have been fully run (process() and
* getRemainingFeatures() calls all made as appropriate) before
* this function is called.
*/
FeatureSet getSummaryForAllOutputs(SummaryType type,
AveragingMethod method = SampleAverage);
protected:
class Impl;
Impl *m_impl;
};
}
}
_VAMP_SDK_HOSTSPACE_END(PluginSummarisingAdapter.h)
#endif

View file

@ -37,14 +37,17 @@
#ifndef _VAMP_PLUGIN_WRAPPER_H_
#define _VAMP_PLUGIN_WRAPPER_H_
#include <vamp-sdk/Plugin.h>
#include "hostguard.h"
#include <vamp-hostsdk/Plugin.h>
_VAMP_SDK_HOSTSPACE_BEGIN(PluginWrapper.h)
namespace Vamp {
namespace HostExt {
/**
* \class PluginWrapper PluginWrapper.h <vamp-sdk/hostext/PluginWrapper.h>
* \class PluginWrapper PluginWrapper.h <vamp-hostsdk/PluginWrapper.h>
*
* PluginWrapper is a simple base class for adapter plugins. It takes
* a pointer to a "to be wrapped" Vamp plugin on construction, and
@ -94,6 +97,30 @@ public:
FeatureSet getRemainingFeatures();
/**
* Return a pointer to the plugin wrapper of type WrapperType
* surrounding this wrapper's plugin, if present.
*
* This is useful in situations where a plugin is wrapped by
* multiple different wrappers (one inside another) and the host
* wants to call some wrapper-specific function on one of the
* layers without having to care about the order in which they are
* wrapped. For example, the plugin returned by
* PluginLoader::loadPlugin may have more than one wrapper; if the
* host wanted to query or fine-tune some property of one of them,
* it would be hard to do so without knowing the order of the
* wrappers. This function therefore gives direct access to the
* wrapper of a particular type.
*/
template <typename WrapperType>
WrapperType *getWrapper() {
WrapperType *w = dynamic_cast<WrapperType *>(this);
if (w) return w;
PluginWrapper *pw = dynamic_cast<PluginWrapper *>(m_plugin);
if (pw) return pw->getWrapper<WrapperType>();
return 0;
}
protected:
PluginWrapper(Plugin *plugin); // I take ownership of plugin
Plugin *m_plugin;
@ -103,4 +130,6 @@ protected:
}
_VAMP_SDK_HOSTSPACE_END(PluginWrapper.h)
#endif

View file

@ -0,0 +1,46 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_HOSTSDK_REALTIME_H_
#define _VAMP_HOSTSDK_REALTIME_H_
// Do not include vamp-sdk/RealTime.h directly from host code. Always
// use this header instead.
#include "hostguard.h"
#include <vamp-sdk/RealTime.h>
#endif

View file

@ -0,0 +1,69 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_HOSTSDK_HOSTGUARD_H_
#define _VAMP_HOSTSDK_HOSTGUARD_H_
#ifdef _VAMP_IN_PLUGINSDK
#error You have included headers from both vamp-sdk and vamp-hostsdk in the same source file. Please include only vamp-sdk headers in plugin code, and only vamp-hostsdk headers in host code.
#else
#define _VAMP_IN_HOSTSDK
#ifdef _VAMP_NO_HOST_NAMESPACE
#define _VAMP_SDK_HOSTSPACE_BEGIN(h)
#define _VAMP_SDK_HOSTSPACE_END(h)
#define _VAMP_SDK_PLUGSPACE_BEGIN(h)
#define _VAMP_SDK_PLUGSPACE_END(h)
#else
#define _VAMP_SDK_HOSTSPACE_BEGIN(h) \
namespace _VampHost {
#define _VAMP_SDK_HOSTSPACE_END(h) \
} \
using namespace _VampHost;
#define _VAMP_SDK_PLUGSPACE_BEGIN(h) \
namespace _VampHost {
#define _VAMP_SDK_PLUGSPACE_END(h) \
} \
using namespace _VampHost;
#endif
#endif
#endif

View file

@ -0,0 +1,53 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_HOSTSDK_SINGLE_INCLUDE_H_
#define _VAMP_HOSTSDK_SINGLE_INCLUDE_H_
#include "PluginBase.h"
#include "PluginBufferingAdapter.h"
#include "PluginChannelAdapter.h"
#include "Plugin.h"
#include "PluginHostAdapter.h"
#include "PluginInputDomainAdapter.h"
#include "PluginLoader.h"
#include "PluginSummarisingAdapter.h"
#include "PluginWrapper.h"
#include "RealTime.h"
#endif

View file

@ -34,16 +34,19 @@
authorization.
*/
#ifndef _VAMP_PLUGIN_H_
#define _VAMP_PLUGIN_H_
#include "PluginBase.h"
#include "RealTime.h"
#ifndef _VAMP_SDK_PLUGIN_H_
#define _VAMP_SDK_PLUGIN_H_
#include <string>
#include <vector>
#include <map>
#include "PluginBase.h"
#include "RealTime.h"
#include "plugguard.h"
_VAMP_SDK_PLUGSPACE_BEGIN(Plugin.h)
namespace Vamp {
/**
@ -200,7 +203,7 @@ public:
/**
* The name of the output, in computer-usable form. Should be
* reasonably short and without whitespace or punctuation, using
* the characters [a-zA-Z0-9_] only.
* the characters [a-zA-Z0-9_-] only.
* Example: "zero_crossing_count"
*/
std::string identifier;
@ -304,6 +307,16 @@ public:
* this to zero if that behaviour is not desired.
*/
float sampleRate;
/**
* True if the returned results for this output are known to
* have a duration field.
*/
bool hasDuration;
OutputDescriptor() : // defaults for mandatory non-class-type members
hasFixedBinCount(false), hasKnownExtents(false), isQuantized(false),
sampleType(OneSamplePerStep), hasDuration(false) { }
};
typedef std::vector<OutputDescriptor> OutputList;
@ -319,17 +332,34 @@ public:
{
/**
* True if an output feature has its own timestamp. This is
* mandatory if the output has VariableSampleRate, and is
* likely to be disregarded otherwise.
* mandatory if the output has VariableSampleRate, optional if
* the output has FixedSampleRate, and unused if the output
* has OneSamplePerStep.
*/
bool hasTimestamp;
/**
* Timestamp of the output feature. This is mandatory if the
* output has VariableSampleRate, and is likely to be
* disregarded otherwise. Undefined if hasTimestamp is false.
* output has VariableSampleRate or if the output has
* FixedSampleRate and hasTimestamp is true, and unused
* otherwise.
*/
RealTime timestamp;
/**
* True if an output feature has a specified duration. This
* is optional if the output has VariableSampleRate or
* FixedSampleRate, and and unused if the output has
* OneSamplePerStep.
*/
bool hasDuration;
/**
* Duration of the output feature. This is mandatory if the
* output has VariableSampleRate or FixedSampleRate and
* hasDuration is true, and unused otherwise.
*/
RealTime duration;
/**
* Results for a single sample of this feature. If the output
@ -342,9 +372,13 @@ public:
* Label for the sample of this feature.
*/
std::string label;
Feature() : // defaults for mandatory non-class-type members
hasTimestamp(false), hasDuration(false) { }
};
typedef std::vector<Feature> FeatureList;
typedef std::map<int, FeatureList> FeatureSet; // key is output no
/**
@ -353,9 +387,9 @@ public:
* If the plugin's inputDomain is TimeDomain, inputBuffers will
* point to one array of floats per input channel, and each of
* these arrays will contain blockSize consecutive audio samples
* (the host will zero-pad as necessary). The timestamp will be
* the real time in seconds of the start of the supplied block of
* samples.
* (the host will zero-pad as necessary). The timestamp in this
* case will be the real time in seconds of the start of the
* supplied block of samples.
*
* If the plugin's inputDomain is FrequencyDomain, inputBuffers
* will point to one array of floats per input channel, and each
@ -399,6 +433,8 @@ protected:
}
_VAMP_SDK_PLUGSPACE_END(Plugin.h)
#endif

View file

@ -37,11 +37,13 @@
#ifndef _VAMP_PLUGIN_ADAPTER_H_
#define _VAMP_PLUGIN_ADAPTER_H_
#include <map>
#include <vamp/vamp.h>
#include "Plugin.h"
#include <map>
#include "plugguard.h"
_VAMP_SDK_PLUGSPACE_BEGIN(PluginAdapter.h)
namespace Vamp {
@ -113,5 +115,7 @@ protected:
}
_VAMP_SDK_PLUGSPACE_END(PluginAdapter.h)
#endif

View file

@ -34,13 +34,18 @@
authorization.
*/
#ifndef _VAMP_PLUGIN_BASE_H_
#define _VAMP_PLUGIN_BASE_H_
#ifndef _VAMP_SDK_PLUGIN_BASE_H_
#define _VAMP_SDK_PLUGIN_BASE_H_
#include <string>
#include <vector>
#define VAMP_SDK_VERSION "1.1"
#define VAMP_SDK_VERSION "2.0"
#define VAMP_SDK_MAJOR_VERSION 2
#define VAMP_SDK_MINOR_VERSION 0
#include "plugguard.h"
_VAMP_SDK_PLUGSPACE_BEGIN(PluginBase.h)
namespace Vamp {
@ -64,12 +69,12 @@ public:
/**
* Get the Vamp API compatibility level of the plugin.
*/
virtual unsigned int getVampApiVersion() const { return 1; }
virtual unsigned int getVampApiVersion() const { return 2; }
/**
* Get the computer-usable name of the plugin. This should be
* reasonably short and contain no whitespace or punctuation
* characters. It may only contain the characters [a-zA-Z0-9_].
* characters. It may only contain the characters [a-zA-Z0-9_-].
* This is the authoritative way for a program to identify a
* plugin within a given library.
*
@ -127,7 +132,7 @@ public:
/**
* The name of the parameter, in computer-usable form. Should
* be reasonably short, and may only contain the characters
* [a-zA-Z0-9_].
* [a-zA-Z0-9_-].
*/
std::string identifier;
@ -190,6 +195,9 @@ public:
* encoded in the names.
*/
std::vector<std::string> valueNames;
ParameterDescriptor() : // the defaults are invalid: you must set them
minValue(0), maxValue(0), defaultValue(0), isQuantized(false) { }
};
typedef std::vector<ParameterDescriptor> ParameterList;
@ -249,4 +257,6 @@ public:
}
_VAMP_SDK_PLUGSPACE_END(PluginBase.h)
#endif

View file

@ -51,6 +51,9 @@
struct timeval;
#endif
#include "plugguard.h"
_VAMP_SDK_PLUGSPACE_BEGIN(RealTime.h)
namespace Vamp {
/**
@ -158,5 +161,7 @@ struct RealTime
std::ostream &operator<<(std::ostream &out, const RealTime &rt);
}
_VAMP_SDK_PLUGSPACE_END(RealTime.h)
#endif

View file

@ -1,99 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL.
This file by Mark Levy, Copyright 2007 QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
#define _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
#include "PluginWrapper.h"
namespace Vamp {
namespace HostExt {
/**
* \class PluginBufferingAdapter PluginBufferingAdapter.h <vamp-sdk/hostext/PluginBufferingAdapter.h>
*
* PluginBufferingAdapter is a Vamp plugin adapter that allows plugins
* to be used by a host supplying an audio stream in non-overlapping
* buffers of arbitrary size.
*
* A host using PluginBufferingAdapter may ignore the preferred step
* and block size reported by the plugin, and still expect the plugin
* to run. The value of blockSize and stepSize passed to initialise
* should be the size of the buffer which the host will supply; the
* stepSize should be equal to the blockSize.
*
* If the internal step size used for the plugin differs from that
* supplied by the host, the adapter will modify the sample rate
* specifications for the plugin outputs (setting them all to
* VariableSampleRate) and set timestamps on the output features for
* outputs that formerly used a different sample rate specification.
* This is necessary in order to obtain correct time stamping.
*
* In other respects, the PluginBufferingAdapter behaves identically
* to the plugin that it wraps. The wrapped plugin will be deleted
* when the wrapper is deleted.
*/
class PluginBufferingAdapter : public PluginWrapper
{
public:
PluginBufferingAdapter(Plugin *plugin); // I take ownership of plugin
virtual ~PluginBufferingAdapter();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
size_t getPreferredStepSize() const;
OutputList getOutputDescriptors() const;
void reset();
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures();
protected:
class Impl;
Impl *m_impl;
};
}
}
#endif

View file

@ -0,0 +1,98 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_SDK_PLUGGUARD_H_
#define _VAMP_SDK_PLUGGUARD_H_
/**
* Normal usage should be:
*
* - Plugins include vamp-sdk/Plugin.h or vamp-sdk/PluginBase.h.
* These files include this header, which specifies an appropriate
* namespace for the plugin classes to avoid any risk of conflict
* with non-plugin class implementations in the host on load.
*
* - Hosts include vamp-hostsdk/Plugin.h, vamp-hostsdk/PluginBase.h,
* vamp-hostsdk/PluginHostAdapter, vamp-hostsdk/PluginLoader.h etc.
* These files include vamp-hostsdk/hostguard.h, which makes a note
* that we are in a host. A file such as vamp-hostsdk/Plugin.h
* then simply includes vamp-sdk/Plugin.h, and this guard header
* takes notice of the fact that it has been included from a host
* and leaves the plugin namespace unset.
*
* Problems will occur when a host includes files directly from the
* vamp-sdk directory. There are two reasons this might happen:
* mistake, perhaps owing to ignorance of the fact that this isn't
* allowed (particularly since it was the normal mechanism in v1 of
* the SDK); and a wish to incorporate plugin code directly into the
* host rather than having to load it.
*
* What if the host does include a vamp-sdk header by mistake? We can
* catch it if it's included before something from vamp-hostsdk. If
* it's included after something from vamp-hostsdk, it will work OK
* anyway. The remaining problem case is where nothing from
* vamp-hostsdk is included in the same file. We can't catch that.
*/
#ifndef _VAMP_IN_HOSTSDK
#define _VAMP_IN_PLUGINSDK 1
#ifdef _VAMP_NO_PLUGIN_NAMESPACE
#define _VAMP_SDK_PLUGSPACE_BEGIN(h)
#define _VAMP_SDK_PLUGSPACE_END(h)
#else
#ifdef _VAMP_PLUGIN_IN_HOST_NAMESPACE
#define _VAMP_SDK_PLUGSPACE_BEGIN(h) \
namespace _VampHost {
#define _VAMP_SDK_PLUGSPACE_END(h) \
} \
using namespace _VampHost;
#else
#define _VAMP_SDK_PLUGSPACE_BEGIN(h) \
namespace _VampPlugin {
#define _VAMP_SDK_PLUGSPACE_END(h) \
} \
using namespace _VampPlugin;
#endif
#endif
#endif
#endif

View file

@ -0,0 +1,46 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_SDK_SINGLE_INCLUDE_H_
#define _VAMP_SDK_SINGLE_INCLUDE_H_
#include "PluginBase.h"
#include "Plugin.h"
#include "RealTime.h"
#endif

View file

@ -50,7 +50,7 @@ extern "C" {
* See also the vampApiVersion field in the plugin descriptor, and the
* hostApiVersion argument to the vampGetPluginDescriptor function.
*/
#define VAMP_API_VERSION 1
#define VAMP_API_VERSION 2
/**
* C language API for Vamp plugins.
@ -160,6 +160,15 @@ typedef struct _VampOutputDescriptor
"Resolution" of result, if sampleType is vampVariableSampleRate. */
float sampleRate;
/** 1 if the returned results for this output are known to have a
duration field.
This field is new in Vamp API version 2; it must not be tested
for plugins that report an older API version in their plugin
descriptor.
*/
int hasDuration;
} VampOutputDescriptor;
typedef struct _VampFeature
@ -184,13 +193,46 @@ typedef struct _VampFeature
} VampFeature;
typedef struct _VampFeatureV2
{
/** 1 if the feature has a duration. */
int hasDuration;
/** Seconds component of duratiion. */
int durationSec;
/** Nanoseconds component of duration. */
int durationNsec;
} VampFeatureV2;
typedef union _VampFeatureUnion
{
// sizeof(featureV1) >= sizeof(featureV2) for backward compatibility
VampFeature v1;
VampFeatureV2 v2;
} VampFeatureUnion;
typedef struct _VampFeatureList
{
/** Number of features in this feature list. */
unsigned int featureCount;
/** Features in this feature list. May be NULL if featureCount is zero. */
VampFeature *features;
/** Features in this feature list. May be NULL if featureCount is
zero.
If present, this array must contain featureCount feature
structures for a Vamp API version 1 plugin, or 2*featureCount
feature unions for a Vamp API version 2 plugin.
The features returned by an API version 2 plugin must consist
of the same feature structures as in API version 1 for the
first featureCount array elements, followed by featureCount
unions that contain VampFeatureV2 structures (or NULL pointers
if no V2 feature structures are present).
*/
VampFeatureUnion *features;
} VampFeatureList;
@ -289,7 +331,7 @@ typedef struct _VampPluginDescriptor
handle, or releaseOutputDescriptor for this descriptor. Host
must call releaseOutputDescriptor after use. */
VampOutputDescriptor *(*getOutputDescriptor)(VampPluginHandle,
unsigned int);
unsigned int);
/** Destroy a descriptor for a feature output. */
void (*releaseOutputDescriptor)(VampOutputDescriptor *);
@ -312,6 +354,7 @@ typedef struct _VampPluginDescriptor
} VampPluginDescriptor;
/** Get the descriptor for a given plugin index in this library.
Return NULL if the index is outside the range of valid indices for
this plugin library.
@ -324,10 +367,16 @@ typedef struct _VampPluginDescriptor
field for its actual compatibility level, the host should be able
to do the right thing with it: use it if possible, discard it
otherwise.
This is the only symbol that a Vamp plugin actually needs to
export from its shared object; all others can be hidden. See the
accompanying documentation for notes on how to achieve this with
certain compilers.
*/
const VampPluginDescriptor *vampGetPluginDescriptor
(unsigned int hostApiVersion, unsigned int index);
/** Function pointer type for vampGetPluginDescriptor. */
typedef const VampPluginDescriptor *(*VampGetPluginDescriptorFunction)
(unsigned int, unsigned int);