Mercurial > hg > vamp-plugin-sdk
diff host/vamp-simple-host.cpp @ 59:fa79c4ec847d host-factory-stuff
* 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
author | cannam |
---|---|
date | Thu, 24 May 2007 15:17:07 +0000 |
parents | 09a1aac6c362 |
children | 97c5ac99d725 |
line wrap: on
line diff
--- 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 <iostream> #include <sndfile.h> @@ -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<string> 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<Vamp::PluginLoader::PluginKey> plugins = loader.listPlugins(); - typedef std::multimap<std::string, Vamp::PluginLoader::PluginKey> + std::vector<PluginLoader::PluginKey> plugins = loader->listPlugins(); + typedef std::multimap<std::string, PluginLoader::PluginKey> 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