annotate src/vamp-hostsdk/PluginLoader.cpp @ 455:5c07a86abddd outputid-string-in-featureset

Make RequestResponse types more consistent by adding plugin to ConfigurationResponse and introducing a FinishRequest
author Chris Cannam
date Mon, 19 Sep 2016 13:35:56 +0100
parents c053e5e79b8f
children 86624d166f88
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@426 64 PluginStaticDataList listPluginData();
cannam@233 65
cannam@233 66 Plugin *loadPlugin(PluginKey key,
cannam@233 67 float inputSampleRate,
cannam@233 68 int adapterFlags);
cannam@233 69
Chris@423 70 LoadResponse loadPlugin(LoadRequest req);
Chris@423 71
Chris@431 72 ConfigurationResponse configurePlugin(ConfigurationRequest req);
Chris@423 73
cannam@233 74 PluginKey composePluginKey(string libraryName, string identifier);
cannam@233 75
cannam@233 76 PluginCategoryHierarchy getPluginCategory(PluginKey key);
cannam@233 77
cannam@233 78 string getLibraryPathForPlugin(PluginKey key);
cannam@233 79
cannam@233 80 static void setInstanceToClean(PluginLoader *instance);
cannam@233 81
cannam@233 82 protected:
cannam@233 83 class PluginDeletionNotifyAdapter : public PluginWrapper {
cannam@233 84 public:
cannam@233 85 PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
cannam@233 86 virtual ~PluginDeletionNotifyAdapter();
cannam@233 87 protected:
cannam@233 88 Impl *m_loader;
cannam@233 89 };
cannam@233 90
cannam@233 91 class InstanceCleaner {
cannam@233 92 public:
cannam@233 93 InstanceCleaner() : m_instance(0) { }
cannam@233 94 ~InstanceCleaner() { delete m_instance; }
cannam@233 95 void setInstance(PluginLoader *instance) { m_instance = instance; }
cannam@233 96 protected:
cannam@233 97 PluginLoader *m_instance;
cannam@233 98 };
cannam@233 99
cannam@233 100 virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
cannam@233 101
cannam@233 102 map<PluginKey, string> m_pluginLibraryNameMap;
cannam@233 103 bool m_allPluginsEnumerated;
cannam@233 104 void enumeratePlugins(PluginKey forPlugin = "");
cannam@233 105
cannam@233 106 map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
cannam@233 107 void generateTaxonomy();
cannam@233 108
cannam@233 109 map<Plugin *, void *> m_pluginLibraryHandleMap;
cannam@233 110
cannam@233 111 bool decomposePluginKey(PluginKey key,
cannam@233 112 string &libraryName, string &identifier);
cannam@233 113
cannam@233 114 static InstanceCleaner m_cleaner;
cannam@233 115 };
cannam@233 116
cannam@233 117 PluginLoader *
cannam@233 118 PluginLoader::m_instance = 0;
cannam@233 119
cannam@233 120 PluginLoader::Impl::InstanceCleaner
cannam@233 121 PluginLoader::Impl::m_cleaner;
cannam@233 122
cannam@233 123 PluginLoader::PluginLoader()
cannam@233 124 {
cannam@233 125 m_impl = new Impl();
cannam@233 126 }
cannam@233 127
cannam@233 128 PluginLoader::~PluginLoader()
cannam@233 129 {
cannam@233 130 delete m_impl;
cannam@233 131 }
cannam@233 132
cannam@233 133 PluginLoader *
cannam@233 134 PluginLoader::getInstance()
cannam@233 135 {
cannam@233 136 if (!m_instance) {
cannam@233 137 // The cleaner doesn't own the instance, because we leave the
cannam@233 138 // instance pointer in the base class for binary backwards
cannam@233 139 // compatibility reasons and to avoid waste
cannam@233 140 m_instance = new PluginLoader();
cannam@233 141 Impl::setInstanceToClean(m_instance);
cannam@233 142 }
cannam@233 143 return m_instance;
cannam@233 144 }
cannam@233 145
Chris@426 146 PluginLoader::PluginKeyList
cannam@233 147 PluginLoader::listPlugins()
cannam@233 148 {
cannam@233 149 return m_impl->listPlugins();
cannam@233 150 }
cannam@233 151
Chris@426 152 PluginLoader::PluginStaticDataList
Chris@426 153 PluginLoader::listPluginData()
Chris@426 154 {
Chris@426 155 return m_impl->listPluginData();
Chris@426 156 }
Chris@426 157
cannam@233 158 Plugin *
cannam@233 159 PluginLoader::loadPlugin(PluginKey key,
cannam@233 160 float inputSampleRate,
cannam@233 161 int adapterFlags)
cannam@233 162 {
cannam@233 163 return m_impl->loadPlugin(key, inputSampleRate, adapterFlags);
cannam@233 164 }
cannam@233 165
Chris@423 166 LoadResponse
Chris@423 167 PluginLoader::loadPlugin(LoadRequest req)
Chris@423 168 {
Chris@423 169 return m_impl->loadPlugin(req);
Chris@423 170 }
Chris@423 171
Chris@431 172 ConfigurationResponse
Chris@431 173 PluginLoader::configurePlugin(ConfigurationRequest req)
Chris@423 174 {
Chris@431 175 return m_impl->configurePlugin(req);
Chris@423 176 }
Chris@423 177
cannam@233 178 PluginLoader::PluginKey
cannam@233 179 PluginLoader::composePluginKey(string libraryName, string identifier)
cannam@233 180 {
cannam@233 181 return m_impl->composePluginKey(libraryName, identifier);
cannam@233 182 }
cannam@233 183
cannam@233 184 PluginLoader::PluginCategoryHierarchy
cannam@233 185 PluginLoader::getPluginCategory(PluginKey key)
cannam@233 186 {
cannam@233 187 return m_impl->getPluginCategory(key);
cannam@233 188 }
cannam@233 189
cannam@233 190 string
cannam@233 191 PluginLoader::getLibraryPathForPlugin(PluginKey key)
cannam@233 192 {
cannam@233 193 return m_impl->getLibraryPathForPlugin(key);
cannam@233 194 }
cannam@233 195
cannam@233 196 PluginLoader::Impl::Impl() :
cannam@233 197 m_allPluginsEnumerated(false)
cannam@233 198 {
cannam@233 199 }
cannam@233 200
cannam@233 201 PluginLoader::Impl::~Impl()
cannam@233 202 {
cannam@233 203 }
cannam@233 204
cannam@233 205 void
cannam@233 206 PluginLoader::Impl::setInstanceToClean(PluginLoader *instance)
cannam@233 207 {
cannam@233 208 m_cleaner.setInstance(instance);
cannam@233 209 }
cannam@233 210
Chris@426 211 PluginLoader::PluginKeyList
cannam@233 212 PluginLoader::Impl::listPlugins()
cannam@233 213 {
cannam@233 214 if (!m_allPluginsEnumerated) enumeratePlugins();
cannam@233 215
cannam@233 216 vector<PluginKey> plugins;
cannam@233 217 for (map<PluginKey, string>::iterator mi = m_pluginLibraryNameMap.begin();
cannam@233 218 mi != m_pluginLibraryNameMap.end(); ++mi) {
cannam@233 219 plugins.push_back(mi->first);
cannam@233 220 }
cannam@233 221
cannam@233 222 return plugins;
cannam@233 223 }
cannam@233 224
Chris@426 225 PluginLoader::PluginStaticDataList
Chris@426 226 PluginLoader::Impl::listPluginData()
Chris@426 227 {
Chris@426 228 PluginKeyList keys = listPlugins();
Chris@426 229 PluginStaticDataList dataList;
Chris@426 230
Chris@426 231 for (PluginKeyList::const_iterator ki = keys.begin(); ki != keys.end(); ++ki) {
Chris@426 232 string key = *ki;
Chris@426 233 Plugin *p = loadPlugin(key, 44100, 0);
Chris@426 234 if (p) {
Chris@426 235 PluginCategoryHierarchy category = getPluginCategory(key);
Chris@426 236 dataList.push_back(PluginStaticData::fromPlugin(key, category, p));
Chris@426 237 }
Chris@426 238 delete p;
Chris@426 239 }
Chris@426 240
Chris@426 241 return dataList;
Chris@426 242 }
Chris@426 243
cannam@233 244 void
cannam@233 245 PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin)
cannam@233 246 {
cannam@233 247 string libraryName, identifier;
Chris@390 248 vector<string> fullPaths;
Chris@390 249
cannam@233 250 if (forPlugin != "") {
cannam@233 251 if (!decomposePluginKey(forPlugin, libraryName, identifier)) {
cannam@233 252 std::cerr << "WARNING: Vamp::HostExt::PluginLoader: Invalid plugin key \""
cannam@233 253 << forPlugin << "\" in enumerate" << std::endl;
cannam@233 254 return;
cannam@233 255 }
Chris@390 256 fullPaths = Files::listLibraryFilesMatching(libraryName);
Chris@390 257 } else {
Chris@390 258 fullPaths = Files::listLibraryFiles();
cannam@233 259 }
cannam@233 260
Chris@390 261 for (size_t i = 0; i < fullPaths.size(); ++i) {
cannam@233 262
Chris@390 263 string fullPath = fullPaths[i];
Chris@390 264 void *handle = Files::loadLibrary(fullPath);
Chris@390 265 if (!handle) continue;
cannam@233 266
Chris@390 267 VampGetPluginDescriptorFunction fn =
Chris@390 268 (VampGetPluginDescriptorFunction)Files::lookupInLibrary
Chris@390 269 (handle, "vampGetPluginDescriptor");
cannam@233 270
Chris@390 271 if (!fn) {
Chris@390 272 if (forPlugin != "") {
Chris@390 273 cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
cannam@295 274 << fullPath << "\"" << endl;
cannam@295 275 }
Chris@390 276 Files::unloadLibrary(handle);
Chris@390 277 continue;
Chris@390 278 }
cannam@233 279
Chris@390 280 int index = 0;
Chris@390 281 const VampPluginDescriptor *descriptor = 0;
Chris@390 282 bool found = false;
Chris@390 283
Chris@390 284 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@390 285 ++index;
Chris@390 286 if (identifier != "") {
Chris@390 287 if (descriptor->identifier != identifier) continue;
Chris@390 288 }
Chris@390 289 found = true;
Chris@390 290 PluginKey key = composePluginKey(fullPath, descriptor->identifier);
Chris@390 291 // std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl;
Chris@390 292 if (m_pluginLibraryNameMap.find(key) ==
Chris@390 293 m_pluginLibraryNameMap.end()) {
Chris@390 294 m_pluginLibraryNameMap[key] = fullPath;
Chris@390 295 }
cannam@233 296 }
Chris@390 297
Chris@390 298 if (!found && forPlugin != "") {
Chris@390 299 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
Chris@390 300 << identifier << "\" not found in library \""
Chris@390 301 << fullPath << "\"" << endl;
Chris@390 302 }
Chris@390 303
Chris@390 304 Files::unloadLibrary(handle);
cannam@233 305 }
cannam@233 306
cannam@233 307 if (forPlugin == "") m_allPluginsEnumerated = true;
cannam@233 308 }
cannam@233 309
cannam@233 310 PluginLoader::PluginKey
cannam@233 311 PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
cannam@233 312 {
Chris@390 313 string basename = Files::lcBasename(libraryName);
cannam@233 314 return basename + ":" + identifier;
cannam@233 315 }
cannam@233 316
cannam@233 317 bool
cannam@233 318 PluginLoader::Impl::decomposePluginKey(PluginKey key,
cannam@233 319 string &libraryName,
cannam@233 320 string &identifier)
cannam@233 321 {
cannam@233 322 string::size_type ki = key.find(':');
cannam@233 323 if (ki == string::npos) {
cannam@233 324 return false;
cannam@233 325 }
cannam@233 326
cannam@233 327 libraryName = key.substr(0, ki);
cannam@233 328 identifier = key.substr(ki + 1);
cannam@233 329 return true;
cannam@233 330 }
cannam@233 331
cannam@233 332 PluginLoader::PluginCategoryHierarchy
cannam@233 333 PluginLoader::Impl::getPluginCategory(PluginKey plugin)
cannam@233 334 {
cannam@233 335 if (m_taxonomy.empty()) generateTaxonomy();
cannam@233 336 if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
cannam@233 337 return PluginCategoryHierarchy();
cannam@233 338 }
cannam@233 339 return m_taxonomy[plugin];
cannam@233 340 }
cannam@233 341
cannam@233 342 string
cannam@233 343 PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
cannam@233 344 {
cannam@233 345 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@233 346 if (m_allPluginsEnumerated) return "";
cannam@233 347 enumeratePlugins(plugin);
cannam@233 348 }
cannam@233 349 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@233 350 return "";
cannam@233 351 }
cannam@233 352 return m_pluginLibraryNameMap[plugin];
cannam@233 353 }
cannam@233 354
cannam@233 355 Plugin *
cannam@233 356 PluginLoader::Impl::loadPlugin(PluginKey key,
cannam@233 357 float inputSampleRate, int adapterFlags)
cannam@233 358 {
cannam@233 359 string libname, identifier;
cannam@233 360 if (!decomposePluginKey(key, libname, identifier)) {
cannam@233 361 std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \""
cannam@233 362 << key << "\" in loadPlugin" << std::endl;
cannam@233 363 return 0;
cannam@233 364 }
cannam@233 365
cannam@233 366 string fullPath = getLibraryPathForPlugin(key);
cannam@293 367 if (fullPath == "") {
cannam@295 368 std::cerr << "Vamp::HostExt::PluginLoader: No library found in Vamp path for plugin \"" << key << "\"" << std::endl;
cannam@293 369 return 0;
cannam@293 370 }
cannam@233 371
Chris@390 372 void *handle = Files::loadLibrary(fullPath);
cannam@233 373 if (!handle) return 0;
cannam@233 374
cannam@233 375 VampGetPluginDescriptorFunction fn =
Chris@390 376 (VampGetPluginDescriptorFunction)Files::lookupInLibrary
cannam@233 377 (handle, "vampGetPluginDescriptor");
cannam@233 378
cannam@233 379 if (!fn) {
cannam@293 380 cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
cannam@293 381 << fullPath << "\"" << endl;
Chris@390 382 Files::unloadLibrary(handle);
cannam@233 383 return 0;
cannam@233 384 }
cannam@233 385
cannam@233 386 int index = 0;
cannam@233 387 const VampPluginDescriptor *descriptor = 0;
cannam@233 388
cannam@233 389 while ((descriptor = fn(VAMP_API_VERSION, index))) {
cannam@233 390
cannam@233 391 if (string(descriptor->identifier) == identifier) {
cannam@233 392
cannam@233 393 Vamp::PluginHostAdapter *plugin =
cannam@233 394 new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
cannam@233 395
cannam@233 396 Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
cannam@233 397
cannam@233 398 m_pluginLibraryHandleMap[adapter] = handle;
cannam@233 399
cannam@233 400 if (adapterFlags & ADAPT_INPUT_DOMAIN) {
cannam@233 401 if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
cannam@233 402 adapter = new PluginInputDomainAdapter(adapter);
cannam@233 403 }
cannam@233 404 }
cannam@233 405
cannam@233 406 if (adapterFlags & ADAPT_BUFFER_SIZE) {
cannam@233 407 adapter = new PluginBufferingAdapter(adapter);
cannam@233 408 }
cannam@233 409
cannam@233 410 if (adapterFlags & ADAPT_CHANNEL_COUNT) {
cannam@233 411 adapter = new PluginChannelAdapter(adapter);
cannam@233 412 }
cannam@233 413
cannam@233 414 return adapter;
cannam@233 415 }
cannam@233 416
cannam@233 417 ++index;
cannam@233 418 }
cannam@233 419
cannam@233 420 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
cannam@233 421 << identifier << "\" not found in library \""
cannam@233 422 << fullPath << "\"" << endl;
cannam@233 423
cannam@233 424 return 0;
cannam@233 425 }
cannam@233 426
Chris@423 427 LoadResponse
Chris@423 428 PluginLoader::Impl::loadPlugin(LoadRequest req)
Chris@423 429 {
Chris@423 430 Plugin *plugin = loadPlugin(req.pluginKey,
Chris@423 431 req.inputSampleRate,
Chris@423 432 req.adapterFlags);
Chris@423 433 LoadResponse response;
Chris@425 434 response.plugin = plugin;
Chris@423 435 if (!plugin) return response;
Chris@423 436
Chris@423 437 response.plugin = plugin;
Chris@423 438 response.staticData = PluginStaticData::fromPlugin
Chris@423 439 (req.pluginKey,
Chris@423 440 getPluginCategory(req.pluginKey),
Chris@423 441 plugin);
Chris@423 442
Chris@423 443 int defaultChannels = 0;
Chris@423 444 if (plugin->getMinChannelCount() == plugin->getMaxChannelCount()) {
Chris@423 445 defaultChannels = plugin->getMinChannelCount();
Chris@423 446 }
Chris@423 447
Chris@423 448 response.defaultConfiguration = PluginConfiguration::fromPlugin
Chris@423 449 (plugin,
Chris@423 450 defaultChannels,
Chris@423 451 plugin->getPreferredStepSize(),
Chris@423 452 plugin->getPreferredBlockSize());
Chris@423 453
Chris@423 454 return response;
Chris@423 455 }
Chris@423 456
Chris@431 457 ConfigurationResponse
Chris@431 458 PluginLoader::Impl::configurePlugin(ConfigurationRequest req)
Chris@423 459 {
Chris@423 460 for (PluginConfiguration::ParameterMap::const_iterator i =
Chris@431 461 req.configuration.parameterValues.begin();
Chris@431 462 i != req.configuration.parameterValues.end(); ++i) {
Chris@431 463 req.plugin->setParameter(i->first, i->second);
Chris@423 464 }
Chris@423 465
Chris@431 466 if (req.configuration.currentProgram != "") {
Chris@431 467 req.plugin->selectProgram(req.configuration.currentProgram);
Chris@423 468 }
Chris@423 469
Chris@431 470 ConfigurationResponse response;
Chris@431 471
Chris@455 472 response.plugin = req.plugin;
Chris@455 473
Chris@431 474 if (req.plugin->initialise(req.configuration.channelCount,
Chris@431 475 req.configuration.stepSize,
Chris@431 476 req.configuration.blockSize)) {
Chris@431 477 response.outputs = req.plugin->getOutputDescriptors();
Chris@423 478 }
Chris@431 479
Chris@431 480 return response;
Chris@423 481 }
Chris@423 482
cannam@233 483 void
cannam@233 484 PluginLoader::Impl::generateTaxonomy()
cannam@233 485 {
cannam@233 486 // cerr << "PluginLoader::Impl::generateTaxonomy" << endl;
cannam@233 487
cannam@233 488 vector<string> path = PluginHostAdapter::getPluginPath();
cannam@233 489 string libfragment = "/lib/";
cannam@233 490 vector<string> catpath;
cannam@233 491
cannam@233 492 string suffix = "cat";
cannam@233 493
cannam@233 494 for (vector<string>::iterator i = path.begin();
cannam@233 495 i != path.end(); ++i) {
cannam@233 496
cannam@233 497 // It doesn't matter that we're using literal forward-slash in
cannam@233 498 // this bit, as it's only relevant if the path contains
cannam@233 499 // "/lib/", which is only meaningful and only plausible on
cannam@233 500 // systems with forward-slash delimiters
cannam@233 501
cannam@233 502 string dir = *i;
cannam@233 503 string::size_type li = dir.find(libfragment);
cannam@233 504
cannam@233 505 if (li != string::npos) {
cannam@233 506 catpath.push_back
cannam@233 507 (dir.substr(0, li)
cannam@233 508 + "/share/"
cannam@233 509 + dir.substr(li + libfragment.length()));
cannam@233 510 }
cannam@233 511
cannam@233 512 catpath.push_back(dir);
cannam@233 513 }
cannam@233 514
cannam@233 515 char buffer[1024];
cannam@233 516
cannam@233 517 for (vector<string>::iterator i = catpath.begin();
cannam@233 518 i != catpath.end(); ++i) {
cannam@233 519
Chris@390 520 vector<string> files = Files::listFiles(*i, suffix);
cannam@233 521
cannam@233 522 for (vector<string>::iterator fi = files.begin();
cannam@233 523 fi != files.end(); ++fi) {
cannam@233 524
Chris@390 525 string filepath = Files::splicePath(*i, *fi);
cannam@233 526 ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
cannam@233 527
cannam@233 528 if (is.fail()) {
cannam@233 529 // cerr << "failed to open: " << filepath << endl;
cannam@233 530 continue;
cannam@233 531 }
cannam@233 532
cannam@233 533 // cerr << "opened: " << filepath << endl;
cannam@233 534
cannam@233 535 while (!!is.getline(buffer, 1024)) {
cannam@233 536
cannam@233 537 string line(buffer);
cannam@233 538
cannam@233 539 // cerr << "line = " << line << endl;
cannam@233 540
cannam@233 541 string::size_type di = line.find("::");
cannam@233 542 if (di == string::npos) continue;
cannam@233 543
cannam@233 544 string id = line.substr(0, di);
cannam@233 545 string encodedCat = line.substr(di + 2);
cannam@233 546
cannam@233 547 if (id.substr(0, 5) != "vamp:") continue;
cannam@233 548 id = id.substr(5);
cannam@233 549
cannam@233 550 while (encodedCat.length() >= 1 &&
cannam@233 551 encodedCat[encodedCat.length()-1] == '\r') {
cannam@233 552 encodedCat = encodedCat.substr(0, encodedCat.length()-1);
cannam@233 553 }
cannam@233 554
cannam@233 555 // cerr << "id = " << id << ", cat = " << encodedCat << endl;
cannam@233 556
cannam@233 557 PluginCategoryHierarchy category;
cannam@233 558 string::size_type ai;
cannam@233 559 while ((ai = encodedCat.find(" > ")) != string::npos) {
cannam@233 560 category.push_back(encodedCat.substr(0, ai));
cannam@233 561 encodedCat = encodedCat.substr(ai + 3);
cannam@233 562 }
cannam@233 563 if (encodedCat != "") category.push_back(encodedCat);
cannam@233 564
cannam@233 565 m_taxonomy[id] = category;
cannam@233 566 }
cannam@233 567 }
cannam@233 568 }
cannam@233 569 }
cannam@233 570
cannam@233 571 void
cannam@233 572 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
cannam@233 573 {
cannam@233 574 void *handle = m_pluginLibraryHandleMap[adapter];
Chris@390 575 if (handle) Files::unloadLibrary(handle);
cannam@233 576 m_pluginLibraryHandleMap.erase(adapter);
cannam@233 577 }
cannam@233 578
cannam@233 579 PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
cannam@233 580 Impl *loader) :
cannam@233 581 PluginWrapper(plugin),
cannam@233 582 m_loader(loader)
cannam@233 583 {
cannam@233 584 }
cannam@233 585
cannam@233 586 PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
cannam@233 587 {
cannam@233 588 // We need to delete the plugin before calling pluginDeleted, as
cannam@233 589 // the delete call may require calling through to the descriptor
cannam@233 590 // (for e.g. cleanup) but pluginDeleted may unload the required
cannam@233 591 // library for the call. To prevent a double deletion when our
cannam@233 592 // parent's destructor runs (after this one), be sure to set
cannam@233 593 // m_plugin to 0 after deletion.
cannam@233 594 delete m_plugin;
cannam@233 595 m_plugin = 0;
cannam@233 596
cannam@233 597 if (m_loader) m_loader->pluginDeleted(this);
cannam@233 598 }
cannam@233 599
cannam@233 600 }
cannam@233 601
cannam@233 602 }
cannam@263 603
cannam@263 604 _VAMP_SDK_HOSTSPACE_END(PluginLoader.cpp)
cannam@263 605