annotate host/vamp-simple-host.cpp @ 98:896a97349ac5

* Add a static wrapper object to wrap the static instance pointer, so that it can be properly deleted on program exit instead of showing up in certain tools as leaked
author cannam
date Mon, 03 Dec 2007 12:57:27 +0000
parents cd4425ab7b98
children fe31e6aed666
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@1 9 Copyright 2006 Chris Cannam.
cannam@16 10 FFT code from Don Cross's public domain FFT implementation.
cannam@1 11
cannam@1 12 Permission is hereby granted, free of charge, to any person
cannam@1 13 obtaining a copy of this software and associated documentation
cannam@1 14 files (the "Software"), to deal in the Software without
cannam@1 15 restriction, including without limitation the rights to use, copy,
cannam@1 16 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@1 17 of the Software, and to permit persons to whom the Software is
cannam@1 18 furnished to do so, subject to the following conditions:
cannam@1 19
cannam@1 20 The above copyright notice and this permission notice shall be
cannam@1 21 included in all copies or substantial portions of the Software.
cannam@1 22
cannam@1 23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@1 24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@1 25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@6 26 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@1 27 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@1 28 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@1 29 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@1 30
cannam@1 31 Except as contained in this notice, the names of the Centre for
cannam@1 32 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@1 33 shall not be used in advertising or otherwise to promote the sale,
cannam@1 34 use or other dealings in this Software without prior written
cannam@1 35 authorization.
cannam@1 36 */
cannam@1 37
cannam@64 38 #include "vamp-sdk/PluginHostAdapter.h"
cannam@64 39 #include "vamp-sdk/hostext/PluginChannelAdapter.h"
cannam@64 40 #include "vamp-sdk/hostext/PluginInputDomainAdapter.h"
cannam@64 41 #include "vamp-sdk/hostext/PluginLoader.h"
cannam@64 42 #include "vamp/vamp.h"
cannam@1 43
cannam@16 44 #include <iostream>
cannam@88 45 #include <fstream>
cannam@16 46 #include <sndfile.h>
cannam@1 47
cannam@1 48 #include "system.h"
cannam@1 49
cannam@19 50 #include <cmath>
cannam@19 51
cannam@16 52 using std::cout;
cannam@16 53 using std::cerr;
cannam@16 54 using std::endl;
cannam@16 55 using std::string;
cannam@32 56 using std::vector;
cannam@88 57 using std::ofstream;
cannam@88 58 using std::ios;
cannam@16 59
cannam@64 60 using Vamp::HostExt::PluginLoader;
cannam@64 61
cannam@64 62 #define HOST_VERSION "1.1"
cannam@40 63
cannam@95 64 enum Verbosity {
cannam@95 65 PluginIds,
cannam@95 66 PluginOutputIds,
cannam@95 67 PluginInformation
cannam@95 68 };
cannam@95 69
cannam@88 70 void printFeatures(int, int, int, Vamp::Plugin::FeatureSet, ofstream *);
cannam@16 71 void transformInput(float *, size_t);
cannam@16 72 void fft(unsigned int, bool, double *, double *, double *, double *);
cannam@64 73 void printPluginPath(bool verbose);
cannam@95 74 void enumeratePlugins(Verbosity);
cannam@64 75 void listPluginsInLibrary(string soname);
cannam@64 76 int runPlugin(string myname, string soname, string id, string output,
cannam@88 77 int outputNo, string inputFile, string outfilename);
cannam@40 78
cannam@64 79 void usage(const char *name)
cannam@64 80 {
cannam@64 81 cerr << "\n"
cannam@64 82 << name << ": A simple Vamp plugin host.\n\n"
cannam@64 83 "Centre for Digital Music, Queen Mary, University of London.\n"
cannam@64 84 "Copyright 2006-2007 Chris Cannam and QMUL.\n"
cannam@64 85 "Freely redistributable; published under a BSD-style license.\n\n"
cannam@64 86 "Usage:\n\n"
cannam@95 87 " " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o out.txt]\n"
cannam@95 88 " " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno] [-o out.txt]\n\n"
cannam@64 89 " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n"
cannam@73 90 " audio data in \"file.wav\", retrieving the named \"output\", or output\n"
cannam@73 91 " number \"outputno\" (the first output by default) and dumping it to\n"
cannam@95 92 " standard output, or to \"out.txt\" if the -o option is given.\n\n"
cannam@73 93 " \"pluginlibrary\" should be a library name, not a file path; the\n"
cannam@73 94 " standard Vamp library search path will be used to locate it. If\n"
cannam@73 95 " a file path is supplied, the directory part(s) will be ignored.\n\n"
cannam@64 96 " " << name << " -l\n\n"
cannam@95 97 " -- List the plugin libraries and Vamp plugins in the library search path\n"
cannam@95 98 " in a verbose human-readable format.\n\n"
cannam@95 99 " " << name << " --list-ids\n\n"
cannam@95 100 " -- List the plugins in the search path in a terse machine-readable format,\n"
cannam@95 101 " in the form vamp:soname:identifier.\n\n"
cannam@95 102 " " << name << " --list-outputs\n\n"
cannam@95 103 " -- List the outputs for plugins in the search path in a machine-readable\n"
cannam@95 104 " format, in the form vamp:soname:identifier:output.\n\n"
cannam@64 105 " " << name << " -p\n\n"
cannam@73 106 " -- Print out the Vamp library search path.\n\n"
cannam@64 107 " " << name << " -v\n\n"
cannam@95 108 " -- Display version information only.\n"
cannam@64 109 << endl;
cannam@64 110 exit(2);
cannam@64 111 }
cannam@1 112
cannam@1 113 int main(int argc, char **argv)
cannam@1 114 {
cannam@64 115 char *scooter = argv[0];
cannam@64 116 char *name = 0;
cannam@64 117 while (scooter && *scooter) {
cannam@64 118 if (*scooter == '/' || *scooter == '\\') name = ++scooter;
cannam@64 119 else ++scooter;
cannam@1 120 }
cannam@64 121 if (!name || !*name) name = argv[0];
cannam@43 122
cannam@88 123 if (argc < 2) usage(name);
cannam@64 124
cannam@88 125 if (argc == 2) {
cannam@88 126
cannam@88 127 if (!strcmp(argv[1], "-v")) {
cannam@88 128
cannam@88 129 cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl
cannam@88 130 << "Vamp API version: " << VAMP_API_VERSION << endl
cannam@88 131 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl;
cannam@88 132 return 0;
cannam@88 133
cannam@88 134 } else if (!strcmp(argv[1], "-l")) {
cannam@88 135
cannam@88 136 printPluginPath(true);
cannam@95 137 enumeratePlugins(PluginInformation);
cannam@88 138 return 0;
cannam@88 139
cannam@88 140 } else if (!strcmp(argv[1], "-p")) {
cannam@88 141
cannam@88 142 printPluginPath(false);
cannam@88 143 return 0;
cannam@88 144
cannam@95 145 } else if (!strcmp(argv[1], "--list-ids")) {
cannam@95 146
cannam@95 147 enumeratePlugins(PluginIds);
cannam@95 148 return 0;
cannam@95 149
cannam@95 150 } else if (!strcmp(argv[1], "--list-outputs")) {
cannam@95 151
cannam@95 152 enumeratePlugins(PluginOutputIds);
cannam@95 153 return 0;
cannam@95 154
cannam@88 155 } else usage(name);
cannam@64 156 }
cannam@64 157
cannam@88 158 if (argc < 3) usage(name);
cannam@88 159
cannam@88 160 string soname = argv[1];
cannam@88 161 string wavname = argv[2];
cannam@88 162 string plugid = "";
cannam@88 163 string output = "";
cannam@88 164 int outputNo = -1;
cannam@88 165 string outfilename;
cannam@88 166
cannam@88 167 if (argc >= 4) {
cannam@88 168
cannam@88 169 int idx = 3;
cannam@88 170
cannam@88 171 if (isdigit(*argv[idx])) {
cannam@88 172 outputNo = atoi(argv[idx++]);
cannam@88 173 }
cannam@88 174
cannam@88 175 if (argc == idx + 2) {
cannam@88 176 if (!strcmp(argv[idx], "-o")) {
cannam@88 177 outfilename = argv[idx+1];
cannam@88 178 } else usage(name);
cannam@88 179 } else if (argc != idx) {
cannam@88 180 (usage(name));
cannam@88 181 }
cannam@40 182 }
cannam@40 183
cannam@64 184 cerr << endl << name << ": Running..." << endl;
cannam@1 185
cannam@88 186 cerr << "Reading file: \"" << wavname << "\", writing to ";
cannam@88 187 if (outfilename == "") {
cannam@88 188 cerr << "standard output" << endl;
cannam@88 189 } else {
cannam@88 190 cerr << "\"" << outfilename << "\"" << endl;
cannam@88 191 }
cannam@16 192
cannam@64 193 string::size_type sep = soname.find(':');
cannam@64 194
cannam@64 195 if (sep != string::npos) {
cannam@49 196 plugid = soname.substr(sep + 1);
cannam@20 197 soname = soname.substr(0, sep);
cannam@1 198
cannam@64 199 sep = plugid.find(':');
cannam@64 200 if (sep != string::npos) {
cannam@64 201 output = plugid.substr(sep + 1);
cannam@64 202 plugid = plugid.substr(0, sep);
cannam@16 203 }
cannam@16 204 }
cannam@16 205
cannam@64 206 if (plugid == "") {
cannam@64 207 usage(name);
cannam@16 208 }
cannam@64 209
cannam@64 210 if (output != "" && outputNo != -1) {
cannam@64 211 usage(name);
cannam@64 212 }
cannam@64 213
cannam@84 214 if (output == "" && outputNo == -1) {
cannam@84 215 outputNo = 0;
cannam@84 216 }
cannam@84 217
cannam@88 218 return runPlugin(name, soname, plugid, output, outputNo,
cannam@88 219 wavname, outfilename);
cannam@64 220 }
cannam@64 221
cannam@64 222
cannam@64 223 int runPlugin(string myname, string soname, string id,
cannam@88 224 string output, int outputNo, string wavname,
cannam@88 225 string outfilename)
cannam@64 226 {
cannam@64 227 PluginLoader *loader = PluginLoader::getInstance();
cannam@64 228
cannam@64 229 PluginLoader::PluginKey key = loader->composePluginKey(soname, id);
cannam@16 230
cannam@16 231 SNDFILE *sndfile;
cannam@16 232 SF_INFO sfinfo;
cannam@16 233 memset(&sfinfo, 0, sizeof(SF_INFO));
cannam@16 234
cannam@16 235 sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
cannam@16 236 if (!sndfile) {
cannam@64 237 cerr << myname << ": ERROR: Failed to open input file \""
cannam@64 238 << wavname << "\": " << sf_strerror(sndfile) << endl;
cannam@16 239 return 1;
cannam@16 240 }
cannam@16 241
cannam@88 242 ofstream *out = 0;
cannam@88 243 if (outfilename != "") {
cannam@88 244 out = new ofstream(outfilename.c_str(), ios::out);
cannam@88 245 if (!*out) {
cannam@88 246 cerr << myname << ": ERROR: Failed to open output file \""
cannam@88 247 << outfilename << "\" for writing" << endl;
cannam@88 248 delete out;
cannam@88 249 return 1;
cannam@88 250 }
cannam@88 251 }
cannam@88 252
cannam@64 253 Vamp::Plugin *plugin = loader->loadPlugin
cannam@92 254 (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE);
cannam@64 255 if (!plugin) {
cannam@64 256 cerr << myname << ": ERROR: Failed to load plugin \"" << id
cannam@64 257 << "\" from library \"" << soname << "\"" << endl;
cannam@64 258 sf_close(sndfile);
cannam@88 259 if (out) {
cannam@88 260 out->close();
cannam@88 261 delete out;
cannam@88 262 }
cannam@64 263 return 1;
cannam@64 264 }
cannam@16 265
cannam@64 266 cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
cannam@16 267
cannam@16 268 int blockSize = plugin->getPreferredBlockSize();
cannam@16 269 int stepSize = plugin->getPreferredStepSize();
cannam@16 270
cannam@91 271 if (blockSize == 0) {
cannam@91 272 blockSize = 1024;
cannam@91 273 }
cannam@83 274 if (stepSize == 0) {
cannam@83 275 if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
cannam@83 276 stepSize = blockSize/2;
cannam@83 277 } else {
cannam@83 278 stepSize = blockSize;
cannam@83 279 }
cannam@91 280 } else if (stepSize > blockSize) {
cannam@91 281 cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to ";
cannam@91 282 if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
cannam@91 283 blockSize = stepSize * 2;
cannam@91 284 } else {
cannam@91 285 blockSize = stepSize;
cannam@91 286 }
cannam@91 287 cerr << blockSize << endl;
cannam@83 288 }
cannam@83 289
cannam@16 290 int channels = sfinfo.channels;
cannam@16 291
cannam@16 292 float *filebuf = new float[blockSize * channels];
cannam@16 293 float **plugbuf = new float*[channels];
cannam@47 294 for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2];
cannam@16 295
cannam@16 296 cerr << "Using block size = " << blockSize << ", step size = "
cannam@16 297 << stepSize << endl;
cannam@16 298
cannam@16 299 int minch = plugin->getMinChannelCount();
cannam@16 300 int maxch = plugin->getMaxChannelCount();
cannam@16 301 cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
cannam@64 302 cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
cannam@16 303
cannam@16 304 Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors();
cannam@16 305 Vamp::Plugin::OutputDescriptor od;
cannam@16 306
cannam@29 307 int returnValue = 1;
cannam@88 308 int progress = 0;
cannam@29 309
cannam@16 310 if (outputs.empty()) {
cannam@64 311 cerr << "ERROR: Plugin has no outputs!" << endl;
cannam@16 312 goto done;
cannam@16 313 }
cannam@16 314
cannam@64 315 if (outputNo < 0) {
cannam@16 316
cannam@64 317 for (size_t oi = 0; oi < outputs.size(); ++oi) {
cannam@64 318 if (outputs[oi].identifier == output) {
cannam@64 319 outputNo = oi;
cannam@64 320 break;
cannam@64 321 }
cannam@64 322 }
cannam@64 323
cannam@64 324 if (outputNo < 0) {
cannam@64 325 cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
cannam@64 326 goto done;
cannam@64 327 }
cannam@64 328
cannam@64 329 } else {
cannam@64 330
cannam@64 331 if (int(outputs.size()) <= outputNo) {
cannam@64 332 cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
cannam@64 333 goto done;
cannam@64 334 }
cannam@64 335 }
cannam@64 336
cannam@64 337 od = outputs[outputNo];
cannam@64 338 cerr << "Output is: \"" << od.identifier << "\"" << endl;
cannam@16 339
cannam@29 340 if (!plugin->initialise(channels, stepSize, blockSize)) {
cannam@29 341 cerr << "ERROR: Plugin initialise (channels = " << channels
cannam@29 342 << ", stepSize = " << stepSize << ", blockSize = "
cannam@29 343 << blockSize << ") failed." << endl;
cannam@29 344 goto done;
cannam@29 345 }
cannam@16 346
cannam@16 347 for (size_t i = 0; i < sfinfo.frames; i += stepSize) {
cannam@16 348
cannam@16 349 int count;
cannam@16 350
cannam@16 351 if (sf_seek(sndfile, i, SEEK_SET) < 0) {
cannam@16 352 cerr << "ERROR: sf_seek failed: " << sf_strerror(sndfile) << endl;
cannam@16 353 break;
cannam@16 354 }
cannam@16 355
cannam@16 356 if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
cannam@16 357 cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
cannam@16 358 break;
cannam@16 359 }
cannam@16 360
cannam@16 361 for (int c = 0; c < channels; ++c) {
cannam@64 362 int j = 0;
cannam@64 363 while (j < count) {
cannam@64 364 plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
cannam@64 365 ++j;
cannam@64 366 }
cannam@64 367 while (j < blockSize) {
cannam@16 368 plugbuf[c][j] = 0.0f;
cannam@64 369 ++j;
cannam@16 370 }
cannam@16 371 }
cannam@16 372
cannam@16 373 printFeatures
cannam@64 374 (i, sfinfo.samplerate, outputNo, plugin->process
cannam@88 375 (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate)),
cannam@88 376 out);
cannam@88 377
cannam@88 378 int pp = progress;
cannam@88 379 progress = lrintf((float(i) / sfinfo.frames) * 100.f);
cannam@88 380 if (progress != pp && out) {
cannam@88 381 cerr << "\r" << progress << "%";
cannam@88 382 }
cannam@16 383 }
cannam@88 384 if (out) cerr << "\rDone" << endl;
cannam@16 385
cannam@64 386 printFeatures(sfinfo.frames, sfinfo.samplerate, outputNo,
cannam@88 387 plugin->getRemainingFeatures(), out);
cannam@16 388
cannam@29 389 returnValue = 0;
cannam@29 390
cannam@16 391 done:
cannam@16 392 delete plugin;
cannam@88 393 if (out) {
cannam@88 394 out->close();
cannam@88 395 delete out;
cannam@88 396 }
cannam@16 397 sf_close(sndfile);
cannam@29 398 return returnValue;
cannam@1 399 }
cannam@1 400
cannam@16 401 void
cannam@64 402 printPluginPath(bool verbose)
cannam@40 403 {
cannam@64 404 if (verbose) {
cannam@64 405 cout << "\nVamp plugin search path: ";
cannam@64 406 }
cannam@64 407
cannam@40 408 vector<string> path = Vamp::PluginHostAdapter::getPluginPath();
cannam@40 409 for (size_t i = 0; i < path.size(); ++i) {
cannam@64 410 if (verbose) {
cannam@64 411 cout << "[" << path[i] << "]";
cannam@64 412 } else {
cannam@64 413 cout << path[i] << endl;
cannam@64 414 }
cannam@40 415 }
cannam@64 416
cannam@64 417 if (verbose) cout << endl;
cannam@40 418 }
cannam@40 419
cannam@40 420 void
cannam@95 421 enumeratePlugins(Verbosity verbosity)
cannam@40 422 {
cannam@64 423 PluginLoader *loader = PluginLoader::getInstance();
cannam@64 424
cannam@95 425 if (verbosity == PluginInformation) {
cannam@95 426 cout << "\nVamp plugin libraries found in search path:" << endl;
cannam@95 427 }
cannam@64 428
cannam@64 429 std::vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
cannam@64 430 typedef std::multimap<std::string, PluginLoader::PluginKey>
cannam@64 431 LibraryMap;
cannam@64 432 LibraryMap libraryMap;
cannam@64 433
cannam@64 434 for (size_t i = 0; i < plugins.size(); ++i) {
cannam@64 435 std::string path = loader->getLibraryPathForPlugin(plugins[i]);
cannam@64 436 libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
cannam@64 437 }
cannam@64 438
cannam@64 439 std::string prevPath = "";
cannam@64 440 int index = 0;
cannam@64 441
cannam@64 442 for (LibraryMap::iterator i = libraryMap.begin();
cannam@64 443 i != libraryMap.end(); ++i) {
cannam@64 444
cannam@64 445 std::string path = i->first;
cannam@64 446 PluginLoader::PluginKey key = i->second;
cannam@64 447
cannam@64 448 if (path != prevPath) {
cannam@64 449 prevPath = path;
cannam@64 450 index = 0;
cannam@95 451 if (verbosity == PluginInformation) {
cannam@95 452 cout << "\n " << path << ":" << endl;
cannam@95 453 }
cannam@40 454 }
cannam@64 455
cannam@64 456 Vamp::Plugin *plugin = loader->loadPlugin(key, 48000);
cannam@64 457 if (plugin) {
cannam@64 458
cannam@64 459 char c = char('A' + index);
cannam@64 460 if (c > 'Z') c = char('a' + (index - 26));
cannam@64 461
cannam@95 462 if (verbosity == PluginInformation) {
cannam@64 463
cannam@95 464 cout << " [" << c << "] [v"
cannam@95 465 << plugin->getVampApiVersion() << "] "
cannam@95 466 << plugin->getName() << ", \""
cannam@95 467 << plugin->getIdentifier() << "\"" << " ["
cannam@95 468 << plugin->getMaker() << "]" << endl;
cannam@95 469
cannam@95 470 PluginLoader::PluginCategoryHierarchy category =
cannam@95 471 loader->getPluginCategory(key);
cannam@95 472
cannam@95 473 if (!category.empty()) {
cannam@95 474 cout << " ";
cannam@95 475 for (size_t ci = 0; ci < category.size(); ++ci) {
cannam@95 476 cout << " > " << category[ci];
cannam@95 477 }
cannam@95 478 cout << endl;
cannam@64 479 }
cannam@95 480
cannam@95 481 if (plugin->getDescription() != "") {
cannam@95 482 cout << " - " << plugin->getDescription() << endl;
cannam@95 483 }
cannam@95 484
cannam@95 485 } else if (verbosity == PluginIds) {
cannam@95 486 cout << "vamp:" << key << endl;
cannam@47 487 }
cannam@95 488
cannam@64 489 Vamp::Plugin::OutputList outputs =
cannam@64 490 plugin->getOutputDescriptors();
cannam@64 491
cannam@95 492 if (outputs.size() > 1 || verbosity == PluginOutputIds) {
cannam@64 493 for (size_t j = 0; j < outputs.size(); ++j) {
cannam@95 494 if (verbosity == PluginInformation) {
cannam@95 495 cout << " (" << j << ") "
cannam@95 496 << outputs[j].name << ", \""
cannam@95 497 << outputs[j].identifier << "\"" << endl;
cannam@95 498 if (outputs[j].description != "") {
cannam@95 499 cout << " - "
cannam@95 500 << outputs[j].description << endl;
cannam@95 501 }
cannam@95 502 } else if (verbosity == PluginOutputIds) {
cannam@95 503 cout << "vamp:" << key << ":" << outputs[j].identifier << endl;
cannam@40 504 }
cannam@40 505 }
cannam@64 506 }
cannam@64 507
cannam@64 508 ++index;
cannam@64 509
cannam@64 510 delete plugin;
cannam@40 511 }
cannam@40 512 }
cannam@64 513
cannam@95 514 if (verbosity == PluginInformation) {
cannam@95 515 cout << endl;
cannam@95 516 }
cannam@40 517 }
cannam@40 518
cannam@40 519 void
cannam@88 520 printFeatures(int frame, int sr, int output,
cannam@88 521 Vamp::Plugin::FeatureSet features, ofstream *out)
cannam@16 522 {
cannam@16 523 for (unsigned int i = 0; i < features[output].size(); ++i) {
cannam@88 524
cannam@16 525 Vamp::RealTime rt = Vamp::RealTime::frame2RealTime(frame, sr);
cannam@88 526
cannam@16 527 if (features[output][i].hasTimestamp) {
cannam@16 528 rt = features[output][i].timestamp;
cannam@16 529 }
cannam@88 530
cannam@88 531 (out ? *out : cout) << rt.toString() << ":";
cannam@88 532
cannam@16 533 for (unsigned int j = 0; j < features[output][i].values.size(); ++j) {
cannam@88 534 (out ? *out : cout) << " " << features[output][i].values[j];
cannam@16 535 }
cannam@88 536
cannam@88 537 (out ? *out : cout) << endl;
cannam@16 538 }
cannam@16 539 }
cannam@16 540
cannam@16 541
cannam@16 542