# HG changeset patch # User cannam # Date 1226335661 0 # Node ID 7b90fe049d04834de0d2c192af6316967494805a # Parent cc467e52da4c05ce128b81c74993856789ba5e28 * Add --list-full to "simple" Vamp host diff -r cc467e52da4c -r 7b90fe049d04 host/vamp-simple-host.cpp --- a/host/vamp-simple-host.cpp Mon Nov 10 12:39:19 2008 +0000 +++ b/host/vamp-simple-host.cpp Mon Nov 10 16:47:41 2008 +0000 @@ -7,7 +7,6 @@ Centre for Digital Music, Queen Mary, University of London. Copyright 2006 Chris Cannam. - FFT code from Don Cross's public domain FFT implementation. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -35,6 +34,18 @@ authorization. */ + +/* + * This "simple" Vamp plugin host is no longer as simple as it was; it + * now has a lot of options and includes a lot of code to handle the + * various useful list options it supports. + * + * However, the runPlugin function still contains a reasonable + * implementation of a fairly generic Vamp plugin host capable of + * evaluating a given output on a given plugin for a sound file read + * via libsndfile. + */ + #include #include #include @@ -60,12 +71,13 @@ using Vamp::HostExt::PluginWrapper; using Vamp::HostExt::PluginInputDomainAdapter; -#define HOST_VERSION "1.3" +#define HOST_VERSION "1.4" enum Verbosity { PluginIds, PluginOutputIds, - PluginInformation + PluginInformation, + PluginInformationDetailed }; void printFeatures(int, int, int, Plugin::FeatureSet, ofstream *, bool frames); @@ -81,7 +93,7 @@ void usage(const char *name) { cerr << "\n" - << name << ": A simple Vamp plugin host.\n\n" + << name << ": A command-line host for Vamp audio analysis plugins.\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" @@ -98,9 +110,13 @@ " If the -s option is given, results will be labelled with the audio\n" " sample frame at which they occur. Otherwise, they will be labelled\n" " with time in seconds.\n\n" - " " << name << " -l\n\n" + " " << name << " -l\n" + " " << name << " --list\n\n" " -- List the plugin libraries and Vamp plugins in the library search path\n" " in a verbose human-readable format.\n\n" + " " << name << " --list-full\n\n" + " -- List all data reported by all the Vamp plugins in the library search\n" + " path in a very verbose human-readable format.\n\n" " " << name << " --list-ids\n\n" " -- List the plugins in the search path in a terse machine-readable format,\n" " in the form vamp:soname:identifier.\n\n" @@ -139,12 +155,17 @@ << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; return 0; - } else if (!strcmp(argv[1], "-l")) { + } else if (!strcmp(argv[1], "-l") || !strcmp(argv[1], "--list")) { printPluginPath(true); enumeratePlugins(PluginInformation); return 0; + } else if (!strcmp(argv[1], "--list-full")) { + + enumeratePlugins(PluginInformationDetailed); + return 0; + } else if (!strcmp(argv[1], "-p")) { printPluginPath(false); @@ -286,6 +307,17 @@ cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; + // Note that the following would be much simpler if we used a + // PluginBufferingAdapter as well -- i.e. if we had passed + // PluginLoader::ADAPT_ALL to loader->loadPlugin() above, instead + // of ADAPT_ALL_SAFE. Then we could simply specify our own block + // size, keep the step size equal to the block size, and ignore + // the plugin's bleatings. However, there are some issues with + // using a PluginBufferingAdapter that make the results sometimes + // technically different from (if effectively the same as) the + // un-adapted plugin, so we aren't doing that here. See the + // PluginBufferingAdapter documentation for details. + int blockSize = plugin->getPreferredBlockSize(); int stepSize = plugin->getPreferredStepSize(); @@ -317,6 +349,10 @@ cerr << "Using block size = " << blockSize << ", step size = " << stepSize << endl; + // The channel queries here are for informational purposes only -- + // a PluginChannelAdapter is being used automatically behind the + // scenes, and it will take case of any channel mismatch + int minch = plugin->getMinChannelCount(); int maxch = plugin->getMaxChannelCount(); cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; @@ -371,6 +407,8 @@ wrapper = dynamic_cast(plugin); if (wrapper) { + // See documentation for + // PluginInputDomainAdapter::getTimestampAdjustment PluginInputDomainAdapter *ida = wrapper->getWrapper(); if (ida) adjustment = ida->getTimestampAdjustment(); @@ -505,6 +543,18 @@ if (verbose) cout << endl; } +static +string +header(string text, int level) +{ + string out = '\n' + text + '\n'; + for (size_t i = 0; i < text.length(); ++i) { + out += (level == 1 ? '=' : level == 2 ? '-' : '~'); + } + out += '\n'; + return out; +} + void enumeratePlugins(Verbosity verbosity) { @@ -538,6 +588,10 @@ index = 0; if (verbosity == PluginInformation) { cout << "\n " << path << ":" << endl; + } else if (verbosity == PluginInformationDetailed) { + string::size_type ki = i->second.find(':'); + string text = "Library \"" + i->second.substr(0, ki) + "\""; + cout << "\n" << header(text, 1); } } @@ -547,6 +601,16 @@ char c = char('A' + index); if (c > 'Z') c = char('a' + (index - 26)); + PluginLoader::PluginCategoryHierarchy category = + loader->getPluginCategory(key); + string catstr; + if (!category.empty()) { + for (size_t ci = 0; ci < category.size(); ++ci) { + if (ci > 0) catstr += " > "; + catstr += category[ci]; + } + } + if (verbosity == PluginInformation) { cout << " [" << c << "] [v" @@ -554,22 +618,42 @@ << plugin->getName() << ", \"" << plugin->getIdentifier() << "\"" << " [" << plugin->getMaker() << "]" << endl; - - PluginLoader::PluginCategoryHierarchy category = - loader->getPluginCategory(key); - - if (!category.empty()) { - cout << " "; - for (size_t ci = 0; ci < category.size(); ++ci) { - cout << " > " << category[ci]; - } - cout << endl; + + if (catstr != "") { + cout << " > " << catstr << endl; } if (plugin->getDescription() != "") { cout << " - " << plugin->getDescription() << endl; } + } else if (verbosity == PluginInformationDetailed) { + + cout << header(plugin->getName(), 2); + cout << "- Identifier: " + << key << endl; + cout << "- Plugin Version: " + << plugin->getPluginVersion() << endl; + cout << "- Vamp API Version: " + << plugin->getVampApiVersion() << endl; + cout << "- Maker: \"" + << plugin->getMaker() << "\"" << endl; + cout << "- Copyright: \"" + << plugin->getCopyright() << "\"" << endl; + cout << "- Description: \"" + << plugin->getDescription() << "\"" << endl; + cout << "- Input Domain: " + << (plugin->getInputDomain() == Vamp::Plugin::TimeDomain ? + "Time Domain" : "Frequency Domain") << endl; + cout << "- Default Step Size: " + << plugin->getPreferredStepSize() << endl; + cout << "- Default Block Size: " + << plugin->getPreferredBlockSize() << endl; + cout << "- Minimum Channels: " + << plugin->getMinChannelCount() << endl; + cout << "- Maximum Channels: " + << plugin->getMaxChannelCount() << endl; + } else if (verbosity == PluginIds) { cout << "vamp:" << key << endl; } @@ -577,6 +661,83 @@ Plugin::OutputList outputs = plugin->getOutputDescriptors(); + if (verbosity == PluginInformationDetailed) { + + Plugin::ParameterList params = plugin->getParameterDescriptors(); + for (size_t j = 0; j < params.size(); ++j) { + Plugin::ParameterDescriptor &pd(params[j]); + cout << "\nParameter " << j+1 << ": \"" << pd.name << "\"" << endl; + cout << "- Identifier: " << pd.identifier << endl; + cout << "- Description: \"" << pd.description << "\"" << endl; + if (pd.unit != "") { + cout << "- Unit: " << pd.unit << endl; + } + cout << "- Range: "; + cout << pd.minValue << " -> " << pd.maxValue << endl; + cout << "- Default: "; + cout << pd.defaultValue << endl; + if (pd.isQuantized) { + cout << "- Quantize Step: " + << pd.quantizeStep << endl; + } + if (!pd.valueNames.empty()) { + cout << "- Value Names: "; + for (size_t k = 0; k < pd.valueNames.size(); ++k) { + if (k > 0) cout << ", "; + cout << "\"" << pd.valueNames[k] << "\""; + } + cout << endl; + } + } + + if (outputs.empty()) { + cout << "\n** Note: This plugin reports no outputs!" << endl; + } + for (size_t j = 0; j < outputs.size(); ++j) { + Plugin::OutputDescriptor &od(outputs[j]); + cout << "\nOutput " << j+1 << ": \"" << od.name << "\"" << endl; + cout << "- Identifier: " << od.identifier << endl; + cout << "- Description: \"" << od.description << "\"" << endl; + if (od.unit != "") { + cout << "- Unit: " << od.unit << endl; + } + if (od.hasFixedBinCount) { + cout << "- Default Bin Count: " << od.binCount << endl; + } + if (!od.binNames.empty()) { + cout << "- Bin Names: "; + for (size_t k = 0; k < od.binNames.size(); ++k) { + if (k > 0) cout << ", "; + cout << "\"" << od.binNames[k] << "\""; + } + cout << endl; + } + if (od.hasKnownExtents) { + cout << "- Default Extents: "; + cout << od.minValue << " -> " << od.maxValue << endl; + } + if (od.isQuantized) { + cout << "- Quantize Step: " + << od.quantizeStep << endl; + } + cout << "- Sample Type: " + << (od.sampleType == + Plugin::OutputDescriptor::OneSamplePerStep ? + "One Sample Per Step" : + od.sampleType == + Plugin::OutputDescriptor::FixedSampleRate ? + "Fixed Sample Rate" : + "Variable Sample Rate") << endl; + if (od.sampleType != + Plugin::OutputDescriptor::OneSamplePerStep) { + cout << "- Default Rate: " + << od.sampleRate << endl; + } + cout << "- Has Duration: " + << (od.hasDuration ? "Yes" : "No") << endl; + } + } + if (outputs.size() > 1 || verbosity == PluginOutputIds) { for (size_t j = 0; j < outputs.size(); ++j) { if (verbosity == PluginInformation) { @@ -599,7 +760,8 @@ } } - if (verbosity == PluginInformation) { + if (verbosity == PluginInformation || + verbosity == PluginInformationDetailed) { cout << endl; } } diff -r cc467e52da4c -r 7b90fe049d04 src/vamp-hostsdk/PluginHostAdapter.cpp --- a/src/vamp-hostsdk/PluginHostAdapter.cpp Mon Nov 10 12:39:19 2008 +0000 +++ b/src/vamp-hostsdk/PluginHostAdapter.cpp Mon Nov 10 16:47:41 2008 +0000 @@ -327,7 +327,7 @@ d.unit = sd->unit; d.hasFixedBinCount = sd->hasFixedBinCount; d.binCount = sd->binCount; - if (d.hasFixedBinCount) { + if (d.hasFixedBinCount && sd->binNames) { for (unsigned int j = 0; j < sd->binCount; ++j) { d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : ""); } diff -r cc467e52da4c -r 7b90fe049d04 src/vamp-sdk/PluginAdapter.cpp --- a/src/vamp-sdk/PluginAdapter.cpp Mon Nov 10 12:39:19 2008 +0000 +++ b/src/vamp-sdk/PluginAdapter.cpp Mon Nov 10 16:47:41 2008 +0000 @@ -661,7 +661,12 @@ desc->hasFixedBinCount = od.hasFixedBinCount; desc->binCount = od.binCount; - if (od.hasFixedBinCount && od.binCount > 0) { + if (od.hasFixedBinCount && od.binCount > 0 + // We would like to do "&& !od.binNames.empty()" here -- but we + // can't, because it will crash older versions of the host adapter + // which try to copy the names across whenever the bin count is + // non-zero, regardless of whether they exist or not + ) { desc->binNames = (const char **) malloc(od.binCount * sizeof(const char *));