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 frame...
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)
RealTime getTimestampAdjustment() const
Return the amount by which the timestamps supplied to process() are being incremented when they are p...
virtual std::string getIdentifier() const =0
Get the computer-usable name of the plugin.
virtual unsigned int getVampApiVersion() const
Get the Vamp API compatibility level 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 FeatureSet process(const float *const *inputBuffers, RealTime timestamp)=0
Process a single block of input data.
int main(int argc, char **argv)
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).
#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 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.
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 ...
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)
virtual size_t getPreferredBlockSize() const
Get the preferred block size (window size – the number of sample frames passed in each block to the p...
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)