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 <<
" -L\n" 118 " " << name <<
" --list-full\n\n" 119 " -- List all data reported by all the Vamp plugins in the library search\n" 120 " path in a very verbose human-readable format.\n\n" 121 " " << name <<
" --list-ids\n\n" 122 " -- List the plugins in the search path in a terse machine-readable format,\n" 123 " in the form vamp:soname:identifier.\n\n" 124 " " << name <<
" --list-outputs\n\n" 125 " -- List the outputs for plugins in the search path in a machine-readable\n" 126 " format, in the form vamp:soname:identifier:output.\n\n" 127 " " << name <<
" --list-by-category\n\n" 128 " -- List the plugins as a plugin index by category, in a machine-readable\n" 129 " format. The format may change in future releases.\n\n" 130 " " << name <<
" -p\n\n" 131 " -- Print out the Vamp library search path.\n\n" 132 " " << name <<
" -v\n\n" 133 " -- Display version information only.\n" 138 int main(
int argc,
char **argv)
140 char *scooter = argv[0];
142 while (scooter && *scooter) {
143 if (*scooter ==
'/' || *scooter ==
'\\') name = ++scooter;
146 if (!name || !*name) name = argv[0];
148 if (argc < 2)
usage(name);
152 if (!strcmp(argv[1],
"-v")) {
154 cout <<
"Simple Vamp plugin host version: " <<
HOST_VERSION << endl
159 }
else if (!strcmp(argv[1],
"-l") || !strcmp(argv[1],
"--list")) {
165 }
else if (!strcmp(argv[1],
"-L") || !strcmp(argv[1],
"--list-full")) {
170 }
else if (!strcmp(argv[1],
"-p")) {
175 }
else if (!strcmp(argv[1],
"--list-ids")) {
180 }
else if (!strcmp(argv[1],
"--list-outputs")) {
185 }
else if (!strcmp(argv[1],
"--list-by-category")) {
193 if (argc < 3)
usage(name);
195 bool useFrames =
false;
198 if (!strcmp(argv[1],
"-s")) {
203 string soname = argv[base];
204 string wavname = argv[base+1];
210 if (argc >= base+3) {
214 if (isdigit(*argv[idx])) {
215 outputNo = atoi(argv[idx++]);
218 if (argc == idx + 2) {
219 if (!strcmp(argv[idx],
"-o")) {
220 outfilename = argv[idx+1];
222 }
else if (argc != idx) {
227 cerr << endl << name <<
": Running..." << endl;
229 cerr <<
"Reading file: \"" << wavname <<
"\", writing to ";
230 if (outfilename ==
"") {
231 cerr <<
"standard output" << endl;
233 cerr <<
"\"" << outfilename <<
"\"" << endl;
236 string::size_type sep = soname.find(
':');
238 if (sep != string::npos) {
239 plugid = soname.substr(sep + 1);
240 soname = soname.substr(0, sep);
242 sep = plugid.find(
':');
243 if (sep != string::npos) {
244 output = plugid.substr(sep + 1);
245 plugid = plugid.substr(0, sep);
253 if (output !=
"" && outputNo != -1) {
257 if (output ==
"" && outputNo == -1) {
261 return runPlugin(name, soname, plugid, output, outputNo,
262 wavname, outfilename, useFrames);
267 string output,
int outputNo,
string wavname,
268 string outfilename,
bool useFrames)
276 memset(&sfinfo, 0,
sizeof(SF_INFO));
278 sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
280 cerr << myname <<
": ERROR: Failed to open input file \"" 281 << wavname <<
"\": " << sf_strerror(sndfile) << endl;
286 if (outfilename !=
"") {
287 out =
new ofstream(outfilename.c_str(), ios::out);
289 cerr << myname <<
": ERROR: Failed to open output file \"" 290 << outfilename <<
"\" for writing" << endl;
297 (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE);
299 cerr << myname <<
": ERROR: Failed to load plugin \"" <<
id 300 <<
"\" from library \"" << soname <<
"\"" << endl;
309 cerr <<
"Running plugin: \"" << plugin->
getIdentifier() <<
"\"..." << endl;
325 if (blockSize == 0) {
330 stepSize = blockSize/2;
332 stepSize = blockSize;
334 }
else if (stepSize > blockSize) {
335 cerr <<
"WARNING: stepSize " << stepSize <<
" > blockSize " << blockSize <<
", resetting blockSize to ";
337 blockSize = stepSize * 2;
339 blockSize = stepSize;
341 cerr << blockSize << endl;
343 int overlapSize = blockSize - stepSize;
344 sf_count_t currentStep = 0;
345 int finalStepsRemaining = max(1, (blockSize / stepSize) - 1);
347 int channels = sfinfo.channels;
349 float *filebuf =
new float[blockSize * channels];
350 float **plugbuf =
new float*[channels];
351 for (
int c = 0; c < channels; ++c) plugbuf[c] =
new float[blockSize + 2];
353 cerr <<
"Using block size = " << blockSize <<
", step size = " 362 cerr <<
"Plugin accepts " << minch <<
" -> " << maxch <<
" channel(s)" << endl;
363 cerr <<
"Sound file has " << channels <<
" (will mix/augment if necessary)" << endl;
366 Plugin::OutputDescriptor od;
373 RealTime adjustment = RealTime::zeroTime;
375 if (outputs.empty()) {
376 cerr <<
"ERROR: Plugin has no outputs!" << endl;
382 for (
size_t oi = 0; oi < outputs.size(); ++oi) {
383 if (outputs[oi].identifier == output) {
390 cerr <<
"ERROR: Non-existent output \"" << output <<
"\" requested" << endl;
396 if (
int(outputs.size()) <= outputNo) {
397 cerr <<
"ERROR: Output " << outputNo <<
" requested, but plugin has only " << outputs.size() <<
" output(s)" << endl;
402 od = outputs[outputNo];
403 cerr <<
"Output is: \"" << od.identifier <<
"\"" << endl;
405 if (!plugin->
initialise(channels, stepSize, blockSize)) {
406 cerr <<
"ERROR: Plugin initialise (channels = " << channels
407 <<
", stepSize = " << stepSize <<
", blockSize = " 408 << blockSize <<
") failed." << endl;
426 if ((blockSize==stepSize) || (currentStep==0)) {
428 if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
429 cerr <<
"ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
432 if (count != blockSize) --finalStepsRemaining;
435 memmove(filebuf, filebuf + (stepSize * channels), overlapSize * channels *
sizeof(
float));
436 if ((count = sf_readf_float(sndfile, filebuf + (overlapSize * channels), stepSize)) < 0) {
437 cerr <<
"ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
440 if (count != stepSize) --finalStepsRemaining;
441 count += overlapSize;
444 for (
int c = 0; c < channels; ++c) {
447 plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
450 while (j < blockSize) {
451 plugbuf[c][j] = 0.0f;
456 rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
459 (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
460 sfinfo.samplerate, outputNo, plugin->
process(plugbuf, rt),
463 if (sfinfo.frames > 0){
465 progress = (int)((
float(currentStep * stepSize) / sfinfo.frames) * 100.f + 0.5f);
466 if (progress != pp && out) {
467 cerr <<
"\r" << progress <<
"%";
473 }
while (finalStepsRemaining > 0);
475 if (out) cerr <<
"\rDone" << endl;
477 rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
479 printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
480 sfinfo.samplerate, outputNo,
497 Plugin::FeatureSet features, ofstream *out,
bool useFrames)
499 for (
unsigned int i = 0; i < features[output].size(); ++i) {
503 int displayFrame = frame;
505 if (features[output][i].hasTimestamp) {
506 displayFrame = RealTime::realTime2Frame
507 (features[output][i].timestamp, sr);
510 (out ? *out : cout) << displayFrame;
512 if (features[output][i].hasDuration) {
513 displayFrame = RealTime::realTime2Frame
514 (features[output][i].duration, sr);
515 (out ? *out : cout) <<
"," << displayFrame;
518 (out ? *out : cout) <<
":";
522 RealTime rt = RealTime::frame2RealTime(frame, sr);
524 if (features[output][i].hasTimestamp) {
525 rt = features[output][i].timestamp;
528 (out ? *out : cout) << rt.
toString();
530 if (features[output][i].hasDuration) {
531 rt = features[output][i].duration;
532 (out ? *out : cout) <<
"," << rt.
toString();
535 (out ? *out : cout) <<
":";
538 for (
unsigned int j = 0; j < features[output][i].values.size(); ++j) {
539 (out ? *out : cout) <<
" " << features[output][i].values[j];
541 (out ? *out : cout) <<
" " << features[output][i].label;
543 (out ? *out : cout) << endl;
551 cout <<
"\nVamp plugin search path: ";
554 vector<string> path = PluginHostAdapter::getPluginPath();
555 for (
size_t i = 0; i < path.size(); ++i) {
557 cout <<
"[" << path[i] <<
"]";
559 cout << path[i] << endl;
563 if (verbose) cout << endl;
570 string out =
'\n' + text +
'\n';
571 for (
size_t i = 0; i < text.length(); ++i) {
572 out += (level == 1 ?
'=' : level == 2 ?
'-' :
'~');
584 cout <<
"\nVamp plugin libraries found in search path:" << endl;
587 vector<PluginLoader::PluginKey> plugins = loader->
listPlugins();
588 typedef multimap<string, PluginLoader::PluginKey>
590 LibraryMap libraryMap;
592 for (
size_t i = 0; i < plugins.size(); ++i) {
594 libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
597 string prevPath =
"";
600 for (LibraryMap::iterator i = libraryMap.begin();
601 i != libraryMap.end(); ++i) {
603 string path = i->first;
604 PluginLoader::PluginKey key = i->second;
606 if (path != prevPath) {
610 cout <<
"\n " << path <<
":" << endl;
612 string::size_type ki = i->second.find(
':');
613 string text =
"Library \"" + i->second.substr(0, ki) +
"\"";
614 cout <<
"\n" <<
header(text, 1);
621 char c = char(
'A' + index);
622 if (c >
'Z') c = char(
'a' + (index - 26));
624 PluginLoader::PluginCategoryHierarchy category =
627 if (!category.empty()) {
628 for (
size_t ci = 0; ci < category.size(); ++ci) {
629 if (ci > 0) catstr +=
" > ";
630 catstr += category[ci];
636 cout <<
" [" << c <<
"] [v" 640 << plugin->
getMaker() <<
"]" << endl;
643 cout <<
" > " << catstr << endl;
653 cout <<
" - Identifier: " 655 cout <<
" - Plugin Version: " 657 cout <<
" - Vamp API Version: " 659 cout <<
" - Maker: \"" 660 << plugin->
getMaker() <<
"\"" << endl;
661 cout <<
" - Copyright: \"" 663 cout <<
" - Description: \"" 665 cout <<
" - Input Domain: " 667 "Time Domain" :
"Frequency Domain") << endl;
668 cout <<
" - Default Step Size: " 670 cout <<
" - Default Block Size: " 672 cout <<
" - Minimum Channels: " 674 cout <<
" - Maximum Channels: " 678 cout <<
"vamp:" << key << endl;
681 Plugin::OutputList outputs =
687 for (
size_t j = 0; j < params.size(); ++j) {
688 Plugin::ParameterDescriptor &pd(params[j]);
689 cout <<
"\nParameter " << j+1 <<
": \"" << pd.name <<
"\"" << endl;
690 cout <<
" - Identifier: " << pd.identifier << endl;
691 cout <<
" - Description: \"" << pd.description <<
"\"" << endl;
693 cout <<
" - Unit: " << pd.unit << endl;
695 cout <<
" - Range: ";
696 cout << pd.minValue <<
" -> " << pd.maxValue << endl;
697 cout <<
" - Default: ";
698 cout << pd.defaultValue << endl;
699 if (pd.isQuantized) {
700 cout <<
" - Quantize Step: " 701 << pd.quantizeStep << endl;
703 if (!pd.valueNames.empty()) {
704 cout <<
" - Value Names: ";
705 for (
size_t k = 0; k < pd.valueNames.size(); ++k) {
706 if (k > 0) cout <<
", ";
707 cout <<
"\"" << pd.valueNames[k] <<
"\"";
713 if (outputs.empty()) {
714 cout <<
"\n** Note: This plugin reports no outputs!" << endl;
716 for (
size_t j = 0; j < outputs.size(); ++j) {
717 Plugin::OutputDescriptor &od(outputs[j]);
718 cout <<
"\nOutput " << j+1 <<
": \"" << od.name <<
"\"" << endl;
719 cout <<
" - Identifier: " << od.identifier << endl;
720 cout <<
" - Description: \"" << od.description <<
"\"" << endl;
722 cout <<
" - Unit: " << od.unit << endl;
724 if (od.hasFixedBinCount) {
725 cout <<
" - Default Bin Count: " << od.binCount << endl;
727 if (!od.binNames.empty()) {
729 for (
size_t k = 0; k < od.binNames.size(); ++k) {
730 if (od.binNames[k] !=
"") {
735 cout <<
" - Bin Names: ";
736 for (
size_t k = 0; k < od.binNames.size(); ++k) {
737 if (k > 0) cout <<
", ";
738 cout <<
"\"" << od.binNames[k] <<
"\"";
743 if (od.hasKnownExtents) {
744 cout <<
" - Default Extents: ";
745 cout << od.minValue <<
" -> " << od.maxValue << endl;
747 if (od.isQuantized) {
748 cout <<
" - Quantize Step: " 749 << od.quantizeStep << endl;
751 cout <<
" - Sample Type: " 753 Plugin::OutputDescriptor::OneSamplePerStep ?
754 "One Sample Per Step" :
756 Plugin::OutputDescriptor::FixedSampleRate ?
757 "Fixed Sample Rate" :
758 "Variable Sample Rate") << endl;
760 Plugin::OutputDescriptor::OneSamplePerStep) {
761 cout <<
" - Default Rate: " 762 << od.sampleRate << endl;
764 cout <<
" - Has Duration: " 765 << (od.hasDuration ?
"Yes" :
"No") << endl;
770 for (
size_t j = 0; j < outputs.size(); ++j) {
772 cout <<
" (" << j <<
") " 773 << outputs[j].name <<
", \"" 774 << outputs[j].identifier <<
"\"" << endl;
775 if (outputs[j].description !=
"") {
777 << outputs[j].description << endl;
780 cout <<
"vamp:" << key <<
":" << outputs[j].identifier << endl;
802 vector<PluginLoader::PluginKey> plugins = loader->
listPlugins();
804 set<string> printedcats;
806 for (
size_t i = 0; i < plugins.size(); ++i) {
808 PluginLoader::PluginKey key = plugins[i];
810 PluginLoader::PluginCategoryHierarchy category =
814 if (!plugin)
continue;
818 if (category.empty()) catstr =
'|';
820 for (
size_t j = 0; j < category.size(); ++j) {
821 catstr += category[j];
823 if (printedcats.find(catstr) == printedcats.end()) {
824 std::cout << catstr << std::endl;
825 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 int getPluginVersion() const =0
Get the version number of the plugin.
virtual std::string getName() const =0
Get a human-readable name or title of the plugin.
int runPlugin(string myname, string soname, string id, string output, int outputNo, string inputFile, string outfilename, bool frames)
void transformInput(float *, size_t)
virtual std::string getIdentifier() const =0
Get the computer-usable name of the plugin.
virtual OutputList getOutputDescriptors() const =0
Get the outputs of this 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 unsigned int getVampApiVersion() const
Get the Vamp API compatibility level of the 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 size_t getPreferredBlockSize() const
Get the preferred block size (window size – the number of sample frames passed in each block to the ...
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...
std::string toString() const
Return a human-readable debug-type string to full precision (probably not a format to show to a user ...
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 size_t getMinChannelCount() const
Get the minimum supported number of input channels.
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).
#define VAMP_API_VERSION
Plugin API version.
virtual size_t getMaxChannelCount() const
Get the maximum supported number of input channels.
RealTime getTimestampAdjustment() const
Return the amount by which the timestamps supplied to process() are being incremented when they are p...
virtual size_t getPreferredStepSize() const
Get the preferred step size (window increment – the distance in sample frames between the start fram...
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 InputDomain getInputDomain() const =0
Get the plugin's required input domain.
void printPluginCategoryList()
void usage(const char *name)
Vamp::HostExt::PluginLoader is a convenience class for discovering and loading Vamp plugins using the...
virtual std::string getCopyright() const =0
Get the copyright statement or licensing summary for the plugin.
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.
void fft(unsigned int, bool, double *, double *, double *, double *)
virtual std::string getDescription() const =0
Get a human-readable description for the plugin, typically a line of text that may optionally be disp...
void printPluginPath(bool verbose)
PluginCategoryHierarchy getPluginCategory(PluginKey plugin)
Return the category hierarchy for a Vamp plugin, given its identifying key.
void enumeratePlugins(Verbosity)