upgrade VAMP SDK to latest (or newer) version

git-svn-id: svn://localhost/ardour2/branches/3.0@9030 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2011-03-02 12:38:17 +00:00
parent 3deba1921b
commit 730cdb38bc
16 changed files with 329 additions and 90 deletions

View file

@ -6,8 +6,8 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
This file by Mark Levy and Chris Cannam, Copyright 2007-2008 QMUL. This file by Mark Levy and Chris Cannam, Copyright 2007-2009 QMUL.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation
@ -39,6 +39,7 @@
#include <map> #include <map>
#include "vamp-hostsdk/PluginBufferingAdapter.h" #include "vamp-hostsdk/PluginBufferingAdapter.h"
#include "vamp-hostsdk/PluginInputDomainAdapter.h"
using std::vector; using std::vector;
using std::map; using std::map;
@ -652,6 +653,14 @@ PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
FeatureSet featureSet = m_plugin->process(m_buffers, timestamp); FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
PluginWrapper *wrapper = dynamic_cast<PluginWrapper *>(m_plugin);
RealTime adjustment;
if (wrapper) {
PluginInputDomainAdapter *ida =
wrapper->getWrapper<PluginInputDomainAdapter>();
if (ida) adjustment = ida->getTimestampAdjustment();
}
for (FeatureSet::iterator iter = featureSet.begin(); for (FeatureSet::iterator iter = featureSet.begin();
iter != featureSet.end(); ++iter) { iter != featureSet.end(); ++iter) {
@ -667,14 +676,14 @@ PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
case OutputDescriptor::OneSamplePerStep: case OutputDescriptor::OneSamplePerStep:
// use our internal timestamp, always // use our internal timestamp, always
featureList[i].timestamp = timestamp; featureList[i].timestamp = timestamp + adjustment;
featureList[i].hasTimestamp = true; featureList[i].hasTimestamp = true;
break; break;
case OutputDescriptor::FixedSampleRate: case OutputDescriptor::FixedSampleRate:
// use our internal timestamp if feature lacks one // use our internal timestamp if feature lacks one
if (!featureList[i].hasTimestamp) { if (!featureList[i].hasTimestamp) {
featureList[i].timestamp = timestamp; featureList[i].timestamp = timestamp + adjustment;
featureList[i].hasTimestamp = true; featureList[i].hasTimestamp = true;
} }
break; break;

View file

@ -6,7 +6,7 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation

View file

@ -37,8 +37,8 @@
#include "vamp-hostsdk/PluginHostAdapter.h" #include "vamp-hostsdk/PluginHostAdapter.h"
#include <cstdlib> #include <cstdlib>
#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 0 ) #if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 2 )
#error Incorrect Vamp SDK header included (not the expected 2.0 SDK) #error Unexpected version of Vamp SDK header included
#endif #endif
_VAMP_SDK_HOSTSPACE_BEGIN(PluginHostAdapter.cpp) _VAMP_SDK_HOSTSPACE_BEGIN(PluginHostAdapter.cpp)

View file

@ -6,7 +6,7 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
This file is based in part on Don Cross's public domain FFT This file is based in part on Don Cross's public domain FFT
implementation. implementation.
@ -83,11 +83,15 @@ public:
~Impl(); ~Impl();
bool initialise(size_t channels, size_t stepSize, size_t blockSize); bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
size_t getPreferredStepSize() const; size_t getPreferredStepSize() const;
size_t getPreferredBlockSize() const; size_t getPreferredBlockSize() const;
FeatureSet process(const float *const *inputBuffers, RealTime timestamp); FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
void setProcessTimestampMethod(ProcessTimestampMethod m);
ProcessTimestampMethod getProcessTimestampMethod() const;
RealTime getTimestampAdjustment() const; RealTime getTimestampAdjustment() const;
@ -95,12 +99,17 @@ protected:
Plugin *m_plugin; Plugin *m_plugin;
float m_inputSampleRate; float m_inputSampleRate;
int m_channels; int m_channels;
int m_stepSize;
int m_blockSize; int m_blockSize;
float **m_freqbuf; float **m_freqbuf;
double *m_ri; double *m_ri;
double *m_window; double *m_window;
ProcessTimestampMethod m_method;
int m_processCount;
float **m_shiftBuffers;
#ifdef HAVE_FFTW3 #ifdef HAVE_FFTW3
fftw_plan m_plan; fftw_plan m_plan;
fftw_complex *m_cbuf; fftw_complex *m_cbuf;
@ -111,6 +120,9 @@ protected:
double *ri, double *ii, double *ro, double *io); double *ri, double *ii, double *ro, double *io);
#endif #endif
FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp);
FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp);
size_t makeBlockSizeAcceptable(size_t) const; size_t makeBlockSizeAcceptable(size_t) const;
}; };
@ -131,6 +143,12 @@ PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t bl
return m_impl->initialise(channels, stepSize, blockSize); return m_impl->initialise(channels, stepSize, blockSize);
} }
void
PluginInputDomainAdapter::reset()
{
m_impl->reset();
}
Plugin::InputDomain Plugin::InputDomain
PluginInputDomainAdapter::getInputDomain() const PluginInputDomainAdapter::getInputDomain() const
{ {
@ -155,6 +173,18 @@ PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime tim
return m_impl->process(inputBuffers, timestamp); return m_impl->process(inputBuffers, timestamp);
} }
void
PluginInputDomainAdapter::setProcessTimestampMethod(ProcessTimestampMethod m)
{
m_impl->setProcessTimestampMethod(m);
}
PluginInputDomainAdapter::ProcessTimestampMethod
PluginInputDomainAdapter::getProcessTimestampMethod() const
{
return m_impl->getProcessTimestampMethod();
}
RealTime RealTime
PluginInputDomainAdapter::getTimestampAdjustment() const PluginInputDomainAdapter::getTimestampAdjustment() const
{ {
@ -166,10 +196,14 @@ PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
m_plugin(plugin), m_plugin(plugin),
m_inputSampleRate(inputSampleRate), m_inputSampleRate(inputSampleRate),
m_channels(0), m_channels(0),
m_stepSize(0),
m_blockSize(0), m_blockSize(0),
m_freqbuf(0), m_freqbuf(0),
m_ri(0), m_ri(0),
m_window(0), m_window(0),
m_method(ShiftTimestamp),
m_processCount(0),
m_shiftBuffers(0),
#ifdef HAVE_FFTW3 #ifdef HAVE_FFTW3
m_plan(0), m_plan(0),
m_cbuf(0) m_cbuf(0)
@ -184,6 +218,13 @@ PluginInputDomainAdapter::Impl::~Impl()
{ {
// the adapter will delete the plugin // the adapter will delete the plugin
if (m_shiftBuffers) {
for (int c = 0; c < m_channels; ++c) {
delete[] m_shiftBuffers[c];
}
delete[] m_shiftBuffers;
}
if (m_channels > 0) { if (m_channels > 0) {
for (int c = 0; c < m_channels; ++c) { for (int c = 0; c < m_channels; ++c) {
delete[] m_freqbuf[c]; delete[] m_freqbuf[c];
@ -215,6 +256,7 @@ PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, siz
{ {
if (m_plugin->getInputDomain() == TimeDomain) { if (m_plugin->getInputDomain() == TimeDomain) {
m_stepSize = int(stepSize);
m_blockSize = int(blockSize); m_blockSize = int(blockSize);
m_channels = int(channels); m_channels = int(channels);
@ -222,12 +264,12 @@ PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, siz
} }
if (blockSize < 2) { if (blockSize < 2) {
std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not supported" << std::endl; std::cerr << "ERROR: PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl;
return false; return false;
} }
if (blockSize & (blockSize-1)) { if (blockSize & (blockSize-1)) {
std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl; std::cerr << "ERROR: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
return false; return false;
} }
@ -251,6 +293,7 @@ PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, siz
delete[] m_window; delete[] m_window;
} }
m_stepSize = int(stepSize);
m_blockSize = int(blockSize); m_blockSize = int(blockSize);
m_channels = int(channels); m_channels = int(channels);
@ -275,9 +318,18 @@ PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, siz
m_io = new double[m_blockSize]; m_io = new double[m_blockSize];
#endif #endif
m_processCount = 0;
return m_plugin->initialise(channels, stepSize, blockSize); return m_plugin->initialise(channels, stepSize, blockSize);
} }
void
PluginInputDomainAdapter::Impl::reset()
{
m_processCount = 0;
m_plugin->reset();
}
size_t size_t
PluginInputDomainAdapter::Impl::getPreferredStepSize() const PluginInputDomainAdapter::Impl::getPreferredStepSize() const
{ {
@ -311,7 +363,7 @@ PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
{ {
if (blockSize < 2) { if (blockSize < 2) {
std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not" << std::endl std::cerr << "WARNING: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl
<< "supported, increasing from " << blockSize << " to 2" << std::endl; << "supported, increasing from " << blockSize << " to 2" << std::endl;
blockSize = 2; blockSize = 2;
@ -340,7 +392,7 @@ PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
nearest = nearest*2; nearest = nearest*2;
} }
std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl; std::cerr << "WARNING: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
blockSize = nearest; blockSize = nearest;
#endif #endif
@ -354,12 +406,26 @@ PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
{ {
if (m_plugin->getInputDomain() == TimeDomain) { if (m_plugin->getInputDomain() == TimeDomain) {
return RealTime::zeroTime; return RealTime::zeroTime;
} else if (m_method == ShiftData || m_method == NoShift) {
return RealTime::zeroTime;
} else { } else {
return RealTime::frame2RealTime return RealTime::frame2RealTime
(m_blockSize/2, int(m_inputSampleRate + 0.5)); (m_blockSize/2, int(m_inputSampleRate + 0.5));
} }
} }
void
PluginInputDomainAdapter::Impl::setProcessTimestampMethod(ProcessTimestampMethod m)
{
m_method = m;
}
PluginInputDomainAdapter::ProcessTimestampMethod
PluginInputDomainAdapter::Impl::getProcessTimestampMethod() const
{
return m_method;
}
Plugin::FeatureSet Plugin::FeatureSet
PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers, PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
RealTime timestamp) RealTime timestamp)
@ -368,53 +434,20 @@ PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
return m_plugin->process(inputBuffers, timestamp); return m_plugin->process(inputBuffers, timestamp);
} }
// The timestamp supplied should be (according to the Vamp::Plugin if (m_method == ShiftTimestamp || m_method == NoShift) {
// spec) the time of the start of the time-domain input block. return processShiftingTimestamp(inputBuffers, timestamp);
// However, we want to pass to the plugin an FFT output calculated } else {
// from the block of samples _centred_ on that timestamp. return processShiftingData(inputBuffers, timestamp);
// }
// We have two options: }
//
// 1. Buffer the input, calculating the fft of the values at the
// passed-in block minus blockSize/2 rather than starting at the
// passed-in block. So each time we call process on the plugin,
// we are passing in the same timestamp as was passed to our own
// process plugin, but not (the frequency domain representation
// of) the same set of samples. Advantages: avoids confusion in
// the host by ensuring the returned values have timestamps
// comparable with that passed in to this function (in fact this
// is pretty much essential for one-value-per-block outputs);
// consistent with hosts such as SV that deal with the
// frequency-domain transform themselves. Disadvantages: means
// making the not necessarily correct assumption that the samples
// preceding the first official block are all zero (or some other
// known value).
//
// 2. Increase the passed-in timestamps by half the blocksize. So
// when we call process, we are passing in the frequency domain
// representation of the same set of samples as passed to us, but
// with a different timestamp. Advantages: simplicity; avoids
// iffy assumption mentioned above. Disadvantages: inconsistency
// with SV in cases where stepSize != blockSize/2; potential
// confusion arising from returned timestamps being calculated
// from the adjusted input timestamps rather than the original
// ones (and inaccuracy where the returned timestamp is implied,
// as in one-value-per-block).
//
// Neither way is ideal, but I don't think either is strictly
// incorrect either. I think this is just a case where the same
// plugin can legitimately produce differing results from the same
// input data, depending on how that data is packaged.
//
// We'll go for option 2, adjusting the timestamps. Note in
// particular that this means some results can differ from those
// produced by SV.
// std::cerr << "PluginInputDomainAdapter: sampleRate " << m_inputSampleRate << ", blocksize " << m_blockSize << ", adjusting time from " << timestamp; Plugin::FeatureSet
PluginInputDomainAdapter::Impl::processShiftingTimestamp(const float *const *inputBuffers,
timestamp = timestamp + getTimestampAdjustment(); RealTime timestamp)
{
// std::cerr << " to " << timestamp << std::endl; if (m_method == ShiftTimestamp) {
timestamp = timestamp + getTimestampAdjustment();
}
for (int c = 0; c < m_channels; ++c) { for (int c = 0; c < m_channels; ++c) {
@ -430,29 +463,87 @@ PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
} }
#ifdef HAVE_FFTW3 #ifdef HAVE_FFTW3
fftw_execute(m_plan); fftw_execute(m_plan);
for (int i = 0; i <= m_blockSize/2; ++i) { for (int i = 0; i <= m_blockSize/2; ++i) {
m_freqbuf[c][i * 2] = float(m_cbuf[i][0]); m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]); m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
} }
#else #else
fft(m_blockSize, false, m_ri, 0, m_ro, m_io); fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
for (int i = 0; i <= m_blockSize/2; ++i) { for (int i = 0; i <= m_blockSize/2; ++i) {
m_freqbuf[c][i * 2] = float(m_ro[i]); m_freqbuf[c][i * 2] = float(m_ro[i]);
m_freqbuf[c][i * 2 + 1] = float(m_io[i]); m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
} }
#endif #endif
} }
return m_plugin->process(m_freqbuf, timestamp); return m_plugin->process(m_freqbuf, timestamp);
} }
Plugin::FeatureSet
PluginInputDomainAdapter::Impl::processShiftingData(const float *const *inputBuffers,
RealTime timestamp)
{
if (m_processCount == 0) {
if (!m_shiftBuffers) {
m_shiftBuffers = new float *[m_channels];
for (int c = 0; c < m_channels; ++c) {
m_shiftBuffers[c] = new float[m_blockSize + m_blockSize/2];
}
}
for (int c = 0; c < m_channels; ++c) {
for (int i = 0; i < m_blockSize + m_blockSize/2; ++i) {
m_shiftBuffers[c][i] = 0.f;
}
}
}
for (int c = 0; c < m_channels; ++c) {
for (int i = m_stepSize; i < m_blockSize + m_blockSize/2; ++i) {
m_shiftBuffers[c][i - m_stepSize] = m_shiftBuffers[c][i];
}
for (int i = 0; i < m_blockSize; ++i) {
m_shiftBuffers[c][i + m_blockSize/2] = inputBuffers[c][i];
}
}
for (int c = 0; c < m_channels; ++c) {
for (int i = 0; i < m_blockSize; ++i) {
m_ri[i] = double(m_shiftBuffers[c][i]) * m_window[i];
}
for (int i = 0; i < m_blockSize/2; ++i) {
// FFT shift
double value = m_ri[i];
m_ri[i] = m_ri[i + m_blockSize/2];
m_ri[i + m_blockSize/2] = value;
}
#ifdef HAVE_FFTW3
fftw_execute(m_plan);
for (int i = 0; i <= m_blockSize/2; ++i) {
m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
}
#else
fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
for (int i = 0; i <= m_blockSize/2; ++i) {
m_freqbuf[c][i * 2] = float(m_ro[i]);
m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
}
#endif
}
++m_processCount;
return m_plugin->process(m_freqbuf, timestamp);
}
#ifndef HAVE_FFTW3 #ifndef HAVE_FFTW3
void void

