74 #define HOST_VERSION "1.5" 83 void printFeatures(
int,
int,
int, Plugin::FeatureSet, ofstream *,
bool frames);
85 void fft(
unsigned int,
bool,
double *,
double *,
double *,
double *);
90 int runPlugin(
string myname,
string soname,
string id,
string output,
91 int outputNo,
string inputFile,
string outfilename,
bool frames);
96 << name <<
": A command-line host for Vamp audio analysis plugins.\n\n" 97 "Centre for Digital Music, Queen Mary, University of London.\n" 98 "Copyright 2006-2009 Chris Cannam and QMUL.\n" 99 "Freely redistributable; published under a BSD-style license.\n\n" 101 " " << name <<
" [-s] pluginlibrary[." <<
PLUGIN_SUFFIX <<
"]:plugin[:output] file.wav [-o out.txt]\n" 102 " " << name <<
" [-s] pluginlibrary[." <<
PLUGIN_SUFFIX <<
"]:plugin file.wav [outputno] [-o out.txt]\n\n" 103 " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n" 104 " audio data in \"file.wav\", retrieving the named \"output\", or output\n" 105 " number \"outputno\" (the first output by default) and dumping it to\n" 106 " standard output, or to \"out.txt\" if the -o option is given.\n\n" 107 " \"pluginlibrary\" should be a library name, not a file path; the\n" 108 " standard Vamp library search path will be used to locate it. If\n" 109 " a file path is supplied, the directory part(s) will be ignored.\n\n" 110 " If the -s option is given, results will be labelled with the audio\n" 111 " sample frame at which they occur. Otherwise, they will be labelled\n" 112 " with time in seconds.\n\n" 113 " " << name <<
" -l\n" 114 " " << name <<
" --list\n\n" 115 " -- List the plugin libraries and Vamp plugins in the library search path\n" 116 " in a verbose human-readable format.\n\n" 117 " " << name <<
" --list-full\n\n" 118 " -- List all data reported by all the Vamp plugins in the library search\n" 119 " path in a very verbose human-readable format.\n\n" 120 " " << name <<
" --list-ids\n\n" 121 " -- List the plugins in the search path in a terse machine-readable format,\n" 122 " in the form vamp:soname:identifier.\n\n" 123 " " << name <<
" --list-outputs\n\n" 124 " -- List the outputs for plugins in the search path in a machine-readable\n" 125 " format, in the form vamp:soname:identifier:output.\n\n" 126 " " << name <<
" --list-by-category\n\n" 127 " -- List the plugins as a plugin index by category, in a machine-readable\n" 128 " format. The format may change in future releases.\n\n" 129 " " << name <<
" -p\n\n" 130 " -- Print out the Vamp library search path.\n\n" 131 " " << name <<
" -v\n\n" 132 " -- Display version information only.\n" 137 int main(
int argc,
char **argv)
139 char *scooter = argv[0];
141 while (scooter && *scooter) {
142 if (*scooter ==
'/' || *scooter ==
'\\') name = ++scooter;
145 if (!name || !*name) name = argv[0];
147 if (argc < 2)
usage(name);
151 if (!strcmp(argv[1],
"-v")) {
153 cout <<
"Simple Vamp plugin host version: " <<
HOST_VERSION << endl
158 }
else if (!strcmp(argv[1],
"-l") || !strcmp(argv[1],
"--list")) {
164 }
else if (!strcmp(argv[1],
"--list-full")) {
169 }
else if (!strcmp(argv[1],
"-p")) {
174 }
else if (!strcmp(argv[1],
"--list-ids")) {
179 }
else if (!strcmp(argv[1],
"--list-outputs")) {
184 }
else if (!strcmp(argv[1],
"--list-by-category")) {
192 if (argc < 3)
usage(name);
194 bool useFrames =
false;
197 if (!strcmp(argv[1],
"-s")) {
202 string soname = argv[base];
203 string wavname = argv[base+1];
209 if (argc >= base+3) {
213 if (isdigit(*argv[idx])) {
214 outputNo = atoi(argv[idx++]);
217 if (argc == idx + 2) {
218 if (!strcmp(argv[idx],
"-o")) {
219 outfilename = argv[idx+1];
221 }
else if (argc != idx) {
226 cerr << endl << name <<
": Running..." << endl;
228 cerr <<
"Reading file: \"" << wavname <<
"\", writing to ";
229 if (outfilename ==
"") {
230 cerr <<
"standard output" << endl;
232 cerr <<
"\"" << outfilename <<
"\"" << endl;
235 string::size_type sep = soname.find(
':');
237 if (sep != string::npos) {
238 plugid = soname.substr(sep + 1);
239 soname = soname.substr(0, sep);
241 sep = plugid.find(
':');
242 if (sep != string::npos) {
243 output = plugid.substr(sep + 1);
244 plugid = plugid.substr(0, sep);
252 if (output !=
"" && outputNo != -1) {
256 if (output ==
"" && outputNo == -1) {
260 return runPlugin(name, soname, plugid, output, outputNo,
261 wavname, outfilename, useFrames);
266 string output,
int outputNo,
string wavname,
267 string outfilename,
bool useFrames)
275 memset(&sfinfo, 0,
sizeof(SF_INFO));
277 sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
279 cerr << myname <<
": ERROR: Failed to open input file \"" 280 << wavname <<
"\": " << sf_strerror(sndfile) << endl;
285 if (outfilename !=
"") {
286 out =
new ofstream(outfilename.c_str(), ios::out);
288 cerr << myname <<
": ERROR: Failed to open output file \"" 289 << outfilename <<
"\" for writing" << endl;
296 (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE);
298 cerr << myname <<
": ERROR: Failed to load plugin \"" <<
id 299 <<
"\" from library \"" << soname <<
"\"" << endl;
308 cerr <<
"Running plugin: \"" << plugin->
getIdentifier() <<
"\"..." << endl;
324 if (blockSize == 0) {
329 stepSize = blockSize/2;
331 stepSize = blockSize;
333 }
else if (stepSize > blockSize) {
334 cerr <<
"WARNING: stepSize " << stepSize <<
" > blockSize " << blockSize <<
", resetting blockSize to ";
336 blockSize = stepSize * 2;
338 blockSize = stepSize;
340 cerr << blockSize << endl;
342 int overlapSize = blockSize - stepSize;
343 sf_count_t currentStep = 0;
344 int finalStepsRemaining = max(1, (blockSize / stepSize) - 1);
346 int channels = sfinfo.channels;
348 float *filebuf =
new float[blockSize * channels];
349 float **plugbuf =
new float*[channels];
350 for (
int c = 0; c < channels; ++c) plugbuf[c] =
new float[blockSize + 2];
352 cerr <<
"Using block size = " << blockSize <<
", step size = " 361 cerr <<
"Plugin accepts " << minch <<
" -> " << maxch <<
" channel(s)" << endl;
362 cerr <<
"Sound file has " << channels <<
" (will mix/augment if necessary)" << endl;
365 Plugin::OutputDescriptor od;
372 RealTime adjustment = RealTime::zeroTime;
374 if (outputs.empty()) {
375 cerr <<
"ERROR: Plugin has no outputs!" << endl;
381 for (
size_t oi = 0; oi < outputs.size(); ++oi) {
382 if (outputs[oi].identifier == output) {
389 cerr <<
"ERROR: Non-existent output \"" << output <<
"\" requested" << endl;
395 if (
int(outputs.size()) <= outputNo) {
396 cerr <<
"ERROR: Output " << outputNo <<
" requested, but plugin has only " << outputs.size() <<
" output(s)" << endl;
401 od = outputs[outputNo];
402 cerr <<
"Output is: \"" << od.identifier <<
"\"" << endl;
404 if (!plugin->
initialise(channels, stepSize, blockSize)) {
405 cerr <<
"ERROR: Plugin initialise (channels = " << channels
406 <<
", stepSize = " << stepSize <<
", blockSize = " 407 << blockSize <<
") failed." << endl;
425 if ((blockSize==stepSize) || (currentStep==0)) {
427 if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
428 cerr <<
"ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
431 if (count != blockSize) --finalStepsRemaining;
434 memmove(filebuf, filebuf + (stepSize * channels), overlapSize * channels *
sizeof(
float));
435 if ((count = sf_readf_float(sndfile, filebuf + (overlapSize * channels), stepSize)) < 0) {
436 cerr <<
"ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
439 if (count != stepSize) --finalStepsRemaining;
440 count += overlapSize;
443 for (
int c = 0; c < channels; ++c) {
446 plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
449 while (j < blockSize) {
450 plugbuf[c][j] = 0.0f;
455 rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
458 (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
459 sfinfo.samplerate, outputNo, plugin->
process(plugbuf, rt),
462 if (sfinfo.frames > 0){
464 progress = lrintf((
float(currentStep * stepSize) / sfinfo.frames) * 100.f);
465 if (progress != pp && out) {
466 cerr <<
"\r" << progress <<
"%";
472 }
while (finalStepsRemaining > 0);
474 if (out) cerr <<
"\rDone" << endl;
476 rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
478 printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
479 sfinfo.samplerate, outputNo,
496 Plugin::FeatureSet features, ofstream *out,
bool useFrames)
498 for (
unsigned int i = 0; i < features[output].size(); ++i) {
502 int displayFrame = frame;
504 if (features[output][i].hasTimestamp) {
505 displayFrame = RealTime::realTime2Frame
506 (features[output][i].timestamp, sr);
509 (out ? *out : cout) << displayFrame;
511 if (features[output][i].hasDuration) {
512 displayFrame = RealTime::realTime2Frame
513 (features[output][i].duration, sr);
514 (out ? *out : cout) <<
"," << displayFrame;
517 (out ? *out : cout) <<
":";
521 RealTime rt = RealTime::frame2RealTime(frame, sr);
523 if (features[output][i].hasTimestamp) {
524 rt = features[output][i].timestamp;
527 (out ? *out : cout) << rt.
toString();
529 if (features[output][i].hasDuration) {
530 rt = features[output][i].duration;
531 (out ? *out : cout) <<
"," << rt.
toString();
534 (out ? *out : cout) <<
":";
537 for (
unsigned int j = 0; j < features[output][i].values.size(); ++j) {
538 (out ? *out : cout) <<
" " << features[output][i].values[j];
540 (out ? *out : cout) <<
" " << features[output][i].label;
542 (out ? *out : cout) << endl;
550 cout <<
"\nVamp plugin search path: ";
553 vector<string> path = PluginHostAdapter::getPluginPath();
554 for (
size_t i = 0; i < path.size(); ++i) {
556 cout <<
"[" << path[i] <<
"]";
558 cout << path[i] << endl;
562 if (verbose) cout << endl;
569 string out =
'\n' + text +
'\n';
570 for (
size_t i = 0; i < text.length(); ++i) {
571 out += (level == 1 ?
'=' : level == 2 ?
'-' :
'~');
583 cout <<
"\nVamp plugin libraries found in search path:" << endl;
586 vector<PluginLoader::PluginKey> plugins = loader->
listPlugins();
587 typedef multimap<string, PluginLoader::PluginKey>
589 LibraryMap libraryMap;
591 for (
size_t i = 0; i < plugins.size(); ++i) {
593 libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
596 string prevPath =
"";
599 for (LibraryMap::iterator i = libraryMap.begin();
600 i != libraryMap.end(); ++i) {
602 string path = i->first;
603 PluginLoader::PluginKey key = i->second;
605 if (path != prevPath) {
609 cout <<
"\n " << path <<
":" << endl;
611 string::size_type ki = i->second.find(
':');
612 string text =
"Library \"" + i->second.substr(0, ki) +
"\"";
613 cout <<
"\n" <<
header(text, 1);
620 char c = char(
'A' + index);
621 if (c >
'Z') c = char(
'a' + (index - 26));
623 PluginLoader::PluginCategoryHierarchy category =
626 if (!category.empty()) {
627 for (
size_t ci = 0; ci < category.size(); ++ci) {
628 if (ci > 0) catstr +=
" > ";
629 catstr += category[ci];
635 cout <<
" [" << c <<
"] [v" 639 << plugin->
getMaker() <<
"]" << endl;
642 cout <<
" > " << catstr << endl;
652 cout <<
" - Identifier: " 654 cout <<
" - Plugin Version: " 656 cout <<
" - Vamp API Version: " 658 cout <<
" - Maker: \"" 659 << plugin->
getMaker() <<
"\"" << endl;
660 cout <<
" - Copyright: \"" 662 cout <<
" - Description: \"" 664 cout <<
" - Input Domain: " 666 "Time Domain" :
"Frequency Domain") << endl;
667 cout <<
" - Default Step Size: " 669 cout <<
" - Default Block Size: " 671 cout <<
" - Minimum Channels: " 673 cout <<
" - Maximum Channels: " 677 cout <<
"vamp:" << key << endl;
680 Plugin::OutputList outputs =
686 for (
size_t j = 0; j < params.size(); ++j) {
687 Plugin::ParameterDescriptor &pd(params[j]);
688 cout <<
"\nParameter " << j+1 <<
": \"" << pd.name <<
"\"" << endl;
689 cout <<
" - Identifier: " << pd.identifier << endl;
690 cout <<
" - Description: \"" << pd.description <<
"\"" << endl;
692 cout <<
" - Unit: " << pd.unit << endl;
694 cout <<
" - Range: ";
695 cout << pd.minValue <<
" -> " << pd.maxValue << endl;
696 cout <<
" - Default: ";
697 cout << pd.defaultValue << endl;
698 if (pd.isQuantized) {
699 cout <<
" - Quantize Step: " 700 << pd.quantizeStep << endl;
702 if (!pd.valueNames.empty()) {
703 cout <<
" - Value Names: ";
704 for (
size_t k = 0; k < pd.valueNames.size(); ++k) {
705 if (k > 0) cout <<
", ";
706 cout <<
"\"" << pd.valueNames[k] <<
"\"";
712 if (outputs.empty()) {
713 cout <<
"\n** Note: This plugin reports no outputs!" << endl;
715 for (
size_t j = 0; j < outputs.size(); ++j) {
716 Plugin::OutputDescriptor &od(outputs[j]);
717 cout <<
"\nOutput " << j+1 <<
": \"" << od.name <<
"\"" << endl;
718 cout <<
" - Identifier: " << od.identifier << endl;
719 cout <<
" - Description: \"" << od.description <<
"\"" << endl;
721 cout <<
" - Unit: " << od.unit << endl;
723 if (od.hasFixedBinCount) {
724 cout <<
" - Default Bin Count: " << od.binCount << endl;
726 if (!od.binNames.empty()) {
728 for (
size_t k = 0; k < od.binNames.size(); ++k) {
729 if (od.binNames[k] !=
"") {
734 cout <<
" - Bin Names: ";
735 for (
size_t k = 0; k < od.binNames.size(); ++k) {
736 if (k > 0) cout <<
", ";
737 cout <<
"\"" << od.binNames[k] <<
"\"";
742 if (od.hasKnownExtents) {
743 cout <<
" - Default Extents: ";
744 cout << od.minValue <<
" -> " << od.maxValue << endl;
746 if (od.isQuantized) {
747 cout <<
" - Quantize Step: " 748 << od.quantizeStep << endl;
750 cout <<
" - Sample Type: " 752 Plugin::OutputDescriptor::OneSamplePerStep ?
753 "One Sample Per Step" :
755 Plugin::OutputDescriptor::FixedSampleRate ?
756 "Fixed Sample Rate" :
757 "Variable Sample Rate") << endl;
759 Plugin::OutputDescriptor::OneSamplePerStep) {
760 cout <<
" - Default Rate: " 761 << od.sampleRate << endl;
763 cout <<
" - Has Duration: " 764 << (od.hasDuration ?
"Yes" :
"No") << endl;
769 for (
size_t j = 0; j < outputs.size(); ++j) {
771 cout <<
" (" << j <<
") " 772 << outputs[j].name <<
", \"" 773 << outputs[j].identifier <<
"\"" << endl;
774 if (outputs[j].description !=
"") {
776 << outputs[j].description << endl;
779 cout <<
"vamp:" << key <<
":" << outputs[j].identifier << endl;
801 vector<PluginLoader::PluginKey> plugins = loader->
listPlugins();
803 set<string> printedcats;
805 for (
size_t i = 0; i < plugins.size(); ++i) {
807 PluginLoader::PluginKey key = plugins[i];
809 PluginLoader::PluginCategoryHierarchy category =
813 if (!plugin)
continue;
817 if (category.empty()) catstr =
'|';
819 for (
size_t j = 0; j < category.size(); ++j) {
820 catstr += category[j];
822 if (printedcats.find(catstr) == printedcats.end()) {
823 std::cout << catstr << std::endl;
824 printedcats.insert(catstr);
PluginKey composePluginKey(std::string libraryName, std::string identifier)
Given a Vamp plugin library name and plugin identifier, return the corresponding plugin key in a form...
Vamp::Plugin is a base class for plugin instance classes that provide feature extraction from audio o...
void listPluginsInLibrary(string soname)
virtual size_t getPreferredStepSize() const
Get the preferred step size (window increment – the distance in sample frames between the start fram...
int runPlugin(string myname, string soname, string id, string output, int outputNo, string inputFile, string outfilename, bool frames)
void transformInput(float *, size_t)
virtual int getPluginVersion() const =0
Get the version number of the plugin.
RealTime getTimestampAdjustment() const
Return the amount by which the timestamps supplied to process() are being incremented when they are p...
virtual std::string getCopyright() const =0
Get the copyright statement or licensing summary for the plugin.
virtual InputDomain getInputDomain() const =0
Get the plugin's required input domain.
virtual unsigned int getVampApiVersion() const
Get the Vamp API compatibility level of the plugin.
static string header(string text, int level)
WrapperType * getWrapper()
Return a pointer to the plugin wrapper of type WrapperType surrounding this wrapper's plugin...
virtual FeatureSet process(const float *const *inputBuffers, RealTime timestamp)=0
Process a single block of input data.
int main(int argc, char **argv)
virtual std::string getDescription() const =0
Get a human-readable description for the plugin, typically a line of text that may optionally be disp...
std::string getLibraryPathForPlugin(PluginKey plugin)
Return the file path of the dynamic library from which the given plugin will be loaded (if available)...
PluginInputDomainAdapter is a Vamp plugin adapter that converts time-domain input into frequency-doma...
virtual std::string getMaker() const =0
Get the name of the author or vendor of the plugin in human-readable form.
PluginKeyList listPlugins()
Search for all available Vamp plugins, and return a list of them in the order in which they were foun...
virtual bool initialise(size_t inputChannels, size_t stepSize, size_t blockSize)=0
Initialise a plugin to prepare it for use with the given number of input channels, step size (window increment, in sample frames) and block size (window size, in sample frames).
virtual OutputList getOutputDescriptors() const =0
Get the outputs of this plugin.
#define VAMP_API_VERSION
Plugin API version.
RealTime represents time values to nanosecond precision with accurate arithmetic and frame-rate conve...
PluginHostAdapter is a wrapper class that a Vamp host can use to make the C-language VampPluginDescri...
void printFeatures(int, int, int, Plugin::FeatureSet, ofstream *, bool frames)
PluginWrapper is a simple base class for adapter plugins.
Plugin * loadPlugin(PluginKey key, float inputSampleRate, int adapterFlags=0)
Load a Vamp plugin, given its identifying key.
virtual std::string getName() const =0
Get a human-readable name or title of the plugin.
void printPluginCategoryList()
void usage(const char *name)
Vamp::HostExt::PluginLoader is a convenience class for discovering and loading Vamp plugins using the...
virtual FeatureSet getRemainingFeatures()=0
After all blocks have been processed, calculate and return any remaining features derived from the co...
virtual ParameterList getParameterDescriptors() const
Get the controllable parameters of this plugin.
virtual size_t getMaxChannelCount() const
Get the maximum supported number of input channels.
void fft(unsigned int, bool, double *, double *, double *, double *)
std::string toString() const
Return a human-readable debug-type string to full precision (probably not a format to show to a user ...
void printPluginPath(bool verbose)
virtual size_t getPreferredBlockSize() const
Get the preferred block size (window size – the number of sample frames passed in each block to the ...
virtual size_t getMinChannelCount() const
Get the minimum supported number of input channels.
PluginCategoryHierarchy getPluginCategory(PluginKey plugin)
Return the category hierarchy for a Vamp plugin, given its identifying key.
void enumeratePlugins(Verbosity)
virtual std::string getIdentifier() const =0
Get the computer-usable name of the plugin.