vamp-simple-host.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Vamp
5 
6  An API for audio analysis and feature extraction plugins.
7 
8  Centre for Digital Music, Queen Mary, University of London.
9  Copyright 2006 Chris Cannam, copyright 2007-2008 QMUL.
10 
11  Permission is hereby granted, free of charge, to any person
12  obtaining a copy of this software and associated documentation
13  files (the "Software"), to deal in the Software without
14  restriction, including without limitation the rights to use, copy,
15  modify, merge, publish, distribute, sublicense, and/or sell copies
16  of the Software, and to permit persons to whom the Software is
17  furnished to do so, subject to the following conditions:
18 
19  The above copyright notice and this permission notice shall be
20  included in all copies or substantial portions of the Software.
21 
22  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
26  ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27  CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 
30  Except as contained in this notice, the names of the Centre for
31  Digital Music; Queen Mary, University of London; and Chris Cannam
32  shall not be used in advertising or otherwise to promote the sale,
33  use or other dealings in this Software without prior written
34  authorization.
35 */
36 
37 
38 /*
39  * This "simple" Vamp plugin host is no longer as simple as it was; it
40  * now has a lot of options and includes a lot of code to handle the
41  * various useful listing modes it supports.
42  *
43  * However, the runPlugin function still contains a reasonable
44  * implementation of a fairly generic Vamp plugin host capable of
45  * evaluating a given output on a given plugin for a sound file read
46  * via libsndfile.
47  */
48 
52 
53 #include <iostream>
54 #include <fstream>
55 #include <set>
56 #include <sndfile.h>
57 
58 #include <cstring>
59 #include <cstdlib>
60 
61 #include "system.h"
62 
63 #include <cmath>
64 
65 using namespace std;
66 
67 using Vamp::Plugin;
69 using Vamp::RealTime;
73 
74 #define HOST_VERSION "1.5"
75 
76 enum Verbosity {
81 };
82 
83 void printFeatures(int, int,
84  const Plugin::OutputDescriptor &, int,
85  const Plugin::FeatureSet &, ofstream *, bool frames);
86 void transformInput(float *, size_t);
87 void fft(unsigned int, bool, double *, double *, double *, double *);
88 void printPluginPath(bool verbose);
91 void listPluginsInLibrary(string soname);
92 int runPlugin(string myname, string soname, string id, string output,
93  int outputNo, string inputFile, string outfilename, bool frames);
94 
95 void usage(const char *name)
96 {
97  cerr << "\n"
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"
102  "Usage:\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"
136  << endl;
137  exit(2);
138 }
139 
140 int main(int argc, char **argv)
141 {
142  char *scooter = argv[0];
143  char *name = 0;
144  while (scooter && *scooter) {
145  if (*scooter == '/' || *scooter == '\\') name = ++scooter;
146  else ++scooter;
147  }
148  if (!name || !*name) name = argv[0];
149 
150  if (argc < 2) usage(name);
151 
152  if (argc == 2) {
153 
154  if (!strcmp(argv[1], "-v")) {
155 
156  cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl
157  << "Vamp API version: " << VAMP_API_VERSION << endl
158  << "Vamp SDK version: " << VAMP_SDK_VERSION << endl;
159  return 0;
160 
161  } else if (!strcmp(argv[1], "-l") || !strcmp(argv[1], "--list")) {
162 
163  printPluginPath(true);
165  return 0;
166 
167  } else if (!strcmp(argv[1], "-L") || !strcmp(argv[1], "--list-full")) {
168 
170  return 0;
171 
172  } else if (!strcmp(argv[1], "-p")) {
173 
174  printPluginPath(false);
175  return 0;
176 
177  } else if (!strcmp(argv[1], "--list-ids")) {
178 
180  return 0;
181 
182  } else if (!strcmp(argv[1], "--list-outputs")) {
183 
185  return 0;
186 
187  } else if (!strcmp(argv[1], "--list-by-category")) {
188 
190  return 0;
191 
192  } else usage(name);
193  }
194 
195  if (argc < 3) usage(name);
196 
197  bool useFrames = false;
198 
199  int base = 1;
200  if (!strcmp(argv[1], "-s")) {
201  useFrames = true;
202  base = 2;
203  }
204 
205  string soname = argv[base];
206  string wavname = argv[base+1];
207  string plugid = "";
208  string output = "";
209  int outputNo = -1;
210  string outfilename;
211 
212  if (argc >= base+3) {
213 
214  int idx = base+2;
215 
216  if (isdigit(*argv[idx])) {
217  outputNo = atoi(argv[idx++]);
218  }
219 
220  if (argc == idx + 2) {
221  if (!strcmp(argv[idx], "-o")) {
222  outfilename = argv[idx+1];
223  } else usage(name);
224  } else if (argc != idx) {
225  (usage(name));
226  }
227  }
228 
229  cerr << endl << name << ": Running..." << endl;
230 
231  cerr << "Reading file: \"" << wavname << "\", writing to ";
232  if (outfilename == "") {
233  cerr << "standard output" << endl;
234  } else {
235  cerr << "\"" << outfilename << "\"" << endl;
236  }
237 
238  string::size_type sep = soname.find(':');
239 
240  if (sep != string::npos) {
241  plugid = soname.substr(sep + 1);
242  soname = soname.substr(0, sep);
243 
244  sep = plugid.find(':');
245  if (sep != string::npos) {
246  output = plugid.substr(sep + 1);
247  plugid = plugid.substr(0, sep);
248  }
249  }
250 
251  if (plugid == "") {
252  usage(name);
253  }
254 
255  if (output != "" && outputNo != -1) {
256  usage(name);
257  }
258 
259  if (output == "" && outputNo == -1) {
260  outputNo = 0;
261  }
262 
263  return runPlugin(name, soname, plugid, output, outputNo,
264  wavname, outfilename, useFrames);
265 }
266 
267 
268 int runPlugin(string myname, string soname, string id,
269  string output, int outputNo, string wavname,
270  string outfilename, bool useFrames)
271 {
272  PluginLoader *loader = PluginLoader::getInstance();
273 
274  PluginLoader::PluginKey key = loader->composePluginKey(soname, id);
275 
276  SNDFILE *sndfile;
277  SF_INFO sfinfo;
278  memset(&sfinfo, 0, sizeof(SF_INFO));
279 
280  sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
281  if (!sndfile) {
282  cerr << myname << ": ERROR: Failed to open input file \""
283  << wavname << "\": " << sf_strerror(sndfile) << endl;
284  return 1;
285  }
286 
287  ofstream *out = 0;
288  if (outfilename != "") {
289  out = new ofstream(outfilename.c_str(), ios::out);
290  if (!*out) {
291  cerr << myname << ": ERROR: Failed to open output file \""
292  << outfilename << "\" for writing" << endl;
293  delete out;
294  return 1;
295  }
296  }
297 
298  Plugin *plugin = loader->loadPlugin
299  (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE);
300  if (!plugin) {
301  cerr << myname << ": ERROR: Failed to load plugin \"" << id
302  << "\" from library \"" << soname << "\"" << endl;
303  sf_close(sndfile);
304  if (out) {
305  out->close();
306  delete out;
307  }
308  return 1;
309  }
310 
311  cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
312 
313  // Note that the following would be much simpler if we used a
314  // PluginBufferingAdapter as well -- i.e. if we had passed
315  // PluginLoader::ADAPT_ALL to loader->loadPlugin() above, instead
316  // of ADAPT_ALL_SAFE. Then we could simply specify our own block
317  // size, keep the step size equal to the block size, and ignore
318  // the plugin's bleatings. However, there are some issues with
319  // using a PluginBufferingAdapter that make the results sometimes
320  // technically different from (if effectively the same as) the
321  // un-adapted plugin, so we aren't doing that here. See the
322  // PluginBufferingAdapter documentation for details.
323 
324  int blockSize = plugin->getPreferredBlockSize();
325  int stepSize = plugin->getPreferredStepSize();
326 
327  if (blockSize == 0) {
328  blockSize = 1024;
329  }
330  if (stepSize == 0) {
331  if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
332  stepSize = blockSize/2;
333  } else {
334  stepSize = blockSize;
335  }
336  } else if (stepSize > blockSize) {
337  cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to ";
338  if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
339  blockSize = stepSize * 2;
340  } else {
341  blockSize = stepSize;
342  }
343  cerr << blockSize << endl;
344  }
345  int overlapSize = blockSize - stepSize;
346  sf_count_t currentStep = 0;
347  int finalStepsRemaining = max(1, (blockSize / stepSize) - 1); // at end of file, this many part-silent frames needed after we hit EOF
348 
349  int channels = sfinfo.channels;
350 
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];
354 
355  cerr << "Using block size = " << blockSize << ", step size = "
356  << stepSize << endl;
357 
358  // The channel queries here are for informational purposes only --
359  // a PluginChannelAdapter is being used automatically behind the
360  // scenes, and it will take case of any channel mismatch
361 
362  int minch = plugin->getMinChannelCount();
363  int maxch = plugin->getMaxChannelCount();
364  cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
365  cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
366 
367  Plugin::OutputList outputs = plugin->getOutputDescriptors();
368  Plugin::OutputDescriptor od;
369  Plugin::FeatureSet features;
370 
371  int returnValue = 1;
372  int progress = 0;
373 
374  RealTime rt;
375  PluginWrapper *wrapper = 0;
376  RealTime adjustment = RealTime::zeroTime;
377 
378  if (outputs.empty()) {
379  cerr << "ERROR: Plugin has no outputs!" << endl;
380  goto done;
381  }
382 
383  if (outputNo < 0) {
384 
385  for (size_t oi = 0; oi < outputs.size(); ++oi) {
386  if (outputs[oi].identifier == output) {
387  outputNo = oi;
388  break;
389  }
390  }
391 
392  if (outputNo < 0) {
393  cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
394  goto done;
395  }
396 
397  } else {
398 
399  if (int(outputs.size()) <= outputNo) {
400  cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
401  goto done;
402  }
403  }
404 
405  od = outputs[outputNo];
406  cerr << "Output is: \"" << od.identifier << "\"" << endl;
407 
408  if (!plugin->initialise(channels, stepSize, blockSize)) {
409  cerr << "ERROR: Plugin initialise (channels = " << channels
410  << ", stepSize = " << stepSize << ", blockSize = "
411  << blockSize << ") failed." << endl;
412  goto done;
413  }
414 
415  wrapper = dynamic_cast<PluginWrapper *>(plugin);
416  if (wrapper) {
417  // See documentation for
418  // PluginInputDomainAdapter::getTimestampAdjustment
421  if (ida) adjustment = ida->getTimestampAdjustment();
422  }
423 
424  // Here we iterate over the frames, avoiding asking the numframes in case it's streaming input.
425  do {
426 
427  int count;
428 
429  if ((blockSize==stepSize) || (currentStep==0)) {
430  // read a full fresh block
431  if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
432  cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
433  break;
434  }
435  if (count != blockSize) --finalStepsRemaining;
436  } else {
437  // otherwise shunt the existing data down and read the remainder.
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;
441  break;
442  }
443  if (count != stepSize) --finalStepsRemaining;
444  count += overlapSize;
445  }
446 
447  for (int c = 0; c < channels; ++c) {
448  int j = 0;
449  while (j < count) {
450  plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
451  ++j;
452  }
453  while (j < blockSize) {
454  plugbuf[c][j] = 0.0f;
455  ++j;
456  }
457  }
458 
459  rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
460 
461  features = plugin->process(plugbuf, rt);
462 
464  (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
465  sfinfo.samplerate, od, outputNo, features, out, useFrames);
466 
467  if (sfinfo.frames > 0){
468  int pp = progress;
469  progress = (int)((float(currentStep * stepSize) / sfinfo.frames) * 100.f + 0.5f);
470  if (progress != pp && out) {
471  cerr << "\r" << progress << "%";
472  }
473  }
474 
475  ++currentStep;
476 
477  } while (finalStepsRemaining > 0);
478 
479  if (out) cerr << "\rDone" << endl;
480 
481  rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
482 
483  features = plugin->getRemainingFeatures();
484 
485  printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
486  sfinfo.samplerate, od, outputNo, features, out, useFrames);
487 
488  returnValue = 0;
489 
490 done:
491  delete plugin;
492  if (out) {
493  out->close();
494  delete out;
495  }
496  sf_close(sndfile);
497  return returnValue;
498 }
499 
500 static double
501 toSeconds(const RealTime &time)
502 {
503  return time.sec + double(time.nsec + 1) / 1000000000.0;
504 }
505 
506 void
507 printFeatures(int frame, int sr,
508  const Plugin::OutputDescriptor &output, int outputNo,
509  const Plugin::FeatureSet &features, ofstream *out, bool useFrames)
510 {
511  static int featureCount = -1;
512 
513  if (features.find(outputNo) == features.end()) return;
514 
515  for (size_t i = 0; i < features.at(outputNo).size(); ++i) {
516 
517  const Plugin::Feature &f = features.at(outputNo).at(i);
518 
519  bool haveRt = false;
520  RealTime rt;
521 
522  if (output.sampleType == Plugin::OutputDescriptor::VariableSampleRate) {
523  rt = f.timestamp;
524  haveRt = true;
525  } else if (output.sampleType == Plugin::OutputDescriptor::FixedSampleRate) {
526  int n = featureCount + 1;
527  if (f.hasTimestamp) {
528  n = int(round(toSeconds(f.timestamp) * output.sampleRate));
529  }
530  rt = RealTime::fromSeconds(double(n) / output.sampleRate);
531  haveRt = true;
532  featureCount = n;
533  }
534 
535  if (useFrames) {
536 
537  int displayFrame = frame;
538 
539  if (haveRt) {
540  displayFrame = RealTime::realTime2Frame(rt, sr);
541  }
542 
543  (out ? *out : cout) << displayFrame;
544 
545  if (f.hasDuration) {
546  displayFrame = RealTime::realTime2Frame(f.duration, sr);
547  (out ? *out : cout) << "," << displayFrame;
548  }
549 
550  (out ? *out : cout) << ":";
551 
552  } else {
553 
554  if (!haveRt) {
555  rt = RealTime::frame2RealTime(frame, sr);
556  }
557 
558  (out ? *out : cout) << rt.toString();
559 
560  if (f.hasDuration) {
561  rt = f.duration;
562  (out ? *out : cout) << "," << rt.toString();
563  }
564 
565  (out ? *out : cout) << ":";
566  }
567 
568  for (unsigned int j = 0; j < f.values.size(); ++j) {
569  (out ? *out : cout) << " " << f.values[j];
570  }
571  (out ? *out : cout) << " " << f.label;
572 
573  (out ? *out : cout) << endl;
574  }
575 }
576 
577 void
578 printPluginPath(bool verbose)
579 {
580  if (verbose) {
581  cout << "\nVamp plugin search path: ";
582  }
583 
584  vector<string> path = PluginHostAdapter::getPluginPath();
585  for (size_t i = 0; i < path.size(); ++i) {
586  if (verbose) {
587  cout << "[" << path[i] << "]";
588  } else {
589  cout << path[i] << endl;
590  }
591  }
592 
593  if (verbose) cout << endl;
594 }
595 
596 static
597 string
598 header(string text, int level)
599 {
600  string out = '\n' + text + '\n';
601  for (size_t i = 0; i < text.length(); ++i) {
602  out += (level == 1 ? '=' : level == 2 ? '-' : '~');
603  }
604  out += '\n';
605  return out;
606 }
607 
608 void
610 {
611  PluginLoader *loader = PluginLoader::getInstance();
612 
613  if (verbosity == PluginInformation) {
614  cout << "\nVamp plugin libraries found in search path:" << endl;
615  }
616 
617  vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
618  typedef multimap<string, PluginLoader::PluginKey>
619  LibraryMap;
620  LibraryMap libraryMap;
621 
622  for (size_t i = 0; i < plugins.size(); ++i) {
623  string path = loader->getLibraryPathForPlugin(plugins[i]);
624  libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
625  }
626 
627  string prevPath = "";
628  int index = 0;
629 
630  for (LibraryMap::iterator i = libraryMap.begin();
631  i != libraryMap.end(); ++i) {
632 
633  string path = i->first;
634  PluginLoader::PluginKey key = i->second;
635 
636  if (path != prevPath) {
637  prevPath = path;
638  index = 0;
639  if (verbosity == PluginInformation) {
640  cout << "\n " << path << ":" << endl;
641  } else if (verbosity == PluginInformationDetailed) {
642  string::size_type ki = i->second.find(':');
643  string text = "Library \"" + i->second.substr(0, ki) + "\"";
644  cout << "\n" << header(text, 1);
645  }
646  }
647 
648  Plugin *plugin = loader->loadPlugin(key, 48000);
649  if (plugin) {
650 
651  char c = char('A' + index);
652  if (c > 'Z') c = char('a' + (index - 26));
653 
654  PluginLoader::PluginCategoryHierarchy category =
655  loader->getPluginCategory(key);
656  string catstr;
657  if (!category.empty()) {
658  for (size_t ci = 0; ci < category.size(); ++ci) {
659  if (ci > 0) catstr += " > ";
660  catstr += category[ci];
661  }
662  }
663 
664  if (verbosity == PluginInformation) {
665 
666  cout << " [" << c << "] [v"
667  << plugin->getVampApiVersion() << "] "
668  << plugin->getName() << ", \""
669  << plugin->getIdentifier() << "\"" << " ["
670  << plugin->getMaker() << "]" << endl;
671 
672  if (catstr != "") {
673  cout << " > " << catstr << endl;
674  }
675 
676  if (plugin->getDescription() != "") {
677  cout << " - " << plugin->getDescription() << endl;
678  }
679 
680  } else if (verbosity == PluginInformationDetailed) {
681 
682  cout << header(plugin->getName(), 2);
683  cout << " - Identifier: "
684  << key << endl;
685  cout << " - Plugin Version: "
686  << plugin->getPluginVersion() << endl;
687  cout << " - Vamp API Version: "
688  << plugin->getVampApiVersion() << endl;
689  cout << " - Maker: \""
690  << plugin->getMaker() << "\"" << endl;
691  cout << " - Copyright: \""
692  << plugin->getCopyright() << "\"" << endl;
693  cout << " - Description: \""
694  << plugin->getDescription() << "\"" << endl;
695  cout << " - Input Domain: "
696  << (plugin->getInputDomain() == Vamp::Plugin::TimeDomain ?
697  "Time Domain" : "Frequency Domain") << endl;
698  cout << " - Default Step Size: "
699  << plugin->getPreferredStepSize() << endl;
700  cout << " - Default Block Size: "
701  << plugin->getPreferredBlockSize() << endl;
702  cout << " - Minimum Channels: "
703  << plugin->getMinChannelCount() << endl;
704  cout << " - Maximum Channels: "
705  << plugin->getMaxChannelCount() << endl;
706 
707  } else if (verbosity == PluginIds) {
708  cout << "vamp:" << key << endl;
709  }
710 
711  Plugin::OutputList outputs =
712  plugin->getOutputDescriptors();
713 
714  if (verbosity == PluginInformationDetailed) {
715 
716  Plugin::ParameterList params = plugin->getParameterDescriptors();
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;
722  if (pd.unit != "") {
723  cout << " - Unit: " << pd.unit << endl;
724  }
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;
732  }
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] << "\"";
738  }
739  cout << endl;
740  }
741  }
742 
743  if (outputs.empty()) {
744  cout << "\n** Note: This plugin reports no outputs!" << endl;
745  }
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;
751  if (od.unit != "") {
752  cout << " - Unit: " << od.unit << endl;
753  }
754  if (od.hasFixedBinCount) {
755  cout << " - Default Bin Count: " << od.binCount << endl;
756  }
757  if (!od.binNames.empty()) {
758  bool have = false;
759  for (size_t k = 0; k < od.binNames.size(); ++k) {
760  if (od.binNames[k] != "") {
761  have = true; break;
762  }
763  }
764  if (have) {
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] << "\"";
769  }
770  cout << endl;
771  }
772  }
773  if (od.hasKnownExtents) {
774  cout << " - Default Extents: ";
775  cout << od.minValue << " -> " << od.maxValue << endl;
776  }
777  if (od.isQuantized) {
778  cout << " - Quantize Step: "
779  << od.quantizeStep << endl;
780  }
781  cout << " - Sample Type: "
782  << (od.sampleType ==
783  Plugin::OutputDescriptor::OneSamplePerStep ?
784  "One Sample Per Step" :
785  od.sampleType ==
786  Plugin::OutputDescriptor::FixedSampleRate ?
787  "Fixed Sample Rate" :
788  "Variable Sample Rate") << endl;
789  if (od.sampleType !=
790  Plugin::OutputDescriptor::OneSamplePerStep) {
791  cout << " - Default Rate: "
792  << od.sampleRate << endl;
793  }
794  cout << " - Has Duration: "
795  << (od.hasDuration ? "Yes" : "No") << endl;
796  }
797  }
798 
799  if (outputs.size() > 1 || verbosity == PluginOutputIds) {
800  for (size_t j = 0; j < outputs.size(); ++j) {
801  if (verbosity == PluginInformation) {
802  cout << " (" << j << ") "
803  << outputs[j].name << ", \""
804  << outputs[j].identifier << "\"" << endl;
805  if (outputs[j].description != "") {
806  cout << " - "
807  << outputs[j].description << endl;
808  }
809  } else if (verbosity == PluginOutputIds) {
810  cout << "vamp:" << key << ":" << outputs[j].identifier << endl;
811  }
812  }
813  }
814 
815  ++index;
816 
817  delete plugin;
818  }
819  }
820 
821  if (verbosity == PluginInformation ||
822  verbosity == PluginInformationDetailed) {
823  cout << endl;
824  }
825 }
826 
827 void
829 {
830  PluginLoader *loader = PluginLoader::getInstance();
831 
832  vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
833 
834  set<string> printedcats;
835 
836  for (size_t i = 0; i < plugins.size(); ++i) {
837 
838  PluginLoader::PluginKey key = plugins[i];
839 
840  PluginLoader::PluginCategoryHierarchy category =
841  loader->getPluginCategory(key);
842 
843  Plugin *plugin = loader->loadPlugin(key, 48000);
844  if (!plugin) continue;
845 
846  string catstr = "";
847 
848  if (category.empty()) catstr = '|';
849  else {
850  for (size_t j = 0; j < category.size(); ++j) {
851  catstr += category[j];
852  catstr += '|';
853  if (printedcats.find(catstr) == printedcats.end()) {
854  std::cout << catstr << std::endl;
855  printedcats.insert(catstr);
856  }
857  }
858  }
859 
860  std::cout << catstr << key << ":::" << plugin->getName() << ":::" << plugin->getMaker() << ":::" << plugin->getDescription() << std::endl;
861  }
862 }
863 
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)
void printFeatures(int, int, const Plugin::OutputDescriptor &, int, const Plugin::FeatureSet &, ofstream *, bool frames)
RealTime getTimestampAdjustment() const
Return the amount by which the timestamps supplied to process() are being incremented when they are p...
#define VAMP_SDK_VERSION
Definition: plugguard.h:74
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&#39;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.
#define PLUGIN_SUFFIX
Definition: system.h:67
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.
Definition: vamp.h:53
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...
PluginWrapper is a simple base class for adapter plugins.
Definition: PluginWrapper.h:65
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&#39;s required input domain.
void printPluginCategoryList()
void usage(const char *name)
#define HOST_VERSION
static double toSeconds(const RealTime &time)
Vamp::HostExt::PluginLoader is a convenience class for discovering and loading Vamp plugins using the...
Definition: PluginLoader.h:75
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)