annotate plugin/FeatureExtractionPluginFactory.cpp @ 167:665342c6ec57

* Add a bit of resistance to pane dragging so as to make it harder to inadvertently drag in the other axis from the one you intended
author Chris Cannam
date Fri, 22 Sep 2006 16:46:10 +0000
parents 5ae5885d6ce3
children 06ad01f3e553
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@52 7 This file copyright 2006 Chris Cannam.
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@0 31 static FeatureExtractionPluginFactory *_nativeInstance = 0;
Chris@0 32
Chris@0 33 FeatureExtractionPluginFactory *
Chris@0 34 FeatureExtractionPluginFactory::instance(QString pluginType)
Chris@0 35 {
Chris@71 36 if (pluginType == "vamp") {
Chris@0 37 if (!_nativeInstance) {
Chris@0 38 std::cerr << "FeatureExtractionPluginFactory::instance(" << pluginType.toStdString()
Chris@0 39 << "): creating new FeatureExtractionPluginFactory" << std::endl;
Chris@0 40 _nativeInstance = new FeatureExtractionPluginFactory();
Chris@0 41 }
Chris@0 42 return _nativeInstance;
Chris@0 43 }
Chris@0 44
Chris@0 45 else return 0;
Chris@0 46 }
Chris@0 47
Chris@0 48 FeatureExtractionPluginFactory *
Chris@0 49 FeatureExtractionPluginFactory::instanceFor(QString identifier)
Chris@0 50 {
Chris@0 51 QString type, soName, label;
Chris@0 52 PluginIdentifier::parseIdentifier(identifier, type, soName, label);
Chris@0 53 return instance(type);
Chris@0 54 }
Chris@0 55
Chris@0 56 std::vector<QString>
Chris@66 57 FeatureExtractionPluginFactory::getPluginPath()
Chris@66 58 {
Chris@117 59 if (!m_pluginPath.empty()) return m_pluginPath;
Chris@117 60
Chris@66 61 std::vector<QString> path;
Chris@66 62 std::string envPath;
Chris@66 63
Chris@78 64 char *cpath = getenv("VAMP_PATH");
Chris@66 65 if (cpath) envPath = cpath;
Chris@66 66
Chris@66 67 if (envPath == "") {
Chris@78 68 envPath = DEFAULT_VAMP_PATH;
Chris@66 69 char *chome = getenv("HOME");
Chris@66 70 if (chome) {
Chris@78 71 std::string home(chome);
Chris@78 72 int f;
Chris@78 73 while ((f = envPath.find("$HOME")) >= 0 && f < envPath.length()) {
Chris@78 74 envPath.replace(f, 5, home);
Chris@78 75 }
Chris@66 76 }
Chris@83 77 #ifdef Q_WS_WIN32
Chris@83 78 char *cpfiles = getenv("ProgramFiles");
Chris@83 79 if (!cpfiles) cpfiles = "C:\\Program Files";
Chris@83 80 std::string pfiles(cpfiles);
Chris@83 81 int f;
Chris@83 82 while ((f = envPath.find("%ProgramFiles%")) >= 0 && f < envPath.length()) {
Chris@83 83 envPath.replace(f, 14, pfiles);
Chris@83 84 }
Chris@83 85 #endif
Chris@66 86 }
Chris@66 87
Chris@78 88 std::cerr << "VAMP path is: \"" << envPath << "\"" << std::endl;
Chris@78 89
Chris@66 90 std::string::size_type index = 0, newindex = 0;
Chris@66 91
Chris@78 92 while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) {
Chris@66 93 path.push_back(envPath.substr(index, newindex - index).c_str());
Chris@66 94 index = newindex + 1;
Chris@66 95 }
Chris@66 96
Chris@66 97 path.push_back(envPath.substr(index).c_str());
Chris@66 98
Chris@117 99 m_pluginPath = path;
Chris@66 100 return path;
Chris@66 101 }
Chris@66 102
Chris@66 103 std::vector<QString>
Chris@0 104 FeatureExtractionPluginFactory::getAllPluginIdentifiers()
Chris@0 105 {
Chris@0 106 FeatureExtractionPluginFactory *factory;
Chris@0 107 std::vector<QString> rv;
Chris@0 108
Chris@66 109 factory = instance("vamp");
Chris@0 110 if (factory) {
Chris@0 111 std::vector<QString> tmp = factory->getPluginIdentifiers();
Chris@0 112 for (size_t i = 0; i < tmp.size(); ++i) {
Chris@0 113 rv.push_back(tmp[i]);
Chris@0 114 }
Chris@0 115 }
Chris@0 116
Chris@0 117 // Plugins can change the locale, revert it to default.
Chris@0 118 setlocale(LC_ALL, "C");
Chris@0 119 return rv;
Chris@0 120 }
Chris@0 121
Chris@0 122 std::vector<QString>
Chris@0 123 FeatureExtractionPluginFactory::getPluginIdentifiers()
Chris@0 124 {
Chris@0 125 std::vector<QString> rv;
Chris@66 126 std::vector<QString> path = getPluginPath();
Chris@66 127
Chris@66 128 for (std::vector<QString>::iterator i = path.begin(); i != path.end(); ++i) {
Chris@66 129
Chris@117 130 // std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << i->toStdString() << std::endl;
Chris@66 131
Chris@66 132 QDir pluginDir(*i, PLUGIN_GLOB,
Chris@66 133 QDir::Name | QDir::IgnoreCase,
Chris@66 134 QDir::Files | QDir::Readable);
Chris@66 135
Chris@66 136 for (unsigned int j = 0; j < pluginDir.count(); ++j) {
Chris@66 137
Chris@66 138 QString soname = pluginDir.filePath(pluginDir[j]);
Chris@66 139
Chris@66 140 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
Chris@66 141
Chris@66 142 if (!libraryHandle) {
Chris@71 143 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl;
Chris@66 144 continue;
Chris@66 145 }
Chris@66 146
Chris@66 147 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 148 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 149
Chris@66 150 if (!fn) {
Chris@66 151 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname.toStdString() << std::endl;
Chris@66 152 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 153 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 154 }
Chris@66 155 continue;
Chris@66 156 }
Chris@66 157
Chris@66 158 const VampPluginDescriptor *descriptor = 0;
Chris@66 159 int index = 0;
Chris@66 160
Chris@66 161 while ((descriptor = fn(index))) {
Chris@82 162 QString id = PluginIdentifier::createIdentifier
Chris@82 163 ("vamp", soname, descriptor->name);
Chris@66 164 rv.push_back(id);
Chris@66 165 std::cerr << "Found id " << id.toStdString() << std::endl;
Chris@66 166 ++index;
Chris@66 167 }
Chris@66 168
Chris@66 169 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 170 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 171 }
Chris@66 172 }
Chris@66 173 }
Chris@66 174
Chris@165 175 generateTaxonomy();
Chris@165 176
Chris@0 177 return rv;
Chris@0 178 }
Chris@0 179
Chris@66 180 QString
Chris@66 181 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir)
Chris@66 182 {
Chris@66 183 QString file = "";
Chris@66 184
Chris@66 185 if (inDir != "") {
Chris@66 186
Chris@66 187 QDir dir(inDir, PLUGIN_GLOB,
Chris@66 188 QDir::Name | QDir::IgnoreCase,
Chris@66 189 QDir::Files | QDir::Readable);
Chris@66 190 if (!dir.exists()) return "";
Chris@66 191
Chris@66 192 file = dir.filePath(QFileInfo(soname).fileName());
Chris@66 193 if (QFileInfo(file).exists()) {
Chris@66 194 return file;
Chris@66 195 }
Chris@66 196
Chris@66 197 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@66 198 file = dir.filePath(dir[j]);
Chris@66 199 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) {
Chris@66 200 return file;
Chris@66 201 }
Chris@66 202 }
Chris@66 203
Chris@66 204 return "";
Chris@66 205
Chris@66 206 } else {
Chris@66 207
Chris@66 208 QFileInfo fi(soname);
Chris@66 209 if (fi.exists()) return soname;
Chris@66 210
Chris@66 211 if (fi.isAbsolute() && fi.absolutePath() != "") {
Chris@66 212 file = findPluginFile(soname, fi.absolutePath());
Chris@66 213 if (file != "") return file;
Chris@66 214 }
Chris@66 215
Chris@66 216 std::vector<QString> path = getPluginPath();
Chris@66 217 for (std::vector<QString>::iterator i = path.begin();
Chris@66 218 i != path.end(); ++i) {
Chris@66 219 if (*i != "") {
Chris@66 220 file = findPluginFile(soname, *i);
Chris@66 221 if (file != "") return file;
Chris@66 222 }
Chris@66 223 }
Chris@66 224
Chris@66 225 return "";
Chris@66 226 }
Chris@66 227 }
Chris@66 228
Chris@66 229 Vamp::Plugin *
Chris@0 230 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier,
Chris@0 231 float inputSampleRate)
Chris@0 232 {
Chris@66 233 Vamp::Plugin *rv = 0;
Chris@66 234
Chris@66 235 const VampPluginDescriptor *descriptor = 0;
Chris@66 236 int index = 0;
Chris@66 237
Chris@66 238 QString type, soname, label;
Chris@66 239 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@71 240 if (type != "vamp") {
Chris@0 241 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type.toStdString() << std::endl;
Chris@0 242 return 0;
Chris@0 243 }
Chris@0 244
Chris@66 245 QString found = findPluginFile(soname);
Chris@66 246
Chris@66 247 if (found == "") {
Chris@66 248 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname.toStdString() << std::endl;
Chris@117 249 return 0;
Chris@66 250 } else if (found != soname) {
Chris@117 251 // std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: WARNING: Given library name was " << soname.toStdString() << ", found at " << found.toStdString() << std::endl;
Chris@117 252 // std::cerr << soname.toStdString() << " -> " << found.toStdString() << std::endl;
Chris@0 253 }
Chris@0 254
Chris@66 255 soname = found;
Chris@66 256
Chris@66 257 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
Chris@66 258
Chris@66 259 if (!libraryHandle) {
Chris@71 260 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl;
Chris@66 261 return 0;
Chris@19 262 }
Chris@19 263
Chris@66 264 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 265 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 266
Chris@66 267 if (!fn) {
Chris@66 268 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname.toStdString() << std::endl;
Chris@66 269 goto done;
Chris@0 270 }
Chris@0 271
Chris@66 272 while ((descriptor = fn(index))) {
Chris@66 273 if (label == descriptor->name) break;
Chris@66 274 ++index;
Chris@47 275 }
Chris@47 276
Chris@66 277 if (!descriptor) {
Chris@66 278 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label.toStdString() << "\" in library " << soname.toStdString() << std::endl;
Chris@66 279 goto done;
Martin@37 280 }
Martin@37 281
Chris@66 282 rv = new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
Chris@66 283
Chris@117 284 // std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << std::endl;
Chris@79 285
Chris@66 286 //!!! need to dlclose() when plugins from a given library are unloaded
Chris@66 287
Chris@66 288 done:
Chris@66 289 if (!rv) {
Chris@66 290 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 291 std::cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 292 }
Chris@66 293 }
Chris@73 294
Chris@73 295 // 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 296
Chris@66 297 return rv;
Chris@0 298 }
Chris@0 299
Chris@165 300 QString
Chris@165 301 FeatureExtractionPluginFactory::getPluginCategory(QString identifier)
Chris@165 302 {
Chris@165 303 return m_taxonomy[identifier];
Chris@165 304 }
Chris@165 305
Chris@165 306 void
Chris@165 307 FeatureExtractionPluginFactory::generateTaxonomy()
Chris@165 308 {
Chris@165 309 std::vector<QString> pluginPath = getPluginPath();
Chris@165 310 std::vector<QString> path;
Chris@165 311
Chris@165 312 for (size_t i = 0; i < pluginPath.size(); ++i) {
Chris@165 313 if (pluginPath[i].contains("/lib/")) {
Chris@165 314 QString p(pluginPath[i]);
Chris@165 315 path.push_back(p);
Chris@165 316 p.replace("/lib/", "/share/");
Chris@165 317 path.push_back(p);
Chris@165 318 }
Chris@165 319 path.push_back(pluginPath[i]);
Chris@165 320 }
Chris@165 321
Chris@165 322 for (size_t i = 0; i < path.size(); ++i) {
Chris@165 323
Chris@165 324 QDir dir(path[i], "*.cat");
Chris@165 325
Chris@165 326 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i].toStdString() << " has " << dir.count() << " .cat files" << std::endl;
Chris@165 327 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@165 328
Chris@165 329 QFile file(path[i] + "/" + dir[j]);
Chris@165 330
Chris@165 331 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i].toStdString() + "/" + dir[j].toStdString()) << std::endl;
Chris@165 332
Chris@165 333 if (file.open(QIODevice::ReadOnly)) {
Chris@165 334 // std::cerr << "...opened" << std::endl;
Chris@165 335 QTextStream stream(&file);
Chris@165 336 QString line;
Chris@165 337
Chris@165 338 while (!stream.atEnd()) {
Chris@165 339 line = stream.readLine();
Chris@165 340 // std::cerr << "line is: \"" << line.toStdString() << "\"" << std::endl;
Chris@165 341 QString id = PluginIdentifier::canonicalise
Chris@165 342 (line.section("::", 0, 0));
Chris@165 343 QString cat = line.section("::", 1, 1);
Chris@165 344 m_taxonomy[id] = cat;
Chris@165 345 // std::cerr << "FeatureExtractionPluginFactory: set id \"" << id.toStdString() << "\" to cat \"" << cat.toStdString() << "\"" << std::endl;
Chris@165 346 }
Chris@165 347 }
Chris@165 348 }
Chris@165 349 }
Chris@165 350 }