annotate plugin/FeatureExtractionPluginFactory.cpp @ 876:47aa3aeb687b tonioni

For outputs with unknown bin count or multiple bins with variable sample rate, create additional output models for bins beyond the first
author Chris Cannam
date Wed, 29 Jan 2014 09:31:22 +0000
parents f5cd33909744
children 7aa9088e9bcd
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@249 33 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1
Chris@249 34
Chris@298 35 class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper {
Chris@298 36 public:
Chris@298 37 PluginDeletionNotifyAdapter(Vamp::Plugin *plugin,
Chris@298 38 FeatureExtractionPluginFactory *factory) :
Chris@298 39 PluginWrapper(plugin), m_factory(factory) { }
Chris@298 40 virtual ~PluginDeletionNotifyAdapter();
Chris@298 41 protected:
Chris@298 42 FeatureExtractionPluginFactory *m_factory;
Chris@298 43 };
Chris@298 44
Chris@298 45 PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
Chris@298 46 {
Chris@298 47 // see notes in vamp-sdk/hostext/PluginLoader.cpp from which this is drawn
Chris@298 48 Vamp::Plugin *p = m_plugin;
Chris@298 49 delete m_plugin;
Chris@298 50 m_plugin = 0;
Chris@298 51 if (m_factory) m_factory->pluginDeleted(p);
Chris@298 52 }
Chris@298 53
Chris@0 54 static FeatureExtractionPluginFactory *_nativeInstance = 0;
Chris@0 55
Chris@0 56 FeatureExtractionPluginFactory *
Chris@0 57 FeatureExtractionPluginFactory::instance(QString pluginType)
Chris@0 58 {
Chris@71 59 if (pluginType == "vamp") {
Chris@0 60 if (!_nativeInstance) {
Chris@690 61 // SVDEBUG << "FeatureExtractionPluginFactory::instance(" << pluginType// << "): creating new FeatureExtractionPluginFactory" << endl;
Chris@0 62 _nativeInstance = new FeatureExtractionPluginFactory();
Chris@0 63 }
Chris@0 64 return _nativeInstance;
Chris@0 65 }
Chris@0 66
Chris@0 67 else return 0;
Chris@0 68 }
Chris@0 69
Chris@0 70 FeatureExtractionPluginFactory *
Chris@0 71 FeatureExtractionPluginFactory::instanceFor(QString identifier)
Chris@0 72 {
Chris@0 73 QString type, soName, label;
Chris@0 74 PluginIdentifier::parseIdentifier(identifier, type, soName, label);
Chris@0 75 return instance(type);
Chris@0 76 }
Chris@0 77
Chris@0 78 std::vector<QString>
Chris@66 79 FeatureExtractionPluginFactory::getPluginPath()
Chris@66 80 {
Chris@117 81 if (!m_pluginPath.empty()) return m_pluginPath;
Chris@117 82
Chris@186 83 std::vector<std::string> p = Vamp::PluginHostAdapter::getPluginPath();
Chris@186 84 for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str());
Chris@186 85 return m_pluginPath;
Chris@66 86 }
Chris@66 87
Chris@66 88 std::vector<QString>
Chris@0 89 FeatureExtractionPluginFactory::getAllPluginIdentifiers()
Chris@0 90 {
Chris@0 91 FeatureExtractionPluginFactory *factory;
Chris@0 92 std::vector<QString> rv;
Chris@0 93
Chris@66 94 factory = instance("vamp");
Chris@0 95 if (factory) {
Chris@0 96 std::vector<QString> tmp = factory->getPluginIdentifiers();
Chris@0 97 for (size_t i = 0; i < tmp.size(); ++i) {
Chris@843 98 // cerr << "identifier: " << tmp[i] << endl;
Chris@0 99 rv.push_back(tmp[i]);
Chris@0 100 }
Chris@0 101 }
Chris@0 102
Chris@0 103 // Plugins can change the locale, revert it to default.
Chris@608 104 RestoreStartupLocale();
Chris@608 105
Chris@0 106 return rv;
Chris@0 107 }
Chris@0 108
Chris@0 109 std::vector<QString>
Chris@0 110 FeatureExtractionPluginFactory::getPluginIdentifiers()
Chris@0 111 {
Chris@408 112 Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers");
Chris@408 113
Chris@0 114 std::vector<QString> rv;
Chris@66 115 std::vector<QString> path = getPluginPath();
Chris@66 116
Chris@66 117 for (std::vector<QString>::iterator i = path.begin(); i != path.end(); ++i) {
Chris@66 118
Chris@249 119 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 120 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << i-<< endl;
Chris@249 121 #endif
Chris@66 122
Chris@66 123 QDir pluginDir(*i, PLUGIN_GLOB,
Chris@66 124 QDir::Name | QDir::IgnoreCase,
Chris@66 125 QDir::Files | QDir::Readable);
Chris@66 126
Chris@66 127 for (unsigned int j = 0; j < pluginDir.count(); ++j) {
Chris@66 128
Chris@66 129 QString soname = pluginDir.filePath(pluginDir[j]);
Chris@66 130
Chris@249 131 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 132 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: trying potential library " << soname << endl;
Chris@249 133 #endif
Chris@249 134
Chris@435 135 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL);
Chris@66 136
Chris@66 137 if (!libraryHandle) {
Chris@843 138 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname << ": " << DLERROR() << endl;
Chris@66 139 continue;
Chris@66 140 }
Chris@66 141
Chris@249 142 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 143 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: It's a library all right, checking for descriptor" << endl;
Chris@249 144 #endif
Chris@249 145
Chris@66 146 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 147 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 148
Chris@66 149 if (!fn) {
Chris@843 150 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname << endl;
Chris@66 151 if (DLCLOSE(libraryHandle) != 0) {
Chris@843 152 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl;
Chris@66 153 }
Chris@66 154 continue;
Chris@66 155 }
Chris@66 156
Chris@249 157 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 158 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl;
Chris@249 159 #endif
Chris@249 160
Chris@66 161 const VampPluginDescriptor *descriptor = 0;
Chris@66 162 int index = 0;
Chris@66 163
Chris@251 164 std::map<std::string, int> known;
Chris@251 165 bool ok = true;
Chris@251 166
Chris@239 167 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@251 168
Chris@251 169 if (known.find(descriptor->identifier) != known.end()) {
Chris@843 170 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library "
Chris@844 171 << soname
Chris@251 172 << " returns the same plugin identifier \""
Chris@251 173 << descriptor->identifier << "\" at indices "
Chris@251 174 << known[descriptor->identifier] << " and "
Chris@843 175 << index << endl;
Chris@690 176 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl;
Chris@251 177 ok = false;
Chris@251 178 break;
Chris@251 179 } else {
Chris@251 180 known[descriptor->identifier] = index;
Chris@251 181 }
Chris@251 182
Chris@251 183 ++index;
Chris@251 184 }
Chris@251 185
Chris@251 186 if (ok) {
Chris@251 187
Chris@251 188 index = 0;
Chris@251 189
Chris@251 190 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@251 191
Chris@251 192 QString id = PluginIdentifier::createIdentifier
Chris@251 193 ("vamp", soname, descriptor->identifier);
Chris@251 194 rv.push_back(id);
Chris@249 195 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 196 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl;
Chris@249 197 #endif
Chris@251 198 ++index;
Chris@251 199 }
Chris@66 200 }
Chris@66 201
Chris@66 202 if (DLCLOSE(libraryHandle) != 0) {
Chris@843 203 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl;
Chris@66 204 }
Chris@66 205 }
Chris@66 206 }
Chris@66 207
Chris@165 208 generateTaxonomy();
Chris@165 209
Chris@0 210 return rv;
Chris@0 211 }
Chris@0 212
Chris@66 213 QString
Chris@66 214 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir)
Chris@66 215 {
Chris@66 216 QString file = "";
Chris@66 217
Chris@249 218 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 219 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile(\""
Chris@686 220 << soname << "\", \"" << inDir << "\")"
Chris@687 221 << endl;
Chris@249 222 #endif
Chris@249 223
Chris@66 224 if (inDir != "") {
Chris@66 225
Chris@66 226 QDir dir(inDir, PLUGIN_GLOB,
Chris@66 227 QDir::Name | QDir::IgnoreCase,
Chris@66 228 QDir::Files | QDir::Readable);
Chris@66 229 if (!dir.exists()) return "";
Chris@66 230
Chris@66 231 file = dir.filePath(QFileInfo(soname).fileName());
Chris@249 232
Chris@249 233 if (QFileInfo(file).exists() && QFileInfo(file).isFile()) {
Chris@249 234
Chris@249 235 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 236 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 237 << "found trivially at " << file << endl;
Chris@249 238 #endif
Chris@249 239
Chris@66 240 return file;
Chris@66 241 }
Chris@66 242
Chris@66 243 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@66 244 file = dir.filePath(dir[j]);
Chris@66 245 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) {
Chris@249 246
Chris@249 247 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 248 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 249 << "found \"" << soname << "\" at " << file << endl;
Chris@249 250 #endif
Chris@249 251
Chris@66 252 return file;
Chris@66 253 }
Chris@66 254 }
Chris@66 255
Chris@249 256 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 257 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile (with dir): "
Chris@687 258 << "not found" << endl;
Chris@249 259 #endif
Chris@249 260
Chris@66 261 return "";
Chris@66 262
Chris@66 263 } else {
Chris@66 264
Chris@66 265 QFileInfo fi(soname);
Chris@249 266
Chris@249 267 if (fi.isAbsolute() && fi.exists() && fi.isFile()) {
Chris@249 268 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 269 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 270 << "found trivially at " << soname << endl;
Chris@249 271 #endif
Chris@249 272 return soname;
Chris@249 273 }
Chris@66 274
Chris@66 275 if (fi.isAbsolute() && fi.absolutePath() != "") {
Chris@66 276 file = findPluginFile(soname, fi.absolutePath());
Chris@66 277 if (file != "") return file;
Chris@66 278 }
Chris@66 279
Chris@66 280 std::vector<QString> path = getPluginPath();
Chris@66 281 for (std::vector<QString>::iterator i = path.begin();
Chris@66 282 i != path.end(); ++i) {
Chris@66 283 if (*i != "") {
Chris@66 284 file = findPluginFile(soname, *i);
Chris@66 285 if (file != "") return file;
Chris@66 286 }
Chris@66 287 }
Chris@66 288
Chris@249 289 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 290 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile: "
Chris@687 291 << "not found" << endl;
Chris@249 292 #endif
Chris@249 293
Chris@66 294 return "";
Chris@66 295 }
Chris@66 296 }
Chris@66 297
Chris@66 298 Vamp::Plugin *
Chris@0 299 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier,
Chris@0 300 float inputSampleRate)
Chris@0 301 {
Chris@408 302 Profiler profiler("FeatureExtractionPluginFactory::instantiatePlugin");
Chris@408 303
Chris@66 304 Vamp::Plugin *rv = 0;
Chris@298 305 Vamp::PluginHostAdapter *plugin = 0;
Chris@66 306
Chris@66 307 const VampPluginDescriptor *descriptor = 0;
Chris@66 308 int index = 0;
Chris@66 309
Chris@66 310 QString type, soname, label;
Chris@66 311 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@71 312 if (type != "vamp") {
Chris@690 313 SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl;
Chris@0 314 return 0;
Chris@0 315 }
Chris@0 316
Chris@66 317 QString found = findPluginFile(soname);
Chris@66 318
Chris@66 319 if (found == "") {
Chris@843 320 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname << endl;
Chris@117 321 return 0;
Chris@66 322 } else if (found != soname) {
Chris@249 323
Chris@249 324 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
Chris@690 325 SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Given library name was " << soname << ", found at " << found << endl;
Chris@843 326 cerr << soname << " -> " << found << endl;
Chris@249 327 #endif
Chris@249 328
Chris@249 329 }
Chris@0 330
Chris@66 331 soname = found;
Chris@66 332
Chris@435 333 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL);
Chris@66 334
Chris@66 335 if (!libraryHandle) {
Chris@843 336 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname << ": " << DLERROR() << endl;
Chris@66 337 return 0;
Chris@19 338 }
Chris@19 339
Chris@66 340 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 341 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 342
Chris@66 343 if (!fn) {
Chris@690 344 SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname << endl;
Chris@66 345 goto done;
Chris@0 346 }
Chris@0 347
Chris@239 348 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@238 349 if (label == descriptor->identifier) break;
Chris@66 350 ++index;
Chris@47 351 }
Chris@47 352
Chris@66 353 if (!descriptor) {
Chris@843 354 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label << "\" in library " << soname << endl;
Chris@66 355 goto done;
Martin@37 356 }
Martin@37 357
Chris@298 358 plugin = new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
Chris@298 359
Chris@298 360 if (plugin) {
Chris@298 361 m_handleMap[plugin] = libraryHandle;
Chris@298 362 rv = new PluginDeletionNotifyAdapter(plugin, this);
Chris@298 363 }
Chris@66 364
Chris@690 365 // SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << endl;
Chris@79 366
Chris@66 367 //!!! need to dlclose() when plugins from a given library are unloaded
Chris@66 368
Chris@66 369 done:
Chris@66 370 if (!rv) {
Chris@66 371 if (DLCLOSE(libraryHandle) != 0) {
Chris@843 372 cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl;
Chris@66 373 }
Chris@66 374 }
Chris@73 375
Chris@690 376 // SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl;
Chris@73 377
Chris@66 378 return rv;
Chris@0 379 }
Chris@0 380
Chris@298 381 void
Chris@298 382 FeatureExtractionPluginFactory::pluginDeleted(Vamp::Plugin *plugin)
Chris@298 383 {
Chris@298 384 void *handle = m_handleMap[plugin];
Chris@298 385 if (handle) {
Chris@690 386 // SVDEBUG << "unloading library " << handle << " for plugin " << plugin << endl;
Chris@298 387 DLCLOSE(handle);
Chris@298 388 }
Chris@298 389 m_handleMap.erase(plugin);
Chris@298 390 }
Chris@298 391
Chris@165 392 QString
Chris@165 393 FeatureExtractionPluginFactory::getPluginCategory(QString identifier)
Chris@165 394 {
Chris@165 395 return m_taxonomy[identifier];
Chris@165 396 }
Chris@165 397
Chris@165 398 void
Chris@165 399 FeatureExtractionPluginFactory::generateTaxonomy()
Chris@165 400 {
Chris@165 401 std::vector<QString> pluginPath = getPluginPath();
Chris@165 402 std::vector<QString> path;
Chris@165 403
Chris@165 404 for (size_t i = 0; i < pluginPath.size(); ++i) {
Chris@165 405 if (pluginPath[i].contains("/lib/")) {
Chris@165 406 QString p(pluginPath[i]);
Chris@165 407 path.push_back(p);
Chris@165 408 p.replace("/lib/", "/share/");
Chris@165 409 path.push_back(p);
Chris@165 410 }
Chris@165 411 path.push_back(pluginPath[i]);
Chris@165 412 }
Chris@165 413
Chris@165 414 for (size_t i = 0; i < path.size(); ++i) {
Chris@165 415
Chris@165 416 QDir dir(path[i], "*.cat");
Chris@165 417
Chris@690 418 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << endl;
Chris@165 419 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@165 420
Chris@165 421 QFile file(path[i] + "/" + dir[j]);
Chris@165 422
Chris@690 423 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i]+ "/" + dir[j]) << endl;
Chris@165 424
Chris@165 425 if (file.open(QIODevice::ReadOnly)) {
Chris@843 426 // cerr << "...opened" << endl;
Chris@165 427 QTextStream stream(&file);
Chris@165 428 QString line;
Chris@165 429
Chris@165 430 while (!stream.atEnd()) {
Chris@165 431 line = stream.readLine();
Chris@843 432 // cerr << "line is: \"" << line << "\"" << endl;
Chris@165 433 QString id = PluginIdentifier::canonicalise
Chris@165 434 (line.section("::", 0, 0));
Chris@165 435 QString cat = line.section("::", 1, 1);
Chris@165 436 m_taxonomy[id] = cat;
Chris@843 437 // cerr << "FeatureExtractionPluginFactory: set id \"" << id << "\" to cat \"" << cat << "\"" << endl;
Chris@165 438 }
Chris@165 439 }
Chris@165 440 }
Chris@165 441 }
Chris@165 442 }