annotate src/vamp-hostsdk/PluginLoader.cpp @ 541:0e32c328b02a tip

Added tag vamp-plugin-sdk-v2.10 for changeset fa74c473e48c
author Chris Cannam
date Mon, 18 May 2020 11:53:49 +0100
parents 762b79b49c31
children
rev   line source
cannam@233 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@233 2
cannam@233 3 /*
cannam@233 4 Vamp
cannam@233 5
cannam@233 6 An API for audio analysis and feature extraction plugins.
cannam@233 7
cannam@233 8 Centre for Digital Music, Queen Mary, University of London.
Chris@423 9 Copyright 2006-2016 Chris Cannam and QMUL.
cannam@233 10
cannam@233 11 Permission is hereby granted, free of charge, to any person
cannam@233 12 obtaining a copy of this software and associated documentation
cannam@233 13 files (the "Software"), to deal in the Software without
cannam@233 14 restriction, including without limitation the rights to use, copy,
cannam@233 15 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@233 16 of the Software, and to permit persons to whom the Software is
cannam@233 17 furnished to do so, subject to the following conditions:
cannam@233 18
cannam@233 19 The above copyright notice and this permission notice shall be
cannam@233 20 included in all copies or substantial portions of the Software.
cannam@233 21
cannam@233 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@233 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@233 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@233 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@233 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@233 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@233 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@233 29
cannam@233 30 Except as contained in this notice, the names of the Centre for
cannam@233 31 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@233 32 shall not be used in advertising or otherwise to promote the sale,
cannam@233 33 use or other dealings in this Software without prior written
cannam@233 34 authorization.
cannam@233 35 */
cannam@233 36
cannam@233 37 #include <vamp-hostsdk/PluginLoader.h>
cannam@233 38 #include <vamp-hostsdk/PluginInputDomainAdapter.h>
cannam@233 39 #include <vamp-hostsdk/PluginChannelAdapter.h>
cannam@233 40 #include <vamp-hostsdk/PluginBufferingAdapter.h>
Chris@390 41 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@390 42
Chris@390 43 #include <vamp/vamp.h>
Chris@390 44
Chris@390 45 #include "Files.h"
cannam@233 46
cannam@233 47 #include <fstream>
cannam@233 48
cannam@233 49 using namespace std;
cannam@233 50
cannam@263 51 _VAMP_SDK_HOSTSPACE_BEGIN(PluginLoader.cpp)
cannam@263 52
cannam@233 53 namespace Vamp {
cannam@233 54
cannam@233 55 namespace HostExt {
cannam@233 56
cannam@233 57 class PluginLoader::Impl
cannam@233 58 {
cannam@233 59 public:
cannam@233 60 Impl();
cannam@233 61 virtual ~Impl();
cannam@233 62
cannam@233 63 PluginKeyList listPlugins();
Chris@473 64 PluginKeyList listPluginsIn(vector<string>);
Chris@473 65 PluginKeyList listPluginsNotIn(vector<string>);
Chris@456 66
cannam@233 67 Plugin *loadPlugin(PluginKey key,
cannam@233 68 float inputSampleRate,
cannam@233 69 int adapterFlags);
Chris@423 70
cannam@233 71 PluginKey composePluginKey(string libraryName, string identifier);
cannam@233 72
cannam@233 73 PluginCategoryHierarchy getPluginCategory(PluginKey key);
cannam@233 74
cannam@233 75 string getLibraryPathForPlugin(PluginKey key);
cannam@233 76
cannam@233 77 static void setInstanceToClean(PluginLoader *instance);
cannam@233 78
cannam@233 79 protected:
cannam@233 80 class PluginDeletionNotifyAdapter : public PluginWrapper {
cannam@233 81 public:
cannam@233 82 PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
cannam@233 83 virtual ~PluginDeletionNotifyAdapter();
cannam@233 84 protected:
cannam@233 85 Impl *m_loader;
cannam@233 86 };
cannam@233 87
cannam@233 88 class InstanceCleaner {
cannam@233 89 public:
cannam@233 90 InstanceCleaner() : m_instance(0) { }
cannam@233 91 ~InstanceCleaner() { delete m_instance; }
cannam@233 92 void setInstance(PluginLoader *instance) { m_instance = instance; }
cannam@233 93 protected:
cannam@233 94 PluginLoader *m_instance;
cannam@233 95 };
cannam@233 96
cannam@233 97 virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
cannam@233 98
cannam@233 99 map<PluginKey, string> m_pluginLibraryNameMap;
cannam@233 100 bool m_allPluginsEnumerated;
Chris@473 101
Chris@473 102 struct Enumeration {
Chris@473 103 enum { All, SinglePlugin, InLibraries, NotInLibraries } type;
Chris@473 104 PluginKey key;
Chris@473 105 vector<string> libraryNames;
Chris@473 106 Enumeration() : type(All) { }
Chris@473 107 };
Chris@473 108 vector<string> listLibraryFilesFor(Enumeration);
Chris@473 109
Chris@473 110 /// Populate m_pluginLibraryNameMap and return a list of the keys
Chris@473 111 /// that were added to it
Chris@473 112 vector<PluginKey> enumeratePlugins(Enumeration);
cannam@233 113
cannam@233 114 map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
cannam@233 115 void generateTaxonomy();
cannam@233 116
cannam@233 117 map<Plugin *, void *> m_pluginLibraryHandleMap;
cannam@233 118
cannam@233 119 bool decomposePluginKey(PluginKey key,
cannam@233 120 string &libraryName, string &identifier);
cannam@233 121
cannam@233 122 static InstanceCleaner m_cleaner;
cannam@233 123 };
cannam@233 124
cannam@233 125 PluginLoader *
cannam@233 126 PluginLoader::m_instance = 0;
cannam@233 127
cannam@233 128 PluginLoader::Impl::InstanceCleaner
cannam@233 129 PluginLoader::Impl::m_cleaner;
cannam@233 130
cannam@233 131 PluginLoader::PluginLoader()
cannam@233 132 {
cannam@233 133 m_impl = new Impl();
cannam@233 134 }
cannam@233 135
cannam@233 136 PluginLoader::~PluginLoader()
cannam@233 137 {
cannam@233 138 delete m_impl;
cannam@233 139 }
cannam@233 140
cannam@233 141 PluginLoader *
cannam@233 142 PluginLoader::getInstance()
cannam@233 143 {
cannam@233 144 if (!m_instance) {
cannam@233 145 // The cleaner doesn't own the instance, because we leave the
cannam@233 146 // instance pointer in the base class for binary backwards
cannam@233 147 // compatibility reasons and to avoid waste
cannam@233 148 m_instance = new PluginLoader();
cannam@233 149 Impl::setInstanceToClean(m_instance);
cannam@233 150 }
cannam@233 151 return m_instance;
cannam@233 152 }
cannam@233 153
Chris@426 154 PluginLoader::PluginKeyList
cannam@233 155 PluginLoader::listPlugins()
cannam@233 156 {
cannam@233 157 return m_impl->listPlugins();
cannam@233 158 }
cannam@233 159
Chris@473 160 PluginLoader::PluginKeyList
Chris@473 161 PluginLoader::listPluginsIn(vector<string> libs)
Chris@473 162 {
Chris@473 163 return m_impl->listPluginsIn(libs);
Chris@473 164 }
Chris@473 165
Chris@473 166 PluginLoader::PluginKeyList
Chris@473 167 PluginLoader::listPluginsNotIn(vector<string> libs)
Chris@473 168 {
Chris@473 169 return m_impl->listPluginsNotIn(libs);
Chris@473 170 }
Chris@473 171
cannam@233 172 Plugin *
cannam@233 173 PluginLoader::loadPlugin(PluginKey key,
cannam@233 174 float inputSampleRate,
cannam@233 175 int adapterFlags)
cannam@233 176 {
cannam@233 177 return m_impl->loadPlugin(key, inputSampleRate, adapterFlags);
cannam@233 178 }
cannam@233 179
cannam@233 180 PluginLoader::PluginKey
cannam@233 181 PluginLoader::composePluginKey(string libraryName, string identifier)
cannam@233 182 {
cannam@233 183 return m_impl->composePluginKey(libraryName, identifier);
cannam@233 184 }
cannam@233 185
cannam@233 186 PluginLoader::PluginCategoryHierarchy
cannam@233 187 PluginLoader::getPluginCategory(PluginKey key)
cannam@233 188 {
cannam@233 189 return m_impl->getPluginCategory(key);
cannam@233 190 }
cannam@233 191
cannam@233 192 string
cannam@233 193 PluginLoader::getLibraryPathForPlugin(PluginKey key)
cannam@233 194 {
cannam@233 195 return m_impl->getLibraryPathForPlugin(key);
cannam@233 196 }
cannam@233 197
cannam@233 198 PluginLoader::Impl::Impl() :
cannam@233 199 m_allPluginsEnumerated(false)
cannam@233 200 {
cannam@233 201 }
cannam@233 202
cannam@233 203 PluginLoader::Impl::~Impl()
cannam@233 204 {
cannam@233 205 }
cannam@233 206
cannam@233 207 void
cannam@233 208 PluginLoader::Impl::setInstanceToClean(PluginLoader *instance)
cannam@233 209 {
cannam@233 210 m_cleaner.setInstance(instance);
cannam@233 211 }
cannam@233 212
Chris@426 213 PluginLoader::PluginKeyList
cannam@233 214 PluginLoader::Impl::listPlugins()
cannam@233 215 {
Chris@477 216 if (!m_allPluginsEnumerated) enumeratePlugins(Enumeration());
cannam@233 217
cannam@233 218 vector<PluginKey> plugins;
Chris@477 219 for (map<PluginKey, string>::const_iterator i =
Chris@477 220 m_pluginLibraryNameMap.begin();
Chris@477 221 i != m_pluginLibraryNameMap.end(); ++i) {
Chris@477 222 plugins.push_back(i->first);
cannam@233 223 }
cannam@233 224
cannam@233 225 return plugins;
cannam@233 226 }
cannam@233 227
Chris@473 228 PluginLoader::PluginKeyList
Chris@473 229 PluginLoader::Impl::listPluginsIn(vector<string> libs)
Chris@473 230 {
Chris@473 231 Enumeration enumeration;
Chris@473 232 enumeration.type = Enumeration::InLibraries;
Chris@473 233 enumeration.libraryNames = libs;
Chris@473 234 return enumeratePlugins(enumeration);
Chris@473 235 }
Chris@473 236
Chris@473 237 PluginLoader::PluginKeyList
Chris@473 238 PluginLoader::Impl::listPluginsNotIn(vector<string> libs)
Chris@473 239 {
Chris@473 240 Enumeration enumeration;
Chris@473 241 enumeration.type = Enumeration::NotInLibraries;
Chris@473 242 enumeration.libraryNames = libs;
Chris@473 243 return enumeratePlugins(enumeration);
Chris@473 244 }
Chris@473 245
Chris@473 246 vector<string>
Chris@473 247 PluginLoader::Impl::listLibraryFilesFor(Enumeration enumeration)
Chris@473 248 {
Chris@473 249 Files::Filter filter;
Chris@473 250
Chris@473 251 switch (enumeration.type) {
Chris@473 252
Chris@473 253 case Enumeration::All:
Chris@473 254 filter.type = Files::Filter::All;
Chris@473 255 break;
Chris@473 256
Chris@473 257 case Enumeration::SinglePlugin:
Chris@473 258 {
Chris@473 259 string libraryName, identifier;
Chris@473 260 if (!decomposePluginKey(enumeration.key, libraryName, identifier)) {
Chris@473 261 std::cerr << "WARNING: Vamp::HostExt::PluginLoader: "
Chris@473 262 << "Invalid plugin key \"" << enumeration.key
Chris@473 263 << "\" in enumerate" << std::endl;
Chris@477 264 return vector<string>();
Chris@473 265 }
Chris@473 266 filter.type = Files::Filter::Matching;
Chris@477 267 filter.libraryNames.clear();
Chris@477 268 filter.libraryNames.push_back(libraryName);
Chris@473 269 break;
Chris@473 270 }
Chris@473 271
Chris@473 272 case Enumeration::InLibraries:
Chris@473 273 filter.type = Files::Filter::Matching;
Chris@473 274 filter.libraryNames = enumeration.libraryNames;
Chris@473 275 break;
Chris@473 276
Chris@473 277 case Enumeration::NotInLibraries:
Chris@473 278 filter.type = Files::Filter::NotMatching;
Chris@473 279 filter.libraryNames = enumeration.libraryNames;
Chris@473 280 break;
Chris@473 281 }
Chris@473 282
Chris@473 283 return Files::listLibraryFilesMatching(filter);
Chris@473 284 }
Chris@473 285
Chris@473 286 vector<PluginLoader::PluginKey>
Chris@473 287 PluginLoader::Impl::enumeratePlugins(Enumeration enumeration)
cannam@233 288 {
cannam@233 289 string libraryName, identifier;
Chris@473 290 if (enumeration.type == Enumeration::SinglePlugin) {
Chris@473 291 decomposePluginKey(enumeration.key, libraryName, identifier);
Chris@473 292 }
Chris@390 293
Chris@473 294 vector<string> fullPaths = listLibraryFilesFor(enumeration);
cannam@233 295
Chris@473 296 // For these we should warn if a plugin can be loaded from a library
Chris@473 297 bool specific = (enumeration.type == Enumeration::SinglePlugin ||
Chris@473 298 enumeration.type == Enumeration::InLibraries);
Chris@473 299
Chris@473 300 vector<PluginKey> added;
Chris@473 301
Chris@390 302 for (size_t i = 0; i < fullPaths.size(); ++i) {
cannam@233 303
Chris@390 304 string fullPath = fullPaths[i];
Chris@390 305 void *handle = Files::loadLibrary(fullPath);
Chris@390 306 if (!handle) continue;
cannam@233 307
Chris@390 308 VampGetPluginDescriptorFunction fn =
Chris@390 309 (VampGetPluginDescriptorFunction)Files::lookupInLibrary
Chris@390 310 (handle, "vampGetPluginDescriptor");
cannam@233 311
Chris@390 312 if (!fn) {
Chris@473 313 if (specific) {
Chris@473 314 cerr << "Vamp::HostExt::PluginLoader: "
Chris@473 315 << "No vampGetPluginDescriptor function found in library \""
cannam@295 316 << fullPath << "\"" << endl;
cannam@295 317 }
Chris@390 318 Files::unloadLibrary(handle);
Chris@390 319 continue;
Chris@390 320 }
cannam@233 321
Chris@390 322 int index = 0;
Chris@390 323 const VampPluginDescriptor *descriptor = 0;
Chris@390 324 bool found = false;
Chris@390 325
Chris@390 326 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@390 327 ++index;
Chris@390 328 if (identifier != "") {
Chris@473 329 if (descriptor->identifier != identifier) {
Chris@473 330 continue;
Chris@473 331 }
Chris@390 332 }
Chris@390 333 found = true;
Chris@390 334 PluginKey key = composePluginKey(fullPath, descriptor->identifier);
Chris@390 335 if (m_pluginLibraryNameMap.find(key) ==
Chris@390 336 m_pluginLibraryNameMap.end()) {
Chris@390 337 m_pluginLibraryNameMap[key] = fullPath;
Chris@390 338 }
Chris@473 339 added.push_back(key);
cannam@233 340 }
Chris@390 341
Chris@473 342 if (!found && specific) {
Chris@390 343 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
Chris@390 344 << identifier << "\" not found in library \""
Chris@390 345 << fullPath << "\"" << endl;
Chris@390 346 }
Chris@390 347
Chris@390 348 Files::unloadLibrary(handle);
cannam@233 349 }
cannam@233 350
Chris@473 351 if (enumeration.type == Enumeration::All) {
Chris@473 352 m_allPluginsEnumerated = true;
Chris@473 353 }
Chris@473 354
Chris@473 355 return added;
cannam@233 356 }
cannam@233 357
cannam@233 358 PluginLoader::PluginKey
cannam@233 359 PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
cannam@233 360 {
Chris@390 361 string basename = Files::lcBasename(libraryName);
cannam@233 362 return basename + ":" + identifier;
cannam@233 363 }
cannam@233 364
cannam@233 365 bool
cannam@233 366 PluginLoader::Impl::decomposePluginKey(PluginKey key,
cannam@233 367 string &libraryName,
cannam@233 368 string &identifier)
cannam@233 369 {
cannam@233 370 string::size_type ki = key.find(':');
cannam@233 371 if (ki == string::npos) {
cannam@233 372 return false;
cannam@233 373 }
cannam@233 374
cannam@233 375 libraryName = key.substr(0, ki);
cannam@233 376 identifier = key.substr(ki + 1);
cannam@233 377 return true;
cannam@233 378 }
cannam@233 379
cannam@233 380 PluginLoader::PluginCategoryHierarchy
cannam@233 381 PluginLoader::Impl::getPluginCategory(PluginKey plugin)
cannam@233 382 {
cannam@233 383 if (m_taxonomy.empty()) generateTaxonomy();
cannam@233 384 if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
cannam@233 385 return PluginCategoryHierarchy();
cannam@233 386 }
cannam@233 387 return m_taxonomy[plugin];
cannam@233 388 }
cannam@233 389
cannam@233 390 string
cannam@233 391 PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
cannam@233 392 {
cannam@233 393 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@233 394 if (m_allPluginsEnumerated) return "";
Chris@473 395 Enumeration enumeration;
Chris@473 396 enumeration.type = Enumeration::SinglePlugin;
Chris@473 397 enumeration.key = plugin;
Chris@473 398 enumeratePlugins(enumeration);
cannam@233 399 }
cannam@233 400 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@233 401 return "";
cannam@233 402 }
cannam@233 403 return m_pluginLibraryNameMap[plugin];
cannam@233 404 }
cannam@233 405
cannam@233 406 Plugin *
cannam@233 407 PluginLoader::Impl::loadPlugin(PluginKey key,
cannam@233 408 float inputSampleRate, int adapterFlags)
cannam@233 409 {
cannam@233 410 string libname, identifier;
cannam@233 411 if (!decomposePluginKey(key, libname, identifier)) {
cannam@233 412 std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \""
cannam@233 413 << key << "\" in loadPlugin" << std::endl;
cannam@233 414 return 0;
cannam@233 415 }
cannam@233 416
cannam@233 417 string fullPath = getLibraryPathForPlugin(key);
cannam@293 418 if (fullPath == "") {
cannam@295 419 std::cerr << "Vamp::HostExt::PluginLoader: No library found in Vamp path for plugin \"" << key << "\"" << std::endl;
cannam@293 420 return 0;
cannam@293 421 }
cannam@233 422
Chris@390 423 void *handle = Files::loadLibrary(fullPath);
cannam@233 424 if (!handle) return 0;
cannam@233 425
cannam@233 426 VampGetPluginDescriptorFunction fn =
Chris@390 427 (VampGetPluginDescriptorFunction)Files::lookupInLibrary
cannam@233 428 (handle, "vampGetPluginDescriptor");
cannam@233 429
cannam@233 430 if (!fn) {
cannam@293 431 cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
cannam@293 432 << fullPath << "\"" << endl;
Chris@390 433 Files::unloadLibrary(handle);
cannam@233 434 return 0;
cannam@233 435 }
cannam@233 436
cannam@233 437 int index = 0;
cannam@233 438 const VampPluginDescriptor *descriptor = 0;
cannam@233 439
cannam@233 440 while ((descriptor = fn(VAMP_API_VERSION, index))) {
cannam@233 441
cannam@233 442 if (string(descriptor->identifier) == identifier) {
cannam@233 443
cannam@233 444 Vamp::PluginHostAdapter *plugin =
cannam@233 445 new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
cannam@233 446
cannam@233 447 Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
cannam@233 448
cannam@233 449 m_pluginLibraryHandleMap[adapter] = handle;
cannam@233 450
cannam@233 451 if (adapterFlags & ADAPT_INPUT_DOMAIN) {
cannam@233 452 if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
cannam@233 453 adapter = new PluginInputDomainAdapter(adapter);
cannam@233 454 }
cannam@233 455 }
cannam@233 456
cannam@233 457 if (adapterFlags & ADAPT_BUFFER_SIZE) {
cannam@233 458 adapter = new PluginBufferingAdapter(adapter);
cannam@233 459 }
cannam@233 460
cannam@233 461 if (adapterFlags & ADAPT_CHANNEL_COUNT) {
cannam@233 462 adapter = new PluginChannelAdapter(adapter);
cannam@233 463 }
cannam@233 464
cannam@233 465 return adapter;
cannam@233 466 }
cannam@233 467
cannam@233 468 ++index;
cannam@233 469 }
cannam@233 470
cannam@233 471 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
cannam@233 472 << identifier << "\" not found in library \""
cannam@233 473 << fullPath << "\"" << endl;
cannam@233 474
cannam@233 475 return 0;
cannam@233 476 }
cannam@233 477
cannam@233 478 void
cannam@233 479 PluginLoader::Impl::generateTaxonomy()
cannam@233 480 {
cannam@233 481 // cerr << "PluginLoader::Impl::generateTaxonomy" << endl;
cannam@233 482
cannam@233 483 vector<string> path = PluginHostAdapter::getPluginPath();
cannam@233 484 string libfragment = "/lib/";
cannam@233 485 vector<string> catpath;
cannam@233 486
cannam@233 487 string suffix = "cat";
cannam@233 488
cannam@233 489 for (vector<string>::iterator i = path.begin();
cannam@233 490 i != path.end(); ++i) {
cannam@233 491
cannam@233 492 // It doesn't matter that we're using literal forward-slash in
cannam@233 493 // this bit, as it's only relevant if the path contains
cannam@233 494 // "/lib/", which is only meaningful and only plausible on
cannam@233 495 // systems with forward-slash delimiters
cannam@233 496
cannam@233 497 string dir = *i;
cannam@233 498 string::size_type li = dir.find(libfragment);
cannam@233 499
cannam@233 500 if (li != string::npos) {
cannam@233 501 catpath.push_back
cannam@233 502 (dir.substr(0, li)
cannam@233 503 + "/share/"
cannam@233 504 + dir.substr(li + libfragment.length()));
cannam@233 505 }
cannam@233 506
cannam@233 507 catpath.push_back(dir);
cannam@233 508 }
cannam@233 509
cannam@233 510 char buffer[1024];
cannam@233 511
cannam@233 512 for (vector<string>::iterator i = catpath.begin();
cannam@233 513 i != catpath.end(); ++i) {
cannam@233 514
Chris@390 515 vector<string> files = Files::listFiles(*i, suffix);
cannam@233 516
cannam@233 517 for (vector<string>::iterator fi = files.begin();
cannam@233 518 fi != files.end(); ++fi) {
cannam@233 519
Chris@390 520 string filepath = Files::splicePath(*i, *fi);
cannam@233 521 ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
cannam@233 522
cannam@233 523 if (is.fail()) {
cannam@233 524 // cerr << "failed to open: " << filepath << endl;
cannam@233 525 continue;
cannam@233 526 }
cannam@233 527
cannam@233 528 // cerr << "opened: " << filepath << endl;
cannam@233 529
cannam@233 530 while (!!is.getline(buffer, 1024)) {
cannam@233 531
cannam@233 532 string line(buffer);
cannam@233 533
cannam@233 534 // cerr << "line = " << line << endl;
cannam@233 535
cannam@233 536 string::size_type di = line.find("::");
cannam@233 537 if (di == string::npos) continue;
cannam@233 538
cannam@233 539 string id = line.substr(0, di);
cannam@233 540 string encodedCat = line.substr(di + 2);
cannam@233 541
cannam@233 542 if (id.substr(0, 5) != "vamp:") continue;
cannam@233 543 id = id.substr(5);
cannam@233 544
cannam@233 545 while (encodedCat.length() >= 1 &&
cannam@233 546 encodedCat[encodedCat.length()-1] == '\r') {
cannam@233 547 encodedCat = encodedCat.substr(0, encodedCat.length()-1);
cannam@233 548 }
cannam@233 549
cannam@233 550 // cerr << "id = " << id << ", cat = " << encodedCat << endl;
cannam@233 551
cannam@233 552 PluginCategoryHierarchy category;
cannam@233 553 string::size_type ai;
cannam@233 554 while ((ai = encodedCat.find(" > ")) != string::npos) {
cannam@233 555 category.push_back(encodedCat.substr(0, ai));
cannam@233 556 encodedCat = encodedCat.substr(ai + 3);
cannam@233 557 }
cannam@233 558 if (encodedCat != "") category.push_back(encodedCat);
cannam@233 559
cannam@233 560 m_taxonomy[id] = category;
cannam@233 561 }
cannam@233 562 }
cannam@233 563 }
cannam@233 564 }
cannam@233 565
cannam@233 566 void
cannam@233 567 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
cannam@233 568 {
cannam@233 569 void *handle = m_pluginLibraryHandleMap[adapter];
Chris@524 570 if (!handle) return;
Chris@524 571
cannam@233 572 m_pluginLibraryHandleMap.erase(adapter);
Chris@524 573
Chris@524 574 for (auto h: m_pluginLibraryHandleMap) {
Chris@524 575 if (h.second == handle) {
Chris@524 576 // still in use
Chris@524 577 return;
Chris@524 578 }
Chris@524 579 }
Chris@524 580
Chris@524 581 Files::unloadLibrary(handle);
cannam@233 582 }
cannam@233 583
cannam@233 584 PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
cannam@233 585 Impl *loader) :
cannam@233 586 PluginWrapper(plugin),
cannam@233 587 m_loader(loader)
cannam@233 588 {
cannam@233 589 }
cannam@233 590
cannam@233 591 PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
cannam@233 592 {
cannam@233 593 // We need to delete the plugin before calling pluginDeleted, as
cannam@233 594 // the delete call may require calling through to the descriptor
cannam@233 595 // (for e.g. cleanup) but pluginDeleted may unload the required
cannam@233 596 // library for the call. To prevent a double deletion when our
cannam@233 597 // parent's destructor runs (after this one), be sure to set
cannam@233 598 // m_plugin to 0 after deletion.
cannam@233 599 delete m_plugin;
cannam@233 600 m_plugin = 0;
cannam@233 601
cannam@233 602 if (m_loader) m_loader->pluginDeleted(this);
cannam@233 603 }
cannam@233 604
cannam@233 605 }
cannam@233 606
cannam@233 607 }
cannam@263 608
cannam@263 609 _VAMP_SDK_HOSTSPACE_END(PluginLoader.cpp)
cannam@263 610