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 size_t getPreferredStepSize() const
Get the preferred step size (window increment – the distance in sample frames between the start fram...
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 ...
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)