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