View file

@ -6,7 +6,7 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation
@ -270,25 +270,38 @@ PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin)
(handle, "vampGetPluginDescriptor"); (handle, "vampGetPluginDescriptor");
if (!fn) { if (!fn) {
if (forPlugin != "") {
cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
<< fullPath << "\"" << endl;
}
unloadLibrary(handle); unloadLibrary(handle);
continue; continue;
} }
int index = 0; int index = 0;
const VampPluginDescriptor *descriptor = 0; const VampPluginDescriptor *descriptor = 0;
bool found = false;
while ((descriptor = fn(VAMP_API_VERSION, index))) { while ((descriptor = fn(VAMP_API_VERSION, index))) {
++index; ++index;
if (identifier != "") { if (identifier != "") {
if (descriptor->identifier != identifier) continue; if (descriptor->identifier != identifier) continue;
} }
found = true;
PluginKey key = composePluginKey(*fi, descriptor->identifier); PluginKey key = composePluginKey(*fi, descriptor->identifier);
// std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl;
if (m_pluginLibraryNameMap.find(key) == if (m_pluginLibraryNameMap.find(key) ==
m_pluginLibraryNameMap.end()) { m_pluginLibraryNameMap.end()) {
m_pluginLibraryNameMap[key] = fullPath; m_pluginLibraryNameMap[key] = fullPath;
} }
} }
if (!found && forPlugin != "") {
cerr << "Vamp::HostExt::PluginLoader: Plugin \""
<< identifier << "\" not found in library \""
<< fullPath << "\"" << endl;
}
unloadLibrary(handle); unloadLibrary(handle);
} }
@ -345,9 +358,11 @@ PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
{ {
if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
if (m_allPluginsEnumerated) return ""; if (m_allPluginsEnumerated) return "";
cerr << "plug not found enumerate" << endl;
enumeratePlugins(plugin); enumeratePlugins(plugin);
} }
if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cerr << "plug not found enumerate" << endl;
return ""; return "";
} }
return m_pluginLibraryNameMap[plugin]; return m_pluginLibraryNameMap[plugin];
@ -365,7 +380,10 @@ PluginLoader::Impl::loadPlugin(PluginKey key,
} }
string fullPath = getLibraryPathForPlugin(key); string fullPath = getLibraryPathForPlugin(key);
if (fullPath == "") return 0; if (fullPath == "") {
std::cerr << "Vamp::HostExt::PluginLoader: No library found in Vamp path for plugin \"" << key << "\"" << std::endl;
return 0;
}
void *handle = loadLibrary(fullPath); void *handle = loadLibrary(fullPath);
if (!handle) return 0; if (!handle) return 0;
@ -375,6 +393,8 @@ PluginLoader::Impl::loadPlugin(PluginKey key,
(handle, "vampGetPluginDescriptor"); (handle, "vampGetPluginDescriptor");
if (!fn) { if (!fn) {
cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
<< fullPath << "\"" << endl;
unloadLibrary(handle); unloadLibrary(handle);
return 0; return 0;
} }
@ -513,7 +533,21 @@ PluginLoader::Impl::loadLibrary(string path)
{ {
void *handle = 0; void *handle = 0;
#ifdef _WIN32 #ifdef _WIN32
#ifdef UNICODE
int len = path.length(); // cannot be more wchars than length in bytes of utf8 string
wchar_t *buffer = new wchar_t[len];
int rv = MultiByteToWideChar(CP_UTF8, 0, path.c_str(), len, buffer, len);
if (rv <= 0) {
cerr << "Vamp::HostExt::PluginLoader: Unable to convert library path \""
<< path << "\" to wide characters " << endl;
delete[] buffer;
return handle;
}
handle = LoadLibrary(buffer);
delete[] buffer;
#else
handle = LoadLibrary(path.c_str()); handle = LoadLibrary(path.c_str());
#endif
if (!handle) { if (!handle) {
cerr << "Vamp::HostExt::PluginLoader: Unable to load library \"" cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
<< path << "\"" << endl; << path << "\"" << endl;
@ -564,8 +598,41 @@ PluginLoader::Impl::listFiles(string dir, string extension)
vector<string> files; vector<string> files;
#ifdef _WIN32 #ifdef _WIN32
string expression = dir + "\\*." + extension; string expression = dir + "\\*." + extension;
#ifdef UNICODE
int len = expression.length(); // cannot be more wchars than length in bytes of utf8 string
wchar_t *buffer = new wchar_t[len];
int rv = MultiByteToWideChar(CP_UTF8, 0, expression.c_str(), len, buffer, len);
if (rv <= 0) {
cerr << "Vamp::HostExt::PluginLoader: Unable to convert wildcard path \""
<< expression << "\" to wide characters" << endl;
delete[] buffer;
return files;
}
WIN32_FIND_DATA data;
HANDLE fh = FindFirstFile(buffer, &data);
if (fh == INVALID_HANDLE_VALUE) {
delete[] buffer;
return files;
}
bool ok = true;
while (ok) {
wchar_t *fn = data.cFileName;
int wlen = wcslen(fn);
int maxlen = wlen * 6;
char *conv = new char[maxlen];
int rv = WideCharToMultiByte(CP_UTF8, 0, fn, wlen, conv, maxlen, 0, 0);
if (rv > 0) {
files.push_back(conv);
}
delete[] conv;
ok = FindNextFile(fh, &data);
}
FindClose(fh);
delete[] buffer;
#else
WIN32_FIND_DATA data; WIN32_FIND_DATA data;
HANDLE fh = FindFirstFile(expression.c_str(), &data); HANDLE fh = FindFirstFile(expression.c_str(), &data);
if (fh == INVALID_HANDLE_VALUE) return files; if (fh == INVALID_HANDLE_VALUE) return files;
@ -577,7 +644,7 @@ PluginLoader::Impl::listFiles(string dir, string extension)
} }
FindClose(fh); FindClose(fh);
#endif
#else #else
size_t extlen = extension.length(); size_t extlen = extension.length();

View file

@ -6,7 +6,7 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2008 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation

View file

@ -6,7 +6,7 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation

View file

@ -39,8 +39,8 @@
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 0 ) #if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 2 )
#error Incorrect Vamp SDK header included (not the expected 2.0 SDK) #error Unexpected version of Vamp SDK header included
#endif #endif
@ -168,6 +168,11 @@ PluginAdapterBase::Impl::getDescriptor()
if (m_populated) return &m_descriptor; if (m_populated) return &m_descriptor;
Plugin *plugin = m_base->createPlugin(48000); Plugin *plugin = m_base->createPlugin(48000);
if (!plugin) {
std::cerr << "PluginAdapterBase::Impl::getDescriptor: Failed to create plugin" << std::endl;
return 0;
}
if (plugin->getVampApiVersion() != VAMP_API_VERSION) { if (plugin->getVampApiVersion() != VAMP_API_VERSION) {
std::cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: " std::cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: "
@ -583,7 +588,7 @@ PluginAdapterBase::Impl::vampGetRemainingFeatures(VampPluginHandle handle)
} }
void void
PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList */*fs*/) PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *fs)
{ {
#ifdef DEBUG_PLUGIN_ADAPTER #ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << std::endl; std::cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << std::endl;

View file

@ -6,7 +6,7 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
This file by Mark Levy and Chris Cannam, Copyright 2007-2008 QMUL. This file by Mark Levy and Chris Cannam, Copyright 2007-2008 QMUL.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person

View file

@ -6,7 +6,7 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation

View file

@ -6,7 +6,7 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation
@ -91,6 +91,7 @@ public:
virtual ~PluginInputDomainAdapter(); virtual ~PluginInputDomainAdapter();
bool initialise(size_t channels, size_t stepSize, size_t blockSize); bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
InputDomain getInputDomain() const; InputDomain getInputDomain() const;
@ -99,6 +100,63 @@ public:
FeatureSet process(const float *const *inputBuffers, RealTime timestamp); FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
/**
* ProcessTimestampMethod determines how the
* PluginInputDomainAdapter handles timestamps for the data passed
* to the process() function of the plugin it wraps, in the case
* where the plugin is expecting frequency-domain data.
*
* The Vamp specification requires that the timestamp passed to
* the plugin for frequency-domain input should be that of the
* centre of the processing block, rather than the start as is the
* case for time-domain input.
*
* Since PluginInputDomainAdapter aims to be transparent in use,
* it needs to handle this timestamp adjustment itself. However,
* some control is available over the method used for adjustment,
* by means of the ProcessTimestampMethod setting.
*
* If ProcessTimestampMethod is set to ShiftTimestamp (the
* default), then the data passed to the wrapped plugin will be
* calculated from the same input data block as passed to the
* wrapper, but the timestamp passed to the plugin will be
* advanced by half of the window size.
*
* If ProcessTimestampMethod is set to ShiftData, then the
* timestamp passed to the wrapped plugin will be the same as that
* passed to the process call of the wrapper, but the data block
* used to calculate the input will be shifted back (earlier) by
* half of the window size, with half a block of zero padding at
* the start of the first process call. This has the advantage of
* preserving the first half block of audio without any
* deterioration from window shaping.
*
* If ProcessTimestampMethod is set to NoShift, then no adjustment
* will be made and the timestamps will be incorrect.
*/
enum ProcessTimestampMethod {
ShiftTimestamp,
ShiftData,
NoShift
};
/**
* Set the method used for timestamp adjustment in plugins taking
* frequency-domain input. See the ProcessTimestampMethod
* documentation for details.
*
* This function must be called before the first call to
* process().
*/
void setProcessTimestampMethod(ProcessTimestampMethod);
/**
* Retrieve the method used for timestamp adjustment in plugins
* taking frequency-domain input. See the ProcessTimestampMethod
* documentation for details.
*/
ProcessTimestampMethod getProcessTimestampMethod() const;
/** /**
* Return the amount by which the timestamps supplied to process() * Return the amount by which the timestamps supplied to process()
* are being incremented when they are passed to the plugin's own * are being incremented when they are passed to the plugin's own
@ -116,9 +174,13 @@ public:
* timestamps) the host may need to be aware that this adjustment * timestamps) the host may need to be aware that this adjustment
* is taking place. * is taking place.
* *
* If the plugin requires time-domain input, this function will * If the plugin requires time-domain input or the
* return zero. The result of calling this function before * PluginInputDomainAdapter is configured with its
* initialise() has been called is undefined. * ProcessTimestampMethod set to ShiftData instead of
* ShiftTimestamp, then this function will return zero.
*
* The result of calling this function before initialise() has
* been called is undefined.
*/ */
RealTime getTimestampAdjustment() const; RealTime getTimestampAdjustment() const;

View file

@ -6,7 +6,7 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation

View file

@ -6,7 +6,7 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2008 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation
@ -156,7 +156,7 @@ public:
*/ */
enum AveragingMethod { enum AveragingMethod {
SampleAverage = 0, SampleAverage = 0,
ContinuousTimeAverage = 1, ContinuousTimeAverage = 1
}; };
/** /**

View file

@ -6,7 +6,7 @@
An API for audio analysis and feature extraction plugins. An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London. Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2007 Chris Cannam and QMUL. Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation obtaining a copy of this software and associated documentation

View file

@ -152,12 +152,17 @@ public:
enum InputDomain { TimeDomain, FrequencyDomain }; enum InputDomain { TimeDomain, FrequencyDomain };
/** /**
* Get the plugin's required input domain. If this is TimeDomain, * Get the plugin's required input domain.
* the samples provided to the process() function (below) will be *
* in the time domain, as for a traditional audio processing * If this is TimeDomain, the samples provided to the process()
* plugin. If this is FrequencyDomain, the host will carry out a * function (below) will be in the time domain, as for a
* windowed FFT of size equal to the negotiated block size on the * traditional audio processing plugin.
* data before passing the frequency bin data in to process(). *
* If this is FrequencyDomain, the host will carry out a windowed
* FFT of size equal to the negotiated block size on the data
* before passing the frequency bin data in to process(). The
* input data for the FFT will be rotated so as to place the
* origin in the centre of the block.
* The plugin does not get to choose the window type -- the host * The plugin does not get to choose the window type -- the host
* will either let the user do so, or will use a Hanning window. * will either let the user do so, or will use a Hanning window.
*/ */

View file

@ -40,9 +40,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
#define VAMP_SDK_VERSION "2.0" #define VAMP_SDK_VERSION "3.5"
#define VAMP_SDK_MAJOR_VERSION 2 #define VAMP_SDK_MAJOR_VERSION 2
#define VAMP_SDK_MINOR_VERSION 0 #define VAMP_SDK_MINOR_VERSION 2
#include "plugguard.h" #include "plugguard.h"
_VAMP_SDK_PLUGSPACE_BEGIN(PluginBase.h) _VAMP_SDK_PLUGSPACE_BEGIN(PluginBase.h)