annotate plugin/FeatureExtractionPluginFactory.cpp @ 1178:bf05d9259dbc pluginscan

First cut running (but not yet using output of, or recovering from errors in) the plugin checker at startup
author Chris Cannam
date Thu, 14 Apr 2016 12:12:04 +0100
parents 6877f4200912
children 6b1af0f05f06
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@202 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "FeatureExtractionPluginFactory.h"
Chris@0 17 #include "PluginIdentifier.h"
Chris@0 18
Chris@475 19 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@475 20 #include <vamp-hostsdk/PluginWrapper.h>
Chris@66 21
Chris@150 22 #include "system/System.h"
Chris@66 23
Chris@66 24 #include <QDir>
Chris@66 25 #include <QFile>
Chris@66 26 #include <QFileInfo>
Chris@165 27 #include <QTextStream>
Chris@66 28
Chris@0 29 #include <iostream>
Chris@0 30
Chris@408 31 #include "base/Profiler.h"
Chris@408 32
Chris@1164 33 using namespace std;
Chris@1164 34
Chris@249 35 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1
Chris@249 36
Chris@298 37 class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper {
Chris@298 38 public:
Chris@298 39 PluginDeletionNotifyAdapter(Vamp::Plugin *plugin,
Chris@298 40 FeatureExtractionPluginFactory *factory) :
Chris@298 41 PluginWrapper(plugin), m_factory(factory) { }
Chris@298 42 virtual ~PluginDeletionNotifyAdapter();
Chris@298 43 protected:
Chris@298 44 FeatureExtractionPluginFactory *m_factory;
Chris@298 45 };
Chris@298 46
Chris@298 47 PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
Chris@298 48 {
Chris@298 49 // see notes in vamp-sdk/hostext/PluginLoader.cpp from which this is drawn
Chris@298 50 Vamp::Plugin *p = m_plugin;
Chris@298 51 delete m_plugin;
Chris@298 52 m_plugin = 0;
Chris@973 53 // acceptable use after free here, as pluginDeleted uses p only as
Chris@973 54 // pointer key and does not deref it
Chris@298 55 if (m_factory) m_factory->pluginDeleted(p);
Chris@298 56 }
Chris@298 57
Chris@0 58 static FeatureExtractionPluginFactory *_nativeInstance = 0;
Chris@0 59
Chris@0 60 FeatureExtractionPluginFactory *
Chris@0 61 FeatureExtractionPluginFactory::instance(QString pluginType)
Chris@0 62 {
Chris@71 63 if (pluginType == "vamp") {
Chris@0 64 if (!_nativeInstance) {
Chris@690 65 // SVDEBUG << "FeatureExtractionPluginFactory::instance(" << pluginType// << "): creating new FeatureExtractionPluginFactory" << endl;
Chris@0 66 _nativeInstance = new FeatureExtractionPluginFactory();
Chris@0 67 }
Chris@0 68 return _nativeInstance;
Chris@0 69 }
Chris@0 70
Chris@0 71 else return 0;
Chris@0 72 }
Chris@0 73
Chris@0 74 FeatureExtractionPluginFactory *
Chris@0 75 FeatureExtractionPluginFactory::instanceFor(QString identifier)
Chris@0 76 {
Chris@0 77 QString type, soName, label;
Chris@0 78 PluginIdentifier::parseIdentifier(identifier, type, soName, label);
Chris@0 79 return instance(type);
Chris@0 80 }
Chris@0 81
Chris@1164 82 vector<QString>
Chris@66 83 FeatureExtractionPluginFactory::getPluginPath()
Chris@66 84 {
Chris@117 85 if (!m_pluginPath.empty()) return m_pluginPath;
Chris@117 86
Chris@1164 87 vector<string> p = Vamp::PluginHostAdapter::getPluginPath();
Chris@186 88 for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str());
Chris@186 89 return m_pluginPath;
Chris@66 90 }
Chris@66 91
Chris@1164 92 vector<QString>
Chris@0 93 FeatureExtractionPluginFactory::getAllPluginIdentifiers()
Chris@0 94 {
Chris@0 95 FeatureExtractionPluginFactory *factory;
Chris@1164 96 vector<QString> rv;
Chris@0 97
Chris@66 98 factory = instance("vamp");
Chris@0 99 if (factory) {
Chris@1164 100 vector<QString> tmp = factory->getPluginIdentifiers();
Chris@0 101 for (size_t i = 0; i < tmp.size(); ++i) {
Chris@843 102 // cerr << "identifier: " << tmp[i] << endl;
Chris@0 103 rv.push_back(tmp[i]);
Chris@0 104 }
Chris@0 105 }
Chris@0 106
Chris@0 107 // Plugins can change the locale, revert it to default.
Chris@608 108 RestoreStartupLocale();
Chris@608 109
Chris@0 110 return rv;
Chris@0 111 }
Chris@0 112
Chris@1164 113 vector<QString>
Chris@1164 114 FeatureExtractionPluginFactory::getPluginCandidateFiles()
Chris@1164 115 {
Chris@1164 116 vector<QString> path = getPluginPath();
Chris@1164 117 vector<QString> candidates;
Chris@1164 118
Chris@1164 119 for (QString dirname : path) {
Chris@1164 120
Chris@1164 121 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1178 122 cerr << "FeatureExtractionPluginFactory::getPluginCandidateFiles: scanning directory " << dirname << endl;
Chris@1164 123 #endif
Chris@1164 124
Chris@1164 125 QDir pluginDir(dirname, PLUGIN_GLOB,
Chris@1164 126 QDir::Name | QDir::IgnoreCase,
Chris@1164 127 QDir::Files | QDir::Readable);
Chris@1164 128
Chris@1164 129 for (unsigned int j = 0; j < pluginDir.count(); ++j) {
Chris@1164 130 QString soname = pluginDir.filePath(pluginDir[j]);
Chris@1164 131 candidates.push_back(soname);
Chris@1164 132 }
Chris@1164 133 }
Chris@1164 134
Chris@1164 135 return candidates;
Chris@1164 136 }
Chris@1164 137
Chris@1164 138 vector<QString>
Chris@1166 139 FeatureExtractionPluginFactory::winnowPluginCandidates(vector<QString> candidates,
Chris@1166 140 QString &warningMessage)
Chris@1165 141 {
Chris@1165 142 vector<QString> good, bad;
Chris@1165 143 vector<PluginLoadStatus> badStatuses;
Chris@1165 144
Chris@1165 145 for (QString c: candidates) {
Chris@1165 146
Chris@1165 147 PluginLoadStatus status =
Chris@1165 148 TestPluginLoadability(c, "vampGetPluginDescriptor");
Chris@1165 149
Chris@1165 150 if (status == PluginLoadOK) {
Chris@1165 151 good.push_back(c);
Chris@1165 152 } else if (status == UnknownPluginLoadStatus) {
Chris@1165 153 cerr << "WARNING: Unknown load status for plugin candidate \""
Chris@1165 154 << c << "\", continuing" << endl;
Chris@1165 155 good.push_back(c);
Chris@1165 156 } else {
Chris@1165 157 bad.push_back(c);
Chris@1165 158 badStatuses.push_back(status);
Chris@1165 159 }
Chris@1165 160 }
Chris@1165 161
Chris@1165 162 if (!bad.empty()) {
Chris@1166 163 warningMessage =
Chris@1166 164 QObject::tr("<b>Failed to load plugins</b>"
Chris@1166 165 "<p>Failed to load one or more plugin libraries:</p>\n");
Chris@1166 166 warningMessage += "<ul>";
Chris@1167 167 for (int i = 0; in_range_for(bad, i); ++i) {
Chris@1165 168 QString m;
Chris@1165 169 if (badStatuses[i] == PluginLoadFailedToLoadLibrary) {
Chris@1166 170 m = QObject::tr("Failed to load library");
Chris@1165 171 } else if (badStatuses[i] == PluginLoadFailedToFindDescriptor) {
Chris@1166 172 m = QObject::tr("Failed to query plugins from library after loading");
Chris@1165 173 } else if (badStatuses[i] == PluginLoadFailedElsewhere) {
Chris@1166 174 m = QObject::tr("Unknown failure");
Chris@1165 175 } else {
Chris@1166 176 m = QObject::tr("Success: internal error?");
Chris@1165 177 }
Chris@1165 178 warningMessage += QString("<li>%1 (%2)</li>\n")
Chris@1165 179 .arg(bad[i])
Chris@1165 180 .arg(m);
Chris@1165 181 }
Chris@1165 182 warningMessage += "</ul>";
Chris@1165 183 }
Chris@1165 184 return good;
Chris@1165 185 }
Chris@1165 186
Chris@1165 187 vector<QString>
Chris@0 188 FeatureExtractionPluginFactory::getPluginIdentifiers()
Chris@0 189 {
Chris@408 190 Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers");
Chris@408 191
Chris@1164 192 vector<QString> rv;
Chris@1166 193 vector<QString> candidates = winnowPluginCandidates(getPluginCandidateFiles(),
Chris@1166 194 m_pluginScanError);
Chris@1165 195
Chris@1164 196 for (QString soname : candidates) {
Chris@66 197
Chris@1164 198 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL);
Chris@1164 199
Chris@1164 200 if (!libraryHandle) {
Chris@1164 201 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname << ": " << DLERROR() << endl;
Chris@1164 202 continue;
Chris@1164 203 }
Chris@66 204
Chris@1164 205 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@1164 206 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@1164 207
Chris@1164 208 if (!fn) {
Chris@1164 209 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname << endl;
Chris@1164 210 if (DLCLOSE(libraryHandle) != 0) {
Chris@1164 211 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl;
Chris@1164 212 }
Chris@1164 213 continue;
Chris@1164 214 }
Chris@1164 215
Chris@1164 216 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 217 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl;
Chris@1164 218 #endif
Chris@1164 219
Chris@1164 220 const VampPluginDescriptor *descriptor = 0;
Chris@1164 221 int index = 0;
Chris@1164 222
Chris@1164 223 map<string, int> known;
Chris@1164 224 bool ok = true;
Chris@1164 225
Chris@1164 226 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@1164 227
Chris@1164 228 if (known.find(descriptor->identifier) != known.end()) {
Chris@1164 229 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library "
Chris@1164 230 << soname
Chris@1164 231 << " returns the same plugin identifier \""
Chris@1164 232 << descriptor->identifier << "\" at indices "
Chris@1164 233 << known[descriptor->identifier] << " and "
Chris@1164 234 << index << endl;
Chris@1160 235 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl;
Chris@1164 236 ok = false;
Chris@1164 237 break;
Chris@1164 238 } else {
Chris@1164 239 known[descriptor->identifier] = index;
Chris@66 240 }
Chris@66 241
Chris@1164 242 ++index;
Chris@1164 243 }
Chris@249 244
Chris@1164 245 if (ok) {
Chris@66 246
Chris@1164 247 index = 0;
Chris@251 248
Chris@239 249 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@251 250
Chris@1164 251 QString id = PluginIdentifier::createIdentifier
Chris@1164 252 ("vamp", soname, descriptor->identifier);
Chris@1164 253 rv.push_back(id);
Chris@1164 254 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1170 255 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl;
Chris@1164 256 #endif
Chris@251 257 ++index;
Chris@251 258 }
Chris@1164 259 }
Chris@66 260
Chris@1164 261 if (DLCLOSE(libraryHandle) != 0) {
Chris@1164 262 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl;
Chris@1164 263 }
Chris@66 264 }
Chris@66 265
Chris@165 266 generateTaxonomy();
Chris@165 267
Chris@0 268 return rv;
Chris@0 269 }
Chris@0 270
Chris@66 271 QString
Chris@66 272 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir)
Chris@66 273 {
Chris@66 274 QString file = "";
Chris@66 275
Chris@249 276 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 277 cerr << "FeatureExtractionPluginFactory::findPluginFile(\""
Chris@686 278 << soname << "\", \"" << inDir << "\")"
Chris@687 279 << endl;
Chris@249 280 #endif
Chris@249 281
Chris@66 282 if (inDir != "") {
Chris@66 283
Chris@66 284 QDir dir(inDir, PLUGIN_GLOB,
Chris@66 285 QDir::Name | QDir::IgnoreCase,
Chris@66 286 QDir::Files | QDir::Readable);
Chris@66 287 if (!dir.exists()) return "";
Chris@66 288
Chris@66 289 file = dir.filePath(QFileInfo(soname).fileName());
Chris@249 290
Chris@249 291 if (QFileInfo(file).exists() && QFileInfo(file).isFile()) {
Chris@249 292
Chris@249 293 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 294 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 295 << "found trivially at " << file << endl;
Chris@249 296 #endif
Chris@249 297
Chris@66 298 return file;
Chris@66 299 }
Chris@66 300
Chris@66 301 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@66 302 file = dir.filePath(dir[j]);
Chris@66 303 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) {
Chris@249 304
Chris@249 305 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 306 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 307 << "found \"" << soname << "\" at " << file << endl;
Chris@249 308 #endif
Chris@249 309
Chris@66 310 return file;
Chris@66 311 }
Chris@66 312 }
Chris@66 313
Chris@249 314 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 315 cerr << "FeatureExtractionPluginFactory::findPluginFile (with dir): "
Chris@687 316 << "not found" << endl;
Chris@249 317 #endif
Chris@249 318
Chris@66 319 return "";
Chris@66 320
Chris@66 321 } else {
Chris@66 322
Chris@66 323 QFileInfo fi(soname);
Chris@249 324
Chris@249 325 if (fi.isAbsolute() && fi.exists() && fi.isFile()) {
Chris@249 326 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 327 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 328 << "found trivially at " << soname << endl;
Chris@249 329 #endif
Chris@249 330 return soname;
Chris@249 331 }
Chris@66 332
Chris@66 333 if (fi.isAbsolute() && fi.absolutePath() != "") {
Chris@66 334 file = findPluginFile(soname, fi.absolutePath());
Chris@66 335 if (file != "") return file;
Chris@66 336 }
Chris@66 337
Chris@1164 338 vector<QString> path = getPluginPath();
Chris@1164 339 for (vector<QString>::iterator i = path.begin();
Chris@66 340 i != path.end(); ++i) {
Chris@66 341 if (*i != "") {
Chris@66 342 file = findPluginFile(soname, *i);
Chris@66 343 if (file != "") return file;
Chris@66 344 }
Chris@66 345 }
Chris@66 346
Chris@249 347 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 348 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 349 << "not found" << endl;
Chris@249 350 #endif
Chris@249 351
Chris@66 352 return "";
Chris@66 353 }
Chris@66 354 }
Chris@66 355
Chris@66 356 Vamp::Plugin *
Chris@0 357 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier,
Chris@1040 358 sv_samplerate_t inputSampleRate)
Chris@0 359 {
Chris@408 360 Profiler profiler("FeatureExtractionPluginFactory::instantiatePlugin");
Chris@408 361
Chris@66 362 Vamp::Plugin *rv = 0;
Chris@298 363 Vamp::PluginHostAdapter *plugin = 0;
Chris@66 364
Chris@66 365 const VampPluginDescriptor *descriptor = 0;
Chris@66 366 int index = 0;
Chris@66 367
Chris@66 368 QString type, soname, label;
Chris@66 369 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@71 370 if (type != "vamp") {
Chris@1167 371 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1167 372 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl;
Chris@1167 373 #endif
Chris@0 374 return 0;
Chris@0 375 }
Chris@0 376
Chris@66 377 QString found = findPluginFile(soname);
Chris@66 378
Chris@66 379 if (found == "") {
Chris@843 380 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname << endl;
Chris@117 381 return 0;
Chris@66 382 } else if (found != soname) {
Chris@249 383
Chris@249 384 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1140 385 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Given library name was " << soname << ", found at " << found << endl;
Chris@843 386 cerr << soname << " -> " << found << endl;
Chris@249 387 #endif
Chris@249 388
Chris@249 389 }
Chris@0 390
Chris@66 391 soname = found;
Chris@66 392
Chris@435 393 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL);
Chris@66 394
Chris@66 395 if (!libraryHandle) {
Chris@843 396 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname << ": " << DLERROR() << endl;
Chris@66 397 return 0;
Chris@19 398 }
Chris@19 399
Chris@66 400 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 401 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 402
Chris@66 403 if (!fn) {
Chris@1140 404 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname << endl;
Chris@66 405 goto done;
Chris@0 406 }
Chris@0 407
Chris@239 408 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@238 409 if (label == descriptor->identifier) break;
Chris@66 410 ++index;
Chris@47 411 }
Chris@47 412
Chris@66 413 if (!descriptor) {
Chris@843 414 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label << "\" in library " << soname << endl;
Chris@66 415 goto done;
Martin@37 416 }
Martin@37 417
Chris@1040 418 plugin = new Vamp::PluginHostAdapter(descriptor, float(inputSampleRate));
Chris@298 419
Chris@298 420 if (plugin) {
Chris@298 421 m_handleMap[plugin] = libraryHandle;
Chris@298 422 rv = new PluginDeletionNotifyAdapter(plugin, this);
Chris@298 423 }
Chris@66 424
Chris@690 425 // SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << endl;
Chris@79 426
Chris@66 427 //!!! need to dlclose() when plugins from a given library are unloaded
Chris@66 428
Chris@66 429 done:
Chris@66 430 if (!rv) {
Chris@66 431 if (DLCLOSE(libraryHandle) != 0) {
Chris@843 432 cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl;
Chris@66 433 }
Chris@66 434 }
Chris@73 435
Chris@1167 436 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1167 437 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl;
Chris@1167 438 #endif
Chris@73 439
Chris@66 440 return rv;
Chris@0 441 }
Chris@0 442
Chris@298 443 void
Chris@298 444 FeatureExtractionPluginFactory::pluginDeleted(Vamp::Plugin *plugin)
Chris@298 445 {
Chris@298 446 void *handle = m_handleMap[plugin];
Chris@298 447 if (handle) {
Chris@1167 448 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@1167 449 cerr << "unloading library " << handle << " for plugin " << plugin << endl;
Chris@1167 450 #endif
Chris@298 451 DLCLOSE(handle);
Chris@298 452 }
Chris@298 453 m_handleMap.erase(plugin);
Chris@298 454 }
Chris@298 455
Chris@165 456 QString
Chris@165 457 FeatureExtractionPluginFactory::getPluginCategory(QString identifier)
Chris@165 458 {
Chris@165 459 return m_taxonomy[identifier];
Chris@165 460 }
Chris@165 461
Chris@165 462 void
Chris@165 463 FeatureExtractionPluginFactory::generateTaxonomy()
Chris@165 464 {
Chris@1164 465 vector<QString> pluginPath = getPluginPath();
Chris@1164 466 vector<QString> path;
Chris@165 467
Chris@165 468 for (size_t i = 0; i < pluginPath.size(); ++i) {
Chris@165 469 if (pluginPath[i].contains("/lib/")) {
Chris@165 470 QString p(pluginPath[i]);
Chris@165 471 path.push_back(p);
Chris@165 472 p.replace("/lib/", "/share/");
Chris@165 473 path.push_back(p);
Chris@165 474 }
Chris@165 475 path.push_back(pluginPath[i]);
Chris@165 476 }
Chris@165 477
Chris@165 478 for (size_t i = 0; i < path.size(); ++i) {
Chris@165 479
Chris@165 480 QDir dir(path[i], "*.cat");
Chris@165 481
Chris@690 482 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << endl;
Chris@165 483 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@165 484
Chris@165 485 QFile file(path[i] + "/" + dir[j]);
Chris@165 486
Chris@690 487 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i]+ "/" + dir[j]) << endl;
Chris@165 488
Chris@165 489 if (file.open(QIODevice::ReadOnly)) {
Chris@843 490 // cerr << "...opened" << endl;
Chris@165 491 QTextStream stream(&file);
Chris@165 492 QString line;
Chris@165 493
Chris@165 494 while (!stream.atEnd()) {
Chris@165 495 line = stream.readLine();
Chris@843 496 // cerr << "line is: \"" << line << "\"" << endl;
Chris@165 497 QString id = PluginIdentifier::canonicalise
Chris@165 498 (line.section("::", 0, 0));
Chris@165 499 QString cat = line.section("::", 1, 1);
Chris@165 500 m_taxonomy[id] = cat;
Chris@843 501 // cerr << "FeatureExtractionPluginFactory: set id \"" << id << "\" to cat \"" << cat << "\"" << endl;
Chris@165 502 }
Chris@165 503 }
Chris@165 504 }
Chris@165 505 }
Chris@165 506 }