changeset 390:06988ce35ff0 vh

Initial draft of C API for plugin loading
author Chris Cannam
date Wed, 20 May 2015 16:12:18 +0100
parents 93683cf9fce3
children f4e07ae2725a
files src/vamp-hostsdk/Files.cpp src/vamp-hostsdk/Files.h src/vamp-hostsdk/PluginLoader.cpp src/vamp-hostsdk/host-c.cpp
diffstat 4 files changed, 535 insertions(+), 252 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vamp-hostsdk/Files.cpp	Wed May 20 16:12:18 2015 +0100
@@ -0,0 +1,274 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Vamp
+
+    An API for audio analysis and feature extraction plugins.
+
+    Centre for Digital Music, Queen Mary, University of London.
+    Copyright 2006-2015 Chris Cannam and QMUL.
+  
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+    Except as contained in this notice, the names of the Centre for
+    Digital Music; Queen Mary, University of London; and Chris Cannam
+    shall not be used in advertising or otherwise to promote the sale,
+    use or other dealings in this Software without prior written
+    authorization.
+*/
+
+#include <vamp-hostsdk/PluginHostAdapter.h>
+
+#include "Files.h"
+
+#include <cctype> // tolower
+
+#include <cstring>
+
+#ifdef _WIN32
+
+#include <windows.h>
+#include <tchar.h>
+#define PLUGIN_SUFFIX "dll"
+
+#else /* ! _WIN32 */
+
+#include <dirent.h>
+#include <dlfcn.h>
+
+#ifdef __APPLE__
+#define PLUGIN_SUFFIX "dylib"
+#else /* ! __APPLE__ */
+#define PLUGIN_SUFFIX "so"
+#endif /* ! __APPLE__ */
+
+#endif /* ! _WIN32 */
+
+using namespace std;
+
+vector<string>
+Files::listLibraryFiles()
+{
+    return listLibraryFilesMatching("");
+}
+
+vector<string>
+Files::listLibraryFilesMatching(string libraryName)
+{
+    vector<string> path = Vamp::PluginHostAdapter::getPluginPath();
+    vector<string> libraryFiles;
+
+    // we match case-insensitively
+    for (size_t i = 0; i < libraryName.length(); ++i) {
+	libraryName[i] = tolower(libraryName[i]);
+    }
+
+    for (size_t i = 0; i < path.size(); ++i) {
+        
+        vector<string> files = listFiles(path[i], PLUGIN_SUFFIX);
+
+        for (vector<string>::iterator fi = files.begin();
+             fi != files.end(); ++fi) {
+            
+            if (libraryName != "") {
+		// we match case-insensitively
+                string temp = *fi;
+                for (size_t i = 0; i < temp.length(); ++i) {
+                    temp[i] = 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;
+                }
+            }
+
+            string fullPath = path[i];
+            fullPath = splicePath(fullPath, *fi);
+	    libraryFiles.push_back(fullPath);
+	}
+    }
+
+    return libraryFiles;
+}
+
+void *
+Files::loadLibrary(string path)
+{
+    void *handle = 0;
+#ifdef _WIN32
+#ifdef UNICODE
+    int len = path.length() + 1; // cannot be more wchars than length in bytes of utf8 string
+    wchar_t *buffer = new wchar_t[len];
+    int rv = MultiByteToWideChar(CP_UTF8, 0, path.c_str(), len, buffer, len);
+    if (rv <= 0) {
+        cerr << "Vamp::HostExt: Unable to convert library path \""
+             << path << "\" to wide characters " << endl;
+        delete[] buffer;
+        return handle;
+    }
+    handle = LoadLibrary(buffer);
+    delete[] buffer;
+#else
+    handle = LoadLibrary(path.c_str());
+#endif
+    if (!handle) {
+        cerr << "Vamp::HostExt: Unable to load library \""
+             << path << "\"" << endl;
+    }
+#else
+    handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
+    if (!handle) {
+        cerr << "Vamp::HostExt: Unable to load library \""
+             << path << "\": " << dlerror() << endl;
+    }
+#endif
+    return handle;
+}
+
+void
+Files::unloadLibrary(void *handle)
+{
+#ifdef _WIN32
+    FreeLibrary((HINSTANCE)handle);
+#else
+    dlclose(handle);
+#endif
+}
+
+void *
+Files::lookupInLibrary(void *handle, const char *symbol)
+{
+#ifdef _WIN32
+    return (void *)GetProcAddress((HINSTANCE)handle, symbol);
+#else
+    return (void *)dlsym(handle, symbol);
+#endif
+}
+
+string
+Files::lcBasename(string path)
+{
+    string basename(path);
+	
+    string::size_type li = basename.rfind('/');
+    if (li != string::npos) basename = basename.substr(li + 1);
+
+    li = basename.find('.');
+    if (li != string::npos) basename = basename.substr(0, li);
+
+    for (size_t i = 0; i < basename.length(); ++i) {
+        basename[i] = tolower(basename[i]);
+    }
+
+    return basename;
+}
+
+string
+Files::splicePath(string a, string b)
+{
+#ifdef _WIN32
+    return a + "\\" + b;
+#else
+    return a + "/" + b;
+#endif
+}
+
+vector<string>
+Files::listFiles(string dir, string extension)
+{
+    vector<string> files;
+
+#ifdef _WIN32
+    string expression = dir + "\\*." + extension;
+#ifdef UNICODE
+    int len = expression.length() + 1; // cannot be more wchars than length in bytes of utf8 string
+    wchar_t *buffer = new wchar_t[len];
+    int rv = MultiByteToWideChar(CP_UTF8, 0, expression.c_str(), len, buffer, len);
+    if (rv <= 0) {
+        cerr << "Vamp::HostExt: Unable to convert wildcard path \""
+             << expression << "\" to wide characters" << endl;
+        delete[] buffer;
+        return files;
+    }
+    WIN32_FIND_DATA data;
+    HANDLE fh = FindFirstFile(buffer, &data);
+    if (fh == INVALID_HANDLE_VALUE) {
+        delete[] buffer;
+        return files;
+    }
+
+    bool ok = true;
+    while (ok) {
+        wchar_t *fn = data.cFileName;
+        int wlen = wcslen(fn) + 1;
+        int maxlen = wlen * 6;
+        char *conv = new char[maxlen];
+        int rv = WideCharToMultiByte(CP_UTF8, 0, fn, wlen, conv, maxlen, 0, 0);
+        if (rv > 0) {
+            files.push_back(conv);
+        }
+        delete[] conv;
+        ok = FindNextFile(fh, &data);
+    }
+
+    FindClose(fh);
+    delete[] buffer;
+#else
+    WIN32_FIND_DATA data;
+    HANDLE fh = FindFirstFile(expression.c_str(), &data);
+    if (fh == INVALID_HANDLE_VALUE) return files;
+
+    bool ok = true;
+    while (ok) {
+        files.push_back(data.cFileName);
+        ok = FindNextFile(fh, &data);
+    }
+
+    FindClose(fh);
+#endif
+#else
+
+    size_t extlen = extension.length();
+    DIR *d = opendir(dir.c_str());
+    if (!d) return files;
+            
+    struct dirent *e = 0;
+    while ((e = readdir(d))) {
+ 
+        if (!e->d_name) continue;
+       
+        size_t len = strlen(e->d_name);
+        if (len < extlen + 2 ||
+            e->d_name + len - extlen - 1 != "." + extension) {
+            continue;
+        }
+
+        files.push_back(e->d_name);
+    }
+
+    closedir(d);
+#endif
+
+    return files;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vamp-hostsdk/Files.h	Wed May 20 16:12:18 2015 +0100
@@ -0,0 +1,63 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Vamp
+
+    An API for audio analysis and feature extraction plugins.
+
+    Centre for Digital Music, Queen Mary, University of London.
+    Copyright 2006-2015 Chris Cannam and QMUL.
+  
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+    Except as contained in this notice, the names of the Centre for
+    Digital Music; Queen Mary, University of London; and Chris Cannam
+    shall not be used in advertising or otherwise to promote the sale,
+    use or other dealings in this Software without prior written
+    authorization.
+*/
+
+#ifndef VAMP_FILES_H
+#define VAMP_FILES_H
+
+#include <vector>
+#include <string>
+
+/**
+ * This is a private implementation class for the Vamp Host SDK.
+ */
+class Files
+{
+public:
+    static std::vector<std::string> listLibraryFiles();
+    static std::vector<std::string> listLibraryFilesMatching(std::string libname);
+
+    static void *loadLibrary(std::string filename);
+    static void unloadLibrary(void *);
+    static void *lookupInLibrary(void *, const char *symbol);
+
+    static std::string lcBasename(std::string path);
+    static std::string splicePath(std::string a, std::string b);
+    static std::vector<std::string> listFiles(std::string dir, std::string ext);
+};
+
+#endif
+
+    
--- a/src/vamp-hostsdk/PluginLoader.cpp	Wed May 20 13:54:46 2015 +0100
+++ b/src/vamp-hostsdk/PluginLoader.cpp	Wed May 20 16:12:18 2015 +0100
@@ -34,35 +34,17 @@
     authorization.
 */
 
-#include <vamp-hostsdk/PluginHostAdapter.h>
 #include <vamp-hostsdk/PluginLoader.h>
 #include <vamp-hostsdk/PluginInputDomainAdapter.h>
 #include <vamp-hostsdk/PluginChannelAdapter.h>
 #include <vamp-hostsdk/PluginBufferingAdapter.h>
+#include <vamp-hostsdk/PluginHostAdapter.h>
+
+#include <vamp/vamp.h>
+
+#include "Files.h"
 
 #include <fstream>
-#include <cctype> // tolower
-
-#include <cstring>
-
-#ifdef _WIN32
-
-#include <windows.h>
-#include <tchar.h>
-#define PLUGIN_SUFFIX "dll"
-
-#else /* ! _WIN32 */
-
-#include <dirent.h>
-#include <dlfcn.h>
-
-#ifdef __APPLE__
-#define PLUGIN_SUFFIX "dylib"
-#else /* ! __APPLE__ */
-#define PLUGIN_SUFFIX "so"
-#endif /* ! __APPLE__ */
-
-#endif /* ! _WIN32 */
 
 using namespace std;
 
@@ -124,13 +106,6 @@
     bool decomposePluginKey(PluginKey key,
                             string &libraryName, string &identifier);
 
-    void *loadLibrary(string path);
-    void unloadLibrary(void *handle);
-    void *lookupInLibrary(void *handle, const char *symbol);
-
-    string splicePath(string a, string b);
-    vector<string> listFiles(string dir, string ext);
-    
     static InstanceCleaner m_cleaner;
 };
 
