cannam@0: cannam@0:
cannam@0:00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@0: 00002 cannam@0: 00003 /* cannam@0: 00004 Vamp cannam@0: 00005 cannam@0: 00006 An API for audio analysis and feature extraction plugins. cannam@0: 00007 cannam@0: 00008 Centre for Digital Music, Queen Mary, University of London. cannam@21: 00009 Copyright 2006 Chris Cannam, copyright 2007-2008 QMUL. cannam@21: 00010 cannam@21: 00011 Permission is hereby granted, free of charge, to any person cannam@21: 00012 obtaining a copy of this software and associated documentation cannam@21: 00013 files (the "Software"), to deal in the Software without cannam@21: 00014 restriction, including without limitation the rights to use, copy, cannam@21: 00015 modify, merge, publish, distribute, sublicense, and/or sell copies cannam@21: 00016 of the Software, and to permit persons to whom the Software is cannam@21: 00017 furnished to do so, subject to the following conditions: cannam@21: 00018 cannam@21: 00019 The above copyright notice and this permission notice shall be cannam@21: 00020 included in all copies or substantial portions of the Software. cannam@21: 00021 cannam@21: 00022 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, cannam@21: 00023 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF cannam@21: 00024 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND cannam@21: 00025 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR cannam@21: 00026 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF cannam@21: 00027 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION cannam@21: 00028 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cannam@21: 00029 cannam@21: 00030 Except as contained in this notice, the names of the Centre for cannam@21: 00031 Digital Music; Queen Mary, University of London; and Chris Cannam cannam@21: 00032 shall not be used in advertising or otherwise to promote the sale, cannam@21: 00033 use or other dealings in this Software without prior written cannam@21: 00034 authorization. cannam@21: 00035 */ cannam@21: 00036 cannam@0: 00037 cannam@21: 00038 /* cannam@21: 00039 * This "simple" Vamp plugin host is no longer as simple as it was; it cannam@21: 00040 * now has a lot of options and includes a lot of code to handle the cannam@21: 00041 * various useful listing modes it supports. cannam@21: 00042 * cannam@21: 00043 * However, the runPlugin function still contains a reasonable cannam@21: 00044 * implementation of a fairly generic Vamp plugin host capable of cannam@21: 00045 * evaluating a given output on a given plugin for a sound file read cannam@21: 00046 * via libsndfile. cannam@21: 00047 */ cannam@0: 00048 cannam@21: 00049 #include <vamp-hostsdk/PluginHostAdapter.h> cannam@21: 00050 #include <vamp-hostsdk/PluginInputDomainAdapter.h> cannam@21: 00051 #include <vamp-hostsdk/PluginLoader.h> cannam@21: 00052 cannam@21: 00053 #include <iostream> cannam@21: 00054 #include <fstream> cannam@21: 00055 #include <set> cannam@21: 00056 #include <sndfile.h> cannam@0: 00057 cannam@21: 00058 #include <cstring> cannam@21: 00059 #include <cstdlib> cannam@21: 00060 cannam@21: 00061 #include "system.h" cannam@0: 00062 cannam@21: 00063 #include <cmath> cannam@21: 00064 cannam@21: 00065 using namespace std; cannam@21: 00066 cannam@21: 00067 using Vamp::Plugin; cannam@21: 00068 using Vamp::PluginHostAdapter; cannam@21: 00069 using Vamp::RealTime; cannam@21: 00070 using Vamp::HostExt::PluginLoader; cannam@21: 00071 using Vamp::HostExt::PluginWrapper; cannam@21: 00072 using Vamp::HostExt::PluginInputDomainAdapter; cannam@21: 00073 cannam@21: 00074 #define HOST_VERSION "1.4" cannam@21: 00075 cannam@21: 00076 enum Verbosity { cannam@21: 00077 PluginIds, cannam@21: 00078 PluginOutputIds, cannam@21: 00079 PluginInformation, cannam@21: 00080 PluginInformationDetailed cannam@21: 00081 }; cannam@21: 00082 cannam@21: 00083 void printFeatures(int, int, int, Plugin::FeatureSet, ofstream *, bool frames); cannam@21: 00084 void transformInput(float *, size_t); cannam@21: 00085 void fft(unsigned int, bool, double *, double *, double *, double *); cannam@21: 00086 void printPluginPath(bool verbose); cannam@21: 00087 void printPluginCategoryList(); cannam@21: 00088 void enumeratePlugins(Verbosity); cannam@21: 00089 void listPluginsInLibrary(string soname); cannam@21: 00090 int runPlugin(string myname, string soname, string id, string output, cannam@21: 00091 int outputNo, string inputFile, string outfilename, bool frames); cannam@21: 00092 cannam@21: 00093 void usage(const char *name) cannam@21: 00094 { cannam@21: 00095 cerr << "\n" cannam@21: 00096 << name << ": A command-line host for Vamp audio analysis plugins.\n\n" cannam@21: 00097 "Centre for Digital Music, Queen Mary, University of London.\n" cannam@21: 00098 "Copyright 2006-2008 Chris Cannam and QMUL.\n" cannam@21: 00099 "Freely redistributable; published under a BSD-style license.\n\n" cannam@21: 00100 "Usage:\n\n" cannam@21: 00101 " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o out.txt]\n" cannam@21: 00102 " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno] [-o out.txt]\n\n" cannam@21: 00103 " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n" cannam@21: 00104 " audio data in \"file.wav\", retrieving the named \"output\", or output\n" cannam@21: 00105 " number \"outputno\" (the first output by default) and dumping it to\n" cannam@21: 00106 " standard output, or to \"out.txt\" if the -o option is given.\n\n" cannam@21: 00107 " \"pluginlibrary\" should be a library name, not a file path; the\n" cannam@21: 00108 " standard Vamp library search path will be used to locate it. If\n" cannam@21: 00109 " a file path is supplied, the directory part(s) will be ignored.\n\n" cannam@21: 00110 " If the -s option is given, results will be labelled with the audio\n" cannam@21: 00111 " sample frame at which they occur. Otherwise, they will be labelled\n" cannam@21: 00112 " with time in seconds.\n\n" cannam@21: 00113 " " << name << " -l\n" cannam@21: 00114 " " << name << " --list\n\n" cannam@21: 00115 " -- List the plugin libraries and Vamp plugins in the library search path\n" cannam@21: 00116 " in a verbose human-readable format.\n\n" cannam@21: 00117 " " << name << " --list-full\n\n" cannam@21: 00118 " -- List all data reported by all the Vamp plugins in the library search\n" cannam@21: 00119 " path in a very verbose human-readable format.\n\n" cannam@21: 00120 " " << name << " --list-ids\n\n" cannam@21: 00121 " -- List the plugins in the search path in a terse machine-readable format,\n" cannam@21: 00122 " in the form vamp:soname:identifier.\n\n" cannam@21: 00123 " " << name << " --list-outputs\n\n" cannam@21: 00124 " -- List the outputs for plugins in the search path in a machine-readable\n" cannam@21: 00125 " format, in the form vamp:soname:identifier:output.\n\n" cannam@21: 00126 " " << name << " --list-by-category\n\n" cannam@21: 00127 " -- List the plugins as a plugin index by category, in a machine-readable\n" cannam@21: 00128 " format. The format may change in future releases.\n\n" cannam@21: 00129 " " << name << " -p\n\n" cannam@21: 00130 " -- Print out the Vamp library search path.\n\n" cannam@21: 00131 " " << name << " -v\n\n" cannam@21: 00132 " -- Display version information only.\n" cannam@21: 00133 << endl; cannam@21: 00134 exit(2); cannam@21: 00135 } cannam@0: 00136 cannam@21: 00137 int main(int argc, char **argv) cannam@21: 00138 { cannam@21: 00139 char *scooter = argv[0]; cannam@21: 00140 char *name = 0; cannam@21: 00141 while (scooter && *scooter) { cannam@21: 00142 if (*scooter == '/' || *scooter == '\\') name = ++scooter; cannam@21: 00143 else ++scooter; cannam@21: 00144 } cannam@21: 00145 if (!name || !*name) name = argv[0]; cannam@21: 00146 cannam@21: 00147 if (argc < 2) usage(name); cannam@21: 00148 cannam@21: 00149 if (argc == 2) { cannam@21: 00150 cannam@21: 00151 if (!strcmp(argv[1], "-v")) { cannam@0: 00152 cannam@21: 00153 cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl cannam@21: 00154 << "Vamp API version: " << VAMP_API_VERSION << endl cannam@21: 00155 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; cannam@0: 00156 return 0; cannam@0: 00157 cannam@21: 00158 } else if (!strcmp(argv[1], "-l") || !strcmp(argv[1], "--list")) { cannam@0: 00159 cannam@21: 00160 printPluginPath(true); cannam@21: 00161 enumeratePlugins(PluginInformation); cannam@21: 00162 return 0; cannam@21: 00163 cannam@21: 00164 } else if (!strcmp(argv[1], "--list-full")) { cannam@21: 00165 cannam@21: 00166 enumeratePlugins(PluginInformationDetailed); cannam@21: 00167 return 0; cannam@21: 00168 cannam@21: 00169 } else if (!strcmp(argv[1], "-p")) { cannam@0: 00170 cannam@21: 00171 printPluginPath(false); cannam@21: 00172 return 0; cannam@21: 00173 cannam@21: 00174 } else if (!strcmp(argv[1], "--list-ids")) { cannam@21: 00175 cannam@21: 00176 enumeratePlugins(PluginIds); cannam@21: 00177 return 0; cannam@21: 00178 cannam@21: 00179 } else if (!strcmp(argv[1], "--list-outputs")) { cannam@0: 00180 cannam@21: 00181 enumeratePlugins(PluginOutputIds); cannam@21: 00182 return 0; cannam@21: 00183 cannam@21: 00184 } else if (!strcmp(argv[1], "--list-by-category")) { cannam@21: 00185 cannam@21: 00186 printPluginCategoryList(); cannam@21: 00187 return 0; cannam@21: 00188 cannam@21: 00189 } else usage(name); cannam@21: 00190 } cannam@0: 00191 cannam@21: 00192 if (argc < 3) usage(name); cannam@21: 00193 cannam@21: 00194 bool useFrames = false; cannam@21: 00195 cannam@21: 00196 int base = 1; cannam@21: 00197 if (!strcmp(argv[1], "-s")) { cannam@21: 00198 useFrames = true; cannam@21: 00199 base = 2; cannam@21: 00200 } cannam@21: 00201 cannam@21: 00202 string soname = argv[base]; cannam@21: 00203 string wavname = argv[base+1]; cannam@21: 00204 string plugid = ""; cannam@21: 00205 string output = ""; cannam@21: 00206 int outputNo = -1; cannam@21: 00207 string outfilename; cannam@21: 00208 cannam@21: 00209 if (argc >= base+3) { cannam@21: 00210 cannam@21: 00211 int idx = base+2; cannam@21: 00212 cannam@21: 00213 if (isdigit(*argv[idx])) { cannam@21: 00214 outputNo = atoi(argv[idx++]); cannam@21: 00215 } cannam@21: 00216 cannam@21: 00217 if (argc == idx + 2) { cannam@21: 00218 if (!strcmp(argv[idx], "-o")) { cannam@21: 00219 outfilename = argv[idx+1]; cannam@21: 00220 } else usage(name); cannam@21: 00221 } else if (argc != idx) { cannam@21: 00222 (usage(name)); cannam@21: 00223 } cannam@21: 00224 } cannam@21: 00225 cannam@21: 00226 cerr << endl << name << ": Running..." << endl; cannam@21: 00227 cannam@21: 00228 cerr << "Reading file: \"" << wavname << "\", writing to "; cannam@21: 00229 if (outfilename == "") { cannam@21: 00230 cerr << "standard output" << endl; cannam@21: 00231 } else { cannam@21: 00232 cerr << "\"" << outfilename << "\"" << endl; cannam@0: 00233 } cannam@0: 00234 cannam@21: 00235 string::size_type sep = soname.find(':'); cannam@21: 00236 cannam@21: 00237 if (sep != string::npos) { cannam@21: 00238 plugid = soname.substr(sep + 1); cannam@21: 00239 soname = soname.substr(0, sep); cannam@21: 00240 cannam@21: 00241 sep = plugid.find(':'); cannam@21: 00242 if (sep != string::npos) { cannam@21: 00243 output = plugid.substr(sep + 1); cannam@21: 00244 plugid = plugid.substr(0, sep); cannam@21: 00245 } cannam@21: 00246 } cannam@21: 00247 cannam@21: 00248 if (plugid == "") { cannam@21: 00249 usage(name); cannam@21: 00250 } cannam@21: 00251 cannam@21: 00252 if (output != "" && outputNo != -1) { cannam@21: 00253 usage(name); cannam@21: 00254 } cannam@0: 00255 cannam@21: 00256 if (output == "" && outputNo == -1) { cannam@21: 00257 outputNo = 0; cannam@21: 00258 } cannam@21: 00259 cannam@21: 00260 return runPlugin(name, soname, plugid, output, outputNo, cannam@21: 00261 wavname, outfilename, useFrames); cannam@21: 00262 } cannam@21: 00263 cannam@21: 00264 cannam@21: 00265 int runPlugin(string myname, string soname, string id, cannam@21: 00266 string output, int outputNo, string wavname, cannam@21: 00267 string outfilename, bool useFrames) cannam@21: 00268 { cannam@21: 00269 PluginLoader *loader = PluginLoader::getInstance(); cannam@21: 00270 cannam@21: 00271 PluginLoader::PluginKey key = loader->composePluginKey(soname, id); cannam@21: 00272 cannam@21: 00273 SNDFILE *sndfile; cannam@21: 00274 SF_INFO sfinfo; cannam@21: 00275 memset(&sfinfo, 0, sizeof(SF_INFO)); cannam@21: 00276 cannam@21: 00277 sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo); cannam@21: 00278 if (!sndfile) { cannam@21: 00279 cerr << myname << ": ERROR: Failed to open input file \"" cannam@21: 00280 << wavname << "\": " << sf_strerror(sndfile) << endl; cannam@21: 00281 return 1; cannam@21: 00282 } cannam@21: 00283 cannam@21: 00284 ofstream *out = 0; cannam@21: 00285 if (outfilename != "") { cannam@21: 00286 out = new ofstream(outfilename.c_str(), ios::out); cannam@21: 00287 if (!*out) { cannam@21: 00288 cerr << myname << ": ERROR: Failed to open output file \"" cannam@21: 00289 << outfilename << "\" for writing" << endl; cannam@21: 00290 delete out; cannam@21: 00291 return 1; cannam@21: 00292 } cannam@21: 00293 } cannam@21: 00294 cannam@21: 00295 Plugin *plugin = loader->loadPlugin cannam@21: 00296 (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE); cannam@21: 00297 if (!plugin) { cannam@21: 00298 cerr << myname << ": ERROR: Failed to load plugin \"" << id cannam@21: 00299 << "\" from library \"" << soname << "\"" << endl; cannam@21: 00300 sf_close(sndfile); cannam@21: 00301 if (out) { cannam@21: 00302 out->close(); cannam@21: 00303 delete out; cannam@21: 00304 } cannam@21: 00305 return 1; cannam@21: 00306 } cannam@21: 00307 cannam@21: 00308 cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; cannam@21: 00309 cannam@21: 00310 // Note that the following would be much simpler if we used a cannam@21: 00311 // PluginBufferingAdapter as well -- i.e. if we had passed cannam@21: 00312 // PluginLoader::ADAPT_ALL to loader->loadPlugin() above, instead cannam@21: 00313 // of ADAPT_ALL_SAFE. Then we could simply specify our own block cannam@21: 00314 // size, keep the step size equal to the block size, and ignore cannam@21: 00315 // the plugin's bleatings. However, there are some issues with cannam@21: 00316 // using a PluginBufferingAdapter that make the results sometimes cannam@21: 00317 // technically different from (if effectively the same as) the cannam@21: 00318 // un-adapted plugin, so we aren't doing that here. See the cannam@21: 00319 // PluginBufferingAdapter documentation for details. cannam@21: 00320 cannam@21: 00321 int blockSize = plugin->getPreferredBlockSize(); cannam@21: 00322 int stepSize = plugin->getPreferredStepSize(); cannam@21: 00323 cannam@21: 00324 if (blockSize == 0) { cannam@21: 00325 blockSize = 1024; cannam@21: 00326 } cannam@21: 00327 if (stepSize == 0) { cannam@21: 00328 if (plugin->getInputDomain() == Plugin::FrequencyDomain) { cannam@21: 00329 stepSize = blockSize/2; cannam@21: 00330 } else { cannam@21: 00331 stepSize = blockSize; cannam@21: 00332 } cannam@21: 00333 } else if (stepSize > blockSize) { cannam@21: 00334 cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to "; cannam@21: 00335 if (plugin->getInputDomain() == Plugin::FrequencyDomain) { cannam@21: 00336 blockSize = stepSize * 2; cannam@21: 00337 } else { cannam@21: 00338 blockSize = stepSize; cannam@21: 00339 } cannam@21: 00340 cerr << blockSize << endl; cannam@21: 00341 } cannam@21: 00342 cannam@21: 00343 int channels = sfinfo.channels; cannam@0: 00344 cannam@21: 00345 float *filebuf = new float[blockSize * channels]; cannam@21: 00346 float **plugbuf = new float*[channels]; cannam@21: 00347 for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2]; cannam@21: 00348 cannam@21: 00349 cerr << "Using block size = " << blockSize << ", step size = " cannam@21: 00350 << stepSize << endl; cannam@0: 00351 cannam@21: 00352 // The channel queries here are for informational purposes only -- cannam@21: 00353 // a PluginChannelAdapter is being used automatically behind the cannam@21: 00354 // scenes, and it will take case of any channel mismatch cannam@21: 00355 cannam@21: 00356 int minch = plugin->getMinChannelCount(); cannam@21: 00357 int maxch = plugin->getMaxChannelCount(); cannam@21: 00358 cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; cannam@21: 00359 cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl; cannam@0: 00360 cannam@21: 00361 Plugin::OutputList outputs = plugin->getOutputDescriptors(); cannam@21: 00362 Plugin::OutputDescriptor od; cannam@21: 00363 cannam@21: 00364 int returnValue = 1; cannam@21: 00365 int progress = 0; cannam@21: 00366 cannam@21: 00367 RealTime rt; cannam@21: 00368 PluginWrapper *wrapper = 0; cannam@21: 00369 RealTime adjustment = RealTime::zeroTime; cannam@21: 00370 cannam@21: 00371 if (outputs.empty()) { cannam@21: 00372 cerr << "ERROR: Plugin has no outputs!" << endl; cannam@21: 00373 goto done; cannam@21: 00374 } cannam@21: 00375 cannam@21: 00376 if (outputNo < 0) { cannam@21: 00377 cannam@21: 00378 for (size_t oi = 0; oi < outputs.size(); ++oi) { cannam@21: 00379 if (outputs[oi].identifier == output) { cannam@21: 00380 outputNo = oi; cannam@21: 00381 break; cannam@21: 00382 } cannam@21: 00383 } cannam@21: 00384 cannam@21: 00385 if (outputNo < 0) { cannam@21: 00386 cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl; cannam@21: 00387 goto done; cannam@21: 00388 } cannam@21: 00389 cannam@21: 00390 } else { cannam@21: 00391 cannam@21: 00392 if (int(outputs.size()) <= outputNo) { cannam@21: 00393 cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; cannam@21: 00394 goto done; cannam@21: 00395 } cannam@21: 00396 } cannam@21: 00397 cannam@21: 00398 od = outputs[outputNo]; cannam@21: 00399 cerr << "Output is: \"" << od.identifier << "\"" << endl; cannam@21: 00400 cannam@21: 00401 if (!plugin->initialise(channels, stepSize, blockSize)) { cannam@21: 00402 cerr << "ERROR: Plugin initialise (channels = " << channels cannam@21: 00403 << ", stepSize = " << stepSize << ", blockSize = " cannam@21: 00404 << blockSize << ") failed." << endl; cannam@21: 00405 goto done; cannam@21: 00406 } cannam@21: 00407 cannam@21: 00408 wrapper = dynamic_cast<PluginWrapper *>(plugin); cannam@21: 00409 if (wrapper) { cannam@21: 00410 // See documentation for cannam@21: 00411 // PluginInputDomainAdapter::getTimestampAdjustment cannam@21: 00412 PluginInputDomainAdapter *ida = cannam@21: 00413 wrapper->getWrapper<PluginInputDomainAdapter>(); cannam@21: 00414 if (ida) adjustment = ida->getTimestampAdjustment(); cannam@21: 00415 } cannam@21: 00416 cannam@21: 00417 for (size_t i = 0; i < sfinfo.frames; i += stepSize) { cannam@21: 00418 cannam@21: 00419 int count; cannam@21: 00420 cannam@21: 00421 if (sf_seek(sndfile, i, SEEK_SET) < 0) { cannam@21: 00422 cerr << "ERROR: sf_seek failed: " << sf_strerror(sndfile) << endl; cannam@21: 00423 break; cannam@21: 00424 } cannam@21: 00425 cannam@21: 00426 if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) { cannam@21: 00427 cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; cannam@21: 00428 break; cannam@21: 00429 } cannam@21: 00430 cannam@21: 00431 for (int c = 0; c < channels; ++c) { cannam@21: 00432 int j = 0; cannam@21: 00433 while (j < count) { cannam@21: 00434 plugbuf[c][j] = filebuf[j * sfinfo.channels + c]; cannam@21: 00435 ++j; cannam@21: 00436 } cannam@21: 00437 while (j < blockSize) { cannam@21: 00438 plugbuf[c][j] = 0.0f; cannam@21: 00439 ++j; cannam@21: 00440 } cannam@21: 00441 } cannam@0: 00442 cannam@21: 00443 rt = RealTime::frame2RealTime(i, sfinfo.samplerate); cannam@21: 00444 cannam@21: 00445 printFeatures cannam@21: 00446 (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), cannam@21: 00447 sfinfo.samplerate, outputNo, plugin->process(plugbuf, rt), cannam@21: 00448 out, useFrames); cannam@0: 00449 cannam@21: 00450 int pp = progress; cannam@21: 00451 progress = lrintf((float(i) / sfinfo.frames) * 100.f); cannam@21: 00452 if (progress != pp && out) { cannam@21: 00453 cerr << "\r" << progress << "%"; cannam@21: 00454 } cannam@0: 00455 } cannam@21: 00456 if (out) cerr << "\rDone" << endl; cannam@0: 00457 cannam@21: 00458 rt = RealTime::frame2RealTime(sfinfo.frames, sfinfo.samplerate); cannam@21: 00459 cannam@21: 00460 printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), cannam@21: 00461 sfinfo.samplerate, outputNo, cannam@21: 00462 plugin->getRemainingFeatures(), out, useFrames); cannam@21: 00463 cannam@21: 00464 returnValue = 0; cannam@21: 00465 cannam@21: 00466 done: cannam@21: 00467 delete plugin; cannam@21: 00468 if (out) { cannam@21: 00469 out->close(); cannam@21: 00470 delete out; cannam@21: 00471 } cannam@21: 00472 sf_close(sndfile); cannam@21: 00473 return returnValue; cannam@21: 00474 } cannam@21: 00475 cannam@21: 00476 void cannam@21: 00477 printFeatures(int frame, int sr, int output, cannam@21: 00478 Plugin::FeatureSet features, ofstream *out, bool useFrames) cannam@0: 00479 { cannam@21: 00480 for (unsigned int i = 0; i < features[output].size(); ++i) { cannam@0: 00481 cannam@21: 00482 if (useFrames) { cannam@21: 00483 cannam@21: 00484 int displayFrame = frame; cannam@0: 00485 cannam@21: 00486 if (features[output][i].hasTimestamp) { cannam@21: 00487 displayFrame = RealTime::realTime2Frame cannam@21: 00488 (features[output][i].timestamp, sr); cannam@21: 00489 } cannam@0: 00490 cannam@21: 00491 (out ? *out : cout) << displayFrame; cannam@21: 00492 cannam@21: 00493 if (features[output][i].hasDuration) { cannam@21: 00494 displayFrame = RealTime::realTime2Frame cannam@21: 00495 (features[output][i].duration, sr); cannam@21: 00496 (out ? *out : cout) << "," << displayFrame; cannam@21: 00497 } cannam@0: 00498 cannam@21: 00499 (out ? *out : cout) << ":"; cannam@21: 00500 cannam@21: 00501 } else { cannam@21: 00502 cannam@21: 00503 RealTime rt = RealTime::frame2RealTime(frame, sr); cannam@0: 00504 cannam@21: 00505 if (features[output][i].hasTimestamp) { cannam@21: 00506 rt = features[output][i].timestamp; cannam@21: 00507 } cannam@21: 00508 cannam@21: 00509 (out ? *out : cout) << rt.toString(); cannam@21: 00510 cannam@21: 00511 if (features[output][i].hasDuration) { cannam@21: 00512 rt = features[output][i].duration; cannam@21: 00513 (out ? *out : cout) << "," << rt.toString(); cannam@21: 00514 } cannam@0: 00515 cannam@21: 00516 (out ? *out : cout) << ":"; cannam@21: 00517 } cannam@0: 00518 cannam@21: 00519 for (unsigned int j = 0; j < features[output][i].values.size(); ++j) { cannam@21: 00520 (out ? *out : cout) << " " << features[output][i].values[j]; cannam@21: 00521 } cannam@21: 00522 cannam@21: 00523 (out ? *out : cout) << endl; cannam@21: 00524 } cannam@21: 00525 } cannam@0: 00526 cannam@21: 00527 void cannam@21: 00528 printPluginPath(bool verbose) cannam@21: 00529 { cannam@21: 00530 if (verbose) { cannam@21: 00531 cout << "\nVamp plugin search path: "; cannam@21: 00532 } cannam@21: 00533 cannam@21: 00534 vector<string> path = PluginHostAdapter::getPluginPath(); cannam@21: 00535 for (size_t i = 0; i < path.size(); ++i) { cannam@21: 00536 if (verbose) { cannam@21: 00537 cout << "[" << path[i] << "]"; cannam@21: 00538 } else { cannam@21: 00539 cout << path[i] << endl; cannam@21: 00540 } cannam@21: 00541 } cannam@21: 00542 cannam@21: 00543 if (verbose) cout << endl; cannam@21: 00544 } cannam@21: 00545 cannam@21: 00546 static cannam@21: 00547 string cannam@21: 00548 header(string text, int level) cannam@21: 00549 { cannam@21: 00550 string out = '\n' + text + '\n'; cannam@21: 00551 for (size_t i = 0; i < text.length(); ++i) { cannam@21: 00552 out += (level == 1 ? '=' : level == 2 ? '-' : '~'); cannam@21: 00553 } cannam@21: 00554 out += '\n'; cannam@21: 00555 return out; cannam@21: 00556 } cannam@21: 00557 cannam@21: 00558 void cannam@21: 00559 enumeratePlugins(Verbosity verbosity) cannam@21: 00560 { cannam@21: 00561 PluginLoader *loader = PluginLoader::getInstance(); cannam@21: 00562 cannam@21: 00563 if (verbosity == PluginInformation) { cannam@21: 00564 cout << "\nVamp plugin libraries found in search path:" << endl; cannam@21: 00565 } cannam@0: 00566 cannam@21: 00567 vector<PluginLoader::PluginKey> plugins = loader->listPlugins(); cannam@21: 00568 typedef multimap<string, PluginLoader::PluginKey> cannam@21: 00569 LibraryMap; cannam@21: 00570 LibraryMap libraryMap; cannam@21: 00571 cannam@21: 00572 for (size_t i = 0; i < plugins.size(); ++i) { cannam@21: 00573 string path = loader->getLibraryPathForPlugin(plugins[i]); cannam@21: 00574 libraryMap.insert(LibraryMap::value_type(path, plugins[i])); cannam@21: 00575 } cannam@21: 00576 cannam@21: 00577 string prevPath = ""; cannam@21: 00578 int index = 0; cannam@21: 00579 cannam@21: 00580 for (LibraryMap::iterator i = libraryMap.begin(); cannam@21: 00581 i != libraryMap.end(); ++i) { cannam@21: 00582 cannam@21: 00583 string path = i->first; cannam@21: 00584 PluginLoader::PluginKey key = i->second; cannam@21: 00585 cannam@21: 00586 if (path != prevPath) { cannam@21: 00587 prevPath = path; cannam@21: 00588 index = 0; cannam@21: 00589 if (verbosity == PluginInformation) { cannam@21: 00590 cout << "\n " << path << ":" << endl; cannam@21: 00591 } else if (verbosity == PluginInformationDetailed) { cannam@21: 00592 string::size_type ki = i->second.find(':'); cannam@21: 00593 string text = "Library \"" + i->second.substr(0, ki) + "\""; cannam@21: 00594 cout << "\n" << header(text, 1); cannam@21: 00595 } cannam@21: 00596 } cannam@21: 00597 cannam@21: 00598 Plugin *plugin = loader->loadPlugin(key, 48000); cannam@21: 00599 if (plugin) { cannam@21: 00600 cannam@21: 00601 char c = char('A' + index); cannam@21: 00602 if (c > 'Z') c = char('a' + (index - 26)); cannam@21: 00603 cannam@21: 00604 PluginLoader::PluginCategoryHierarchy category = cannam@21: 00605 loader->getPluginCategory(key); cannam@21: 00606 string catstr; cannam@21: 00607 if (!category.empty()) { cannam@21: 00608 for (size_t ci = 0; ci < category.size(); ++ci) { cannam@21: 00609 if (ci > 0) catstr += " > "; cannam@21: 00610 catstr += category[ci]; cannam@21: 00611 } cannam@21: 00612 } cannam@21: 00613 cannam@21: 00614 if (verbosity == PluginInformation) { cannam@21: 00615 cannam@21: 00616 cout << " [" << c << "] [v" cannam@21: 00617 << plugin->getVampApiVersion() << "] " cannam@21: 00618 << plugin->getName() << ", \"" cannam@21: 00619 << plugin->getIdentifier() << "\"" << " [" cannam@21: 00620 << plugin->getMaker() << "]" << endl; cannam@21: 00621 cannam@21: 00622 if (catstr != "") { cannam@21: 00623 cout << " > " << catstr << endl; cannam@21: 00624 } cannam@21: 00625 cannam@21: 00626 if (plugin->getDescription() != "") { cannam@21: 00627 cout << " - " << plugin->getDescription() << endl; cannam@21: 00628 } cannam@21: 00629 cannam@21: 00630 } else if (verbosity == PluginInformationDetailed) { cannam@21: 00631 cannam@21: 00632 cout << header(plugin->getName(), 2); cannam@21: 00633 cout << " - Identifier: " cannam@21: 00634 << key << endl; cannam@21: 00635 cout << " - Plugin Version: " cannam@21: 00636 << plugin->getPluginVersion() << endl; cannam@21: 00637 cout << " - Vamp API Version: " cannam@21: 00638 << plugin->getVampApiVersion() << endl; cannam@21: 00639 cout << " - Maker: \"" cannam@21: 00640 << plugin->getMaker() << "\"" << endl; cannam@21: 00641 cout << " - Copyright: \"" cannam@21: 00642 << plugin->getCopyright() << "\"" << endl; cannam@21: 00643 cout << " - Description: \"" cannam@21: 00644 << plugin->getDescription() << "\"" << endl; cannam@21: 00645 cout << " - Input Domain: " cannam@21: 00646 << (plugin->getInputDomain() == Vamp::Plugin::TimeDomain ? cannam@21: 00647 "Time Domain" : "Frequency Domain") << endl; cannam@21: 00648 cout << " - Default Step Size: " cannam@21: 00649 << plugin->getPreferredStepSize() << endl; cannam@21: 00650 cout << " - Default Block Size: " cannam@21: 00651 << plugin->getPreferredBlockSize() << endl; cannam@21: 00652 cout << " - Minimum Channels: " cannam@21: 00653 << plugin->getMinChannelCount() << endl; cannam@21: 00654 cout << " - Maximum Channels: " cannam@21: 00655 << plugin->getMaxChannelCount() << endl; cannam@21: 00656 cannam@21: 00657 } else if (verbosity == PluginIds) { cannam@21: 00658 cout << "vamp:" << key << endl; cannam@21: 00659 } cannam@21: 00660 cannam@21: 00661 Plugin::OutputList outputs = cannam@21: 00662 plugin->getOutputDescriptors(); cannam@21: 00663 cannam@21: 00664 if (verbosity == PluginInformationDetailed) { cannam@21: 00665 cannam@21: 00666 Plugin::ParameterList params = plugin->getParameterDescriptors(); cannam@21: 00667 for (size_t j = 0; j < params.size(); ++j) { cannam@21: 00668 Plugin::ParameterDescriptor &pd(params[j]); cannam@21: 00669 cout << "\nParameter " << j+1 << ": \"" << pd.name << "\"" << endl; cannam@21: 00670 cout << " - Identifier: " << pd.identifier << endl; cannam@21: 00671 cout << " - Description: \"" << pd.description << "\"" << endl; cannam@21: 00672 if (pd.unit != "") { cannam@21: 00673 cout << " - Unit: " << pd.unit << endl; cannam@21: 00674 } cannam@21: 00675 cout << " - Range: "; cannam@21: 00676 cout << pd.minValue << " -> " << pd.maxValue << endl; cannam@21: 00677 cout << " - Default: "; cannam@21: 00678 cout << pd.defaultValue << endl; cannam@21: 00679 if (pd.isQuantized) { cannam@21: 00680 cout << " - Quantize Step: " cannam@21: 00681 << pd.quantizeStep << endl; cannam@21: 00682 } cannam@21: 00683 if (!pd.valueNames.empty()) { cannam@21: 00684 cout << " - Value Names: "; cannam@21: 00685 for (size_t k = 0; k < pd.valueNames.size(); ++k) { cannam@21: 00686 if (k > 0) cout << ", "; cannam@21: 00687 cout << "\"" << pd.valueNames[k] << "\""; cannam@21: 00688 } cannam@21: 00689 cout << endl; cannam@21: 00690 } cannam@21: 00691 } cannam@21: 00692 cannam@21: 00693 if (outputs.empty()) { cannam@21: 00694 cout << "\n** Note: This plugin reports no outputs!" << endl; cannam@21: 00695 } cannam@21: 00696 for (size_t j = 0; j < outputs.size(); ++j) { cannam@21: 00697 Plugin::OutputDescriptor &od(outputs[j]); cannam@21: 00698 cout << "\nOutput " << j+1 << ": \"" << od.name << "\"" << endl; cannam@21: 00699 cout << " - Identifier: " << od.identifier << endl; cannam@21: 00700 cout << " - Description: \"" << od.description << "\"" << endl; cannam@21: 00701 if (od.unit != "") { cannam@21: 00702 cout << " - Unit: " << od.unit << endl; cannam@21: 00703 } cannam@21: 00704 if (od.hasFixedBinCount) { cannam@21: 00705 cout << " - Default Bin Count: " << od.binCount << endl; cannam@21: 00706 } cannam@21: 00707 if (!od.binNames.empty()) { cannam@21: 00708 bool have = false; cannam@21: 00709 for (size_t k = 0; k < od.binNames.size(); ++k) { cannam@21: 00710 if (od.binNames[k] != "") { cannam@21: 00711 have = true; break; cannam@21: 00712 } cannam@21: 00713 } cannam@21: 00714 if (have) { cannam@21: 00715 cout << " - Bin Names: "; cannam@21: 00716 for (size_t k = 0; k < od.binNames.size(); ++k) { cannam@21: 00717 if (k > 0) cout << ", "; cannam@21: 00718 cout << "\"" << od.binNames[k] << "\""; cannam@21: 00719 } cannam@21: 00720 cout << endl; cannam@21: 00721 } cannam@21: 00722 } cannam@21: 00723 if (od.hasKnownExtents) { cannam@21: 00724 cout << " - Default Extents: "; cannam@21: 00725 cout << od.minValue << " -> " << od.maxValue << endl; cannam@21: 00726 } cannam@21: 00727 if (od.isQuantized) { cannam@21: 00728 cout << " - Quantize Step: " cannam@21: 00729 << od.quantizeStep << endl; cannam@21: 00730 } cannam@21: 00731 cout << " - Sample Type: " cannam@21: 00732 << (od.sampleType == cannam@21: 00733 Plugin::OutputDescriptor::OneSamplePerStep ? cannam@21: 00734 "One Sample Per Step" : cannam@21: 00735 od.sampleType == cannam@21: 00736 Plugin::OutputDescriptor::FixedSampleRate ? cannam@21: 00737 "Fixed Sample Rate" : cannam@21: 00738 "Variable Sample Rate") << endl; cannam@21: 00739 if (od.sampleType != cannam@21: 00740 Plugin::OutputDescriptor::OneSamplePerStep) { cannam@21: 00741 cout << " - Default Rate: " cannam@21: 00742 << od.sampleRate << endl; cannam@21: 00743 } cannam@21: 00744 cout << " - Has Duration: " cannam@21: 00745 << (od.hasDuration ? "Yes" : "No") << endl; cannam@21: 00746 } cannam@21: 00747 } cannam@21: 00748 cannam@21: 00749 if (outputs.size() > 1 || verbosity == PluginOutputIds) { cannam@21: 00750 for (size_t j = 0; j < outputs.size(); ++j) { cannam@21: 00751 if (verbosity == PluginInformation) { cannam@21: 00752 cout << " (" << j << ") " cannam@21: 00753 << outputs[j].name << ", \"" cannam@21: 00754 << outputs[j].identifier << "\"" << endl; cannam@21: 00755 if (outputs[j].description != "") { cannam@21: 00756 cout << " - " cannam@21: 00757 << outputs[j].description << endl; cannam@21: 00758 } cannam@21: 00759 } else if (verbosity == PluginOutputIds) { cannam@21: 00760 cout << "vamp:" << key << ":" << outputs[j].identifier << endl; cannam@21: 00761 } cannam@21: 00762 } cannam@21: 00763 } cannam@21: 00764 cannam@21: 00765 ++index; cannam@21: 00766 cannam@21: 00767 delete plugin; cannam@21: 00768 } cannam@21: 00769 } cannam@21: 00770 cannam@21: 00771 if (verbosity == PluginInformation || cannam@21: 00772 verbosity == PluginInformationDetailed) { cannam@21: 00773 cout << endl; cannam@21: 00774 } cannam@21: 00775 } cannam@21: 00776 cannam@21: 00777 void cannam@21: 00778 printPluginCategoryList() cannam@21: 00779 { cannam@21: 00780 PluginLoader *loader = PluginLoader::getInstance(); cannam@21: 00781 cannam@21: 00782 vector<PluginLoader::PluginKey> plugins = loader->listPlugins(); cannam@21: 00783 cannam@21: 00784 set<string> printedcats; cannam@21: 00785 cannam@21: 00786 for (size_t i = 0; i < plugins.size(); ++i) { cannam@21: 00787 cannam@21: 00788 PluginLoader::PluginKey key = plugins[i]; cannam@21: 00789 cannam@21: 00790 PluginLoader::PluginCategoryHierarchy category = cannam@21: 00791 loader->getPluginCategory(key); cannam@21: 00792 cannam@21: 00793 Plugin *plugin = loader->loadPlugin(key, 48000); cannam@21: 00794 if (!plugin) continue; cannam@21: 00795 cannam@21: 00796 string catstr = ""; cannam@21: 00797 cannam@21: 00798 if (category.empty()) catstr = '|'; cannam@21: 00799 else { cannam@21: 00800 for (size_t j = 0; j < category.size(); ++j) { cannam@21: 00801 catstr += category[j]; cannam@21: 00802 catstr += '|'; cannam@21: 00803 if (printedcats.find(catstr) == printedcats.end()) { cannam@21: 00804 std::cout << catstr << std::endl; cannam@21: 00805 printedcats.insert(catstr); cannam@21: 00806 } cannam@21: 00807 } cannam@21: 00808 } cannam@21: 00809 cannam@21: 00810 std::cout << catstr << key << ":::" << plugin->getName() << ":::" << plugin->getMaker() << ":::" << plugin->getDescription() << std::endl; cannam@21: 00811 } cannam@21: 00812 } cannam@21: 00813 cannam@0: