cannam@0: cannam@0:
cannam@0:00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@0: 00002 cannam@0: 00003 /* cannam@0: 00004 Vamp cannam@0: 00005 cannam@0: 00006 An API for audio analysis and feature extraction plugins. cannam@0: 00007 cannam@0: 00008 Centre for Digital Music, Queen Mary, University of London. cannam@0: 00009 Copyright 2006-2007 Chris Cannam and QMUL. cannam@0: 00010 cannam@0: 00011 Permission is hereby granted, free of charge, to any person cannam@0: 00012 obtaining a copy of this software and associated documentation cannam@0: 00013 files (the "Software"), to deal in the Software without cannam@0: 00014 restriction, including without limitation the rights to use, copy, cannam@0: 00015 modify, merge, publish, distribute, sublicense, and/or sell copies cannam@0: 00016 of the Software, and to permit persons to whom the Software is cannam@0: 00017 furnished to do so, subject to the following conditions: cannam@0: 00018 cannam@0: 00019 The above copyright notice and this permission notice shall be cannam@0: 00020 included in all copies or substantial portions of the Software. cannam@0: 00021 cannam@0: 00022 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, cannam@0: 00023 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF cannam@0: 00024 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND cannam@0: 00025 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR cannam@0: 00026 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF cannam@0: 00027 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION cannam@0: 00028 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cannam@0: 00029 cannam@0: 00030 Except as contained in this notice, the names of the Centre for cannam@0: 00031 Digital Music; Queen Mary, University of London; and Chris Cannam cannam@0: 00032 shall not be used in advertising or otherwise to promote the sale, cannam@0: 00033 use or other dealings in this Software without prior written cannam@0: 00034 authorization. cannam@0: 00035 */ cannam@0: 00036 cannam@0: 00037 #include "vamp-sdk/PluginHostAdapter.h" cannam@0: 00038 #include "PluginLoader.h" cannam@0: 00039 #include "PluginInputDomainAdapter.h" cannam@0: 00040 #include "PluginChannelAdapter.h" cannam@0: 00041 #include "PluginBufferingAdapter.h" cannam@0: 00042 cannam@0: 00043 #include <fstream> cannam@0: 00044 #include <cctype> // tolower cannam@0: 00045 cannam@0: 00046 #include <cstring> cannam@0: 00047 cannam@0: 00048 #ifdef _WIN32 cannam@0: 00049 cannam@0: 00050 #include <windows.h> cannam@0: 00051 #include <tchar.h> cannam@0: 00052 #define PLUGIN_SUFFIX "dll" cannam@0: 00053 cannam@0: 00054 #else /* ! _WIN32 */ cannam@0: 00055 cannam@0: 00056 #include <dirent.h> cannam@0: 00057 #include <dlfcn.h> cannam@0: 00058 cannam@0: 00059 #ifdef __APPLE__ cannam@0: 00060 #define PLUGIN_SUFFIX "dylib" cannam@0: 00061 #else /* ! __APPLE__ */ cannam@0: 00062 #define PLUGIN_SUFFIX "so" cannam@0: 00063 #endif /* ! __APPLE__ */ cannam@0: 00064 cannam@0: 00065 #endif /* ! _WIN32 */ cannam@0: 00066 cannam@0: 00067 using namespace std; cannam@0: 00068 cannam@0: 00069 namespace Vamp { cannam@0: 00070 cannam@0: 00071 namespace HostExt { cannam@0: 00072 cannam@0: 00073 class PluginLoader::Impl cannam@0: 00074 { cannam@0: 00075 public: cannam@0: 00076 Impl(); cannam@0: 00077 virtual ~Impl(); cannam@0: 00078 cannam@0: 00079 PluginKeyList listPlugins(); cannam@0: 00080 cannam@0: 00081 Plugin *loadPlugin(PluginKey key, cannam@0: 00082 float inputSampleRate, cannam@0: 00083 int adapterFlags); cannam@0: 00084 cannam@0: 00085 PluginKey composePluginKey(string libraryName, string identifier); cannam@0: 00086 cannam@0: 00087 PluginCategoryHierarchy getPluginCategory(PluginKey key); cannam@0: 00088 cannam@0: 00089 string getLibraryPathForPlugin(PluginKey key); cannam@0: 00090 cannam@0: 00091 static void setInstanceToClean(PluginLoader *instance); cannam@0: 00092 cannam@0: 00093 protected: cannam@0: 00094 class PluginDeletionNotifyAdapter : public PluginWrapper { cannam@0: 00095 public: cannam@0: 00096 PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader); cannam@0: 00097 virtual ~PluginDeletionNotifyAdapter(); cannam@0: 00098 protected: cannam@0: 00099 Impl *m_loader; cannam@0: 00100 }; cannam@0: 00101 cannam@0: 00102 class InstanceCleaner { cannam@0: 00103 public: cannam@0: 00104 InstanceCleaner() : m_instance(0) { } cannam@0: 00105 ~InstanceCleaner() { delete m_instance; } cannam@0: 00106 void setInstance(PluginLoader *instance) { m_instance = instance; } cannam@0: 00107 protected: cannam@0: 00108 PluginLoader *m_instance; cannam@0: 00109 }; cannam@0: 00110 cannam@0: 00111 virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter); cannam@0: 00112 cannam@0: 00113 map<PluginKey, string> m_pluginLibraryNameMap; cannam@0: 00114 bool m_allPluginsEnumerated; cannam@0: 00115 void enumeratePlugins(PluginKey forPlugin = ""); cannam@0: 00116 cannam@0: 00117 map<PluginKey, PluginCategoryHierarchy> m_taxonomy; cannam@0: 00118 void generateTaxonomy(); cannam@0: 00119 cannam@0: 00120 map<Plugin *, void *> m_pluginLibraryHandleMap; cannam@0: 00121 cannam@0: 00122 bool decomposePluginKey(PluginKey key, cannam@0: 00123 string &libraryName, string &identifier); cannam@0: 00124 cannam@0: 00125 void *loadLibrary(string path); cannam@0: 00126 void unloadLibrary(void *handle); cannam@0: 00127 void *lookupInLibrary(void *handle, const char *symbol); cannam@0: 00128 cannam@0: 00129 string splicePath(string a, string b); cannam@0: 00130 vector<string> listFiles(string dir, string ext); cannam@0: 00131 cannam@0: 00132 static InstanceCleaner m_cleaner; cannam@0: 00133 }; cannam@0: 00134 cannam@0: 00135 PluginLoader * cannam@0: 00136 PluginLoader::m_instance = 0; cannam@0: 00137 cannam@0: 00138 PluginLoader::Impl::InstanceCleaner cannam@0: 00139 PluginLoader::Impl::m_cleaner; cannam@0: 00140 cannam@0: 00141 PluginLoader::PluginLoader() cannam@0: 00142 { cannam@0: 00143 m_impl = new Impl(); cannam@0: 00144 } cannam@0: 00145 cannam@0: 00146 PluginLoader::~PluginLoader() cannam@0: 00147 { cannam@0: 00148 delete m_impl; cannam@0: 00149 } cannam@0: 00150 cannam@0: 00151 PluginLoader * cannam@0: 00152 PluginLoader::getInstance() cannam@0: 00153 { cannam@0: 00154 if (!m_instance) { cannam@0: 00155 // The cleaner doesn't own the instance, because we leave the cannam@0: 00156 // instance pointer in the base class for binary backwards cannam@0: 00157 // compatibility reasons and to avoid waste cannam@0: 00158 m_instance = new PluginLoader(); cannam@0: 00159 Impl::setInstanceToClean(m_instance); cannam@0: 00160 } cannam@0: 00161 return m_instance; cannam@0: 00162 } cannam@0: 00163 cannam@0: 00164 vector<PluginLoader::PluginKey> cannam@0: 00165 PluginLoader::listPlugins() cannam@0: 00166 { cannam@0: 00167 return m_impl->listPlugins(); cannam@0: 00168 } cannam@0: 00169 cannam@0: 00170 Plugin * cannam@0: 00171 PluginLoader::loadPlugin(PluginKey key, cannam@0: 00172 float inputSampleRate, cannam@0: 00173 int adapterFlags) cannam@0: 00174 { cannam@0: 00175 return m_impl->loadPlugin(key, inputSampleRate, adapterFlags); cannam@0: 00176 } cannam@0: 00177 cannam@0: 00178 PluginLoader::PluginKey cannam@0: 00179 PluginLoader::composePluginKey(string libraryName, string identifier) cannam@0: 00180 { cannam@0: 00181 return m_impl->composePluginKey(libraryName, identifier); cannam@0: 00182 } cannam@0: 00183 cannam@0: 00184 PluginLoader::PluginCategoryHierarchy cannam@0: 00185 PluginLoader::getPluginCategory(PluginKey key) cannam@0: 00186 { cannam@0: 00187 return m_impl->getPluginCategory(key); cannam@0: 00188 } cannam@0: 00189 cannam@0: 00190 string cannam@0: 00191 PluginLoader::getLibraryPathForPlugin(PluginKey key) cannam@0: 00192 { cannam@0: 00193 return m_impl->getLibraryPathForPlugin(key); cannam@0: 00194 } cannam@0: 00195 cannam@0: 00196 PluginLoader::Impl::Impl() : cannam@0: 00197 m_allPluginsEnumerated(false) cannam@0: 00198 { cannam@0: 00199 } cannam@0: 00200 cannam@0: 00201 PluginLoader::Impl::~Impl() cannam@0: 00202 { cannam@0: 00203 } cannam@0: 00204 cannam@0: 00205 void cannam@0: 00206 PluginLoader::Impl::setInstanceToClean(PluginLoader *instance) cannam@0: 00207 { cannam@0: 00208 m_cleaner.setInstance(instance); cannam@0: 00209 } cannam@0: 00210 cannam@0: 00211 vector<PluginLoader::PluginKey> cannam@0: 00212 PluginLoader::Impl::listPlugins() cannam@0: 00213 { cannam@0: 00214 if (!m_allPluginsEnumerated) enumeratePlugins(); cannam@0: 00215 cannam@0: 00216 vector<PluginKey> plugins; cannam@0: 00217 for (map<PluginKey, string>::iterator mi = m_pluginLibraryNameMap.begin(); cannam@0: 00218 mi != m_pluginLibraryNameMap.end(); ++mi) { cannam@0: 00219 plugins.push_back(mi->first); cannam@0: 00220 } cannam@0: 00221 cannam@0: 00222 return plugins; cannam@0: 00223 } cannam@0: 00224 cannam@0: 00225 void cannam@0: 00226 PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin) cannam@0: 00227 { cannam@0: 00228 vector<string> path = PluginHostAdapter::getPluginPath(); cannam@0: 00229 cannam@0: 00230 string libraryName, identifier; cannam@0: 00231 if (forPlugin != "") { cannam@0: 00232 if (!decomposePluginKey(forPlugin, libraryName, identifier)) { cannam@0: 00233 std::cerr << "WARNING: Vamp::HostExt::PluginLoader: Invalid plugin key \"" cannam@0: 00234 << forPlugin << "\" in enumerate" << std::endl; cannam@0: 00235 return; cannam@0: 00236 } cannam@0: 00237 } cannam@0: 00238 cannam@0: 00239 for (size_t i = 0; i < path.size(); ++i) { cannam@0: 00240 cannam@0: 00241 vector<string> files = listFiles(path[i], PLUGIN_SUFFIX); cannam@0: 00242 cannam@0: 00243 for (vector<string>::iterator fi = files.begin(); cannam@0: 00244 fi != files.end(); ++fi) { cannam@0: 00245 cannam@0: 00246 if (libraryName != "") { cannam@0: 00247 // libraryName is lowercased and lacking an extension, cannam@0: 00248 // as it came from the plugin key cannam@0: 00249 string temp = *fi; cannam@0: 00250 for (size_t i = 0; i < temp.length(); ++i) { cannam@0: 00251 temp[i] = tolower(temp[i]); cannam@0: 00252 } cannam@0: 00253 string::size_type pi = temp.find('.'); cannam@0: 00254 if (pi == string::npos) { cannam@0: 00255 if (libraryName != temp) continue; cannam@0: 00256 } else { cannam@0: 00257 if (libraryName != temp.substr(0, pi)) continue; cannam@0: 00258 } cannam@0: 00259 } cannam@0: 00260 cannam@0: 00261 string fullPath = path[i]; cannam@0: 00262 fullPath = splicePath(fullPath, *fi); cannam@0: 00263 void *handle = loadLibrary(fullPath); cannam@0: 00264 if (!handle) continue; cannam@0: 00265 cannam@0: 00266 VampGetPluginDescriptorFunction fn = cannam@0: 00267 (VampGetPluginDescriptorFunction)lookupInLibrary cannam@0: 00268 (handle, "vampGetPluginDescriptor"); cannam@0: 00269 cannam@0: 00270 if (!fn) { cannam@0: 00271 unloadLibrary(handle); cannam@0: 00272 continue; cannam@0: 00273 } cannam@0: 00274 cannam@0: 00275 int index = 0; cannam@0: 00276 const VampPluginDescriptor *descriptor = 0; cannam@0: 00277 cannam@0: 00278 while ((descriptor = fn(VAMP_API_VERSION, index))) { cannam@0: 00279 ++index; cannam@0: 00280 if (identifier != "") { cannam@0: 00281 if (descriptor->identifier != identifier) continue; cannam@0: 00282 } cannam@0: 00283 PluginKey key = composePluginKey(*fi, descriptor->identifier); cannam@0: 00284 // std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl; cannam@0: 00285 if (m_pluginLibraryNameMap.find(key) == cannam@0: 00286 m_pluginLibraryNameMap.end()) { cannam@0: 00287 m_pluginLibraryNameMap[key] = fullPath; cannam@0: 00288 } cannam@0: 00289 } cannam@0: 00290 cannam@0: 00291 unloadLibrary(handle); cannam@0: 00292 } cannam@0: 00293 } cannam@0: 00294 cannam@0: 00295 if (forPlugin == "") m_allPluginsEnumerated = true; cannam@0: 00296 } cannam@0: 00297 cannam@0: 00298 PluginLoader::PluginKey cannam@0: 00299 PluginLoader::Impl::composePluginKey(string libraryName, string identifier) cannam@0: 00300 { cannam@0: 00301 string basename = libraryName; cannam@0: 00302 cannam@0: 00303 string::size_type li = basename.rfind('/'); cannam@0: 00304 if (li != string::npos) basename = basename.substr(li + 1); cannam@0: 00305 cannam@0: 00306 li = basename.find('.'); cannam@0: 00307 if (li != string::npos) basename = basename.substr(0, li); cannam@0: 00308 cannam@0: 00309 for (size_t i = 0; i < basename.length(); ++i) { cannam@0: 00310 basename[i] = tolower(basename[i]); cannam@0: 00311 } cannam@0: 00312 cannam@0: 00313 return basename + ":" + identifier; cannam@0: 00314 } cannam@0: 00315 cannam@0: 00316 bool cannam@0: 00317 PluginLoader::Impl::decomposePluginKey(PluginKey key, cannam@0: 00318 string &libraryName, cannam@0: 00319 string &identifier) cannam@0: 00320 { cannam@0: 00321 string::size_type ki = key.find(':'); cannam@0: 00322 if (ki == string::npos) { cannam@0: 00323 return false; cannam@0: 00324 } cannam@0: 00325 cannam@0: 00326 libraryName = key.substr(0, ki); cannam@0: 00327 identifier = key.substr(ki + 1); cannam@0: 00328 return true; cannam@0: 00329 } cannam@0: 00330 cannam@0: 00331 PluginLoader::PluginCategoryHierarchy cannam@0: 00332 PluginLoader::Impl::getPluginCategory(PluginKey plugin) cannam@0: 00333 { cannam@0: 00334 if (m_taxonomy.empty()) generateTaxonomy(); cannam@0: 00335 if (m_taxonomy.find(plugin) == m_taxonomy.end()) { cannam@0: 00336 return PluginCategoryHierarchy(); cannam@0: 00337 } cannam@0: 00338 return m_taxonomy[plugin]; cannam@0: 00339 } cannam@0: 00340 cannam@0: 00341 string cannam@0: 00342 PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin) cannam@0: 00343 { cannam@0: 00344 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { cannam@0: 00345 if (m_allPluginsEnumerated) return ""; cannam@0: 00346 enumeratePlugins(plugin); cannam@0: 00347 } cannam@0: 00348 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) { cannam@0: 00349 return ""; cannam@0: 00350 } cannam@0: 00351 return m_pluginLibraryNameMap[plugin]; cannam@0: 00352 } cannam@0: 00353 cannam@0: 00354 Plugin * cannam@0: 00355 PluginLoader::Impl::loadPlugin(PluginKey key, cannam@0: 00356 float inputSampleRate, int adapterFlags) cannam@0: 00357 { cannam@0: 00358 string libname, identifier; cannam@0: 00359 if (!decomposePluginKey(key, libname, identifier)) { cannam@0: 00360 std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \"" cannam@0: 00361 << key << "\" in loadPlugin" << std::endl; cannam@0: 00362 return 0; cannam@0: 00363 } cannam@0: 00364 cannam@0: 00365 string fullPath = getLibraryPathForPlugin(key); cannam@0: 00366 if (fullPath == "") return 0; cannam@0: 00367 cannam@0: 00368 void *handle = loadLibrary(fullPath); cannam@0: 00369 if (!handle) return 0; cannam@0: 00370 cannam@0: 00371 VampGetPluginDescriptorFunction fn = cannam@0: 00372 (VampGetPluginDescriptorFunction)lookupInLibrary cannam@0: 00373 (handle, "vampGetPluginDescriptor"); cannam@0: 00374 cannam@0: 00375 if (!fn) { cannam@0: 00376 unloadLibrary(handle); cannam@0: 00377 return 0; cannam@0: 00378 } cannam@0: 00379 cannam@0: 00380 int index = 0; cannam@0: 00381 const VampPluginDescriptor *descriptor = 0; cannam@0: 00382 cannam@0: 00383 while ((descriptor = fn(VAMP_API_VERSION, index))) { cannam@0: 00384 cannam@0: 00385 if (string(descriptor->identifier) == identifier) { cannam@0: 00386 cannam@0: 00387 Vamp::PluginHostAdapter *plugin = cannam@0: 00388 new Vamp::PluginHostAdapter(descriptor, inputSampleRate); cannam@0: 00389 cannam@0: 00390 Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this); cannam@0: 00391 cannam@0: 00392 m_pluginLibraryHandleMap[adapter] = handle; cannam@0: 00393 cannam@0: 00394 if (adapterFlags & ADAPT_INPUT_DOMAIN) { cannam@0: 00395 if (adapter->getInputDomain() == Plugin::FrequencyDomain) { cannam@0: 00396 adapter = new PluginInputDomainAdapter(adapter); cannam@0: 00397 } cannam@0: 00398 } cannam@0: 00399 cannam@0: 00400 if (adapterFlags & ADAPT_BUFFER_SIZE) { cannam@0: 00401 adapter = new PluginBufferingAdapter(adapter); cannam@0: 00402 } cannam@0: 00403 cannam@0: 00404 if (adapterFlags & ADAPT_CHANNEL_COUNT) { cannam@0: 00405 adapter = new PluginChannelAdapter(adapter); cannam@0: 00406 } cannam@0: 00407 cannam@0: 00408 return adapter; cannam@0: 00409 } cannam@0: 00410 cannam@0: 00411 ++index; cannam@0: 00412 } cannam@0: 00413 cannam@0: 00414 cerr << "Vamp::HostExt::PluginLoader: Plugin \"" cannam@0: 00415 << identifier << "\" not found in library \"" cannam@0: 00416 << fullPath << "\"" << endl; cannam@0: 00417 cannam@0: 00418 return 0; cannam@0: 00419 } cannam@0: 00420 cannam@0: 00421 void cannam@0: 00422 PluginLoader::Impl::generateTaxonomy() cannam@0: 00423 { cannam@0: 00424 // cerr << "PluginLoader::Impl::generateTaxonomy" << endl; cannam@0: 00425 cannam@0: 00426 vector<string> path = PluginHostAdapter::getPluginPath(); cannam@0: 00427 string libfragment = "/lib/"; cannam@0: 00428 vector<string> catpath; cannam@0: 00429 cannam@0: 00430 string suffix = "cat"; cannam@0: 00431 cannam@0: 00432 for (vector<string>::iterator i = path.begin(); cannam@0: 00433 i != path.end(); ++i) { cannam@0: 00434 cannam@0: 00435 // It doesn't matter that we're using literal forward-slash in cannam@0: 00436 // this bit, as it's only relevant if the path contains cannam@0: 00437 // "/lib/", which is only meaningful and only plausible on cannam@0: 00438 // systems with forward-slash delimiters cannam@0: 00439 cannam@0: 00440 string dir = *i; cannam@0: 00441 string::size_type li = dir.find(libfragment); cannam@0: 00442 cannam@0: 00443 if (li != string::npos) { cannam@0: 00444 catpath.push_back cannam@0: 00445 (dir.substr(0, li) cannam@0: 00446 + "/share/" cannam@0: 00447 + dir.substr(li + libfragment.length())); cannam@0: 00448 } cannam@0: 00449 cannam@0: 00450 catpath.push_back(dir); cannam@0: 00451 } cannam@0: 00452 cannam@0: 00453 char buffer[1024]; cannam@0: 00454 cannam@0: 00455 for (vector<string>::iterator i = catpath.begin(); cannam@0: 00456 i != catpath.end(); ++i) { cannam@0: 00457 cannam@0: 00458 vector<string> files = listFiles(*i, suffix); cannam@0: 00459 cannam@0: 00460 for (vector<string>::iterator fi = files.begin(); cannam@0: 00461 fi != files.end(); ++fi) { cannam@0: 00462 cannam@0: 00463 string filepath = splicePath(*i, *fi); cannam@0: 00464 ifstream is(filepath.c_str(), ifstream::in | ifstream::binary); cannam@0: 00465 cannam@0: 00466 if (is.fail()) { cannam@0: 00467 // cerr << "failed to open: " << filepath << endl; cannam@0: 00468 continue; cannam@0: 00469 } cannam@0: 00470 cannam@0: 00471 // cerr << "opened: " << filepath << endl; cannam@0: 00472 cannam@0: 00473 while (!!is.getline(buffer, 1024)) { cannam@0: 00474 cannam@0: 00475 string line(buffer); cannam@0: 00476 cannam@0: 00477 // cerr << "line = " << line << endl; cannam@0: 00478 cannam@0: 00479 string::size_type di = line.find("::"); cannam@0: 00480 if (di == string::npos) continue; cannam@0: 00481 cannam@0: 00482 string id = line.substr(0, di); cannam@0: 00483 string encodedCat = line.substr(di + 2); cannam@0: 00484 cannam@0: 00485 if (id.substr(0, 5) != "vamp:") continue; cannam@0: 00486 id = id.substr(5); cannam@0: 00487 cannam@0: 00488 while (encodedCat.length() >= 1 && cannam@0: 00489 encodedCat[encodedCat.length()-1] == '\r') { cannam@0: 00490 encodedCat = encodedCat.substr(0, encodedCat.length()-1); cannam@0: 00491 } cannam@0: 00492 cannam@0: 00493 // cerr << "id = " << id << ", cat = " << encodedCat << endl; cannam@0: 00494 cannam@0: 00495 PluginCategoryHierarchy category; cannam@0: 00496 string::size_type ai; cannam@0: 00497 while ((ai = encodedCat.find(" > ")) != string::npos) { cannam@0: 00498 category.push_back(encodedCat.substr(0, ai)); cannam@0: 00499 encodedCat = encodedCat.substr(ai + 3); cannam@0: 00500 } cannam@0: 00501 if (encodedCat != "") category.push_back(encodedCat); cannam@0: 00502 cannam@0: 00503 m_taxonomy[id] = category; cannam@0: 00504 } cannam@0: 00505 } cannam@0: 00506 } cannam@0: 00507 } cannam@0: 00508 cannam@0: 00509 void * cannam@0: 00510 PluginLoader::Impl::loadLibrary(string path) cannam@0: 00511 { cannam@0: 00512 void *handle = 0; cannam@0: 00513 #ifdef _WIN32 cannam@0: 00514 handle = LoadLibrary(path.c_str()); cannam@0: 00515 if (!handle) { cannam@0: 00516 cerr << "Vamp::HostExt::PluginLoader: Unable to load library \"" cannam@0: 00517 << path << "\"" << endl; cannam@0: 00518 } cannam@0: 00519 #else cannam@0: 00520 handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); cannam@0: 00521 if (!handle) { cannam@0: 00522 cerr << "Vamp::HostExt::PluginLoader: Unable to load library \"" cannam@0: 00523 << path << "\": " << dlerror() << endl; cannam@0: 00524 } cannam@0: 00525 #endif cannam@0: 00526 return handle; cannam@0: 00527 } cannam@0: 00528 cannam@0: 00529 void cannam@0: 00530 PluginLoader::Impl::unloadLibrary(void *handle) cannam@0: 00531 { cannam@0: 00532 #ifdef _WIN32 cannam@0: 00533 FreeLibrary((HINSTANCE)handle); cannam@0: 00534 #else cannam@0: 00535 dlclose(handle); cannam@0: 00536 #endif cannam@0: 00537 } cannam@0: 00538 cannam@0: 00539 void * cannam@0: 00540 PluginLoader::Impl::lookupInLibrary(void *handle, const char *symbol) cannam@0: 00541 { cannam@0: 00542 #ifdef _WIN32 cannam@0: 00543 return (void *)GetProcAddress((HINSTANCE)handle, symbol); cannam@0: 00544 #else cannam@0: 00545 return (void *)dlsym(handle, symbol); cannam@0: 00546 #endif cannam@0: 00547 } cannam@0: 00548 cannam@0: 00549 string cannam@0: 00550 PluginLoader::Impl::splicePath(string a, string b) cannam@0: 00551 { cannam@0: 00552 #ifdef _WIN32 cannam@0: 00553 return a + "\\" + b; cannam@0: 00554 #else cannam@0: 00555 return a + "/" + b; cannam@0: 00556 #endif cannam@0: 00557 } cannam@0: 00558 cannam@0: 00559 vector<string> cannam@0: 00560 PluginLoader::Impl::listFiles(string dir, string extension) cannam@0: 00561 { cannam@0: 00562 vector<string> files; cannam@0: 00563 cannam@0: 00564 #ifdef _WIN32 cannam@0: 00565 cannam@0: 00566 string expression = dir + "\\*." + extension; cannam@0: 00567 WIN32_FIND_DATA data; cannam@0: 00568 HANDLE fh = FindFirstFile(expression.c_str(), &data); cannam@0: 00569 if (fh == INVALID_HANDLE_VALUE) return files; cannam@0: 00570 cannam@0: 00571 bool ok = true; cannam@0: 00572 while (ok) { cannam@0: 00573 files.push_back(data.cFileName); cannam@0: 00574 ok = FindNextFile(fh, &data); cannam@0: 00575 } cannam@0: 00576 cannam@0: 00577 FindClose(fh); cannam@0: 00578 cannam@0: 00579 #else cannam@0: 00580 cannam@0: 00581 size_t extlen = extension.length(); cannam@0: 00582 DIR *d = opendir(dir.c_str()); cannam@0: 00583 if (!d) return files; cannam@0: 00584 cannam@0: 00585 struct dirent *e = 0; cannam@0: 00586 while ((e = readdir(d))) { cannam@0: 00587 cannam@0: 00588 if (!e->d_name) continue; cannam@0: 00589 cannam@0: 00590 size_t len = strlen(e->d_name); cannam@0: 00591 if (len < extlen + 2 || cannam@0: 00592 e->d_name + len - extlen - 1 != "." + extension) { cannam@0: 00593 continue; cannam@0: 00594 } cannam@0: 00595 cannam@0: 00596 files.push_back(e->d_name); cannam@0: 00597 } cannam@0: 00598 cannam@0: 00599 closedir(d); cannam@0: 00600 #endif cannam@0: 00601 cannam@0: 00602 return files; cannam@0: 00603 } cannam@0: 00604 cannam@0: 00605 void cannam@0: 00606 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter) cannam@0: 00607 { cannam@0: 00608 void *handle = m_pluginLibraryHandleMap[adapter]; cannam@0: 00609 if (handle) unloadLibrary(handle); cannam@0: 00610 m_pluginLibraryHandleMap.erase(adapter); cannam@0: 00611 } cannam@0: 00612 cannam@0: 00613 PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin, cannam@0: 00614 Impl *loader) : cannam@0: 00615 PluginWrapper(plugin), cannam@0: 00616 m_loader(loader) cannam@0: 00617 { cannam@0: 00618 } cannam@0: 00619 cannam@0: 00620 PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter() cannam@0: 00621 { cannam@0: 00622 // We need to delete the plugin before calling pluginDeleted, as cannam@0: 00623 // the delete call may require calling through to the descriptor cannam@0: 00624 // (for e.g. cleanup) but pluginDeleted may unload the required cannam@0: 00625 // library for the call. To prevent a double deletion when our cannam@0: 00626 // parent's destructor runs (after this one), be sure to set cannam@0: 00627 // m_plugin to 0 after deletion. cannam@0: 00628 delete m_plugin; cannam@0: 00629 m_plugin = 0; cannam@0: 00630 cannam@0: 00631 if (m_loader) m_loader->pluginDeleted(this); cannam@0: 00632 } cannam@0: 00633 cannam@0: 00634 } cannam@0: 00635 cannam@0: 00636 } cannam@0: