changeset 240:7b90fe049d04

* Add --list-full to "simple" Vamp host
author cannam
date Mon, 10 Nov 2008 16:47:41 +0000
parents cc467e52da4c
children 70e6826adc64
files host/vamp-simple-host.cpp src/vamp-hostsdk/PluginHostAdapter.cpp src/vamp-sdk/PluginAdapter.cpp
diffstat 3 files changed, 186 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/host/vamp-simple-host.cpp	Mon Nov 10 12:39:19 2008 +0000
+++ b/host/vamp-simple-host.cpp	Mon Nov 10 16:47:41 2008 +0000
@@ -7,7 +7,6 @@
 
     Centre for Digital Music, Queen Mary, University of London.
     Copyright 2006 Chris Cannam.
-    FFT code from Don Cross's public domain FFT implementation.
   
     Permission is hereby granted, free of charge, to any person
     obtaining a copy of this software and associated documentation
@@ -35,6 +34,18 @@
     authorization.
 */
 
+
+/*
+ * This "simple" Vamp plugin host is no longer as simple as it was; it
+ * now has a lot of options and includes a lot of code to handle the
+ * various useful list options it supports.
+ *
+ * However, the runPlugin function still contains a reasonable
+ * implementation of a fairly generic Vamp plugin host capable of
+ * evaluating a given output on a given plugin for a sound file read
+ * via libsndfile.
+ */
+
 #include <vamp-hostsdk/PluginHostAdapter.h>
 #include <vamp-hostsdk/PluginInputDomainAdapter.h>
 #include <vamp-hostsdk/PluginLoader.h>
@@ -60,12 +71,13 @@
 using Vamp::HostExt::PluginWrapper;
 using Vamp::HostExt::PluginInputDomainAdapter;
 
-#define HOST_VERSION "1.3"
+#define HOST_VERSION "1.4"
 
 enum Verbosity {
     PluginIds,
     PluginOutputIds,
-    PluginInformation
+    PluginInformation,
+    PluginInformationDetailed
 };
 
 void printFeatures(int, int, int, Plugin::FeatureSet, ofstream *, bool frames);
