Mercurial > hg > vamp-plugin-sdk
changeset 56:4ab6224110ef host-factory-stuff
* implement plugin loader and plugin input-domain adapter (to do basic ffts)
author | cannam |
---|---|
date | Fri, 04 May 2007 15:21:12 +0000 |
parents | 0dad357a3406 |
children | 09a1aac6c362 |
files | Makefile host/vamp-simple-host.cpp vamp-hostsdk/PluginHostAdapter.cpp vamp-hostsdk/PluginHostAdapter.h vamp-hostsdk/PluginInputDomainAdapter.cpp vamp-hostsdk/PluginInputDomainAdapter.h vamp-hostsdk/PluginLoader.cpp vamp-hostsdk/PluginLoader.h vamp-hostsdk/system.h vamp-sdk/PluginHostAdapter.cpp vamp-sdk/PluginHostAdapter.h |
diffstat | 11 files changed, 1452 insertions(+), 773 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Fri May 04 12:32:28 2007 +0000 +++ b/Makefile Fri May 04 15:21:12 2007 +0000 @@ -4,6 +4,7 @@ # suit your operating system requirements. SDKDIR = vamp-sdk +HOSTSDKDIR = vamp-hostsdk APIDIR = vamp EXAMPLEDIR = examples HOSTDIR = host @@ -36,17 +37,17 @@ # Compile flags # -CXXFLAGS := $(CXXFLAGS) -O2 -Wall -I$(SDKDIR) -I$(APIDIR) -I. +CXXFLAGS := $(CXXFLAGS) -O2 -Wall -I$(SDKDIR) -I$(HOSTSDKDIR) -I$(APIDIR) -I. # Libraries required for the host at link time # -HOST_LIBS = vamp-sdk/libvamp-hostsdk.a -lsndfile -ldl +HOST_LIBS = $(HOSTSDKDIR)/libvamp-hostsdk.a -lsndfile -ldl # Libraries required for the plugin. Note that we can (and actively # want to) statically link libstdc++, because our plugin exposes only # a C API so there are no boundary compatibility problems. # -PLUGIN_LIBS = vamp-sdk/libvamp-sdk.a +PLUGIN_LIBS = $(SDKDIR)/libvamp-sdk.a #PLUGIN_LIBS = vamp-sdk/libvamp-sdk.a $(shell g++ -print-file-name=libstdc++.a) # Flags required to tell the compiler to link to a dynamically loadable object @@ -76,7 +77,9 @@ HOSTSDK_HEADERS = \ $(SDKDIR)/Plugin.h \ $(SDKDIR)/PluginBase.h \ - $(SDKDIR)/PluginHostAdapter.h \ + $(HOSTSDKDIR)/PluginHostAdapter.h \ + $(HOSTSDKDIR)/PluginInputDomainAdapter.h \ + $(HOSTSDKDIR)/PluginLoader.h \ $(SDKDIR)/RealTime.h SDK_OBJECTS = \ @@ -84,20 +87,22 @@ $(SDKDIR)/RealTime.o HOSTSDK_OBJECTS = \ - $(SDKDIR)/PluginHostAdapter.o \ + $(HOSTSDKDIR)/PluginHostAdapter.o \ + $(HOSTSDKDIR)/PluginInputDomainAdapter.o \ + $(HOSTSDKDIR)/PluginLoader.o \ $(SDKDIR)/RealTime.o SDK_STATIC = \ $(SDKDIR)/libvamp-sdk.a HOSTSDK_STATIC = \ - $(SDKDIR)/libvamp-hostsdk.a + $(HOSTSDKDIR)/libvamp-hostsdk.a SDK_DYNAMIC = \ $(SDKDIR)/libvamp-sdk.so HOSTSDK_DYNAMIC = \ - $(SDKDIR)/libvamp-hostsdk.so + $(HOSTSDKDIR)/libvamp-hostsdk.so SDK_LA = \ $(SDKDIR)/libvamp-sdk.la
--- a/host/vamp-simple-host.cpp Fri May 04 12:32:28 2007 +0000 +++ b/host/vamp-simple-host.cpp Fri May 04 15:21:12 2007 +0000 @@ -36,11 +36,12 @@ */ #include "PluginHostAdapter.h" +#include "PluginInputDomainAdapter.h" +#include "PluginLoader.h" #include "vamp.h" #include <iostream> #include <sndfile.h> -#include <dirent.h> // POSIX directory open and read #include "system.h" @@ -58,10 +59,7 @@ void transformInput(float *, size_t); void fft(unsigned int, bool, double *, double *, double *, double *); void printPluginPath(); - -#ifdef HAVE_OPENDIR void enumeratePlugins(); -#endif /* A very simple Vamp plugin host. Given the name of a plugin @@ -72,7 +70,12 @@ int main(int argc, char **argv) { - if (argc < 2 || argc > 4) { + if (argc < 2 || argc > 4 || + (argc == 2 && + (!strcmp(argv[1], "-?") || + !strcmp(argv[1], "-h") || + !strcmp(argv[1], "--help")))) { + char *scooter = argv[0]; char *name = 0; while (scooter && *scooter) { @@ -113,9 +116,7 @@ } if (argc == 2 && !strcmp(argv[1], "-l")) { -#ifdef HAVE_OPENDIR enumeratePlugins(); -#endif return 0; } if (argc == 2 && !strcmp(argv[1], "-p")) { @@ -209,8 +210,9 @@ return 1; } - Vamp::PluginHostAdapter *plugin = - new Vamp::PluginHostAdapter(descriptor, sfinfo.samplerate); + Vamp::Plugin *plugin = + new Vamp::PluginInputDomainAdapter + (new Vamp::PluginHostAdapter(descriptor, sfinfo.samplerate)); cerr << "Running " << plugin->getIdentifier() << "..." << endl; @@ -334,13 +336,6 @@ } } - if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) { - for (int c = 0; c < sfinfo.channels; ++c) { - transformInput(plugbuf[c], blockSize); - if (mix) break; - } - } - printFeatures (i, sfinfo.samplerate, output, plugin->process (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate))); @@ -368,90 +363,76 @@ } } -#ifdef HAVE_OPENDIR - void enumeratePlugins() { + Vamp::PluginLoader loader; + cerr << endl << "Vamp plugin libraries found in search path:" << endl; - vector<string> path = Vamp::PluginHostAdapter::getPluginPath(); - for (size_t i = 0; i < path.size(); ++i) { - cerr << "\n" << path[i] << ":" << endl; - DIR *d = opendir(path[i].c_str()); - if (!d) { - perror("Failed to open directory"); - continue; + + std::vector<Vamp::PluginLoader::PluginKey> plugins = loader.listPlugins(); + typedef std::multimap<std::string, Vamp::PluginLoader::PluginKey> + LibraryMap; + LibraryMap libraryMap; + + for (size_t i = 0; i < plugins.size(); ++i) { + std::string path = loader.getLibraryPath(plugins[i]); + libraryMap.insert(LibraryMap::value_type(path, plugins[i])); + } + + std::string prevPath = ""; + int index = 0; + + for (LibraryMap::iterator i = libraryMap.begin(); + i != libraryMap.end(); ++i) { + + std::string path = i->first; + Vamp::PluginLoader::PluginKey key = i->second; + + if (path != prevPath) { + prevPath = path; + index = 0; + cerr << "\n " << path << ":" << endl; } - struct dirent *e = 0; - while ((e = readdir(d))) { -// cerr << "reading: " << e->d_name << endl; - if (!(e->d_type & DT_REG)) { -// cerr << e->d_name << ": not a regular file" << endl; - continue; + + Vamp::Plugin *plugin = loader.load(key, 48000); + if (plugin) { + + char c = char('A' + index); + if (c > 'Z') c = char('a' + (index - 26)); + + cerr << " [" << c << "] [v" + << plugin->getVampApiVersion() << "] " + << plugin->getName() << ", \"" + << plugin->getIdentifier() << "\"" << " [" + << plugin->getMaker() << "]" << endl; + + if (plugin->getDescription() != "") { + cerr << " - " << plugin->getDescription() << endl; } - int len = strlen(e->d_name); - if (len < int(strlen(PLUGIN_SUFFIX) + 2) || - e->d_name[len - strlen(PLUGIN_SUFFIX) - 1] != '.' || - strcmp(e->d_name + len - strlen(PLUGIN_SUFFIX), PLUGIN_SUFFIX)) { -// cerr << e->d_name << ": not a library file" << endl; - continue; + + Vamp::Plugin::OutputList outputs = + plugin->getOutputDescriptors(); + + if (outputs.size() > 1) { + for (size_t j = 0; j < outputs.size(); ++j) { + cerr << " (" << j << ") " + << outputs[j].name << ", \"" + << outputs[j].identifier << "\"" << endl; + if (outputs[j].description != "") { + cerr << " - " + << outputs[j].description << endl; + } + } } - char *fp = new char[path[i].length() + len + 3]; - sprintf(fp, "%s/%s", path[i].c_str(), e->d_name); - void *handle = DLOPEN(string(fp), RTLD_LAZY); - if (handle) { - VampGetPluginDescriptorFunction fn = - (VampGetPluginDescriptorFunction)DLSYM - (handle, "vampGetPluginDescriptor"); - if (fn) { - cerr << "\n " << e->d_name << ":" << endl; - int index = 0; - const VampPluginDescriptor *descriptor = 0; - while ((descriptor = fn(VAMP_API_VERSION, index))) { - Vamp::PluginHostAdapter plugin(descriptor, 48000); - char c = char('A' + index); - if (c > 'Z') c = char('a' + (index - 26)); - cerr << " [" << c << "] [v" - << plugin.getVampApiVersion() << "] " - << plugin.getName() - << ", \"" << plugin.getIdentifier() << "\"" - << " [" << plugin.getMaker() - << "]" << endl; - if (plugin.getDescription() != "") { - cerr << " - " << plugin.getDescription() << endl; - } - Vamp::Plugin::OutputList outputs = - plugin.getOutputDescriptors(); - if (outputs.size() > 1) { - for (size_t j = 0; j < outputs.size(); ++j) { - cerr << " (" << j << ") " - << outputs[j].name - << ", \"" << outputs[j].identifier << "\"" - << endl; - if (outputs[j].description != "") { - cerr << " - " - << outputs[j].description << endl; - } - } - } - ++index; - } - } else { -// cerr << e->d_name << ": no Vamp descriptor function" << endl; - } - DLCLOSE(handle); - } else { - cerr << "\n" << e->d_name << ": unable to load library (" << DLERROR() << ")" << endl; - } + + ++index; } - closedir(d); } + cerr << endl; } -#endif - - void printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features) { @@ -468,149 +449,5 @@ } } -void -transformInput(float *buffer, size_t size) -{ - double *inbuf = new double[size * 2]; - double *outbuf = new double[size * 2]; - - // Copy across with Hanning window - for (size_t i = 0; i < size; ++i) { - inbuf[i] = double(buffer[i]) * (0.50 - 0.50 * cos(2 * M_PI * i / size)); - inbuf[i + size] = 0.0; - } - - for (size_t i = 0; i < size/2; ++i) { - double temp = inbuf[i]; - inbuf[i] = inbuf[i + size/2]; - inbuf[i + size/2] = temp; - } - - fft(size, false, inbuf, inbuf + size, outbuf, outbuf + size); - - for (size_t i = 0; i <= size/2; ++i) { - buffer[i * 2] = outbuf[i]; - buffer[i * 2 + 1] = outbuf[i + size]; - } - - delete[] inbuf; - delete[] outbuf; -} - -void -fft(unsigned int n, bool inverse, double *ri, double *ii, double *ro, double *io) -{ - if (!ri || !ro || !io) return; - - unsigned int bits; - unsigned int i, j, k, m; - unsigned int blockSize, blockEnd; - - double tr, ti; - - if (n < 2) return; - if (n & (n-1)) return; - - double angle = 2.0 * M_PI; - if (inverse) angle = -angle; - - for (i = 0; ; ++i) { - if (n & (1 << i)) { - bits = i; - break; - } - } - - static unsigned int tableSize = 0; - static int *table = 0; - - if (tableSize != n) { - - delete[] table; - - table = new int[n]; - - for (i = 0; i < n; ++i) { - - m = i; - - for (j = k = 0; j < bits; ++j) { - k = (k << 1) | (m & 1); - m >>= 1; - } - - table[i] = k; - } - - tableSize = n; - } - - if (ii) { - for (i = 0; i < n; ++i) { - ro[table[i]] = ri[i]; - io[table[i]] = ii[i]; - } - } else { - for (i = 0; i < n; ++i) { - ro[table[i]] = ri[i]; - io[table[i]] = 0.0; - } - } - - blockEnd = 1; - - for (blockSize = 2; blockSize <= n; blockSize <<= 1) { - - double delta = angle / (double)blockSize; - double sm2 = -sin(-2 * delta); - double sm1 = -sin(-delta); - double cm2 = cos(-2 * delta); - double cm1 = cos(-delta); - double w = 2 * cm1; - double ar[3], ai[3]; - - for (i = 0; i < n; i += blockSize) { - - ar[2] = cm2; - ar[1] = cm1; - - ai[2] = sm2; - ai[1] = sm1; - - for (j = i, m = 0; m < blockEnd; j++, m++) { - - ar[0] = w * ar[1] - ar[2]; - ar[2] = ar[1]; - ar[1] = ar[0]; - - ai[0] = w * ai[1] - ai[2]; - ai[2] = ai[1]; - ai[1] = ai[0]; - - k = j + blockEnd; - tr = ar[0] * ro[k] - ai[0] * io[k]; - ti = ar[0] * io[k] + ai[0] * ro[k]; - - ro[k] = ro[j] - tr; - io[k] = io[j] - ti; - - ro[j] += tr; - io[j] += ti; - } - } - - blockEnd = blockSize; - } - - if (inverse) { - - double denom = (double)n; - - for (i = 0; i < n; i++) { - ro[i] /= denom; - io[i] /= denom; - } - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginHostAdapter.cpp Fri May 04 15:21:12 2007 +0000 @@ -0,0 +1,418 @@ +/* -*- 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 "PluginHostAdapter.h" + +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 = "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) return; + 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) { + 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; + + 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) { + + for (unsigned int j = 0; j < list.featureCount; ++j) { + + Feature feature; + feature.hasTimestamp = list.features[j].hasTimestamp; + feature.timestamp = RealTime(list.features[j].sec, + list.features[j].nsec); + + for (unsigned int k = 0; k < list.features[j].valueCount; ++k) { + feature.values.push_back(list.features[j].values[k]); + } + + if (list.features[j].label) { + feature.label = list.features[j].label; + } + + fs[i].push_back(feature); + } + } + } +} + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginHostAdapter.h Fri May 04 15:21:12 2007 +0000 @@ -0,0 +1,115 @@ +/* -*- 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 <vamp/vamp.h> +#include <vamp-sdk/Plugin.h> + +#include <vector> + +namespace Vamp { + +/** + * 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; +}; + +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginInputDomainAdapter.cpp Fri May 04 15:21:12 2007 +0000 @@ -0,0 +1,377 @@ +/* -*- 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 "PluginInputDomainAdapter.h" + +#include <cmath> + +namespace Vamp { + +PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) : + Plugin(0), + m_plugin(plugin), + m_channels(0), + m_blockSize(0), + m_freqbuf(0) +{ +} + +PluginInputDomainAdapter::~PluginInputDomainAdapter() +{ + delete m_plugin; +} + +bool +PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + //!!! complain and die if blocksize is not a power of 2 + + if (m_plugin->getInputDomain() == FrequencyDomain) { + if (m_channels > 0) { + for (size_t c = 0; c < m_channels; ++c) { + delete[] m_freqbuf[c]; + } + delete[] m_freqbuf; + delete[] m_ri; + delete[] m_ro; + delete[] m_io; + } + } + + m_channels = channels; + m_blockSize = blockSize; + + if (m_plugin->getInputDomain() == FrequencyDomain) { + m_freqbuf = new float *[m_channels]; + for (size_t c = 0; c < m_channels; ++c) { + m_freqbuf[c] = new float[m_blockSize + 2]; + } + m_ri = new double[m_blockSize]; + m_ro = new double[m_blockSize]; + m_io = new double[m_blockSize]; + } + + return m_plugin->initialise(channels, stepSize, blockSize); +} + +void +PluginInputDomainAdapter::reset() +{ + m_plugin->reset(); +} + +unsigned int +PluginInputDomainAdapter::getVampApiVersion() const +{ + return m_plugin->getVampApiVersion(); +} + +std::string +PluginInputDomainAdapter::getIdentifier() const +{ + return m_plugin->getIdentifier(); +} + +std::string +PluginInputDomainAdapter::getName() const +{ + return m_plugin->getName(); +} + +std::string +PluginInputDomainAdapter::getDescription() const +{ + return m_plugin->getDescription(); +} + +std::string +PluginInputDomainAdapter::getMaker() const +{ + return m_plugin->getMaker(); +} + +int +PluginInputDomainAdapter::getPluginVersion() const +{ + return m_plugin->getPluginVersion(); +} + +std::string +PluginInputDomainAdapter::getCopyright() const +{ + return m_plugin->getCopyright(); +} + +PluginBase::ParameterList +PluginInputDomainAdapter::getParameterDescriptors() const +{ + return m_plugin->getParameterDescriptors(); +} + +float +PluginInputDomainAdapter::getParameter(std::string parameter) const +{ + return m_plugin->getParameter(parameter); +} + +void +PluginInputDomainAdapter::setParameter(std::string parameter, float value) +{ + m_plugin->setParameter(parameter, value); +} + +PluginBase::ProgramList +PluginInputDomainAdapter::getPrograms() const +{ + return m_plugin->getPrograms(); +} + +std::string +PluginInputDomainAdapter::getCurrentProgram() const +{ + return m_plugin->getCurrentProgram(); +} + +void +PluginInputDomainAdapter::selectProgram(std::string program) +{ + m_plugin->selectProgram(program); +} + +size_t +PluginInputDomainAdapter::getPreferredStepSize() const +{ + size_t step = m_plugin->getPreferredStepSize(); + + if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) { + step = getPreferredBlockSize() / 2; + } + + return step; +} + +size_t +PluginInputDomainAdapter::getPreferredBlockSize() const +{ + size_t block = m_plugin->getPreferredBlockSize(); + + if (block == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) { + block = 1024; + } + + return block; +} + +size_t +PluginInputDomainAdapter::getMinChannelCount() const +{ + return m_plugin->getMinChannelCount(); +} + +size_t PluginInputDomainAdapter::getMaxChannelCount() const +{ + return m_plugin->getMaxChannelCount(); +} + +Plugin::OutputList +PluginInputDomainAdapter::getOutputDescriptors() const +{ + return m_plugin->getOutputDescriptors(); +} + +Plugin::FeatureSet +PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp) +{ + if (m_plugin->getInputDomain() == TimeDomain) { + return m_plugin->process(inputBuffers, timestamp); + } + + for (size_t c = 0; c < m_channels; ++c) { + + for (size_t i = 0; i < m_blockSize; ++i) { + // Hanning window + m_ri[i] = double(inputBuffers[c][i]) + * (0.50 - 0.50 * cos((2 * M_PI * i) + / m_blockSize)); + } + + for (size_t 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; + } + + fft(m_blockSize, false, m_ri, 0, m_ro, m_io); + + for (size_t i = 0; i < m_blockSize/2; ++i) { + m_freqbuf[c][i * 2] = m_ro[i]; + m_freqbuf[c][i * 2 + 1] = m_io[i]; + } + } + + //!!! do we want to adjust the timestamp or anything so as to + // effectively centre the frame? + + return m_plugin->process(m_freqbuf, timestamp); +} + +Plugin::FeatureSet +PluginInputDomainAdapter::getRemainingFeatures() +{ + return m_plugin->getRemainingFeatures(); +} + +void +PluginInputDomainAdapter::fft(unsigned int n, bool inverse, + double *ri, double *ii, double *ro, double *io) +{ + if (!ri || !ro || !io) return; + + unsigned int bits; + unsigned int i, j, k, m; + unsigned int blockSize, blockEnd; + + double tr, ti; + + if (n < 2) return; + if (n & (n-1)) return; + + double angle = 2.0 * M_PI; + if (inverse) angle = -angle; + + for (i = 0; ; ++i) { + if (n & (1 << i)) { + bits = i; + break; + } + } + + static unsigned int tableSize = 0; + static int *table = 0; + + if (tableSize != n) { + + delete[] table; + + table = new int[n]; + + for (i = 0; i < n; ++i) { + + m = i; + + for (j = k = 0; j < bits; ++j) { + k = (k << 1) | (m & 1); + m >>= 1; + } + + table[i] = k; + } + + tableSize = n; + } + + if (ii) { + for (i = 0; i < n; ++i) { + ro[table[i]] = ri[i]; + io[table[i]] = ii[i]; + } + } else { + for (i = 0; i < n; ++i) { + ro[table[i]] = ri[i]; + io[table[i]] = 0.0; + } + } + + blockEnd = 1; + + for (blockSize = 2; blockSize <= n; blockSize <<= 1) { + + double delta = angle / (double)blockSize; + double sm2 = -sin(-2 * delta); + double sm1 = -sin(-delta); + double cm2 = cos(-2 * delta); + double cm1 = cos(-delta); + double w = 2 * cm1; + double ar[3], ai[3]; + + for (i = 0; i < n; i += blockSize) { + + ar[2] = cm2; + ar[1] = cm1; + + ai[2] = sm2; + ai[1] = sm1; + + for (j = i, m = 0; m < blockEnd; j++, m++) { + + ar[0] = w * ar[1] - ar[2]; + ar[2] = ar[1]; + ar[1] = ar[0]; + + ai[0] = w * ai[1] - ai[2]; + ai[2] = ai[1]; + ai[1] = ai[0]; + + k = j + blockEnd; + tr = ar[0] * ro[k] - ai[0] * io[k]; + ti = ar[0] * io[k] + ai[0] * ro[k]; + + ro[k] = ro[j] - tr; + io[k] = io[j] - ti; + + ro[j] += tr; + io[j] += ti; + } + } + + blockEnd = blockSize; + } + + if (inverse) { + + double denom = (double)n; + + for (i = 0; i < n; i++) { + ro[i] /= denom; + io[i] /= denom; + } + } +} + + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginInputDomainAdapter.h Fri May 04 15:21:12 2007 +0000 @@ -0,0 +1,119 @@ +/* -*- 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 _PLUGIN_INPUT_DOMAIN_ADAPTER_H_ + +#include <vamp-sdk/Plugin.h> + +namespace Vamp { + +/** + * An adapter that converts time-domain input into frequency-domain + * input for plugins that need it. In every other respect this + * adapter behaves like the plugin it wraps. The wrapped plugin may + * be a time-domain plugin, in which case this wrapper does nothing. + * + * Uses a Hanning windowed FFT. The FFT implementation is not the + * fastest, so a host can do much better if it cares enough, but it is + * simple and self-contained. + * + * Note that this adapter does not support non-power-of-two block + * sizes. + */ + +//!!! It would also be nice to have a channel wrapper, which deals +//with mixing down channels if the plugin needs a different number +//from the input source. It would have some sort of mixdown/channel +//input policy selection. Probably this class and that one should +//both inherit a PluginAdapter class which contains a plugin and +//delegates all calls through to it; the subclass can then override +//only the ones it needs to handle. + +class PluginInputDomainAdapter : public Plugin +{ +public: + PluginInputDomainAdapter(Plugin *plugin); // I take ownership of plugin + virtual ~PluginInputDomainAdapter(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + void reset(); + + InputDomain getInputDomain() const { return Plugin::TimeDomain; } + + 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: + Plugin *m_plugin; + size_t m_channels; + size_t m_blockSize; + float **m_freqbuf; + double *m_ri; + double *m_ro; + double *m_io; + + void fft(unsigned int n, bool inverse, + double *ri, double *ii, double *ro, double *io); +}; + +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginLoader.cpp Fri May 04 15:21:12 2007 +0000 @@ -0,0 +1,193 @@ +/* -*- 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 "PluginLoader.h" +#include "PluginHostAdapter.h" + +#include "system.h" + +#include <dirent.h> // POSIX directory open and read + +namespace Vamp { + +PluginLoader::PluginLoader() +{ +} + +PluginLoader::~PluginLoader() +{ +} + +std::vector<PluginLoader::PluginKey> +PluginLoader::listPlugins() +{ + if (m_pluginLibraryMap.empty()) { + + std::vector<std::string> path = PluginHostAdapter::getPluginPath(); + + size_t suffixLen = strlen(PLUGIN_SUFFIX); + + for (size_t i = 0; i < path.size(); ++i) { + + DIR *d = opendir(path[i].c_str()); + if (!d) { +// perror("Failed to open directory"); + continue; + } + + struct dirent *e = 0; + while ((e = readdir(d))) { + + if (!(e->d_type & DT_REG) || !e->d_name) { + continue; + } + + int len = strlen(e->d_name); + if (len < int(suffixLen + 2) || + e->d_name[len - suffixLen - 1] != '.' || + strcmp(e->d_name + len - suffixLen, PLUGIN_SUFFIX)) { + continue; + } + + std::string basename = e->d_name; + basename = basename.substr(0, basename.length() - suffixLen - 1); + std::string fullPath = path[i].c_str(); + fullPath = fullPath + "/" + e->d_name; + void *handle = DLOPEN(fullPath, RTLD_LAZY); + + if (!handle) { + std::cerr << "Vamp::PluginLoader: " << e->d_name + << ": unable to load library (" << DLERROR() + << ")" << std::endl; + continue; + } + + VampGetPluginDescriptorFunction fn = + (VampGetPluginDescriptorFunction)DLSYM + (handle, "vampGetPluginDescriptor"); + + if (!fn) { + DLCLOSE(handle); + continue; + } + + int index = 0; + const VampPluginDescriptor *descriptor = 0; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + PluginKey key = basename + ":" + descriptor->identifier; + if (m_pluginLibraryMap.find(key) == + m_pluginLibraryMap.end()) { + m_pluginLibraryMap[key] = fullPath; + } + ++index; + } + + DLCLOSE(handle); + } + + closedir(d); + } + } + + std::vector<PluginKey> plugins; + for (std::map<PluginKey, std::string>::iterator mi = + m_pluginLibraryMap.begin(); + mi != m_pluginLibraryMap.end(); ++mi) { + plugins.push_back(mi->first); + } + + return plugins; +} + +std::string +PluginLoader::getLibraryPath(PluginKey key) +{ + if (m_pluginLibraryMap.empty()) (void)listPlugins(); + if (m_pluginLibraryMap.find(key) == m_pluginLibraryMap.end()) return ""; + return m_pluginLibraryMap[key]; +} + +Plugin * +PluginLoader::load(PluginKey key, float inputSampleRate) +{ + std::string fullPath = getLibraryPath(key); + if (fullPath == "") return 0; + + std::string::size_type ki = key.find(':'); + if (ki == std::string::npos) { + //!!! flag error + return 0; + } + + std::string identifier = key.substr(ki + 1); + + void *handle = DLOPEN(fullPath, RTLD_LAZY); + + if (!handle) { + std::cerr << "Vamp::PluginLoader: " << fullPath + << ": unable to load library (" << DLERROR() + << ")" << std::endl; + return 0; + } + + VampGetPluginDescriptorFunction fn = + (VampGetPluginDescriptorFunction)DLSYM + (handle, "vampGetPluginDescriptor"); + + if (!fn) { + //!!! refcount this! --!!! no, POSIX says dlopen/dlclose will + // reference count. check on win32 + DLCLOSE(handle); + return 0; + } + + int index = 0; + const VampPluginDescriptor *descriptor = 0; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + if (std::string(descriptor->identifier) == identifier) { + return new Vamp::PluginHostAdapter(descriptor, inputSampleRate); + } + ++index; + } + + //!!! flag error + return 0; +} + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/PluginLoader.h Fri May 04 15:21:12 2007 +0000 @@ -0,0 +1,74 @@ +/* -*- 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_LOADER_H_ +#define _VAMP_PLUGIN_LOADER_H_ + +#include <vector> +#include <string> +#include <map> + +namespace Vamp { + +class Plugin; + +class PluginLoader +{ +public: + PluginLoader(); + virtual ~PluginLoader(); + + typedef std::string PluginKey; + + std::vector<PluginKey> listPlugins(); //!!! pass in version number? + + //!!! want to be able to just "delete" the plugin later -- hence + //have to consider library loading issues -- do we have a wrapper + //class that tells us when it's been deleted, and keep a reference + //count for the dynamic library? + Plugin *load(PluginKey key, float inputSampleRate); + + std::string getLibraryPath(PluginKey key); + +protected: + std::map<PluginKey, std::string> m_pluginLibraryMap; +}; + +} + + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-hostsdk/system.h Fri May 04 15:21:12 2007 +0000 @@ -0,0 +1,75 @@ +/* -*- 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 _SYSTEM_H_ +#define _SYSTEM_H_ + +#ifdef _WIN32 + +#include <windows.h> + +#define DLOPEN(a,b) LoadLibrary((a).c_str()) +#define DLSYM(a,b) GetProcAddress((HINSTANCE)(a),(b)) +#define DLCLOSE(a) FreeLibrary((HINSTANCE)(a)) +#define DLERROR() "" + +#define PLUGIN_SUFFIX "dll" + +#else + +#include <dlfcn.h> + +#define DLOPEN(a,b) dlopen((a).c_str(),(b)) +#define DLSYM(a,b) dlsym((a),(b)) +#define DLCLOSE(a) dlclose((a)) +#define DLERROR() dlerror() + +#ifdef __APPLE__ + +#define PLUGIN_SUFFIX "dylib" +#define HAVE_OPENDIR 1 + +#else + +#define PLUGIN_SUFFIX "so" +#define HAVE_OPENDIR 1 + +#endif /* __APPLE__ */ + +#endif /* ! _WIN32 */ + +#endif +
--- a/vamp-sdk/PluginHostAdapter.cpp Fri May 04 12:32:28 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,418 +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 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 "PluginHostAdapter.h" - -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 = "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) return; - 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) { - 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; - - 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) { - - for (unsigned int j = 0; j < list.featureCount; ++j) { - - Feature feature; - feature.hasTimestamp = list.features[j].hasTimestamp; - feature.timestamp = RealTime(list.features[j].sec, - list.features[j].nsec); - - for (unsigned int k = 0; k < list.features[j].valueCount; ++k) { - feature.values.push_back(list.features[j].values[k]); - } - - if (list.features[j].label) { - feature.label = list.features[j].label; - } - - fs[i].push_back(feature); - } - } - } -} - -}
--- a/vamp-sdk/PluginHostAdapter.h Fri May 04 12:32:28 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +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 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 <vamp/vamp.h> - -#include "Plugin.h" - -#include <vector> - -namespace Vamp { - -/** - * 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; -}; - -} - -#endif - -