@@ -227,83 +202,64 @@
 void
 PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin)
 {
-    vector<string> path = PluginHostAdapter::getPluginPath();
-
     string libraryName, identifier;
+    vector<string> fullPaths;
+    
     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();
     }
 
-    for (size_t i = 0; i < path.size(); ++i) {
-        
-        vector<string> files = listFiles(path[i], PLUGIN_SUFFIX);
+    for (size_t i = 0; i < fullPaths.size(); ++i) {
 
-        for (vector<string>::iterator fi = files.begin();
-             fi != files.end(); ++fi) {
+        string fullPath = fullPaths[i];
+        void *handle = Files::loadLibrary(fullPath);
+        if (!handle) continue;
             
-            if (libraryName != "") {
-                // libraryName is lowercased and lacking an extension,
-                // as it came from the plugin key
-                string temp = *fi;
-                for (size_t i = 0; i < temp.length(); ++i) {
-                    temp[i] = tolower(temp[i]);
-                }
-                string::size_type pi = temp.find('.');
-                if (pi == string::npos) {
-                    if (libraryName != temp) continue;
-                } else {
-                    if (libraryName != temp.substr(0, pi)) continue;
-                }
-            }
-
-            string fullPath = path[i];
-            fullPath = splicePath(fullPath, *fi);
-            void *handle = loadLibrary(fullPath);
-            if (!handle) continue;
+        VampGetPluginDescriptorFunction fn =
+            (VampGetPluginDescriptorFunction)Files::lookupInLibrary
+            (handle, "vampGetPluginDescriptor");
             
-            VampGetPluginDescriptorFunction fn =
-                (VampGetPluginDescriptorFunction)lookupInLibrary
-                (handle, "vampGetPluginDescriptor");
-            
-            if (!fn) {
-                if (forPlugin != "") {
-                    cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
-                         << fullPath << "\"" << endl;
-                }
-                unloadLibrary(handle);
-                continue;
-            }
-            
-            int index = 0;
-            const VampPluginDescriptor *descriptor = 0;
-            bool found = false;
-            
-            while ((descriptor = fn(VAMP_API_VERSION, index))) {
-                ++index;
-                if (identifier != "") {
-                    if (descriptor->identifier != identifier) continue;
-                }
-                found = true;
-                PluginKey key = composePluginKey(*fi, descriptor->identifier);
-//                std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl;
-                if (m_pluginLibraryNameMap.find(key) ==
-                    m_pluginLibraryNameMap.end()) {
-                    m_pluginLibraryNameMap[key] = fullPath;
-                }
-            }
-
-            if (!found && forPlugin != "") {
-                cerr << "Vamp::HostExt::PluginLoader: Plugin \""
-                     << identifier << "\" not found in library \""
+        if (!fn) {
+            if (forPlugin != "") {
+                cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
                      << fullPath << "\"" << endl;
             }
+            Files::unloadLibrary(handle);
+            continue;
+        }
             
-            unloadLibrary(handle);
+        int index = 0;
+        const VampPluginDescriptor *descriptor = 0;
+        bool found = false;
+            
+        while ((descriptor = fn(VAMP_API_VERSION, index))) {
+            ++index;
+            if (identifier != "") {
+                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;
+            }
         }
+
+        if (!found && forPlugin != "") {
+            cerr << "Vamp::HostExt::PluginLoader: Plugin \""
+                 << identifier << "\" not found in library \""
+                 << fullPath << "\"" << endl;
+        }
+            
+        Files::unloadLibrary(handle);
     }
 
     if (forPlugin == "") m_allPluginsEnumerated = true;
@@ -312,18 +268,7 @@
 PluginLoader::PluginKey
 PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
 {
-    string basename = libraryName;
-
-    string::size_type li = basename.rfind('/');
-    if (li != string::npos) basename = basename.substr(li + 1);
-
-    li = basename.find('.');
-    if (li != string::npos) basename = basename.substr(0, li);
-
-    for (size_t i = 0; i < basename.length(); ++i) {
-        basename[i] = tolower(basename[i]);
-    }
-
+    string basename = Files::lcBasename(libraryName);
     return basename + ":" + identifier;
 }
 
@@ -382,17 +327,17 @@
         return 0;
     }
     
-    void *handle = loadLibrary(fullPath);
+    void *handle = Files::loadLibrary(fullPath);
     if (!handle) return 0;
     
     VampGetPluginDescriptorFunction fn =
-        (VampGetPluginDescriptorFunction)lookupInLibrary
+        (VampGetPluginDescriptorFunction)Files::lookupInLibrary
         (handle, "vampGetPluginDescriptor");
 
     if (!fn) {
         cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
              << fullPath << "\"" << endl;
-        unloadLibrary(handle);
+        Files::unloadLibrary(handle);
         return 0;
     }
 
@@ -474,12 +419,12 @@
     for (vector<string>::iterator i = catpath.begin();
          i != catpath.end(); ++i) {
         
-        vector<string> files = listFiles(*i, suffix);
+        vector<string> files = Files::listFiles(*i, suffix);
 
         for (vector<string>::iterator fi = files.begin();
              fi != files.end(); ++fi) {
 
-            string filepath = splicePath(*i, *fi);
+            string filepath = Files::splicePath(*i, *fi);
             ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
 
             if (is.fail()) {
@@ -525,154 +470,11 @@
     }
 }    
 
-void *
-PluginLoader::Impl::loadLibrary(string path)
-{
-    void *handle = 0;
-#ifdef _WIN32
-#ifdef UNICODE
-    int len = path.length() + 1; // cannot be more wchars than length in bytes of utf8 string
-    wchar_t *buffer = new wchar_t[len];
-    int rv = MultiByteToWideChar(CP_UTF8, 0, path.c_str(), len, buffer, len);
-    if (rv <= 0) {
-        cerr << "Vamp::HostExt::PluginLoader: Unable to convert library path \""
-             << path << "\" to wide characters " << endl;
-        delete[] buffer;
-        return handle;
-    }
-    handle = LoadLibrary(buffer);
-    delete[] buffer;
-#else
-    handle = LoadLibrary(path.c_str());
-#endif
-    if (!handle) {
-        cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
-             << path << "\"" << endl;
-    }
-#else
-    handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
-    if (!handle) {
-        cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
-             << path << "\": " << dlerror() << endl;
-    }
-#endif
-    return handle;
-}
-
-void
-PluginLoader::Impl::unloadLibrary(void *handle)
-{
-#ifdef _WIN32
-    FreeLibrary((HINSTANCE)handle);
-#else
-    dlclose(handle);
-#endif
-}
-
-void *
-PluginLoader::Impl::lookupInLibrary(void *handle, const char *symbol)
-{
-#ifdef _WIN32
-    return (void *)GetProcAddress((HINSTANCE)handle, symbol);
-#else
-    return (void *)dlsym(handle, symbol);
-#endif
-}
-
-string
-PluginLoader::Impl::splicePath(string a, string b)
-{
-#ifdef _WIN32
-    return a + "\\" + b;
-#else
-    return a + "/" + b;
-#endif
-}
-
-vector<string>
-PluginLoader::Impl::listFiles(string dir, string extension)
-{
-    vector<string> files;
-
-#ifdef _WIN32
-    string expression = dir + "\\*." + extension;
-#ifdef UNICODE
-    int len = expression.length() + 1; // cannot be more wchars than length in bytes of utf8 string
-    wchar_t *buffer = new wchar_t[len];
-    int rv = MultiByteToWideChar(CP_UTF8, 0, expression.c_str(), len, buffer, len);
-    if (rv <= 0) {
-        cerr << "Vamp::HostExt::PluginLoader: Unable to convert wildcard path \""
-             << expression << "\" to wide characters" << endl;
-        delete[] buffer;
-        return files;
-    }
-    WIN32_FIND_DATA data;
-    HANDLE fh = FindFirstFile(buffer, &data);
-    if (fh == INVALID_HANDLE_VALUE) {
-        delete[] buffer;
-        return files;
-    }
-
-    bool ok = true;
-    while (ok) {
-        wchar_t *fn = data.cFileName;
-        int wlen = wcslen(fn) + 1;
-        int maxlen = wlen * 6;
-        char *conv = new char[maxlen];
-        int rv = WideCharToMultiByte(CP_UTF8, 0, fn, wlen, conv, maxlen, 0, 0);
-        if (rv > 0) {
-            files.push_back(conv);
-        }
-        delete[] conv;
-        ok = FindNextFile(fh, &data);
-    }
-
-    FindClose(fh);
-    delete[] buffer;
-#else
-    WIN32_FIND_DATA data;
-    HANDLE fh = FindFirstFile(expression.c_str(), &data);
-    if (fh == INVALID_HANDLE_VALUE) return files;
-
-    bool ok = true;
-    while (ok) {
-        files.push_back(data.cFileName);
-        ok = FindNextFile(fh, &data);
-    }
-
-    FindClose(fh);
-#endif
-#else
-
-    size_t extlen = extension.length();
-    DIR *d = opendir(dir.c_str());
-    if (!d) return files;
-            
-    struct dirent *e = 0;
-    while ((e = readdir(d))) {
- 
-        if (!e->d_name) continue;
-       
-        size_t len = strlen(e->d_name);
-        if (len < extlen + 2 ||
-            e->d_name + len - extlen - 1 != "." + extension) {
-            continue;
-        }
-
-        files.push_back(e->d_name);
-    }
-
-    closedir(d);
-#endif
-
-    return files;
-}
-
 void
 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
 {
     void *handle = m_pluginLibraryHandleMap[adapter];
-    if (handle) unloadLibrary(handle);
+    if (handle) Files::unloadLibrary(handle);
     m_pluginLibraryHandleMap.erase(adapter);
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vamp-hostsdk/host-c.cpp	Wed May 20 16:12:18 2015 +0100
@@ -0,0 +1,144 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Vamp
+
+    An API for audio analysis and feature extraction plugins.
+
+    Centre for Digital Music, Queen Mary, University of London.
+    Copyright 2006-2015 Chris Cannam and QMUL.
+  
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+    Except as contained in this notice, the names of the Centre for
+    Digital Music; Queen Mary, University of London; and Chris Cannam
+    shall not be used in advertising or otherwise to promote the sale,
+    use or other dealings in this Software without prior written
+    authorization.
+*/
+
+#include <vamp-hostsdk/host-c.h>
+
+#include "Files.h"
+
+#include <map>
+#include <iostream>
+
+#include <cstring>
+
+using namespace std;
+
+static vector<string> files;
+static map<string, const char *> cnames;
+static bool haveFiles = false;
+
+struct vhLibrary_t {
+    vhLibrary_t(void *h, VampGetPluginDescriptorFunction f)
+        : handle(h), func(f), nplugins(0) { } 
+    void *handle;
+    VampGetPluginDescriptorFunction func;
+    int nplugins;
+};
+
+static void initFilenames()
+{
+    if (!haveFiles) {
+        files = Files::listLibraryFiles();
+        for (size_t i = 0; i < files.size(); ++i) {
+            cnames[files[i]] = strdup(Files::lcBasename(files[i]).c_str());
+        }
+        haveFiles = true;
+    }
+}
+
+int vhGetLibraryCount()
+{
+    initFilenames();
+    return int(files.size());
+}
+
+const char *vhGetLibraryName(int library)
+{
+    initFilenames();
+    if (library < int(files.size())) {
+        return cnames[files[library]];
+    }
+    else return 0;
+}
+
+vhLibrary vhLoadLibrary(const char *libraryName)
+{
+    for (size_t i = 0; i < files.size(); ++i) {
+
+        if (Files::lcBasename(libraryName) == Files::lcBasename(files[i])) {
+
+            string fullPath = files[i];
+            void *lib = Files::loadLibrary(fullPath);
+
+            if (!lib) return 0;
+            
+            VampGetPluginDescriptorFunction func =
+                (VampGetPluginDescriptorFunction)Files::lookupInLibrary
+                (lib, "vampGetPluginDescriptor");
+            if (!func) {
+                cerr << "vhLoadLibrary: No vampGetPluginDescriptor function found in library \""
+                     << fullPath << "\"" << endl;
+                Files::unloadLibrary(lib);
+                return 0;
+            }
+
+            vhLibrary_t *vhl = new vhLibrary_t(lib, func);
+            while (vhl->func(VAMP_API_VERSION, vhl->nplugins)) {
+                ++vhl->nplugins;
+            }
+            return vhl;
+        }
+    }
+
+    return 0;
+}
+
+int vhGetPluginCount(vhLibrary library)
+{
+    vhLibrary_t *vhl = static_cast<vhLibrary_t *>(library);
+    if (vhl) return vhl->nplugins;
+    else return 0;
+}
+
+const VampPluginDescriptor *vhGetPluginDescriptor(vhLibrary library,
+                                                  int plugin)
+{
+    vhLibrary_t *vhl = static_cast<vhLibrary_t *>(library);
+    if (vhl && plugin >= 0 && plugin < vhl->nplugins) {
+        return vhl->func(VAMP_API_VERSION, plugin);
+    } else {
+        return 0;
+    }
+}
+
+void vhUnloadLibrary(vhLibrary library)
+{
+    vhLibrary_t *vhl = static_cast<vhLibrary_t *>(library);
+    if (vhl && vhl->handle) {
+        Files::unloadLibrary(vhl->handle);
+    }
+    delete vhl;
+}
+