@@ -81,7 +93,7 @@
 void usage(const char *name)
 {
     cerr << "\n"
-         << name << ": A simple Vamp plugin host.\n\n"
+         << name << ": A command-line host for Vamp audio analysis plugins.\n\n"
         "Centre for Digital Music, Queen Mary, University of London.\n"
         "Copyright 2006-2007 Chris Cannam and QMUL.\n"
         "Freely redistributable; published under a BSD-style license.\n\n"
@@ -98,9 +110,13 @@
         "       If the -s option is given, results will be labelled with the audio\n"
         "       sample frame at which they occur. Otherwise, they will be labelled\n"
         "       with time in seconds.\n\n"
-        "  " << name << " -l\n\n"
+        "  " << name << " -l\n"
+        "  " << name << " --list\n\n"
         "    -- List the plugin libraries and Vamp plugins in the library search path\n"
         "       in a verbose human-readable format.\n\n"
+        "  " << name << " --list-full\n\n"
+        "    -- List all data reported by all the Vamp plugins in the library search\n"
+        "       path in a very verbose human-readable format.\n\n"
         "  " << name << " --list-ids\n\n"
         "    -- List the plugins in the search path in a terse machine-readable format,\n"
         "       in the form vamp:soname:identifier.\n\n"
@@ -139,12 +155,17 @@
                  << "Vamp SDK version: " << VAMP_SDK_VERSION << endl;
             return 0;
 
-        } else if (!strcmp(argv[1], "-l")) {
+        } else if (!strcmp(argv[1], "-l") || !strcmp(argv[1], "--list")) {
 
             printPluginPath(true);
             enumeratePlugins(PluginInformation);
             return 0;
 
+        } else if (!strcmp(argv[1], "--list-full")) {
+
+            enumeratePlugins(PluginInformationDetailed);
+            return 0;
+
         } else if (!strcmp(argv[1], "-p")) {
 
             printPluginPath(false);
@@ -286,6 +307,17 @@
 
     cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
 
+    // Note that the following would be much simpler if we used a
+    // PluginBufferingAdapter as well -- i.e. if we had passed
+    // PluginLoader::ADAPT_ALL to loader->loadPlugin() above, instead
+    // of ADAPT_ALL_SAFE.  Then we could simply specify our own block
+    // size, keep the step size equal to the block size, and ignore
+    // the plugin's bleatings.  However, there are some issues with
+    // using a PluginBufferingAdapter that make the results sometimes
+    // technically different from (if effectively the same as) the
+    // un-adapted plugin, so we aren't doing that here.  See the
+    // PluginBufferingAdapter documentation for details.
+
     int blockSize = plugin->getPreferredBlockSize();
     int stepSize = plugin->getPreferredStepSize();
 
@@ -317,6 +349,10 @@
     cerr << "Using block size = " << blockSize << ", step size = "
               << stepSize << endl;
 
+    // The channel queries here are for informational purposes only --
+    // a PluginChannelAdapter is being used automatically behind the
+    // scenes, and it will take case of any channel mismatch
+
     int minch = plugin->getMinChannelCount();
     int maxch = plugin->getMaxChannelCount();
     cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
@@ -371,6 +407,8 @@
 
     wrapper = dynamic_cast<PluginWrapper *>(plugin);
     if (wrapper) {
+        // See documentation for
+        // PluginInputDomainAdapter::getTimestampAdjustment
         PluginInputDomainAdapter *ida =
             wrapper->getWrapper<PluginInputDomainAdapter>();
         if (ida) adjustment = ida->getTimestampAdjustment();
@@ -505,6 +543,18 @@
     if (verbose) cout << endl;
 }
 
+static
+string
+header(string text, int level)
+{
+    string out = '\n' + text + '\n';
+    for (size_t i = 0; i < text.length(); ++i) {
+        out += (level == 1 ? '=' : level == 2 ? '-' : '~');
+    }
+    out += '\n';
+    return out;
+}
+
 void
 enumeratePlugins(Verbosity verbosity)
 {
@@ -538,6 +588,10 @@
             index = 0;
             if (verbosity == PluginInformation) {
                 cout << "\n  " << path << ":" << endl;
+            } else if (verbosity == PluginInformationDetailed) {
+                string::size_type ki = i->second.find(':');
+                string text = "Library \"" + i->second.substr(0, ki) + "\"";
+                cout << "\n" << header(text, 1);
             }
         }
 
@@ -547,6 +601,16 @@
             char c = char('A' + index);
             if (c > 'Z') c = char('a' + (index - 26));
 
+            PluginLoader::PluginCategoryHierarchy category =
+                loader->getPluginCategory(key);
+            string catstr;
+            if (!category.empty()) {
+                for (size_t ci = 0; ci < category.size(); ++ci) {
+                    if (ci > 0) catstr += " > ";
+                        catstr += category[ci];
+                }
+            }
+
             if (verbosity == PluginInformation) {
 
                 cout << "    [" << c << "] [v"
@@ -554,22 +618,42 @@
                      << plugin->getName() << ", \""
                      << plugin->getIdentifier() << "\"" << " ["
                      << plugin->getMaker() << "]" << endl;
-
-                PluginLoader::PluginCategoryHierarchy category =
-                    loader->getPluginCategory(key);
-
-                if (!category.empty()) {
-                    cout << "       ";
-                    for (size_t ci = 0; ci < category.size(); ++ci) {
-                        cout << " > " << category[ci];
-                    }
-                    cout << endl;
+                
+                if (catstr != "") {
+                    cout << "       > " << catstr << endl;
                 }
 
                 if (plugin->getDescription() != "") {
                     cout << "        - " << plugin->getDescription() << endl;
                 }
 
+            } else if (verbosity == PluginInformationDetailed) {
+
+                cout << header(plugin->getName(), 2);
+                cout << "- Identifier:         "
+                     << key << endl;
+                cout << "- Plugin Version:     " 
+                     << plugin->getPluginVersion() << endl;
+                cout << "- Vamp API Version:   "
+                     << plugin->getVampApiVersion() << endl;
+                cout << "- Maker:              \""
+                     << plugin->getMaker() << "\"" << endl;
+                cout << "- Copyright:          \""
+                     << plugin->getCopyright() << "\"" << endl;
+                cout << "- Description:        \""
+                     << plugin->getDescription() << "\"" << endl;
+                cout << "- Input Domain:       "
+                     << (plugin->getInputDomain() == Vamp::Plugin::TimeDomain ?
+                         "Time Domain" : "Frequency Domain") << endl;
+                cout << "- Default Step Size:  " 
+                     << plugin->getPreferredStepSize() << endl;
+                cout << "- Default Block Size: " 
+                     << plugin->getPreferredBlockSize() << endl;
+                cout << "- Minimum Channels:   " 
+                     << plugin->getMinChannelCount() << endl;
+                cout << "- Maximum Channels:   " 
+                     << plugin->getMaxChannelCount() << endl;
+
             } else if (verbosity == PluginIds) {
                 cout << "vamp:" << key << endl;
             }
@@ -577,6 +661,83 @@
             Plugin::OutputList outputs =
                 plugin->getOutputDescriptors();
 
+            if (verbosity == PluginInformationDetailed) {
+
+                Plugin::ParameterList params = plugin->getParameterDescriptors();
+                for (size_t j = 0; j < params.size(); ++j) {
+                    Plugin::ParameterDescriptor &pd(params[j]);
+                    cout << "\nParameter " << j+1 << ": \"" << pd.name << "\"" << endl;
+                    cout << "- Identifier:         " << pd.identifier << endl;
+                    cout << "- Description:        \"" << pd.description << "\"" << endl;
+                    if (pd.unit != "") {
+                        cout << "- Unit:               " << pd.unit << endl;
+                    }
+                    cout << "- Range:              ";
+                    cout << pd.minValue << " -> " << pd.maxValue << endl;
+                    cout << "- Default:            ";
+                    cout << pd.defaultValue << endl;
+                    if (pd.isQuantized) {
+                        cout << "- Quantize Step:      "
+                             << pd.quantizeStep << endl;
+                    }
+                    if (!pd.valueNames.empty()) {
+                        cout << "- Value Names:        ";
+                        for (size_t k = 0; k < pd.valueNames.size(); ++k) {
+                            if (k > 0) cout << ", ";
+                            cout << "\"" << pd.valueNames[k] << "\"";
+                        }
+                        cout << endl;
+                    }
+                }
+
+                if (outputs.empty()) {
+                    cout << "\n** Note: This plugin reports no outputs!" << endl;
+                }
+                for (size_t j = 0; j < outputs.size(); ++j) {
+                    Plugin::OutputDescriptor &od(outputs[j]);
+                    cout << "\nOutput " << j+1 << ": \"" << od.name << "\"" << endl;
+                    cout << "- Identifier:         " << od.identifier << endl;
+                    cout << "- Description:        \"" << od.description << "\"" << endl;
+                    if (od.unit != "") {
+                        cout << "- Unit:               " << od.unit << endl;
+                    }
+                    if (od.hasFixedBinCount) {
+                        cout << "- Default Bin Count:  " << od.binCount << endl;
+                    }
+                    if (!od.binNames.empty()) {
+                        cout << "- Bin Names:          ";
+                        for (size_t k = 0; k < od.binNames.size(); ++k) {
+                            if (k > 0) cout << ", ";
+                            cout << "\"" << od.binNames[k] << "\"";
+                        }
+                        cout << endl;
+                    }
+                    if (od.hasKnownExtents) {
+                        cout << "- Default Extents:    ";
+                        cout << od.minValue << " -> " << od.maxValue << endl;
+                    }
+                    if (od.isQuantized) {
+                        cout << "- Quantize Step:      "
+                             << od.quantizeStep << endl;
+                    }
+                    cout << "- Sample Type:        "
+                         << (od.sampleType ==
+                             Plugin::OutputDescriptor::OneSamplePerStep ?
+                             "One Sample Per Step" :
+                             od.sampleType ==
+                             Plugin::OutputDescriptor::FixedSampleRate ?
+                             "Fixed Sample Rate" :
+                             "Variable Sample Rate") << endl;
+                    if (od.sampleType !=
+                        Plugin::OutputDescriptor::OneSamplePerStep) {
+                        cout << "- Default Rate:       "
+                             << od.sampleRate << endl;
+                    }
+                    cout << "- Has Duration:       "
+                         << (od.hasDuration ? "Yes" : "No") << endl;
+                }
+            }
+
             if (outputs.size() > 1 || verbosity == PluginOutputIds) {
                 for (size_t j = 0; j < outputs.size(); ++j) {
                     if (verbosity == PluginInformation) {
@@ -599,7 +760,8 @@
         }
     }
 
-    if (verbosity == PluginInformation) {
+    if (verbosity == PluginInformation ||
+        verbosity == PluginInformationDetailed) {
         cout << endl;
     }
 }
--- a/src/vamp-hostsdk/PluginHostAdapter.cpp	Mon Nov 10 12:39:19 2008 +0000
+++ b/src/vamp-hostsdk/PluginHostAdapter.cpp	Mon Nov 10 16:47:41 2008 +0000
@@ -327,7 +327,7 @@
         d.unit = sd->unit;
         d.hasFixedBinCount = sd->hasFixedBinCount;
         d.binCount = sd->binCount;
-        if (d.hasFixedBinCount) {
+        if (d.hasFixedBinCount && sd->binNames) {
             for (unsigned int j = 0; j < sd->binCount; ++j) {
                 d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : "");
             }
--- a/src/vamp-sdk/PluginAdapter.cpp	Mon Nov 10 12:39:19 2008 +0000
+++ b/src/vamp-sdk/PluginAdapter.cpp	Mon Nov 10 16:47:41 2008 +0000
@@ -661,7 +661,12 @@
     desc->hasFixedBinCount = od.hasFixedBinCount;
     desc->binCount = od.binCount;
 
-    if (od.hasFixedBinCount && od.binCount > 0) {
+    if (od.hasFixedBinCount && od.binCount > 0
+        // We would like to do "&& !od.binNames.empty()" here -- but we
+        // can't, because it will crash older versions of the host adapter
+        // which try to copy the names across whenever the bin count is
+        // non-zero, regardless of whether they exist or not
+        ) {
         desc->binNames = (const char **)
             malloc(od.binCount * sizeof(const char *));