annotate host/vamp-simple-host.cpp @ 354:e85513153c71

Initialise rate to 0. Otherwise there's a danger plugins will change the SampleType (e.g. to VariableSampleRate) but not set the rate because they don't think they need it (when in fact it needs to be set to 0)
author Chris Cannam
date Thu, 28 Mar 2013 15:49:17 +0000
parents 8cab5a0198d6
children 34ff6b72b0f4
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
Chris@328 74 #define HOST_VERSION "1.5"
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@290 98 "Copyright 2006-2009 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) {
Chris@318 279 cerr << myname << ": ERROR: Failed to open input file \""
cannam@64 280 << wavname << "\": " << sf_strerror(sndfile) << endl;
Chris@318 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 }
Chris@318 342 int overlapSize = blockSize - stepSize;
Chris@318 343 sf_count_t currentStep = 0;
Chris@318 344 int finalStepsRemaining = max(1, (blockSize / stepSize) - 1); // at end of file, this many part-silent frames needed after we hit EOF
cannam@83 345
cannam@16 346 int channels = sfinfo.channels;
cannam@16 347
cannam@16 348 float *filebuf = new float[blockSize * channels];
cannam@16 349 float **plugbuf = new float*[channels];
cannam@47 350 for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2];
cannam@16 351
cannam@16 352 cerr << "Using block size = " << blockSize << ", step size = "
cannam@16 353 << stepSize << endl;
cannam@16 354
cannam@240 355 // The channel queries here are for informational purposes only --
cannam@240 356 // a PluginChannelAdapter is being used automatically behind the
cannam@240 357 // scenes, and it will take case of any channel mismatch
cannam@240 358
cannam@16 359 int minch = plugin->getMinChannelCount();
cannam@16 360 int maxch = plugin->getMaxChannelCount();
cannam@16 361 cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
cannam@64 362 cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
cannam@16 363
cannam@99 364 Plugin::OutputList outputs = plugin->getOutputDescriptors();
cannam@99 365 Plugin::OutputDescriptor od;
cannam@16 366
cannam@29 367 int returnValue = 1;
cannam@88 368 int progress = 0;
cannam@29 369
cannam@190 370 RealTime rt;
cannam@190 371 PluginWrapper *wrapper = 0;
cannam@190 372 RealTime adjustment = RealTime::zeroTime;
cannam@190 373
cannam@16 374 if (outputs.empty()) {
Chris@318 375 cerr << "ERROR: Plugin has no outputs!" << endl;
cannam@16 376 goto done;
cannam@16 377 }
cannam@16 378
cannam@64 379 if (outputNo < 0) {
cannam@16 380
cannam@64 381 for (size_t oi = 0; oi < outputs.size(); ++oi) {
cannam@64 382 if (outputs[oi].identifier == output) {
cannam@64 383 outputNo = oi;
cannam@64 384 break;
cannam@64 385 }
cannam@64 386 }
cannam@64 387
cannam@64 388 if (outputNo < 0) {
cannam@64 389 cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
cannam@64 390 goto done;
cannam@64 391 }
cannam@64 392
cannam@64 393 } else {
cannam@64 394
cannam@64 395 if (int(outputs.size()) <= outputNo) {
cannam@64 396 cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
cannam@64 397 goto done;
cannam@64 398 }
cannam@64 399 }
cannam@64 400
cannam@64 401 od = outputs[outputNo];
cannam@64 402 cerr << "Output is: \"" << od.identifier << "\"" << endl;
cannam@16 403
cannam@29 404 if (!plugin->initialise(channels, stepSize, blockSize)) {
cannam@29 405 cerr << "ERROR: Plugin initialise (channels = " << channels
cannam@29 406 << ", stepSize = " << stepSize << ", blockSize = "
cannam@29 407 << blockSize << ") failed." << endl;
cannam@29 408 goto done;
cannam@29 409 }
cannam@16 410
cannam@190 411 wrapper = dynamic_cast<PluginWrapper *>(plugin);
cannam@190 412 if (wrapper) {
cannam@240 413 // See documentation for
cannam@240 414 // PluginInputDomainAdapter::getTimestampAdjustment
cannam@190 415 PluginInputDomainAdapter *ida =
cannam@190 416 wrapper->getWrapper<PluginInputDomainAdapter>();
cannam@190 417 if (ida) adjustment = ida->getTimestampAdjustment();
cannam@190 418 }
Chris@318 419
Chris@318 420 // Here we iterate over the frames, avoiding asking the numframes in case it's streaming input.
Chris@318 421 do {
cannam@16 422
cannam@16 423 int count;
cannam@16 424
Chris@318 425 if ((blockSize==stepSize) || (currentStep==0)) {
Chris@318 426 // read a full fresh block
Chris@318 427 if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
Chris@318 428 cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
Chris@318 429 break;
Chris@318 430 }
Chris@318 431 if (count != blockSize) --finalStepsRemaining;
Chris@318 432 } else {
Chris@318 433 // otherwise shunt the existing data down and read the remainder.
Chris@318 434 memmove(filebuf, filebuf + (stepSize * channels), overlapSize * channels * sizeof(float));
Chris@318 435 if ((count = sf_readf_float(sndfile, filebuf + (overlapSize * channels), stepSize)) < 0) {
Chris@318 436 cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
Chris@318 437 break;
Chris@318 438 }
Chris@318 439 if (count != stepSize) --finalStepsRemaining;
Chris@318 440 count += overlapSize;
cannam@16 441 }
cannam@16 442
cannam@16 443 for (int c = 0; c < channels; ++c) {
cannam@64 444 int j = 0;
cannam@64 445 while (j < count) {
cannam@64 446 plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
cannam@64 447 ++j;
cannam@64 448 }
cannam@64 449 while (j < blockSize) {
cannam@16 450 plugbuf[c][j] = 0.0f;
cannam@64 451 ++j;
cannam@16 452 }
cannam@16 453 }
cannam@16 454
Chris@318 455 rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
cannam@190 456
cannam@16 457 printFeatures
cannam@190 458 (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
cannam@190 459 sfinfo.samplerate, outputNo, plugin->process(plugbuf, rt),
cannam@109 460 out, useFrames);
cannam@88 461
Chris@318 462 if (sfinfo.frames > 0){
Chris@318 463 int pp = progress;
Chris@318 464 progress = lrintf((float(currentStep * stepSize) / sfinfo.frames) * 100.f);
Chris@318 465 if (progress != pp && out) {
Chris@318 466 cerr << "\r" << progress << "%";
Chris@318 467 }
cannam@88 468 }
Chris@318 469
Chris@318 470 ++currentStep;
Chris@318 471
Chris@318 472 } while (finalStepsRemaining > 0);
Chris@318 473
cannam@88 474 if (out) cerr << "\rDone" << endl;
cannam@16 475
Chris@318 476 rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
cannam@190 477
cannam@190 478 printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
cannam@190 479 sfinfo.samplerate, outputNo,
cannam@109 480 plugin->getRemainingFeatures(), out, useFrames);
cannam@16 481
cannam@29 482 returnValue = 0;
cannam@29 483
cannam@16 484 done:
cannam@16 485 delete plugin;
cannam@88 486 if (out) {
cannam@88 487 out->close();
cannam@88 488 delete out;
cannam@88 489 }
cannam@16 490 sf_close(sndfile);
cannam@29 491 return returnValue;
cannam@1 492 }
cannam@1 493
cannam@16 494 void
cannam@99 495 printFeatures(int frame, int sr, int output,
cannam@109 496 Plugin::FeatureSet features, ofstream *out, bool useFrames)
cannam@99 497 {
cannam@99 498 for (unsigned int i = 0; i < features[output].size(); ++i) {
cannam@99 499
cannam@109 500 if (useFrames) {
cannam@99 501
cannam@109 502 int displayFrame = frame;
cannam@109 503
cannam@109 504 if (features[output][i].hasTimestamp) {
cannam@109 505 displayFrame = RealTime::realTime2Frame
cannam@109 506 (features[output][i].timestamp, sr);
cannam@109 507 }
cannam@109 508
cannam@167 509 (out ? *out : cout) << displayFrame;
cannam@167 510
cannam@167 511 if (features[output][i].hasDuration) {
cannam@167 512 displayFrame = RealTime::realTime2Frame
cannam@167 513 (features[output][i].duration, sr);
cannam@167 514 (out ? *out : cout) << "," << displayFrame;
cannam@167 515 }
cannam@167 516
cannam@167 517 (out ? *out : cout) << ":";
cannam@109 518
cannam@109 519 } else {
cannam@109 520
cannam@109 521 RealTime rt = RealTime::frame2RealTime(frame, sr);
cannam@109 522
cannam@109 523 if (features[output][i].hasTimestamp) {
cannam@109 524 rt = features[output][i].timestamp;
cannam@109 525 }
cannam@109 526
cannam@167 527 (out ? *out : cout) << rt.toString();
cannam@167 528
cannam@167 529 if (features[output][i].hasDuration) {
cannam@167 530 rt = features[output][i].duration;
cannam@167 531 (out ? *out : cout) << "," << rt.toString();
cannam@167 532 }
cannam@167 533
cannam@167 534 (out ? *out : cout) << ":";
cannam@99 535 }
cannam@99 536
cannam@99 537 for (unsigned int j = 0; j < features[output][i].values.size(); ++j) {
cannam@99 538 (out ? *out : cout) << " " << features[output][i].values[j];
cannam@99 539 }
Chris@320 540 (out ? *out : cout) << " " << features[output][i].label;
cannam@99 541
cannam@99 542 (out ? *out : cout) << endl;
cannam@99 543 }
cannam@99 544 }
cannam@99 545
cannam@99 546 void
cannam@64 547 printPluginPath(bool verbose)
cannam@40 548 {
cannam@64 549 if (verbose) {
cannam@64 550 cout << "\nVamp plugin search path: ";
cannam@64 551 }
cannam@64 552
cannam@99 553 vector<string> path = PluginHostAdapter::getPluginPath();
cannam@40 554 for (size_t i = 0; i < path.size(); ++i) {
cannam@64 555 if (verbose) {
cannam@64 556 cout << "[" << path[i] << "]";
cannam@64 557 } else {
cannam@64 558 cout << path[i] << endl;
cannam@64 559 }
cannam@40 560 }
cannam@64 561
cannam@64 562 if (verbose) cout << endl;
cannam@40 563 }
cannam@40 564
cannam@240 565 static
cannam@240 566 string
cannam@240 567 header(string text, int level)
cannam@240 568 {
cannam@240 569 string out = '\n' + text + '\n';
cannam@240 570 for (size_t i = 0; i < text.length(); ++i) {
cannam@240 571 out += (level == 1 ? '=' : level == 2 ? '-' : '~');
cannam@240 572 }
cannam@240 573 out += '\n';
cannam@240 574 return out;
cannam@240 575 }
cannam@240 576
cannam@40 577 void
cannam@95 578 enumeratePlugins(Verbosity verbosity)
cannam@40 579 {
cannam@64 580 PluginLoader *loader = PluginLoader::getInstance();
cannam@64 581
cannam@95 582 if (verbosity == PluginInformation) {
cannam@95 583 cout << "\nVamp plugin libraries found in search path:" << endl;
cannam@95 584 }
cannam@64 585
cannam@99 586 vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
cannam@99 587 typedef multimap<string, PluginLoader::PluginKey>
cannam@64 588 LibraryMap;
cannam@64 589 LibraryMap libraryMap;
cannam@64 590
cannam@64 591 for (size_t i = 0; i < plugins.size(); ++i) {
cannam@99 592 string path = loader->getLibraryPathForPlugin(plugins[i]);
cannam@64 593 libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
cannam@64 594 }
cannam@64 595
cannam@99 596 string prevPath = "";
cannam@64 597 int index = 0;
cannam@64 598
cannam@64 599 for (LibraryMap::iterator i = libraryMap.begin();
cannam@64 600 i != libraryMap.end(); ++i) {
cannam@64 601
cannam@99 602 string path = i->first;
cannam@64 603 PluginLoader::PluginKey key = i->second;
cannam@64 604
cannam@64 605 if (path != prevPath) {
cannam@64 606 prevPath = path;
cannam@64 607 index = 0;
cannam@95 608 if (verbosity == PluginInformation) {
cannam@95 609 cout << "\n " << path << ":" << endl;
cannam@240 610 } else if (verbosity == PluginInformationDetailed) {
cannam@240 611 string::size_type ki = i->second.find(':');
cannam@240 612 string text = "Library \"" + i->second.substr(0, ki) + "\"";
cannam@240 613 cout << "\n" << header(text, 1);
cannam@95 614 }
cannam@40 615 }
cannam@64 616
cannam@99 617 Plugin *plugin = loader->loadPlugin(key, 48000);
cannam@64 618 if (plugin) {
cannam@64 619
cannam@64 620 char c = char('A' + index);
cannam@64 621 if (c > 'Z') c = char('a' + (index - 26));
cannam@64 622
cannam@240 623 PluginLoader::PluginCategoryHierarchy category =
cannam@240 624 loader->getPluginCategory(key);
cannam@240 625 string catstr;
cannam@240 626 if (!category.empty()) {
cannam@240 627 for (size_t ci = 0; ci < category.size(); ++ci) {
cannam@240 628 if (ci > 0) catstr += " > ";
cannam@240 629 catstr += category[ci];
cannam@240 630 }
cannam@240 631 }
cannam@240 632
cannam@95 633 if (verbosity == PluginInformation) {
cannam@64 634
cannam@95 635 cout << " [" << c << "] [v"
cannam@95 636 << plugin->getVampApiVersion() << "] "
cannam@95 637 << plugin->getName() << ", \""
cannam@95 638 << plugin->getIdentifier() << "\"" << " ["
cannam@95 639 << plugin->getMaker() << "]" << endl;
cannam@240 640
cannam@240 641 if (catstr != "") {
cannam@240 642 cout << " > " << catstr << endl;
cannam@64 643 }
cannam@95 644
cannam@95 645 if (plugin->getDescription() != "") {
cannam@95 646 cout << " - " << plugin->getDescription() << endl;
cannam@95 647 }
cannam@95 648
cannam@240 649 } else if (verbosity == PluginInformationDetailed) {
cannam@240 650
cannam@240 651 cout << header(plugin->getName(), 2);
cannam@248 652 cout << " - Identifier: "
cannam@240 653 << key << endl;
cannam@248 654 cout << " - Plugin Version: "
cannam@240 655 << plugin->getPluginVersion() << endl;
cannam@248 656 cout << " - Vamp API Version: "
cannam@240 657 << plugin->getVampApiVersion() << endl;
cannam@248 658 cout << " - Maker: \""
cannam@240 659 << plugin->getMaker() << "\"" << endl;
cannam@248 660 cout << " - Copyright: \""
cannam@240 661 << plugin->getCopyright() << "\"" << endl;
cannam@248 662 cout << " - Description: \""
cannam@240 663 << plugin->getDescription() << "\"" << endl;
cannam@248 664 cout << " - Input Domain: "
cannam@240 665 << (plugin->getInputDomain() == Vamp::Plugin::TimeDomain ?
cannam@240 666 "Time Domain" : "Frequency Domain") << endl;
cannam@248 667 cout << " - Default Step Size: "
cannam@240 668 << plugin->getPreferredStepSize() << endl;
cannam@248 669 cout << " - Default Block Size: "
cannam@240 670 << plugin->getPreferredBlockSize() << endl;
cannam@248 671 cout << " - Minimum Channels: "
cannam@240 672 << plugin->getMinChannelCount() << endl;
cannam@248 673 cout << " - Maximum Channels: "
cannam@240 674 << plugin->getMaxChannelCount() << endl;
cannam@240 675
cannam@95 676 } else if (verbosity == PluginIds) {
cannam@95 677 cout << "vamp:" << key << endl;
cannam@47 678 }
cannam@95 679
cannam@99 680 Plugin::OutputList outputs =
cannam@64 681 plugin->getOutputDescriptors();
cannam@64 682
cannam@240 683 if (verbosity == PluginInformationDetailed) {
cannam@240 684
cannam@240 685 Plugin::ParameterList params = plugin->getParameterDescriptors();
cannam@240 686 for (size_t j = 0; j < params.size(); ++j) {
cannam@240 687 Plugin::ParameterDescriptor &pd(params[j]);
cannam@240 688 cout << "\nParameter " << j+1 << ": \"" << pd.name << "\"" << endl;
cannam@248 689 cout << " - Identifier: " << pd.identifier << endl;
cannam@248 690 cout << " - Description: \"" << pd.description << "\"" << endl;
cannam@240 691 if (pd.unit != "") {
cannam@248 692 cout << " - Unit: " << pd.unit << endl;
cannam@240 693 }
cannam@248 694 cout << " - Range: ";
cannam@240 695 cout << pd.minValue << " -> " << pd.maxValue << endl;
cannam@248 696 cout << " - Default: ";
cannam@240 697 cout << pd.defaultValue << endl;
cannam@240 698 if (pd.isQuantized) {
cannam@248 699 cout << " - Quantize Step: "
cannam@240 700 << pd.quantizeStep << endl;
cannam@240 701 }
cannam@240 702 if (!pd.valueNames.empty()) {
cannam@248 703 cout << " - Value Names: ";
cannam@240 704 for (size_t k = 0; k < pd.valueNames.size(); ++k) {
cannam@240 705 if (k > 0) cout << ", ";
cannam@240 706 cout << "\"" << pd.valueNames[k] << "\"";
cannam@240 707 }
cannam@240 708 cout << endl;
cannam@240 709 }
cannam@240 710 }
cannam@240 711
cannam@240 712 if (outputs.empty()) {
cannam@240 713 cout << "\n** Note: This plugin reports no outputs!" << endl;
cannam@240 714 }
cannam@240 715 for (size_t j = 0; j < outputs.size(); ++j) {
cannam@240 716 Plugin::OutputDescriptor &od(outputs[j]);
cannam@240 717 cout << "\nOutput " << j+1 << ": \"" << od.name << "\"" << endl;
cannam@248 718 cout << " - Identifier: " << od.identifier << endl;
cannam@248 719 cout << " - Description: \"" << od.description << "\"" << endl;
cannam@240 720 if (od.unit != "") {
cannam@248 721 cout << " - Unit: " << od.unit << endl;
cannam@240 722 }
cannam@240 723 if (od.hasFixedBinCount) {
cannam@248 724 cout << " - Default Bin Count: " << od.binCount << endl;
cannam@240 725 }
cannam@240 726 if (!od.binNames.empty()) {
cannam@248 727 bool have = false;
cannam@240 728 for (size_t k = 0; k < od.binNames.size(); ++k) {
cannam@248 729 if (od.binNames[k] != "") {
cannam@248 730 have = true; break;
cannam@248 731 }
cannam@240 732 }
cannam@248 733 if (have) {
cannam@248 734 cout << " - Bin Names: ";
cannam@248 735 for (size_t k = 0; k < od.binNames.size(); ++k) {
cannam@248 736 if (k > 0) cout << ", ";
cannam@248 737 cout << "\"" << od.binNames[k] << "\"";
cannam@248 738 }
cannam@248 739 cout << endl;
cannam@248 740 }
cannam@240 741 }
cannam@240 742 if (od.hasKnownExtents) {
cannam@248 743 cout << " - Default Extents: ";
cannam@240 744 cout << od.minValue << " -> " << od.maxValue << endl;
cannam@240 745 }
cannam@240 746 if (od.isQuantized) {
cannam@248 747 cout << " - Quantize Step: "
cannam@240 748 << od.quantizeStep << endl;
cannam@240 749 }
cannam@248 750 cout << " - Sample Type: "
cannam@240 751 << (od.sampleType ==
cannam@240 752 Plugin::OutputDescriptor::OneSamplePerStep ?
cannam@240 753 "One Sample Per Step" :
cannam@240 754 od.sampleType ==
cannam@240 755 Plugin::OutputDescriptor::FixedSampleRate ?
cannam@240 756 "Fixed Sample Rate" :
cannam@240 757 "Variable Sample Rate") << endl;
cannam@240 758 if (od.sampleType !=
cannam@240 759 Plugin::OutputDescriptor::OneSamplePerStep) {
cannam@248 760 cout << " - Default Rate: "
cannam@240 761 << od.sampleRate << endl;
cannam@240 762 }
cannam@248 763 cout << " - Has Duration: "
cannam@240 764 << (od.hasDuration ? "Yes" : "No") << endl;
cannam@240 765 }
cannam@240 766 }
cannam@240 767
cannam@95 768 if (outputs.size() > 1 || verbosity == PluginOutputIds) {
cannam@64 769 for (size_t j = 0; j < outputs.size(); ++j) {
cannam@95 770 if (verbosity == PluginInformation) {
cannam@95 771 cout << " (" << j << ") "
cannam@95 772 << outputs[j].name << ", \""
cannam@95 773 << outputs[j].identifier << "\"" << endl;
cannam@95 774 if (outputs[j].description != "") {
cannam@95 775 cout << " - "
cannam@95 776 << outputs[j].description << endl;
cannam@95 777 }
cannam@95 778 } else if (verbosity == PluginOutputIds) {
cannam@95 779 cout << "vamp:" << key << ":" << outputs[j].identifier << endl;
cannam@40 780 }
cannam@40 781 }
cannam@64 782 }
cannam@64 783
cannam@64 784 ++index;
cannam@64 785
cannam@64 786 delete plugin;
cannam@40 787 }
cannam@40 788 }
cannam@64 789
cannam@240 790 if (verbosity == PluginInformation ||
cannam@240 791 verbosity == PluginInformationDetailed) {
cannam@95 792 cout << endl;
cannam@95 793 }
cannam@40 794 }
cannam@40 795
cannam@40 796 void
cannam@99 797 printPluginCategoryList()
cannam@16 798 {
cannam@99 799 PluginLoader *loader = PluginLoader::getInstance();
cannam@88 800
cannam@99 801 vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
cannam@88 802
cannam@99 803 set<string> printedcats;
cannam@99 804
cannam@99 805 for (size_t i = 0; i < plugins.size(); ++i) {
cannam@99 806
cannam@99 807 PluginLoader::PluginKey key = plugins[i];
cannam@99 808
cannam@99 809 PluginLoader::PluginCategoryHierarchy category =
cannam@99 810 loader->getPluginCategory(key);
cannam@99 811
cannam@99 812 Plugin *plugin = loader->loadPlugin(key, 48000);
cannam@99 813 if (!plugin) continue;
cannam@99 814
cannam@99 815 string catstr = "";
cannam@99 816
cannam@99 817 if (category.empty()) catstr = '|';
cannam@99 818 else {
cannam@99 819 for (size_t j = 0; j < category.size(); ++j) {
cannam@99 820 catstr += category[j];
cannam@99 821 catstr += '|';
cannam@99 822 if (printedcats.find(catstr) == printedcats.end()) {
cannam@99 823 std::cout << catstr << std::endl;
cannam@99 824 printedcats.insert(catstr);
cannam@99 825 }
cannam@99 826 }
cannam@16 827 }
cannam@88 828
cannam@99 829 std::cout << catstr << key << ":::" << plugin->getName() << ":::" << plugin->getMaker() << ":::" << plugin->getDescription() << std::endl;
cannam@16 830 }
cannam@16 831 }
cannam@16 832