changeset 473:0545cd3f1738 enumerate-options

Add plugin enumeration options (for use by piper server, needs testing)
author Chris Cannam
date Wed, 02 Nov 2016 14:22:20 +0000
parents 79a219ba6178
children 8e846c1aed96
files src/vamp-hostsdk/Files.cpp src/vamp-hostsdk/Files.h src/vamp-hostsdk/PluginLoader.cpp vamp-hostsdk/PluginLoader.h
diffstat 4 files changed, 204 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/src/vamp-hostsdk/Files.cpp	Fri Oct 28 14:30:26 2016 +0100
+++ b/src/vamp-hostsdk/Files.cpp	Wed Nov 02 14:22:20 2016 +0000
@@ -66,21 +66,25 @@
 vector<string>
 Files::listLibraryFiles()
 {
-    return listLibraryFilesMatching("");
+    return listLibraryFilesMatching({});
 }
 
 vector<string>
-Files::listLibraryFilesMatching(string libraryName)
+Files::listLibraryFilesMatching(Filter filter)
 {
     vector<string> path = Vamp::PluginHostAdapter::getPluginPath();
     vector<string> libraryFiles;
 
     // we match case-insensitively, but only with ascii range
-    // characters (this string is expected to be utf-8)
-    for (size_t i = 0; i < libraryName.length(); ++i) {
-        if (!(libraryName[i] & 0x80)) {
-            libraryName[i] = char(tolower(libraryName[i]));
+    // characters (input strings are expected to be utf-8)
+    vector<string> libraryNames;
+    for (auto n: filter.libraryNames) {
+        for (size_t i = 0; i < n.length(); ++i) {
+            if (!(n[i] & 0x80)) {
+                n[i] = char(tolower(n[i]));
+            }
         }
+        libraryNames.push_back(n);
     }
 
     for (size_t i = 0; i < path.size(); ++i) {
@@ -89,27 +93,53 @@
 
         for (vector<string>::iterator fi = files.begin();
              fi != files.end(); ++fi) {
-            
-            if (libraryName != "") {
-		// we match case-insensitively, but only with ascii
-		// range characters (this string is expected to be
-		// utf-8)
-                string temp = *fi;
-                for (size_t i = 0; i < temp.length(); ++i) {
-                    if (!(temp[i] & 0x80)) {
-                        temp[i] = char(tolower(temp[i]));
-                    }
-                }
-                // libraryName should be lacking an extension, as it
-                // is supposed to have come from the plugin key
-                string::size_type pi = temp.find('.');
-                if (pi == string::npos) {
-                    if (libraryName != temp) continue;
-                } else {
-                    if (libraryName != temp.substr(0, pi)) continue;
+
+            // we match case-insensitively, but only with ascii range
+            // characters (this string is expected to be utf-8)
+            string cleaned = *fi;
+            for (size_t i = 0; i < cleaned.length(); ++i) {
+                if (!(cleaned[i] & 0x80)) {
+                    cleaned[i] = char(tolower(cleaned[i]));
                 }
             }
 
+            // libraryName should be lacking an extension, as it is
+            // supposed to have come from the plugin key
+            string::size_type pi = cleaned.find('.');
+            if (pi != string::npos) {
+                cleaned = cleaned.substr(0, pi);
+            }
+            
+            bool matched = false;
+
+            switch (filter.type) {
+
+            case Filter::All:
+                matched = true;
+                break;
+
+            case Filter::Matching:
+                for (const auto &n: libraryNames) {
+                    if (cleaned == n) {
+                        matched = true;
+                        break;
+                    }
+                }
+                break;
+
+            case Filter::NotMatching:
+                matched = true;
+                for (const auto &n: libraryNames) {
+                    if (cleaned == n) {
+                        matched = false;
+                        break;
+                    }
+                }
+                break;
+            }
+
+            if (!matched) continue;
+            
             string fullPath = path[i];
             fullPath = splicePath(fullPath, *fi);
 	    libraryFiles.push_back(fullPath);
--- a/src/vamp-hostsdk/Files.h	Fri Oct 28 14:30:26 2016 +0100
+++ b/src/vamp-hostsdk/Files.h	Wed Nov 02 14:22:20 2016 +0000
@@ -47,7 +47,13 @@
 {
 public:
     static std::vector<std::string> listLibraryFiles();
-    static std::vector<std::string> listLibraryFilesMatching(std::string libname);
+
+    struct Filter {
+        enum { All, Matching, NotMatching } type;
+        std::vector<std::string> libraryNames;
+        Filter() : type(All) { }
+    };
+    static std::vector<std::string> listLibraryFilesMatching(Filter);
 
     static void *loadLibrary(std::string filename);
     static void unloadLibrary(void *);
--- a/src/vamp-hostsdk/PluginLoader.cpp	Fri Oct 28 14:30:26 2016 +0100
+++ b/src/vamp-hostsdk/PluginLoader.cpp	Wed Nov 02 14:22:20 2016 +0000
@@ -61,6 +61,8 @@
     virtual ~Impl();
 
     PluginKeyList listPlugins();
+    PluginKeyList listPluginsIn(vector<string>);
+    PluginKeyList listPluginsNotIn(vector<string>);
 
     Plugin *loadPlugin(PluginKey key,
                        float inputSampleRate,
@@ -96,7 +98,18 @@
 
     map<PluginKey, string> m_pluginLibraryNameMap;
     bool m_allPluginsEnumerated;
-    void enumeratePlugins(PluginKey forPlugin = "");
+
+    struct Enumeration {
+        enum { All, SinglePlugin, InLibraries, NotInLibraries } type;
+        PluginKey key;
+        vector<string> libraryNames;
+        Enumeration() : type(All) { }
+    };
+    vector<string> listLibraryFilesFor(Enumeration);
+
+    /// Populate m_pluginLibraryNameMap and return a list of the keys
+    /// that were added to it
+    vector<PluginKey> enumeratePlugins(Enumeration);
 
     map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
     void generateTaxonomy();
@@ -144,6 +157,18 @@
     return m_impl->listPlugins();
 }
 
+PluginLoader::PluginKeyList
+PluginLoader::listPluginsIn(vector<string> libs) 
+{
+    return m_impl->listPluginsIn(libs);
+}
+
+PluginLoader::PluginKeyList
+PluginLoader::listPluginsNotIn(vector<string> libs) 
+{
+    return m_impl->listPluginsNotIn(libs);
+}
+
 Plugin *
 PluginLoader::loadPlugin(PluginKey key,
                          float inputSampleRate,
@@ -188,34 +213,89 @@
 PluginLoader::PluginKeyList
 PluginLoader::Impl::listPlugins() 
 {
-    if (!m_allPluginsEnumerated) enumeratePlugins();
+    if (!m_allPluginsEnumerated) enumeratePlugins({});
 
     vector<PluginKey> plugins;
-    for (map<PluginKey, string>::iterator mi = m_pluginLibraryNameMap.begin();
-         mi != m_pluginLibraryNameMap.end(); ++mi) {
-        plugins.push_back(mi->first);
+    for (const auto &mi: m_pluginLibraryNameMap) {
+        plugins.push_back(mi.first);
     }
 
     return plugins;
 }
 
-void
-PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin)
+PluginLoader::PluginKeyList
+PluginLoader::Impl::listPluginsIn(vector<string> libs) 
+{
+    Enumeration enumeration;
+    enumeration.type = Enumeration::InLibraries;
+    enumeration.libraryNames = libs;
+    return enumeratePlugins(enumeration);
+}
+
+PluginLoader::PluginKeyList
+PluginLoader::Impl::listPluginsNotIn(vector<string> libs) 
+{
+    Enumeration enumeration;
+    enumeration.type = Enumeration::NotInLibraries;
+    enumeration.libraryNames = libs;
+    return enumeratePlugins(enumeration);
+}
+
+vector<string>
+PluginLoader::Impl::listLibraryFilesFor(Enumeration enumeration)
+{
+    Files::Filter filter;
+    
+    switch (enumeration.type) {
+
+    case Enumeration::All:
+        filter.type = Files::Filter::All;
+        break;
+
+    case Enumeration::SinglePlugin:
+    {
+        string libraryName, identifier;
+        if (!decomposePluginKey(enumeration.key, libraryName, identifier)) {
+            std::cerr << "WARNING: Vamp::HostExt::PluginLoader: "
+                      << "Invalid plugin key \"" << enumeration.key
+                      << "\" in enumerate" << std::endl;
+            return {};
+        }
+        filter.type = Files::Filter::Matching;
+        filter.libraryNames = { libraryName };
+        break;
+    }
+
+    case Enumeration::InLibraries:
+        filter.type = Files::Filter::Matching;
+        filter.libraryNames = enumeration.libraryNames;
+        break;
+
+    case Enumeration::NotInLibraries:
+        filter.type = Files::Filter::NotMatching;
+        filter.libraryNames = enumeration.libraryNames;
+        break;
+    }
+        
+    return Files::listLibraryFilesMatching(filter);
+}
+
+vector<PluginLoader::PluginKey>
+PluginLoader::Impl::enumeratePlugins(Enumeration enumeration)
 {
     string libraryName, identifier;
-    vector<string> fullPaths;
+    if (enumeration.type == Enumeration::SinglePlugin) {
+        decomposePluginKey(enumeration.key, libraryName, identifier);
+    }
     
-    if (forPlugin != "") {
-        if (!decomposePluginKey(forPlugin, libraryName, identifier)) {
-            std::cerr << "WARNING: Vamp::HostExt::PluginLoader: Invalid plugin key \""
-                      << forPlugin << "\" in enumerate" << std::endl;
-            return;
-        }
-        fullPaths = Files::listLibraryFilesMatching(libraryName);
-    } else {
-        fullPaths = Files::listLibraryFiles();
-    }
+    vector<string> fullPaths = listLibraryFilesFor(enumeration);
 
+    // For these we should warn if a plugin can be loaded from a library
+    bool specific = (enumeration.type == Enumeration::SinglePlugin ||
+                     enumeration.type == Enumeration::InLibraries);
+
+    vector<PluginKey> added;
+    
     for (size_t i = 0; i < fullPaths.size(); ++i) {
 
         string fullPath = fullPaths[i];
@@ -227,8 +307,9 @@
             (handle, "vampGetPluginDescriptor");
             
         if (!fn) {
-            if (forPlugin != "") {
-                cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
+            if (specific) {
+                cerr << "Vamp::HostExt::PluginLoader: "
+                    << "No vampGetPluginDescriptor function found in library \""
                      << fullPath << "\"" << endl;
             }
             Files::unloadLibrary(handle);
@@ -242,18 +323,20 @@
         while ((descriptor = fn(VAMP_API_VERSION, index))) {
             ++index;
             if (identifier != "") {
-                if (descriptor->identifier != identifier) continue;
+                if (descriptor->identifier != identifier) {
+                    continue;
+                }
             }
             found = true;
             PluginKey key = composePluginKey(fullPath, descriptor->identifier);
-//                std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl;
             if (m_pluginLibraryNameMap.find(key) ==
                 m_pluginLibraryNameMap.end()) {
                 m_pluginLibraryNameMap[key] = fullPath;
             }
+            added.push_back(key);
         }
 
-        if (!found && forPlugin != "") {
+        if (!found && specific) {
             cerr << "Vamp::HostExt::PluginLoader: Plugin \""
                  << identifier << "\" not found in library \""
                  << fullPath << "\"" << endl;
@@ -262,7 +345,11 @@
         Files::unloadLibrary(handle);
     }
 
-    if (forPlugin == "") m_allPluginsEnumerated = true;
+    if (enumeration.type == Enumeration::All) {
+        m_allPluginsEnumerated = true;
+    }
+
+    return added;
 }
 
 PluginLoader::PluginKey
@@ -302,7 +389,10 @@
 {
     if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
         if (m_allPluginsEnumerated) return "";
-        enumeratePlugins(plugin);
+        Enumeration enumeration;
+        enumeration.type = Enumeration::SinglePlugin;
+        enumeration.key = plugin;
+        enumeratePlugins(enumeration);
     }
     if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
         return "";
--- a/vamp-hostsdk/PluginLoader.h	Fri Oct 28 14:30:26 2016 +0100
+++ b/vamp-hostsdk/PluginLoader.h	Wed Nov 02 14:22:20 2016 +0000
@@ -128,6 +128,34 @@
     PluginKeyList listPlugins();
 
     /**
+     * Search for available Vamp plugins in libraries with the given
+     * library names, and return a list of them in the order in which
+     * they were found. Do not attempt to load any plugin libraries
+     * other than those named.
+     *
+     * The library names should be supplied without path or
+     * suffix. For example, use "vamp-example-plugins" to find plugins
+     * in /install/path/of/vamp-example-plugins.dll (or .so etc). This
+     * is the same concept of "library name" as appears in the plugin
+     * key: \see composePluginKey().
+     */
+    PluginKeyList listPluginsIn(std::vector<std::string> libraryNames);
+
+    /**
+     * Search for available Vamp plugins in libraries other than those
+     * with the given library names, and return a list of them in the
+     * order in which they were found. Do not attempt to load any of
+     * the libraries named.
+     *
+     * The library names should be supplied without path or
+     * suffix. For example, use "vamp-example-plugins" to find plugins
+     * not appearing in /install/path/of/vamp-example-plugins.dll (or
+     * .so etc). This is the same concept of "library name" as appears
+     * in the plugin key: \see composePluginKey().
+     */
+    PluginKeyList listPluginsNotIn(std::vector<std::string> libraryNames);
+
+    /**
      * AdapterFlags contains a set of values that may be OR'd together
      * to indicate in which circumstances PluginLoader should use a
      * plugin adapter to make a plugin easier to use for a host that