cannam@56: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@56: cannam@56: /* cannam@56: Vamp cannam@56: cannam@56: An API for audio analysis and feature extraction plugins. cannam@56: cannam@56: Centre for Digital Music, Queen Mary, University of London. cannam@56: Copyright 2006 Chris Cannam. cannam@56: cannam@56: Permission is hereby granted, free of charge, to any person cannam@56: obtaining a copy of this software and associated documentation cannam@56: files (the "Software"), to deal in the Software without cannam@56: restriction, including without limitation the rights to use, copy, cannam@56: modify, merge, publish, distribute, sublicense, and/or sell copies cannam@56: of the Software, and to permit persons to whom the Software is cannam@56: furnished to do so, subject to the following conditions: cannam@56: cannam@56: The above copyright notice and this permission notice shall be cannam@56: included in all copies or substantial portions of the Software. cannam@56: cannam@56: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, cannam@56: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF cannam@56: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND cannam@56: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR cannam@56: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF cannam@56: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION cannam@56: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cannam@56: cannam@56: Except as contained in this notice, the names of the Centre for cannam@56: Digital Music; Queen Mary, University of London; and Chris Cannam cannam@56: shall not be used in advertising or otherwise to promote the sale, cannam@56: use or other dealings in this Software without prior written cannam@56: authorization. cannam@56: */ cannam@56: cannam@56: #include "PluginLoader.h" cannam@56: #include "PluginHostAdapter.h" cannam@56: cannam@56: #include "system.h" cannam@56: cannam@56: #include // POSIX directory open and read cannam@56: cannam@56: namespace Vamp { cannam@56: cannam@56: PluginLoader::PluginLoader() cannam@56: { cannam@56: } cannam@56: cannam@56: PluginLoader::~PluginLoader() cannam@56: { cannam@56: } cannam@56: cannam@56: std::vector cannam@56: PluginLoader::listPlugins() cannam@56: { cannam@56: if (m_pluginLibraryMap.empty()) { cannam@56: cannam@56: std::vector path = PluginHostAdapter::getPluginPath(); cannam@56: cannam@56: size_t suffixLen = strlen(PLUGIN_SUFFIX); cannam@56: cannam@56: for (size_t i = 0; i < path.size(); ++i) { cannam@56: cannam@56: DIR *d = opendir(path[i].c_str()); cannam@56: if (!d) { cannam@56: // perror("Failed to open directory"); cannam@56: continue; cannam@56: } cannam@56: cannam@56: struct dirent *e = 0; cannam@56: while ((e = readdir(d))) { cannam@56: cannam@56: if (!(e->d_type & DT_REG) || !e->d_name) { cannam@56: continue; cannam@56: } cannam@56: cannam@56: int len = strlen(e->d_name); cannam@56: if (len < int(suffixLen + 2) || cannam@56: e->d_name[len - suffixLen - 1] != '.' || cannam@56: strcmp(e->d_name + len - suffixLen, PLUGIN_SUFFIX)) { cannam@56: continue; cannam@56: } cannam@56: cannam@56: std::string basename = e->d_name; cannam@56: basename = basename.substr(0, basename.length() - suffixLen - 1); cannam@56: std::string fullPath = path[i].c_str(); cannam@56: fullPath = fullPath + "/" + e->d_name; cannam@56: void *handle = DLOPEN(fullPath, RTLD_LAZY); cannam@56: cannam@56: if (!handle) { cannam@56: std::cerr << "Vamp::PluginLoader: " << e->d_name cannam@56: << ": unable to load library (" << DLERROR() cannam@56: << ")" << std::endl; cannam@56: continue; cannam@56: } cannam@56: cannam@56: VampGetPluginDescriptorFunction fn = cannam@56: (VampGetPluginDescriptorFunction)DLSYM cannam@56: (handle, "vampGetPluginDescriptor"); cannam@56: cannam@56: if (!fn) { cannam@56: DLCLOSE(handle); cannam@56: continue; cannam@56: } cannam@56: cannam@56: int index = 0; cannam@56: const VampPluginDescriptor *descriptor = 0; cannam@56: cannam@56: while ((descriptor = fn(VAMP_API_VERSION, index))) { cannam@56: PluginKey key = basename + ":" + descriptor->identifier; cannam@56: if (m_pluginLibraryMap.find(key) == cannam@56: m_pluginLibraryMap.end()) { cannam@56: m_pluginLibraryMap[key] = fullPath; cannam@56: } cannam@56: ++index; cannam@56: } cannam@56: cannam@56: DLCLOSE(handle); cannam@56: } cannam@56: cannam@56: closedir(d); cannam@56: } cannam@56: } cannam@56: cannam@56: std::vector plugins; cannam@56: for (std::map::iterator mi = cannam@56: m_pluginLibraryMap.begin(); cannam@56: mi != m_pluginLibraryMap.end(); ++mi) { cannam@56: plugins.push_back(mi->first); cannam@56: } cannam@56: cannam@56: return plugins; cannam@56: } cannam@56: cannam@56: std::string cannam@56: PluginLoader::getLibraryPath(PluginKey key) cannam@56: { cannam@56: if (m_pluginLibraryMap.empty()) (void)listPlugins(); cannam@56: if (m_pluginLibraryMap.find(key) == m_pluginLibraryMap.end()) return ""; cannam@56: return m_pluginLibraryMap[key]; cannam@56: } cannam@56: cannam@56: Plugin * cannam@56: PluginLoader::load(PluginKey key, float inputSampleRate) cannam@56: { cannam@56: std::string fullPath = getLibraryPath(key); cannam@56: if (fullPath == "") return 0; cannam@56: cannam@56: std::string::size_type ki = key.find(':'); cannam@56: if (ki == std::string::npos) { cannam@56: //!!! flag error cannam@56: return 0; cannam@56: } cannam@56: cannam@56: std::string identifier = key.substr(ki + 1); cannam@56: cannam@56: void *handle = DLOPEN(fullPath, RTLD_LAZY); cannam@56: cannam@56: if (!handle) { cannam@56: std::cerr << "Vamp::PluginLoader: " << fullPath cannam@56: << ": unable to load library (" << DLERROR() cannam@56: << ")" << std::endl; cannam@56: return 0; cannam@56: } cannam@56: cannam@56: VampGetPluginDescriptorFunction fn = cannam@56: (VampGetPluginDescriptorFunction)DLSYM cannam@56: (handle, "vampGetPluginDescriptor"); cannam@56: cannam@56: if (!fn) { cannam@56: //!!! refcount this! --!!! no, POSIX says dlopen/dlclose will cannam@56: // reference count. check on win32 cannam@56: DLCLOSE(handle); cannam@56: return 0; cannam@56: } cannam@56: cannam@56: int index = 0; cannam@56: const VampPluginDescriptor *descriptor = 0; cannam@56: cannam@56: while ((descriptor = fn(VAMP_API_VERSION, index))) { cannam@56: if (std::string(descriptor->identifier) == identifier) { cannam@56: return new Vamp::PluginHostAdapter(descriptor, inputSampleRate); cannam@56: } cannam@56: ++index; cannam@56: } cannam@56: cannam@56: //!!! flag error cannam@56: return 0; cannam@56: } cannam@56: cannam@56: } cannam@56: