# HG changeset patch # User Chris Cannam # Date 1432134738 -3600 # Node ID 06988ce35ff0c5ecf4f1d0bedda78680795dc760 # Parent 93683cf9fce33f69186c4a3cf8b91223f38d74d9 Initial draft of C API for plugin loading diff -r 93683cf9fce3 -r 06988ce35ff0 src/vamp-hostsdk/Files.cpp --- /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 + +#include "Files.h" + +#include // tolower + +#include + +#ifdef _WIN32 + +#include +#include +#define PLUGIN_SUFFIX "dll" + +#else /* ! _WIN32 */ + +#include +#include + +#ifdef __APPLE__ +#define PLUGIN_SUFFIX "dylib" +#else /* ! __APPLE__ */ +#define PLUGIN_SUFFIX "so" +#endif /* ! __APPLE__ */ + +#endif /* ! _WIN32 */ + +using namespace std; + +vector +Files::listLibraryFiles() +{ + return listLibraryFilesMatching(""); +} + +vector +Files::listLibraryFilesMatching(string libraryName) +{ + vector path = Vamp::PluginHostAdapter::getPluginPath(); + vector 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 files = listFiles(path[i], PLUGIN_SUFFIX); + + for (vector::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 +Files::listFiles(string dir, string extension) +{ + vector 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; +} diff -r 93683cf9fce3 -r 06988ce35ff0 src/vamp-hostsdk/Files.h --- /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 +#include + +/** + * This is a private implementation class for the Vamp Host SDK. + */ +class Files +{ +public: + static std::vector listLibraryFiles(); + static std::vector 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 listFiles(std::string dir, std::string ext); +}; + +#endif + + diff -r 93683cf9fce3 -r 06988ce35ff0 src/vamp-hostsdk/PluginLoader.cpp --- 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 #include #include #include #include +#include + +#include + +#include "Files.h" #include -#include // tolower - -#include - -#ifdef _WIN32 - -#include -#include -#define PLUGIN_SUFFIX "dll" - -#else /* ! _WIN32 */ - -#include -#include - -#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 listFiles(string dir, string ext); - static InstanceCleaner m_cleaner; }; @@ -227,83 +202,64 @@ void PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin) { - vector path = PluginHostAdapter::getPluginPath(); - string libraryName, identifier; + vector 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 files = listFiles(path[i], PLUGIN_SUFFIX); + for (size_t i = 0; i < fullPaths.size(); ++i) { - for (vector::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::iterator i = catpath.begin(); i != catpath.end(); ++i) { - vector files = listFiles(*i, suffix); + vector files = Files::listFiles(*i, suffix); for (vector::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 -PluginLoader::Impl::listFiles(string dir, string extension) -{ - vector 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); } diff -r 93683cf9fce3 -r 06988ce35ff0 src/vamp-hostsdk/host-c.cpp --- /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 + +#include "Files.h" + +#include +#include + +#include + +using namespace std; + +static vector files; +static map 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(library); + if (vhl) return vhl->nplugins; + else return 0; +} + +const VampPluginDescriptor *vhGetPluginDescriptor(vhLibrary library, + int plugin) +{ + vhLibrary_t *vhl = static_cast(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(library); + if (vhl && vhl->handle) { + Files::unloadLibrary(vhl->handle); + } + delete vhl; +} +