cannam@0: cannam@0: cannam@0: VampPluginSDK: vamp-simple-host.cpp Source File cannam@35: cannam@0: cannam@0: cannam@35: cannam@0: cannam@21:
cannam@0:

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: */
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@35: 00098         "Copyright 2006-2009 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@35: 00417     for (sf_count_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: 
cannam@35:
Generated on Thu Sep 24 13:40:13 2009 for VampPluginSDK by  cannam@0: cannam@35: doxygen 1.5.8
cannam@0: cannam@0: