74#define HOST_VERSION "1.5"
84 const Plugin::OutputDescriptor &,
int,
87void fft(
unsigned int,
bool,
double *,
double *,
double *,
double *);
92int runPlugin(
string myname,
string soname,
string id,
string output,
93 int outputNo,
string inputFile,
string outfilename,
bool frames);
98 << name <<
": A command-line host for Vamp audio analysis plugins.\n\n"
99 "Centre for Digital Music, Queen Mary, University of London.\n"
100 "Copyright 2006-2009 Chris Cannam and QMUL.\n"
101 "Freely redistributable; published under a BSD-style license.\n\n"
103 " " << name <<
" [-s] pluginlibrary[." <<
PLUGIN_SUFFIX <<
"]:plugin[:output] file.wav [-o out.txt]\n"
104 " " << name <<
" [-s] pluginlibrary[." <<
PLUGIN_SUFFIX <<
"]:plugin file.wav [outputno] [-o out.txt]\n\n"
105 " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n"
106 " audio data in \"file.wav\", retrieving the named \"output\", or output\n"
107 " number \"outputno\" (the first output by default) and dumping it to\n"
108 " standard output, or to \"out.txt\" if the -o option is given.\n\n"
109 " \"pluginlibrary\" should be a library name, not a file path; the\n"
110 " standard Vamp library search path will be used to locate it. If\n"
111 " a file path is supplied, the directory part(s) will be ignored.\n\n"
112 " If the -s option is given, results will be labelled with the audio\n"
113 " sample frame at which they occur. Otherwise, they will be labelled\n"
114 " with time in seconds.\n\n"
115 " " << name <<
" -l\n"
116 " " << name <<
" --list\n\n"
117 " -- List the plugin libraries and Vamp plugins in the library search path\n"
118 " in a verbose human-readable format.\n\n"
119 " " << name <<
" -L\n"
120 " " << name <<
" --list-full\n\n"
121 " -- List all data reported by all the Vamp plugins in the library search\n"
122 " path in a very verbose human-readable format.\n\n"
123 " " << name <<
" --list-ids\n\n"
124 " -- List the plugins in the search path in a terse machine-readable format,\n"
125 " in the form vamp:soname:identifier.\n\n"
126 " " << name <<
" --list-outputs\n\n"
127 " -- List the outputs for plugins in the search path in a machine-readable\n"
128 " format, in the form vamp:soname:identifier:output.\n\n"
129 " " << name <<
" --list-by-category\n\n"
130 " -- List the plugins as a plugin index by category, in a machine-readable\n"
131 " format. The format may change in future releases.\n\n"
132 " " << name <<
" -p\n\n"
133 " -- Print out the Vamp library search path.\n\n"
134 " " << name <<
" -v\n\n"
135 " -- Display version information only.\n"
142 char *scooter = argv[0];
144 while (scooter && *scooter) {
145 if (*scooter ==
'/' || *scooter ==
'\\') name = ++scooter;
148 if (!name || !*name) name = argv[0];
150 if (argc < 2)
usage(name);
154 if (!strcmp(argv[1],
"-v")) {
156 cout <<
"Simple Vamp plugin host version: " <<
HOST_VERSION << endl
161 }
else if (!strcmp(argv[1],
"-l") || !strcmp(argv[1],
"--list")) {
167 }
else if (!strcmp(argv[1],
"-L") || !strcmp(argv[1],
"--list-full")) {
172 }
else if (!strcmp(argv[1],
"-p")) {
177 }
else if (!strcmp(argv[1],
"--list-ids")) {
182 }
else if (!strcmp(argv[1],
"--list-outputs")) {
187 }
else if (!strcmp(argv[1],
"--list-by-category")) {
195 if (argc < 3)
usage(name);
197 bool useFrames =
false;
200 if (!strcmp(argv[1],
"-s")) {
205 string soname = argv[base];
206 string wavname = argv[base+1];
212 if (argc >= base+3) {
216 if (isdigit(*argv[idx])) {
217 outputNo = atoi(argv[idx++]);
220 if (argc == idx + 2) {
221 if (!strcmp(argv[idx],
"-o")) {
222 outfilename = argv[idx+1];
224 }
else if (argc != idx) {
229 cerr << endl << name <<
": Running..." << endl;
231 cerr <<
"Reading file: \"" << wavname <<
"\", writing to ";
232 if (outfilename ==
"") {
233 cerr <<
"standard output" << endl;
235 cerr <<
"\"" << outfilename <<
"\"" << endl;
238 string::size_type sep = soname.find(
':');
240 if (sep != string::npos) {
241 plugid = soname.substr(sep + 1);
242 soname = soname.substr(0, sep);
244 sep = plugid.find(
':');
245 if (sep != string::npos) {
246 output = plugid.substr(sep + 1);
247 plugid = plugid.substr(0, sep);
255 if (output !=
"" && outputNo != -1) {
259 if (output ==
"" && outputNo == -1) {
263 return runPlugin(name, soname, plugid, output, outputNo,
264 wavname, outfilename, useFrames);
269 string output,
int outputNo,
string wavname,
270 string outfilename,
bool useFrames)
278 memset(&sfinfo, 0,
sizeof(SF_INFO));
280 sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
282 cerr << myname <<
": ERROR: Failed to open input file \""
283 << wavname <<
"\": " << sf_strerror(sndfile) << endl;
288 if (outfilename !=
"") {
289 out =
new ofstream(outfilename.c_str(), ios::out);
291 cerr << myname <<
": ERROR: Failed to open output file \""
292 << outfilename <<
"\" for writing" << endl;
301 cerr << myname <<
": ERROR: Failed to load plugin \"" <<
id
302 <<
"\" from library \"" << soname <<
"\"" << endl;
311 cerr <<
"Running plugin: \"" << plugin->
getIdentifier() <<
"\"..." << endl;
327 if (blockSize == 0) {
332 stepSize = blockSize/2;
334 stepSize = blockSize;
336 }
else if (stepSize > blockSize) {
337 cerr <<
"WARNING: stepSize " << stepSize <<
" > blockSize " << blockSize <<
", resetting blockSize to ";
339 blockSize = stepSize * 2;
341 blockSize = stepSize;
343 cerr << blockSize << endl;
345 int overlapSize = blockSize - stepSize;
346 sf_count_t currentStep = 0;
347 int finalStepsRemaining = max(1, (blockSize / stepSize) - 1);
349 int channels = sfinfo.channels;
351 float *filebuf =
new float[blockSize * channels];
352 float **plugbuf =
new float*[channels];
353 for (
int c = 0; c < channels; ++c) plugbuf[c] =
new float[blockSize + 2];
355 cerr <<
"Using block size = " << blockSize <<
", step size = "
364 cerr <<
"Plugin accepts " << minch <<
" -> " << maxch <<
" channel(s)" << endl;
365 cerr <<
"Sound file has " << channels <<
" (will mix/augment if necessary)" << endl;
368 Plugin::OutputDescriptor od;
378 if (outputs.empty()) {
379 cerr <<
"ERROR: Plugin has no outputs!" << endl;
385 for (
size_t oi = 0; oi < outputs.size(); ++oi) {
386 if (outputs[oi].identifier == output) {
393 cerr <<
"ERROR: Non-existent output \"" << output <<
"\" requested" << endl;
399 if (
int(outputs.size()) <= outputNo) {
400 cerr <<
"ERROR: Output " << outputNo <<
" requested, but plugin has only " << outputs.size() <<
" output(s)" << endl;
405 od = outputs[outputNo];
406 cerr <<
"Output is: \"" << od.identifier <<
"\"" << endl;
408 if (!plugin->
initialise(channels, stepSize, blockSize)) {
409 cerr <<
"ERROR: Plugin initialise (channels = " << channels
410 <<
", stepSize = " << stepSize <<
", blockSize = "
411 << blockSize <<
") failed." << endl;
429 if ((blockSize==stepSize) || (currentStep==0)) {
431 if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
432 cerr <<
"ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
435 if (count != blockSize) --finalStepsRemaining;
438 memmove(filebuf, filebuf + (stepSize * channels), overlapSize * channels *
sizeof(
float));
439 if ((count = sf_readf_float(sndfile, filebuf + (overlapSize * channels), stepSize)) < 0) {
440 cerr <<
"ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
443 if (count != stepSize) --finalStepsRemaining;
444 count += overlapSize;
447 for (
int c = 0; c < channels; ++c) {
450 plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
453 while (j < blockSize) {
454 plugbuf[c][j] = 0.0f;
461 features = plugin->
process(plugbuf, rt);
465 sfinfo.samplerate, od, outputNo, features, out, useFrames);
467 if (sfinfo.frames > 0){
469 progress = (int)((
float(currentStep * stepSize) / sfinfo.frames) * 100.f + 0.5f);
470 if (progress != pp && out) {
471 cerr <<
"\r" << progress <<
"%";
477 }
while (finalStepsRemaining > 0);
479 if (out) cerr <<
"\rDone" << endl;
486 sfinfo.samplerate, od, outputNo, features, out, useFrames);
503 return time.
sec + double(time.
nsec + 1) / 1000000000.0;
508 const Plugin::OutputDescriptor &output,
int outputNo,
511 static int featureCount = -1;
513 if (features.find(outputNo) == features.end())
return;
515 for (
size_t i = 0; i < features.at(outputNo).size(); ++i) {
517 const Plugin::Feature &f = features.at(outputNo).at(i);
526 int n = featureCount + 1;
527 if (f.hasTimestamp) {
528 n = int(round(
toSeconds(f.timestamp) * output.sampleRate));
537 int displayFrame = frame;
543 (out ? *out : cout) << displayFrame;
547 (out ? *out : cout) <<
"," << displayFrame;
550 (out ? *out : cout) <<
":";
558 (out ? *out : cout) << rt.
toString();
562 (out ? *out : cout) <<
"," << rt.
toString();
565 (out ? *out : cout) <<
":";
568 for (
unsigned int j = 0; j < f.values.size(); ++j) {
569 (out ? *out : cout) <<
" " << f.values[j];
571 (out ? *out : cout) <<
" " << f.label;
573 (out ? *out : cout) << endl;
581 cout <<
"\nVamp plugin search path: ";
585 for (
size_t i = 0; i < path.size(); ++i) {
587 cout <<
"[" << path[i] <<
"]";
589 cout << path[i] << endl;
593 if (verbose) cout << endl;
600 string out =
'\n' + text +
'\n';
601 for (
size_t i = 0; i < text.length(); ++i) {
602 out += (level == 1 ?
'=' : level == 2 ?
'-' :
'~');
614 cout <<
"\nVamp plugin libraries found in search path:" << endl;
617 vector<PluginLoader::PluginKey> plugins = loader->
listPlugins();
618 typedef multimap<string, PluginLoader::PluginKey>
620 LibraryMap libraryMap;
622 for (
size_t i = 0; i < plugins.size(); ++i) {
624 libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
627 string prevPath =
"";
630 for (LibraryMap::iterator i = libraryMap.begin();
631 i != libraryMap.end(); ++i) {
633 string path = i->first;
636 if (path != prevPath) {
640 cout <<
"\n " << path <<
":" << endl;
642 string::size_type ki = i->second.find(
':');
643 string text =
"Library \"" + i->second.substr(0, ki) +
"\"";
644 cout <<
"\n" <<
header(text, 1);
651 char c = char(
'A' + index);
652 if (c >
'Z') c = char(
'a' + (index - 26));
657 if (!category.empty()) {
658 for (
size_t ci = 0; ci < category.size(); ++ci) {
659 if (ci > 0) catstr +=
" > ";
660 catstr += category[ci];
666 cout <<
" [" << c <<
"] [v"
670 << plugin->
getMaker() <<
"]" << endl;
673 cout <<
" > " << catstr << endl;
683 cout <<
" - Identifier: "
685 cout <<
" - Plugin Version: "
687 cout <<
" - Vamp API Version: "
689 cout <<
" - Maker: \""
690 << plugin->
getMaker() <<
"\"" << endl;
691 cout <<
" - Copyright: \""
693 cout <<
" - Description: \""
695 cout <<
" - Input Domain: "
697 "Time Domain" :
"Frequency Domain") << endl;
698 cout <<
" - Default Step Size: "
700 cout <<
" - Default Block Size: "
702 cout <<
" - Minimum Channels: "
704 cout <<
" - Maximum Channels: "
708 cout <<
"vamp:" << key << endl;
717 for (
size_t j = 0; j < params.size(); ++j) {
718 Plugin::ParameterDescriptor &pd(params[j]);
719 cout <<
"\nParameter " << j+1 <<
": \"" << pd.name <<
"\"" << endl;
720 cout <<
" - Identifier: " << pd.identifier << endl;
721 cout <<
" - Description: \"" << pd.description <<
"\"" << endl;
723 cout <<
" - Unit: " << pd.unit << endl;
725 cout <<
" - Range: ";
726 cout << pd.minValue <<
" -> " << pd.maxValue << endl;
727 cout <<
" - Default: ";
728 cout << pd.defaultValue << endl;
729 if (pd.isQuantized) {
730 cout <<
" - Quantize Step: "
731 << pd.quantizeStep << endl;
733 if (!pd.valueNames.empty()) {
734 cout <<
" - Value Names: ";
735 for (
size_t k = 0; k < pd.valueNames.size(); ++k) {
736 if (k > 0) cout <<
", ";
737 cout <<
"\"" << pd.valueNames[k] <<
"\"";
743 if (outputs.empty()) {
744 cout <<
"\n** Note: This plugin reports no outputs!" << endl;
746 for (
size_t j = 0; j < outputs.size(); ++j) {
747 Plugin::OutputDescriptor &od(outputs[j]);
748 cout <<
"\nOutput " << j+1 <<
": \"" << od.name <<
"\"" << endl;
749 cout <<
" - Identifier: " << od.identifier << endl;
750 cout <<
" - Description: \"" << od.description <<
"\"" << endl;
752 cout <<
" - Unit: " << od.unit << endl;
754 if (od.hasFixedBinCount) {
755 cout <<
" - Default Bin Count: " << od.binCount << endl;
757 if (!od.binNames.empty()) {
759 for (
size_t k = 0; k < od.binNames.size(); ++k) {
760 if (od.binNames[k] !=
"") {
765 cout <<
" - Bin Names: ";
766 for (
size_t k = 0; k < od.binNames.size(); ++k) {
767 if (k > 0) cout <<
", ";
768 cout <<
"\"" << od.binNames[k] <<
"\"";
773 if (od.hasKnownExtents) {
774 cout <<
" - Default Extents: ";
775 cout << od.minValue <<
" -> " << od.maxValue << endl;
777 if (od.isQuantized) {
778 cout <<
" - Quantize Step: "
779 << od.quantizeStep << endl;
781 cout <<
" - Sample Type: "
784 "One Sample Per Step" :
787 "Fixed Sample Rate" :
788 "Variable Sample Rate") << endl;
791 cout <<
" - Default Rate: "
792 << od.sampleRate << endl;
794 cout <<
" - Has Duration: "
795 << (od.hasDuration ?
"Yes" :
"No") << endl;
800 for (
size_t j = 0; j < outputs.size(); ++j) {
802 cout <<
" (" << j <<
") "
803 << outputs[j].name <<
", \""
804 << outputs[j].identifier <<
"\"" << endl;
805 if (outputs[j].description !=
"") {
807 << outputs[j].description << endl;
810 cout <<
"vamp:" << key <<
":" << outputs[j].identifier << endl;
832 vector<PluginLoader::PluginKey> plugins = loader->
listPlugins();
834 set<string> printedcats;
836 for (
size_t i = 0; i < plugins.size(); ++i) {
844 if (!plugin)
continue;
848 if (category.empty()) catstr =
'|';
850 for (
size_t j = 0; j < category.size(); ++j) {
851 catstr += category[j];
853 if (printedcats.find(catstr) == printedcats.end()) {
854 std::cout << catstr << std::endl;
855 printedcats.insert(catstr);
PluginInputDomainAdapter is a Vamp plugin adapter that converts time-domain input into frequency-doma...
RealTime getTimestampAdjustment() const
Return the amount by which the timestamps supplied to process() are being incremented when they are p...
Vamp::HostExt::PluginLoader is a convenience class for discovering and loading Vamp plugins using the...
Plugin * loadPlugin(PluginKey key, float inputSampleRate, int adapterFlags=0)
Load a Vamp plugin, given its identifying key.
std::string PluginKey
PluginKey is a string type that is used to identify a plugin uniquely within the scope of "the curren...
std::string getLibraryPathForPlugin(PluginKey plugin)
Return the file path of the dynamic library from which the given plugin will be loaded (if available)...
static PluginLoader * getInstance()
Obtain a pointer to the singleton instance of PluginLoader.
PluginCategoryHierarchy getPluginCategory(PluginKey plugin)
Return the category hierarchy for a Vamp plugin, given its identifying key.
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...
std::vector< std::string > PluginCategoryHierarchy
PluginCategoryHierarchy is a sequence of general->specific category names, as may be associated with ...
PluginKeyList listPlugins()
Search for all available Vamp plugins, and return a list of them in the order in which they were foun...
PluginWrapper is a simple base class for adapter plugins.
WrapperType * getWrapper()
Return a pointer to the plugin wrapper of type WrapperType surrounding this wrapper's plugin,...
virtual ParameterList getParameterDescriptors() const
Get the controllable parameters of this plugin.
virtual std::string getName() const =0
Get a human-readable name or title of the plugin.
std::vector< ParameterDescriptor > ParameterList
virtual std::string getMaker() const =0
Get the name of the author or vendor of the plugin in human-readable form.
virtual std::string getDescription() const =0
Get a human-readable description for the plugin, typically a line of text that may optionally be disp...
virtual int getPluginVersion() const =0
Get the version number of the plugin.
virtual unsigned int getVampApiVersion() const
Get the Vamp API compatibility level of the plugin.
virtual std::string getCopyright() const =0
Get the copyright statement or licensing summary for the plugin.
virtual std::string getIdentifier() const =0
Get the computer-usable name of the plugin.
PluginHostAdapter is a wrapper class that a Vamp host can use to make the C-language VampPluginDescri...
static std::vector< std::string > getPluginPath()
Vamp::Plugin is a base class for plugin instance classes that provide feature extraction from audio o...
virtual size_t getMaxChannelCount() const
Get the maximum supported number of input channels.
std::vector< OutputDescriptor > OutputList
virtual size_t getPreferredStepSize() const
Get the preferred step size (window increment – the distance in sample frames between the start frame...
std::map< int, FeatureList > FeatureSet
virtual size_t getMinChannelCount() const
Get the minimum supported number of input channels.
virtual OutputList getOutputDescriptors() const =0
Get the outputs of this plugin.
virtual InputDomain getInputDomain() const =0
Get the plugin's required input domain.
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 FeatureSet process(const float *const *inputBuffers, RealTime timestamp)=0
Process a single block of input data.
virtual FeatureSet getRemainingFeatures()=0
After all blocks have been processed, calculate and return any remaining features derived from the co...
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,...
@ OneSamplePerStep
Results from each process() align with that call's block start.
@ FixedSampleRate
Results are evenly spaced in time (sampleRate specified below)
@ VariableSampleRate
Results are unevenly spaced and have individual timestamps.
RealTime represents time values to nanosecond precision with accurate arithmetic and frame-rate conve...
std::string toString() const
Return a human-readable debug-type string to full precision (probably not a format to show to a user ...
static RealTime frame2RealTime(long frame, unsigned int sampleRate)
Convert a sample frame at the given sample rate into a RealTime.
static const RealTime zeroTime
static long realTime2Frame(const RealTime &r, unsigned int sampleRate)
Convert a RealTime into a sample frame at the given sample rate.
static RealTime fromSeconds(double sec)
int main(int argc, char **argv)
void printPluginPath(bool verbose)
void listPluginsInLibrary(string soname)
int runPlugin(string myname, string soname, string id, string output, int outputNo, string inputFile, string outfilename, bool frames)
static string header(string text, int level)
void usage(const char *name)
void enumeratePlugins(Verbosity)
void fft(unsigned int, bool, double *, double *, double *, double *)
@ PluginInformationDetailed
void printFeatures(int, int, const Plugin::OutputDescriptor &, int, const Plugin::FeatureSet &, ofstream *, bool frames)
static double toSeconds(const RealTime &time)
void transformInput(float *, size_t)
void printPluginCategoryList()
#define VAMP_API_VERSION
Plugin API version.