74#define HOST_VERSION "1.5"
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;
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;
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) {
526 int n = featureCount + 1;
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) {
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: ";
727 cout <<
" - Default: ";
730 cout <<
" - Quantize Step: "
734 cout <<
" - Value Names: ";
735 for (
size_t k = 0; k < pd.
valueNames.size(); ++k) {
736 if (k > 0) cout <<
", ";
743 if (outputs.empty()) {
744 cout <<
"\n** Note: This plugin reports no outputs!" << endl;
746 for (
size_t j = 0; j < outputs.size(); ++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;
755 cout <<
" - Default Bin Count: " << od.
binCount << endl;
759 for (
size_t k = 0; k < od.
binNames.size(); ++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] <<
"\"";
774 cout <<
" - Default Extents: ";
778 cout <<
" - Quantize Step: "
781 cout <<
" - Sample Type: "
784 "One Sample Per Step" :
787 "Fixed Sample Rate" :
788 "Variable Sample Rate") << endl;
791 cout <<
" - Default Rate: "
794 cout <<
" - Has Duration: "
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);
static std::vector< std::string > getPluginPath()
std::string PluginKey
PluginKey is a string type that is used to identify a plugin uniquely within the scope of "the curren...
static PluginLoader * getInstance()
Obtain a pointer to the singleton instance of PluginLoader.
std::vector< std::string > PluginCategoryHierarchy
PluginCategoryHierarchy is a sequence of general->specific category names, as may be associated with ...
std::vector< OutputDescriptor > OutputList
std::map< int, FeatureList > FeatureSet
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)
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 getLibraryPathForPlugin(PluginKey plugin)
Return the file path of the dynamic library from which the given plugin will be loaded (if available)...
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...
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...
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.
virtual size_t getPreferredStepSize() const
Get the preferred step size (window increment – the distance in sample frames between the start frame...
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,...
bool hasDuration
True if an output feature has a specified duration.
std::vector< float > values
Results for a single sample of this feature.
std::string label
Label for the sample of this feature.
bool hasTimestamp
True if an output feature has its own timestamp.
RealTime timestamp
Timestamp of the output feature.
RealTime duration
Duration of the output feature.
SampleType sampleType
Positioning in time of the output results.
bool isQuantized
True if the output values are quantized to a particular resolution.
std::vector< std::string > binNames
The (human-readable) names of each of the bins, if appropriate.
float quantizeStep
Quantization resolution of the output values (e.g.
float maxValue
Maximum value of the results in the output.
std::string unit
The unit of the output, in human-readable form.
bool hasDuration
True if the returned results for this output are known to have a duration field.
std::string name
The human-readable name of the output.
@ 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.
float minValue
Minimum value of the results in the output.
float sampleRate
Sample rate of the output results, as samples per second.
std::string identifier
The name of the output, in computer-usable form.
bool hasKnownExtents
True if the results in each output bin fall within a fixed numeric range (minimum and maximum values)...
bool hasFixedBinCount
True if the output has the same number of values per sample for every output sample.
std::string description
A human-readable short text describing the output.
size_t binCount
The number of values per result of the output.
float quantizeStep
Quantization resolution of the parameter values (e.g.
std::string name
The human-readable name of the parameter.
std::string identifier
The name of the parameter, in computer-usable form.
std::string unit
The unit of the parameter, in human-readable form.
std::string description
A human-readable short text describing the parameter.
bool isQuantized
True if the parameter values are quantized to a particular resolution.
std::vector< std::string > valueNames
Names for the quantized values.
float minValue
The minimum value of the parameter.
float maxValue
The maximum value of the parameter.
float defaultValue
The default value of the parameter.
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 ...
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.