Mercurial > hg > vamp-plugin-sdk
changeset 40:ae3e47e76d2d
* Add plugin path traversal and plugin listing option to vamp-simple-host
* Add more notes on plugin lookup and categorisation
author | cannam |
---|---|
date | Mon, 09 Oct 2006 12:45:14 +0000 |
parents | 46c39790588b |
children | 31cd55174467 |
files | README host/system.h host/vamp-simple-host.cpp vamp-sdk/PluginAdapter.cpp |
diffstat | 4 files changed, 160 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/README Thu Sep 21 16:41:10 2006 +0000 +++ b/README Mon Oct 09 12:45:14 2006 +0000 @@ -94,13 +94,36 @@ it to process a complete audio file, with its default parameters. Requires libsndfile. -The Vamp API doesn't officially specify how to load plugin libraries -or where to find them. However, good practice for a host is to use -the Vamp path returned by Vamp::PluginHostAdapter::getPluginPath() and -search each directory in this path for .so, .dll or .dylib files -(depending on platform), loading each one and testing for the -vampGetPluginDescriptor function to enumerate the plugins in this -object. The example host has some code that may help. + +Plugin Lookup and Categorisation +================================ + +The Vamp API does not officially specify how to load plugin libraries +or where to find them. However, the SDK does include a function +(Vamp::PluginHostAdapter::getPluginPath()) that returns a recommended +directory search path that hosts may use for plugin libraries. + +Our suggestion for a host is to search each directory in this path for +.DLL (on Windows), .so (on Linux, Solaris, BSD etc) or .dylib (on +OS/X) files, then to load each one and perform a dynamic name lookup +on the vampGetPluginDescriptor function to enumerate the plugins in +the library. The example host has some code that may help, but this +operation will necessarily be system-dependent. + +Vamp also has an informal convention for sorting plugins into +functional categories. In addition to the library file itself, a +plugin library may install a category file with the same name as the +library but .cat extension. The existence and format of this file are +not specified by the Vamp API, but by convention the file may contain +lines of the format + +vamp:pluginlibrary:pluginname::General Category > Specific Category + +which a host may read and use to assign plugins a location within a +category tree for display to the user. The expectation is that +advanced users may also choose to set up their own preferred category +trees, which is why this information is not queried as part of the +Vamp API itself. Building the SDK
--- a/host/system.h Thu Sep 21 16:41:10 2006 +0000 +++ b/host/system.h Mon Oct 09 12:45:14 2006 +0000 @@ -46,7 +46,7 @@ #define DLCLOSE(a) FreeLibrary((HINSTANCE)(a)) #define DLERROR() "" -#define PLUGIN_GLOB "*.dll" +#define PLUGIN_SUFFIX "dll" #else @@ -59,11 +59,13 @@ #ifdef __APPLE__ -#define PLUGIN_GLOB "*.dylib" +#define PLUGIN_SUFFIX "dylib" +#define HAVE_OPENDIR 1 #else -#define PLUGIN_GLOB "*.so" +#define PLUGIN_SUFFIX "so" +#define HAVE_OPENDIR 1 #endif /* __APPLE__ */
--- a/host/vamp-simple-host.cpp Thu Sep 21 16:41:10 2006 +0000 +++ b/host/vamp-simple-host.cpp Mon Oct 09 12:45:14 2006 +0000 @@ -40,6 +40,7 @@ #include <iostream> #include <sndfile.h> +#include <dirent.h> // POSIX directory open and read #include "system.h" @@ -51,9 +52,16 @@ using std::string; using std::vector; + + void printFeatures(int, int, int, Vamp::Plugin::FeatureSet); 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 @@ -65,26 +73,56 @@ int main(int argc, char **argv) { if (argc < 2 || argc > 4) { - cerr << "Usage: " << argv[0] << " pluginlibrary.so[:plugin] [file.wav] [outputno]" << endl; + 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" + "Note that this host does not use the plugin search path when loading a plugin.\nIf a plugin library is specified, it should be with a full file path.\n" + << endl; return 2; } + if (argc == 2 && !strcmp(argv[1], "-l")) { +#ifdef HAVE_OPENDIR + enumeratePlugins(); +#endif + return 0; + } + if (argc == 2 && !strcmp(argv[1], "-p")) { + printPluginPath(); + return 0; + } + cerr << endl << argv[0] << ": Running..." << endl; - cerr << endl << "Vamp path is set to:" << endl; - vector<string> path = Vamp::PluginHostAdapter::getPluginPath(); - for (size_t i = 0; i < path.size(); ++i) { - cerr << "\t" << path[i] << endl; - } - cerr << "(This program doesn't use the path; just printing it for information)" << endl << endl; - string soname = argv[1]; string plugname = ""; string wavname; if (argc >= 3) wavname = argv[2]; int sep = soname.find(":"); - if (sep >= 0 && sep < soname.length()) { + if (sep >= 0 && sep < int(soname.length())) { plugname = soname.substr(sep + 1); soname = soname.substr(0, sep); } @@ -300,6 +338,78 @@ } void +printPluginPath() +{ + vector<string> path = Vamp::PluginHostAdapter::getPluginPath(); + for (size_t i = 0; i < path.size(); ++i) { + cerr << path[i] << endl; + } +} + +#ifdef HAVE_OPENDIR + +void +enumeratePlugins() +{ + 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; + } + struct dirent *e = 0; + while ((e = readdir(d))) { + if (!(e->d_type & DT_REG)) continue; + 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)) { + continue; + } + 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(index))) { + Vamp::PluginHostAdapter plugin(descriptor, 48000); + cerr << " [" << char('A' + index) << "] " + << plugin.getDescription() + << ", \"" << plugin.getName() << "\"" + << " [" << plugin.getMaker() + << "]" << std::endl; + Vamp::Plugin::OutputList outputs = + plugin.getOutputDescriptors(); + if (outputs.size() > 1) { + for (size_t j = 0; j < outputs.size(); ++j) { + cerr << " (" << j << ") " + << outputs[j].description << endl; + } + } + ++index; + } + } + DLCLOSE(handle); + } + } + closedir(d); + } + cerr << endl; +} + +#endif + + +void printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features) { for (unsigned int i = 0; i < features[output].size(); ++i) {
--- a/vamp-sdk/PluginAdapter.cpp Thu Sep 21 16:41:10 2006 +0000 +++ b/vamp-sdk/PluginAdapter.cpp Mon Oct 09 12:45:14 2006 +0000 @@ -410,8 +410,12 @@ if (desc->name) free((void *)desc->name); if (desc->description) free((void *)desc->description); if (desc->unit) free((void *)desc->unit); - for (unsigned int i = 0; i < desc->binCount; ++i) { - free((void *)desc->binNames[i]); + if (desc->hasFixedBinCount && desc->binNames) { + for (unsigned int i = 0; i < desc->binCount; ++i) { + if (desc->binNames[i]) { + free((void *)desc->binNames[i]); + } + } } if (desc->binNames) free((void *)desc->binNames); free((void *)desc);