annotate plugin/FeatureExtractionPluginFactory.cpp @ 295:a2dc34ce146a

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