# HG changeset patch # User cannam # Date 1180019827 0 # Node ID fa79c4ec847db45f7d600276d045ca45471854d2 # Parent 0284955e31e55f6a120127180085d40206f6d5dd * Put hostext stuff in the HostExt sub-namespace * Tidy up system-specific stuff in PluginLoader * Make PluginLoader return a deletion-notifying wrapper which permits the library to be unloaded when no longer in use * Add PluginChannelAdapter * Make vamp-simple-host use PluginChannelAdapter, and use the PluginLoader for plugin-running task. Also some other enhancements to host diff -r 0284955e31e5 -r fa79c4ec847d Makefile --- a/Makefile Thu May 24 10:05:00 2007 +0000 +++ b/Makefile Thu May 24 15:17:07 2007 +0000 @@ -3,8 +3,6 @@ # libraries, example plugins, and the test host. Please adjust to # suit your operating system requirements. -## Choose your - APIDIR = vamp SDKDIR = vamp-sdk HOSTEXTDIR = vamp-sdk/hostext @@ -29,7 +27,7 @@ # Compile flags # -CXXFLAGS := $(CXXFLAGS) -O2 -Wall -I$(SDKDIR) -I$(HOSTEXTDIR) -I$(APIDIR) -I. +CXXFLAGS := $(CXXFLAGS) -g -Wall -I. # Libraries required for the plugins. # (Note that it is desirable to statically link libstdc++ if possible, @@ -94,6 +92,7 @@ $(SDKDIR)/Plugin.h \ $(SDKDIR)/PluginBase.h \ $(SDKDIR)/PluginHostAdapter.h \ + $(HOSTEXTDIR)/PluginChannelAdapter.h \ $(HOSTEXTDIR)/PluginInputDomainAdapter.h \ $(HOSTEXTDIR)/PluginLoader.h \ $(HOSTEXTDIR)/PluginWrapper.h \ @@ -105,6 +104,7 @@ HOSTSDK_OBJECTS = \ $(SDKDIR)/PluginHostAdapter.o \ + $(HOSTEXTDIR)/PluginChannelAdapter.o \ $(HOSTEXTDIR)/PluginInputDomainAdapter.o \ $(HOSTEXTDIR)/PluginLoader.o \ $(HOSTEXTDIR)/PluginWrapper.o \ @@ -152,9 +152,9 @@ sdk: $(SDK_STATIC) $(SDK_DYNAMIC) $(HOSTSDK_STATIC) $(HOSTSDK_DYNAMIC) -plugins: sdk $(PLUGIN_TARGET) +plugins: $(PLUGIN_TARGET) -host: sdk $(HOST_TARGET) +host: $(HOST_TARGET) all: sdk plugins host test @@ -170,14 +170,14 @@ $(HOSTSDK_DYNAMIC): $(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS) $(CXX) $(LDFLAGS) $(PLUGIN_LDFLAGS) -o $@ $(HOSTSDK_OBJECTS) -$(PLUGIN_TARGET): $(PLUGIN_OBJECTS) $(SDK_TARGET) $(PLUGIN_HEADERS) +$(PLUGIN_TARGET): $(PLUGIN_OBJECTS) $(SDK_STATIC) $(PLUGIN_HEADERS) $(CXX) $(LDFLAGS) $(PLUGIN_LDFLAGS) -o $@ $(PLUGIN_OBJECTS) $(PLUGIN_LIBS) -$(HOST_TARGET): $(HOST_OBJECTS) $(HOSTSDK_TARGET) $(HOST_HEADERS) +$(HOST_TARGET): $(HOST_OBJECTS) $(HOSTSDK_STATIC) $(HOST_HEADERS) $(CXX) $(LDFLAGS) $(HOST_LDFLAGS) -o $@ $(HOST_OBJECTS) $(HOST_LIBS) test: plugins host - $(HOST_TARGET) $(PLUGIN_TARGET) + VAMP_PATH=$(EXAMPLEDIR) $(HOST_TARGET) -l clean: rm -f $(SDK_OBJECTS) $(HOSTSDK_OBJECTS) $(PLUGIN_OBJECTS) $(HOST_OBJECTS) diff -r 0284955e31e5 -r fa79c4ec847d README --- a/README Thu May 24 10:05:00 2007 +0000 +++ b/README Thu May 24 15:17:07 2007 +0000 @@ -190,11 +190,14 @@ ======= Vamp and the Vamp SDK were designed and made at the Centre for Digital -Music at Queen Mary, University of London. The SDK code was written -by Chris Cannam, copyright (c) 2005-2006 Chris Cannam. Mark Sandler -and Christian Landone provided ideas and direction, and Mark Levy, Dan -Stowell, Martin Gasser and Craig Sapp provided testing and other input -for the 1.0 API and SDK. The API reuses some ideas from several prior -plugin systems, notably DSSI (http://dssi.sourceforge.net) and FEAPI -(http://feapi.sourceforge.net). +Music at Queen Mary, University of London. +The SDK was written by Chris Cannam, copyright (c) 2005-2007 +Chris Cannam and QMUL. + +Mark Sandler and Christian Landone provided ideas and direction, and +Mark Levy, Dan Stowell, Martin Gasser and Craig Sapp provided testing +and other input for the 1.0 API and SDK. The API also uses some ideas +from prior plugin systems, notably DSSI (http://dssi.sourceforge.net) +and FEAPI (http://feapi.sourceforge.net). + diff -r 0284955e31e5 -r fa79c4ec847d examples/AmplitudeFollower.h --- a/examples/AmplitudeFollower.h Thu May 24 10:05:00 2007 +0000 +++ b/examples/AmplitudeFollower.h Thu May 24 15:17:07 2007 +0000 @@ -37,7 +37,7 @@ #ifndef _AMPLITUDE_FOLLOWER_PLUGIN_H_ #define _AMPLITUDE_FOLLOWER_PLUGIN_H_ -#include "Plugin.h" +#include "vamp-sdk/Plugin.h" /** * Example plugin implementing the SuperCollider amplitude follower diff -r 0284955e31e5 -r fa79c4ec847d examples/PercussionOnsetDetector.h --- a/examples/PercussionOnsetDetector.h Thu May 24 10:05:00 2007 +0000 +++ b/examples/PercussionOnsetDetector.h Thu May 24 15:17:07 2007 +0000 @@ -37,7 +37,7 @@ #ifndef _PERCUSSION_ONSET_DETECTOR_PLUGIN_H_ #define _PERCUSSION_ONSET_DETECTOR_PLUGIN_H_ -#include "Plugin.h" +#include "vamp-sdk/Plugin.h" /** * Example plugin that detects percussive events. diff -r 0284955e31e5 -r fa79c4ec847d examples/SpectralCentroid.h --- a/examples/SpectralCentroid.h Thu May 24 10:05:00 2007 +0000 +++ b/examples/SpectralCentroid.h Thu May 24 15:17:07 2007 +0000 @@ -37,7 +37,7 @@ #ifndef _SPECTRAL_CENTROID_PLUGIN_H_ #define _SPECTRAL_CENTROID_PLUGIN_H_ -#include "Plugin.h" +#include "vamp-sdk/Plugin.h" /** * Example plugin that calculates the centre of gravity of the diff -r 0284955e31e5 -r fa79c4ec847d examples/ZeroCrossing.h --- a/examples/ZeroCrossing.h Thu May 24 10:05:00 2007 +0000 +++ b/examples/ZeroCrossing.h Thu May 24 15:17:07 2007 +0000 @@ -37,7 +37,7 @@ #ifndef _ZERO_CROSSING_PLUGIN_H_ #define _ZERO_CROSSING_PLUGIN_H_ -#include "Plugin.h" +#include "vamp-sdk/Plugin.h" /** * Example plugin that calculates the positions and density of diff -r 0284955e31e5 -r fa79c4ec847d examples/plugins.cpp --- a/examples/plugins.cpp Thu May 24 10:05:00 2007 +0000 +++ b/examples/plugins.cpp Thu May 24 15:17:07 2007 +0000 @@ -34,9 +34,9 @@ authorization. */ -#include +#include "vamp/vamp.h" +#include "vamp-sdk/PluginAdapter.h" -#include "PluginAdapter.h" #include "ZeroCrossing.h" #include "SpectralCentroid.h" #include "PercussionOnsetDetector.h" diff -r 0284955e31e5 -r fa79c4ec847d host/vamp-simple-host.cpp --- a/host/vamp-simple-host.cpp Thu May 24 10:05:00 2007 +0000 +++ b/host/vamp-simple-host.cpp Thu May 24 15:17:07 2007 +0000 @@ -35,10 +35,11 @@ authorization. */ -#include "PluginHostAdapter.h" -#include "PluginInputDomainAdapter.h" -#include "PluginLoader.h" -#include "vamp.h" +#include "vamp-sdk/PluginHostAdapter.h" +#include "vamp-sdk/hostext/PluginChannelAdapter.h" +#include "vamp-sdk/hostext/PluginInputDomainAdapter.h" +#include "vamp-sdk/hostext/PluginLoader.h" +#include "vamp/vamp.h" #include #include @@ -53,61 +54,62 @@ using std::string; using std::vector; -#define HOST_VERSION "1.0" +using Vamp::HostExt::PluginLoader; + +#define HOST_VERSION "1.1" void printFeatures(int, int, int, Vamp::Plugin::FeatureSet); void transformInput(float *, size_t); void fft(unsigned int, bool, double *, double *, double *, double *); -void printPluginPath(); +void printPluginPath(bool verbose); void enumeratePlugins(); +void listPluginsInLibrary(string soname); +int runPlugin(string myname, string soname, string id, string output, + int outputNo, string inputFile); -/* - A very simple Vamp plugin host. Given the name of a plugin - library and the name of a sound file on the command line, it loads - the first plugin in the library and runs it on the sound file, - dumping the plugin's first output to stdout. -*/ +void usage(const char *name) +{ + cerr << "\n" + << name << ": A simple Vamp plugin host.\n\n" + "Centre for Digital Music, Queen Mary, University of London.\n" + "Copyright 2006-2007 Chris Cannam and QMUL.\n" + "Freely redistributable; published under a BSD-style license.\n\n" + "Usage:\n\n" + " " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav\n" + " " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno]\n\n" + " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n" + " audio data in \"file.wav\"; retrieve the named \"output\", or output\n" + " number \"outputno\" (the first output by default) and dump it to\n" + " standard output.\n\n" + " " << name << " -l\n\n" + " -- List the plugin libraries and Vamp plugins in the plugin search path.\n\n" + " " << name << " -p\n\n" + " -- Print out the Vamp plugin search path.\n\n" + " " << name << " -v\n\n" + " -- Display version information only.\n\n" + << endl; + exit(2); +} int main(int argc, char **argv) { + char *scooter = argv[0]; + char *name = 0; + while (scooter && *scooter) { + if (*scooter == '/' || *scooter == '\\') name = ++scooter; + else ++scooter; + } + if (!name || !*name) name = argv[0]; + 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) { - if (*scooter == '/' || *scooter == '\\') name = ++scooter; - else ++scooter; - } - if (!name || !*name) name = argv[0]; - cerr << "\n" - << name << ": A simple Vamp plugin host.\n\n" - "Centre for Digital Music, Queen Mary, University of London.\n" - "Copyright 2006 Chris Cannam and QMUL.\n" - "Freely redistributable; published under a BSD-style license.\n\n" - "Usage:\n\n" - " " << name << " pluginlibrary." << PLUGIN_SUFFIX << "\n\n" - " -- Load \"pluginlibrary\" and list the Vamp plugins it contains.\n\n" - " " << name << " pluginlibrary." << PLUGIN_SUFFIX << ":plugin file.wav [outputno]\n\n" - " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n" - " audio data in \"file.wav\", dumping the output from \"outputno\"\n" - " (default 0) to standard output.\n\n" -#ifdef HAVE_OPENDIR - " " << name << " -l\n\n" - " -- List the plugin libraries and Vamp plugins in the plugin search path.\n\n" -#endif - " " << name << " -p\n\n" - " -- Print out the Vamp plugin search path.\n\n" - " " << name << " -v\n\n" - " -- Display version information only.\n\n" - "Note that this host does not use the plugin search path when loadinga plugin.\nIf a plugin library is specified, it should be with a full file path.\n" - << endl; - return 2; + usage(name); // does not return } - + if (argc == 2 && !strcmp(argv[1], "-v")) { cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl << "Vamp API version: " << VAMP_API_VERSION << endl @@ -116,87 +118,57 @@ } if (argc == 2 && !strcmp(argv[1], "-l")) { + printPluginPath(true); enumeratePlugins(); return 0; } if (argc == 2 && !strcmp(argv[1], "-p")) { - printPluginPath(); + printPluginPath(false); return 0; } - cerr << endl << argv[0] << ": Running..." << endl; + cerr << endl << name << ": Running..." << endl; string soname = argv[1]; string plugid = ""; + string output = ""; + int outputNo = -1; string wavname; if (argc >= 3) wavname = argv[2]; - int sep = soname.find(":"); - if (sep >= 0 && sep < int(soname.length())) { + string::size_type sep = soname.find(':'); + + if (sep != string::npos) { plugid = soname.substr(sep + 1); soname = soname.substr(0, sep); - } - void *libraryHandle = DLOPEN(soname, RTLD_LAZY); - - if (!libraryHandle) { - cerr << argv[0] << ": Failed to open plugin library " - << soname << ": " << DLERROR() << endl; - return 1; - } - - cerr << argv[0] << ": Opened plugin library " << soname << endl; - - VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) - DLSYM(libraryHandle, "vampGetPluginDescriptor"); - - if (!fn) { - cerr << argv[0] << ": No Vamp descriptor function in library " - << soname << endl; - DLCLOSE(libraryHandle); - return 1; - } - - cerr << argv[0] << ": Found plugin descriptor function" << endl; - - int index = 0; - int plugnumber = -1; - const VampPluginDescriptor *descriptor = 0; - - while ((descriptor = fn(VAMP_API_VERSION, index))) { - - Vamp::PluginHostAdapter plugin(descriptor, 48000); - cerr << argv[0] << ": Plugin " << (index+1) - << " is \"" << plugin.getIdentifier() << "\"" << endl; - - if (plugin.getIdentifier() == plugid) plugnumber = index; - - ++index; - } - - cerr << argv[0] << ": Done\n" << endl; - - if (wavname == "") { - DLCLOSE(libraryHandle); - return 0; - } - - if (plugnumber < 0) { - if (plugid != "") { - cerr << "ERROR: No such plugin as " << plugid << " in library" - << endl; - DLCLOSE(libraryHandle); - return 0; - } else { - plugnumber = 0; + sep = plugid.find(':'); + if (sep != string::npos) { + output = plugid.substr(sep + 1); + plugid = plugid.substr(0, sep); } } - descriptor = fn(VAMP_API_VERSION, plugnumber); - if (!descriptor) { - DLCLOSE(libraryHandle); - return 0; + if (plugid == "") { + usage(name); } + + if (argc == 4) outputNo = atoi(argv[3]); + + if (output != "" && outputNo != -1) { + usage(name); + } + + return runPlugin(name, soname, plugid, output, outputNo, wavname); +} + + +int runPlugin(string myname, string soname, string id, + string output, int outputNo, string wavname) +{ + PluginLoader *loader = PluginLoader::getInstance(); + + PluginLoader::PluginKey key = loader->composePluginKey(soname, id); SNDFILE *sndfile; SF_INFO sfinfo; @@ -204,49 +176,28 @@ sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo); if (!sndfile) { - cerr << "ERROR: Failed to open input file \"" << wavname << "\": " - << sf_strerror(sndfile) << endl; - DLCLOSE(libraryHandle); + cerr << myname << ": ERROR: Failed to open input file \"" + << wavname << "\": " << sf_strerror(sndfile) << endl; return 1; } + Vamp::Plugin *basePlugin = loader->loadPlugin(key, sfinfo.samplerate); + if (!basePlugin) { + cerr << myname << ": ERROR: Failed to load plugin \"" << id + << "\" from library \"" << soname << "\"" << endl; + sf_close(sndfile); + return 1; + } + Vamp::Plugin *plugin = - new Vamp::PluginInputDomainAdapter - (new Vamp::PluginHostAdapter(descriptor, sfinfo.samplerate)); + new Vamp::HostExt::PluginChannelAdapter + (new Vamp::HostExt::PluginInputDomainAdapter(basePlugin)); - cerr << "Running " << plugin->getIdentifier() << "..." << endl; + cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; int blockSize = plugin->getPreferredBlockSize(); int stepSize = plugin->getPreferredStepSize(); - cerr << "Preferred block size = " << blockSize << ", step size = " - << stepSize << endl; - - if (blockSize == 0) blockSize = 1024; - - bool rightBlockSize = true; - - if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) { - - int p = 1, b = blockSize; - while (b) { - p <<= 1; - b >>= 1; - } - if (p != blockSize * 2) { - cerr << "WARNING: Plugin requested non-power-of-two block size of " - << blockSize << ",\nwhich is not supported by this host. "; - blockSize = p; - cerr << "Rounding up to " << blockSize << "." << endl; - rightBlockSize = false; - } - if (stepSize == 0) stepSize = blockSize / 2; - - } else { - - if (stepSize == 0) stepSize = blockSize; - } - int channels = sfinfo.channels; float *filebuf = new float[blockSize * channels]; @@ -259,48 +210,47 @@ int minch = plugin->getMinChannelCount(); int maxch = plugin->getMaxChannelCount(); cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; + cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl; Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors(); Vamp::Plugin::OutputDescriptor od; int returnValue = 1; - int output = 0; - if (argc == 4) output = atoi(argv[3]); - - bool mix = false; - - if (minch > channels || maxch < channels) { - if (minch == 1) { - cerr << "WARNING: Sound file has " << channels << " channels, mixing down to 1" << endl; - mix = true; - channels = 1; - } else { - cerr << "ERROR: Sound file has " << channels << " channels, out of range for plugin" << endl; - goto done; - } - } - if (outputs.empty()) { - cerr << "Plugin has no outputs!" << endl; + cerr << "ERROR: Plugin has no outputs!" << endl; goto done; } - if (int(outputs.size()) <= output) { - cerr << "Output " << output << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; - goto done; - } + if (outputNo < 0) { - od = outputs[output]; - cerr << "Output is " << od.identifier << endl; + for (size_t oi = 0; oi < outputs.size(); ++oi) { + if (outputs[oi].identifier == output) { + outputNo = oi; + break; + } + } + + if (outputNo < 0) { + cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl; + goto done; + } + + } else { + + if (int(outputs.size()) <= outputNo) { + cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; + goto done; + } + } + + od = outputs[outputNo]; + cerr << "Output is: \"" << od.identifier << "\"" << endl; if (!plugin->initialise(channels, stepSize, blockSize)) { cerr << "ERROR: Plugin initialise (channels = " << channels << ", stepSize = " << stepSize << ", blockSize = " << blockSize << ") failed." << endl; - if (!rightBlockSize) { - cerr << "(Probably because I couldn't provide the plugin's preferred block size.)" << endl; - } goto done; } @@ -319,64 +269,66 @@ } for (int c = 0; c < channels; ++c) { - for (int j = 0; j < blockSize; ++j) { + int j = 0; + while (j < count) { + plugbuf[c][j] = filebuf[j * sfinfo.channels + c]; + ++j; + } + while (j < blockSize) { plugbuf[c][j] = 0.0f; - } - } - - for (int j = 0; j < blockSize && j < count; ++j) { - int tc = 0; - for (int c = 0; c < sfinfo.channels; ++c) { - tc = c; - if (mix) tc = 0; - plugbuf[tc][j] += filebuf[j * sfinfo.channels + c]; - } - if (mix) { - plugbuf[0][j] /= sfinfo.channels; + ++j; } } printFeatures - (i, sfinfo.samplerate, output, plugin->process + (i, sfinfo.samplerate, outputNo, plugin->process (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate))); } - printFeatures(sfinfo.frames, sfinfo.samplerate, output, + printFeatures(sfinfo.frames, sfinfo.samplerate, outputNo, plugin->getRemainingFeatures()); returnValue = 0; done: delete plugin; - - DLCLOSE(libraryHandle); sf_close(sndfile); return returnValue; } void -printPluginPath() +printPluginPath(bool verbose) { + if (verbose) { + cout << "\nVamp plugin search path: "; + } + vector path = Vamp::PluginHostAdapter::getPluginPath(); for (size_t i = 0; i < path.size(); ++i) { - cerr << path[i] << endl; + if (verbose) { + cout << "[" << path[i] << "]"; + } else { + cout << path[i] << endl; + } } + + if (verbose) cout << endl; } void enumeratePlugins() { - Vamp::PluginLoader loader; + PluginLoader *loader = PluginLoader::getInstance(); - cerr << endl << "Vamp plugin libraries found in search path:" << endl; + cout << "\nVamp plugin libraries found in search path:" << endl; - std::vector plugins = loader.listPlugins(); - typedef std::multimap + std::vector plugins = loader->listPlugins(); + typedef std::multimap LibraryMap; LibraryMap libraryMap; for (size_t i = 0; i < plugins.size(); ++i) { - std::string path = loader.getLibraryPathForPlugin(plugins[i]); + std::string path = loader->getLibraryPathForPlugin(plugins[i]); libraryMap.insert(LibraryMap::value_type(path, plugins[i])); } @@ -387,39 +339,38 @@ i != libraryMap.end(); ++i) { std::string path = i->first; - Vamp::PluginLoader::PluginKey key = i->second; + PluginLoader::PluginKey key = i->second; if (path != prevPath) { prevPath = path; index = 0; - cerr << "\n " << path << ":" << endl; + cout << "\n " << path << ":" << endl; } - Vamp::Plugin *plugin = loader.load(key, 48000); + Vamp::Plugin *plugin = loader->loadPlugin(key, 48000); if (plugin) { char c = char('A' + index); if (c > 'Z') c = char('a' + (index - 26)); - cerr << " [" << c << "] [v" + cout << " [" << c << "] [v" << plugin->getVampApiVersion() << "] " << plugin->getName() << ", \"" << plugin->getIdentifier() << "\"" << " [" << plugin->getMaker() << "]" << endl; -// cerr << "looking up category for " << key << " ..." << endl; - Vamp::PluginLoader::PluginCategoryHierarchy category = - loader.getPluginCategory(key); + PluginLoader::PluginCategoryHierarchy category = + loader->getPluginCategory(key); if (!category.empty()) { - cerr << " "; + cout << " "; for (size_t ci = 0; ci < category.size(); ++ci) { - cerr << " > " << category[ci]; + cout << " > " << category[ci]; } - cerr << endl; + cout << endl; } if (plugin->getDescription() != "") { - cerr << " - " << plugin->getDescription() << endl; + cout << " - " << plugin->getDescription() << endl; } Vamp::Plugin::OutputList outputs = @@ -427,21 +378,23 @@ if (outputs.size() > 1) { for (size_t j = 0; j < outputs.size(); ++j) { - cerr << " (" << j << ") " + cout << " (" << j << ") " << outputs[j].name << ", \"" << outputs[j].identifier << "\"" << endl; if (outputs[j].description != "") { - cerr << " - " + cout << " - " << outputs[j].description << endl; } } } ++index; + + delete plugin; } } - cerr << endl; + cout << endl; } void diff -r 0284955e31e5 -r fa79c4ec847d vamp-sdk/Plugin.h --- a/vamp-sdk/Plugin.h Thu May 24 10:05:00 2007 +0000 +++ b/vamp-sdk/Plugin.h Thu May 24 15:17:07 2007 +0000 @@ -379,7 +379,7 @@ /** * Used to distinguish between Vamp::Plugin and other potential - * sibling subclasses of PluginBase. Do not implement this + * sibling subclasses of PluginBase. Do not reimplement this * function in your subclass. */ virtual std::string getType() const { return "Feature Extraction Plugin"; } diff -r 0284955e31e5 -r fa79c4ec847d vamp-sdk/PluginBase.h --- a/vamp-sdk/PluginBase.h Thu May 24 10:05:00 2007 +0000 +++ b/vamp-sdk/PluginBase.h Thu May 24 15:17:07 2007 +0000 @@ -40,7 +40,7 @@ #include #include -#define VAMP_SDK_VERSION "1.0" +#define VAMP_SDK_VERSION "1.1" namespace Vamp { diff -r 0284955e31e5 -r fa79c4ec847d vamp-sdk/hostext/PluginChannelAdapter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-sdk/hostext/PluginChannelAdapter.cpp Thu May 24 15:17:07 2007 +0000 @@ -0,0 +1,165 @@ +/* -*- 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 "PluginChannelAdapter.h" + +namespace Vamp { + +namespace HostExt { + +PluginChannelAdapter::PluginChannelAdapter(Plugin *plugin) : + PluginWrapper(plugin), + m_blockSize(0), + m_inputChannels(0), + m_pluginChannels(0), + m_buffer(0), + m_forwardPtrs(0) +{ +} + +PluginChannelAdapter::~PluginChannelAdapter() +{ + if (m_buffer) { + if (m_inputChannels > m_pluginChannels) { + delete[] m_buffer[0]; + } else { + for (size_t i = 0; i < m_pluginChannels - m_inputChannels; ++i) { + delete[] m_buffer[i]; + } + } + delete[] m_buffer; + m_buffer = 0; + } + + if (m_forwardPtrs) { + delete[] m_forwardPtrs; + m_forwardPtrs = 0; + } +} + +bool +PluginChannelAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + m_blockSize = blockSize; + + size_t minch = m_plugin->getMinChannelCount(); + size_t maxch = m_plugin->getMaxChannelCount(); + + m_inputChannels = channels; + + if (channels < minch) { + m_forwardPtrs = new const float *[minch]; + if (m_inputChannels > 1) { + // We need a set of zero-valued buffers to add to the + // forwarded pointers + m_buffer = new float*[minch - channels]; + for (size_t i = 0; i < minch; ++i) { + m_buffer[i] = new float[blockSize]; + for (size_t j = 0; j < blockSize; ++j) { + m_buffer[i][j] = 0.f; + } + } + } + m_pluginChannels = minch; + return m_plugin->initialise(minch, stepSize, blockSize); + } + + if (channels > maxch) { + // We only need m_buffer if we are mixing down to a single + // channel -- otherwise we can just forward the same float* as + // passed in to process(), expecting the excess to be ignored + if (maxch == 1) { + m_buffer = new float *[1]; + m_buffer[0] = new float[blockSize]; + } + m_pluginChannels = maxch; + return m_plugin->initialise(maxch, stepSize, blockSize); + } + + m_pluginChannels = channels; + return m_plugin->initialise(channels, stepSize, blockSize); +} + +PluginChannelAdapter::FeatureSet +PluginChannelAdapter::process(const float *const *inputBuffers, + RealTime timestamp) +{ + if (m_inputChannels < m_pluginChannels) { + + if (m_inputChannels == 1) { + for (size_t i = 0; i < m_pluginChannels; ++i) { + m_forwardPtrs[i] = inputBuffers[0]; + } + } else { + for (size_t i = 0; i < m_inputChannels; ++i) { + m_forwardPtrs[i] = inputBuffers[i]; + } + for (size_t i = m_inputChannels; i < m_pluginChannels; ++i) { + m_forwardPtrs[i] = m_buffer[i - m_inputChannels]; + } + } + + return m_plugin->process(m_forwardPtrs, timestamp); + } + + if (m_inputChannels > m_pluginChannels) { + + if (m_pluginChannels == 1) { + for (size_t j = 0; j < m_blockSize; ++j) { + m_buffer[0][j] = inputBuffers[0][j]; + } + for (size_t i = 1; i < m_inputChannels; ++i) { + for (size_t j = 0; j < m_blockSize; ++j) { + m_buffer[0][j] += inputBuffers[i][j]; + } + } + for (size_t j = 0; j < m_blockSize; ++j) { + m_buffer[0][j] /= m_inputChannels; + } + return m_plugin->process(m_buffer, timestamp); + } else { + return m_plugin->process(inputBuffers, timestamp); + } + } + + return m_plugin->process(inputBuffers, timestamp); +} + +} + +} + + diff -r 0284955e31e5 -r fa79c4ec847d vamp-sdk/hostext/PluginChannelAdapter.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vamp-sdk/hostext/PluginChannelAdapter.h Thu May 24 15:17:07 2007 +0000 @@ -0,0 +1,105 @@ +/* -*- 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_CHANNEL_ADAPTER_H_ +#define _VAMP_PLUGIN_CHANNEL_ADAPTER_H_ + +#include "PluginWrapper.h" + +namespace Vamp { + +namespace HostExt { + +/** + * PluginChannelAdapter implements a policy for management of plugins + * that expect a different number of input channels from the number + * actually available in the source audio data. + * + * A host using PluginChannelAdapter may ignore the getMinChannelCount + * and getMaxChannelCount reported by the plugin, and still expect the + * plugin to run. + * + * PluginChannelAdapter implements the following policy: + * + * -- If the plugin supports the provided number of channels directly, + * PluginChannelAdapter will just run the plugin as normal. + * + * -- If the plugin only supports exactly one channel but more than + * one channel is provided, PluginChannelAdapter will use the mean of + * the channels. This ensures that the resulting values remain within + * the same magnitude range as expected for mono data. + * + * -- If the plugin requires more than one channel but exactly one is + * provided, the provided channel will be duplicated across all the + * plugin input channels. + * + * If none of the above apply: + * + * -- If the plugin requires more channels than are provided, the + * minimum acceptable number of channels will be produced by adding + * empty (zero valued) channels to those provided. + * + * -- If the plugin requires fewer channels than are provided, the + * maximum acceptable number of channels will be produced by + * discarding the excess channels. + * + * Hosts requiring a different channel policy from the above will need + * to implement it themselves, instead of using PluginChannelAdapter. + */ + +class PluginChannelAdapter : public PluginWrapper +{ +public: + PluginChannelAdapter(Plugin *plugin); // I take ownership of plugin + virtual ~PluginChannelAdapter(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + +protected: + size_t m_blockSize; + size_t m_inputChannels; + size_t m_pluginChannels; + float **m_buffer; + const float **m_forwardPtrs; +}; + +} + +} + +#endif diff -r 0284955e31e5 -r fa79c4ec847d vamp-sdk/hostext/PluginInputDomainAdapter.cpp --- a/vamp-sdk/hostext/PluginInputDomainAdapter.cpp Thu May 24 10:05:00 2007 +0000 +++ b/vamp-sdk/hostext/PluginInputDomainAdapter.cpp Thu May 24 15:17:07 2007 +0000 @@ -40,6 +40,8 @@ namespace Vamp { +namespace HostExt { + PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) : PluginWrapper(plugin), m_channels(0), @@ -55,7 +57,7 @@ bool PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) { - //!!! complain and die if blocksize is not a power of 2 + //!!! complain and adapt-or-die if blocksize is not a power of 2 if (m_plugin->getInputDomain() == FrequencyDomain) { if (m_channels > 0) { @@ -106,6 +108,8 @@ size_t PluginInputDomainAdapter::getPreferredBlockSize() const { + //!!! complain and adapt-or-die if blocksize is not a power of 2 + size_t block = m_plugin->getPreferredBlockSize(); if (block == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) { @@ -269,6 +273,7 @@ } } +} } diff -r 0284955e31e5 -r fa79c4ec847d vamp-sdk/hostext/PluginInputDomainAdapter.h --- a/vamp-sdk/hostext/PluginInputDomainAdapter.h Thu May 24 10:05:00 2007 +0000 +++ b/vamp-sdk/hostext/PluginInputDomainAdapter.h Thu May 24 15:17:07 2007 +0000 @@ -34,12 +34,15 @@ authorization. */ -#ifndef _PLUGIN_INPUT_DOMAIN_ADAPTER_H_ +#ifndef _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_ +#define _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_ #include "PluginWrapper.h" namespace Vamp { +namespace HostExt { + /** * An adapter that converts time-domain input into frequency-domain * input for plugins that need it. In every other respect this @@ -78,7 +81,6 @@ FeatureSet process(const float *const *inputBuffers, RealTime timestamp); protected: - Plugin *m_plugin; size_t m_channels; size_t m_blockSize; float **m_freqbuf; @@ -92,4 +94,6 @@ } +} + #endif diff -r 0284955e31e5 -r fa79c4ec847d vamp-sdk/hostext/PluginLoader.cpp --- a/vamp-sdk/hostext/PluginLoader.cpp Thu May 24 10:05:00 2007 +0000 +++ b/vamp-sdk/hostext/PluginLoader.cpp Thu May 24 15:17:07 2007 +0000 @@ -34,19 +34,39 @@ authorization. */ +#include "vamp-sdk/PluginHostAdapter.h" #include "PluginLoader.h" -#include "PluginHostAdapter.h" - -#include "system.h" #include -#include // POSIX directory open and read +#ifdef _WIN32 + +#include +#include +#define PLUGIN_SUFFIX "dll" + +#else /* ! _WIN32 */ + +#include +#include + +#ifdef __APPLE__ +#define PLUGIN_SUFFIX "dylib" +#else /* ! __APPLE__ */ +#define PLUGIN_SUFFIX "so" +#endif /* ! __APPLE__ */ + +#endif /* ! _WIN32 */ using namespace std; namespace Vamp { +namespace HostExt { + +PluginLoader * +PluginLoader::m_instance = 0; + PluginLoader::PluginLoader() { } @@ -55,73 +75,85 @@ { } +PluginLoader * +PluginLoader::getInstance() +{ + if (!m_instance) m_instance = new PluginLoader(); + return m_instance; +} + vector PluginLoader::listPlugins() { - if (m_pluginLibraryMap.empty()) { - - vector path = PluginHostAdapter::getPluginPath(); - - size_t suffixLen = strlen(PLUGIN_SUFFIX); - - for (size_t i = 0; i < path.size(); ++i) { - - vector files = getFilesInDir(path[i], PLUGIN_SUFFIX); - - - for (vector::iterator fi = files.begin(); - fi != files.end(); ++fi) { - - string basename = *fi; - basename = basename.substr(0, basename.length() - suffixLen - 1); - - string fullPath = path[i]; - fullPath = fullPath + "/" + *fi; //!!! systemize - void *handle = DLOPEN(fullPath, RTLD_LAZY); - - if (!handle) { - cerr << "Vamp::PluginLoader: " << *fi - << ": unable to load library (" << DLERROR() - << ")" << 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); - } - } - } + if (m_pluginLibraryNameMap.empty()) generateLibraryMap(); vector plugins; for (map::iterator mi = - m_pluginLibraryMap.begin(); - mi != m_pluginLibraryMap.end(); ++mi) { + m_pluginLibraryNameMap.begin(); + mi != m_pluginLibraryNameMap.end(); ++mi) { plugins.push_back(mi->first); } return plugins; } +void +PluginLoader::generateLibraryMap() +{ + vector path = PluginHostAdapter::getPluginPath(); + + for (size_t i = 0; i < path.size(); ++i) { + + vector files = listFiles(path[i], PLUGIN_SUFFIX); + + for (vector::iterator fi = files.begin(); + fi != files.end(); ++fi) { + + string fullPath = path[i]; + fullPath = splicePath(fullPath, *fi); + void *handle = loadLibrary(fullPath); + if (!handle) continue; + + VampGetPluginDescriptorFunction fn = + (VampGetPluginDescriptorFunction)lookupInLibrary + (handle, "vampGetPluginDescriptor"); + + if (!fn) { + unloadLibrary(handle); + continue; + } + + int index = 0; + const VampPluginDescriptor *descriptor = 0; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + PluginKey key = composePluginKey(*fi, descriptor->identifier); + if (m_pluginLibraryNameMap.find(key) == + m_pluginLibraryNameMap.end()) { + m_pluginLibraryNameMap[key] = fullPath; + } + ++index; + } + + unloadLibrary(handle); + } + } +} + +PluginLoader::PluginKey +PluginLoader::composePluginKey(string libraryName, string identifier) +{ + string basename = libraryName; + + string::size_type li = basename.rfind('/'); + if (li != string::npos) basename = basename.substr(li + 1); + + li = basename.find('.'); + if (li != string::npos) basename = basename.substr(0, li); + + return basename + ":" + identifier; +} + PluginLoader::PluginCategoryHierarchy PluginLoader::getPluginCategory(PluginKey plugin) { @@ -133,13 +165,13 @@ string PluginLoader::getLibraryPathForPlugin(PluginKey plugin) { - if (m_pluginLibraryMap.empty()) (void)listPlugins(); - if (m_pluginLibraryMap.find(plugin) == m_pluginLibraryMap.end()) return ""; - return m_pluginLibraryMap[plugin]; + if (m_pluginLibraryNameMap.empty()) generateLibraryMap(); + if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) return ""; + return m_pluginLibraryNameMap[plugin]; } Plugin * -PluginLoader::load(PluginKey key, float inputSampleRate) +PluginLoader::loadPlugin(PluginKey key, float inputSampleRate) { string fullPath = getLibraryPathForPlugin(key); if (fullPath == "") return 0; @@ -152,23 +184,15 @@ string identifier = key.substr(ki + 1); - void *handle = DLOPEN(fullPath, RTLD_LAZY); - - if (!handle) { - cerr << "Vamp::PluginLoader: " << fullPath - << ": unable to load library (" << DLERROR() - << ")" << endl; - return 0; - } + void *handle = loadLibrary(fullPath); + if (!handle) return 0; VampGetPluginDescriptorFunction fn = - (VampGetPluginDescriptorFunction)DLSYM + (VampGetPluginDescriptorFunction)lookupInLibrary (handle, "vampGetPluginDescriptor"); if (!fn) { - //!!! refcount this! --!!! no, POSIX says dlopen/dlclose will - // reference count. check on win32 - DLCLOSE(handle); + unloadLibrary(handle); return 0; } @@ -176,46 +200,29 @@ const VampPluginDescriptor *descriptor = 0; while ((descriptor = fn(VAMP_API_VERSION, index))) { + if (string(descriptor->identifier) == identifier) { - return new Vamp::PluginHostAdapter(descriptor, inputSampleRate); + + Vamp::PluginHostAdapter *plugin = + new Vamp::PluginHostAdapter(descriptor, inputSampleRate); + + PluginDeletionNotifyAdapter *adapter = + new PluginDeletionNotifyAdapter(plugin, this); + + m_pluginLibraryHandleMap[adapter] = handle; + return adapter; } + ++index; } - - //!!! flag error + + cerr << "Vamp::HostExt::PluginLoader: Plugin \"" + << identifier << "\" not found in library \"" + << fullPath << "\"" << endl; + return 0; } -vector -PluginLoader::getFilesInDir(string dir, string extension) -{ - vector files; - - DIR *d = opendir(dir.c_str()); - if (!d) return files; - - 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(extension.length() + 2) || - e->d_name[len - extension.length() - 1] != '.' || - strcmp(e->d_name + len - extension.length(), extension.c_str())) { - continue; - } - - files.push_back(e->d_name); - } - - closedir(d); - - return files; -} - void PluginLoader::generateTaxonomy() { @@ -229,6 +236,11 @@ for (vector::iterator i = path.begin(); i != path.end(); ++i) { + + // It doesn't matter that we're using literal forward-slash in + // this bit, as it's only relevant if the path contains + // "/lib/", which is only meaningful and only plausible on + // systems with forward-slash delimiters string dir = *i; string::size_type li = dir.find(libfragment); @@ -248,12 +260,12 @@ for (vector::iterator i = catpath.begin(); i != catpath.end(); ++i) { - vector files = getFilesInDir(*i, suffix); + vector files = listFiles(*i, suffix); for (vector::iterator fi = files.begin(); fi != files.end(); ++fi) { - string filepath = *i + "/" + *fi; //!!! systemize + string filepath = splicePath(*i, *fi); ifstream is(filepath.c_str(), ifstream::in | ifstream::binary); if (is.fail()) { @@ -299,5 +311,130 @@ } } +void * +PluginLoader::loadLibrary(string path) +{ + void *handle = 0; +#ifdef _WIN32 + handle = LoadLibrary(path.c_str()); + if (!handle) { + cerr << "Vamp::HostExt::PluginLoader: Unable to load library \"" + << path << "\"" << endl; + } +#else + handle = dlopen(path.c_str(), RTLD_LAZY); + if (!handle) { + cerr << "Vamp::HostExt::PluginLoader: Unable to load library \"" + << path << "\": " << dlerror() << endl; + } +#endif + return handle; +} + +void +PluginLoader::unloadLibrary(void *handle) +{ +#ifdef _WIN32 + FreeLibrary((HINSTANCE)handle); +#else + dlclose(handle); +#endif +} + +void * +PluginLoader::lookupInLibrary(void *handle, const char *symbol) +{ +#ifdef _WIN32 + return (void *)GetProcAddress((HINSTANCE)handle, symbol); +#else + return (void *)dlsym(handle, symbol); +#endif +} + +string +PluginLoader::splicePath(string a, string b) +{ +#ifdef _WIN32 + return a + "\\" + b; +#else + return a + "/" + b; +#endif +} + +vector +PluginLoader::listFiles(string dir, string extension) +{ + vector files; + size_t extlen = extension.length(); + +#ifdef _WIN32 + + string expression = dir + "\\*." + extension; + WIN32_FIND_DATA data; + HANDLE fh = FindFirstFile(expression.c_str(), &data); + if (fh == INVALID_HANDLE_VALUE) return files; + + bool ok = true; + while (ok) { + files.push_back(data.cFileName); + ok = FindNextFile(fh, &data); + } + + FindClose(fh); + +#else + DIR *d = opendir(dir.c_str()); + if (!d) return files; + + struct dirent *e = 0; + while ((e = readdir(d))) { + + if (!(e->d_type & DT_REG) || !e->d_name) continue; + + size_t len = strlen(e->d_name); + if (len < extlen + 2 || + e->d_name + len - extlen - 1 != "." + extension) { + continue; + } + + files.push_back(e->d_name); + } + + closedir(d); +#endif + + return files; +} + +void +PluginLoader::pluginDeleted(PluginDeletionNotifyAdapter *adapter) +{ + void *handle = m_pluginLibraryHandleMap[adapter]; + if (handle) unloadLibrary(handle); + m_pluginLibraryHandleMap.erase(adapter); +} + +PluginLoader::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin, + PluginLoader *loader) : + PluginWrapper(plugin), + m_loader(loader) +{ +} + +PluginLoader::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter() +{ + // We need to delete the plugin before calling pluginDeleted, as + // the delete call may require calling through to the descriptor + // (for e.g. cleanup) but pluginDeleted may unload the required + // library for the call. To prevent a double deletion when our + // parent's destructor runs (after this one), be sure to set + // m_plugin to 0 after deletion. + delete m_plugin; + m_plugin = 0; + + if (m_loader) m_loader->pluginDeleted(this); +} } + +} diff -r 0284955e31e5 -r fa79c4ec847d vamp-sdk/hostext/PluginLoader.h --- a/vamp-sdk/hostext/PluginLoader.h Thu May 24 10:05:00 2007 +0000 +++ b/vamp-sdk/hostext/PluginLoader.h Thu May 24 15:17:07 2007 +0000 @@ -41,40 +41,67 @@ #include #include +#include "PluginWrapper.h" + namespace Vamp { class Plugin; +namespace HostExt { + class PluginLoader { public: - PluginLoader(); - virtual ~PluginLoader(); + static PluginLoader *getInstance(); typedef std::string PluginKey; typedef std::vector PluginCategoryHierarchy; std::vector 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 plugin, float inputSampleRate); + PluginKey composePluginKey(std::string libraryName, std::string identifier); + + Plugin *loadPlugin(PluginKey plugin, float inputSampleRate); PluginCategoryHierarchy getPluginCategory(PluginKey plugin); std::string getLibraryPathForPlugin(PluginKey plugin); protected: - std::map m_pluginLibraryMap; + PluginLoader(); + virtual ~PluginLoader(); + + class PluginDeletionNotifyAdapter : public PluginWrapper { + public: + PluginDeletionNotifyAdapter(Plugin *plugin, PluginLoader *loader); + virtual ~PluginDeletionNotifyAdapter(); + protected: + PluginLoader *m_loader; + }; + + virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter); + + std::map m_pluginLibraryNameMap; + void generateLibraryMap(); + std::map m_taxonomy; void generateTaxonomy(); - std::vector getFilesInDir(std::string dir, std::string ext); + + std::map m_pluginLibraryHandleMap; + + void *loadLibrary(std::string path); + void unloadLibrary(void *handle); + void *lookupInLibrary(void *handle, const char *symbol); + + std::string splicePath(std::string a, std::string b); + std::vector listFiles(std::string dir, std::string ext); + + static PluginLoader *m_instance; }; } +} #endif diff -r 0284955e31e5 -r fa79c4ec847d vamp-sdk/hostext/PluginWrapper.cpp --- a/vamp-sdk/hostext/PluginWrapper.cpp Thu May 24 10:05:00 2007 +0000 +++ b/vamp-sdk/hostext/PluginWrapper.cpp Thu May 24 15:17:07 2007 +0000 @@ -38,8 +38,11 @@ namespace Vamp { +namespace HostExt { + PluginWrapper::PluginWrapper(Plugin *plugin) : - Plugin(0) + Plugin(0), + m_plugin(plugin) { } @@ -187,3 +190,5 @@ } +} + diff -r 0284955e31e5 -r fa79c4ec847d vamp-sdk/hostext/PluginWrapper.h --- a/vamp-sdk/hostext/PluginWrapper.h Thu May 24 10:05:00 2007 +0000 +++ b/vamp-sdk/hostext/PluginWrapper.h Thu May 24 15:17:07 2007 +0000 @@ -34,12 +34,15 @@ authorization. */ -#ifndef _PLUGIN_WRAPPER_H_ +#ifndef _VAMP_PLUGIN_WRAPPER_H_ +#define _VAMP_PLUGIN_WRAPPER_H_ #include namespace Vamp { +namespace HostExt { + class PluginWrapper : public Plugin { public: @@ -85,4 +88,6 @@ } +} + #endif diff -r 0284955e31e5 -r fa79c4ec847d vamp-sdk/hostext/system.h --- a/vamp-sdk/hostext/system.h Thu May 24 10:05:00 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +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 _SYSTEM_H_ -#define _SYSTEM_H_ - -#ifdef _WIN32 - -#include - -#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 - -#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 -