annotate host/vamp-simple-host.cpp @ 263:4454843ff384

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