annotate src/vamp-plugin-sdk-2.4/host/vamp-simple-host.cpp @ 83:ae30d91d2ffe

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