annotate plugin/FeatureExtractionPluginFactory.cpp @ 242:2f7d27648806

* Fix real-time plugin corruption when getLatency is called for some plugins * Other minor changes
author Chris Cannam
date Thu, 01 Mar 2007 15:35:27 +0000
parents 2b40f83e7627
children d3ac9f953ebf
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@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@186 61 std::vector<std::string> p = Vamp::PluginHostAdapter::getPluginPath();
Chris@186 62 for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str());
Chris@186 63 return m_pluginPath;
Chris@66 64 }
Chris@66 65
Chris@66 66 std::vector<QString>
Chris@0 67 FeatureExtractionPluginFactory::getAllPluginIdentifiers()
Chris@0 68 {
Chris@0 69 FeatureExtractionPluginFactory *factory;
Chris@0 70 std::vector<QString> rv;
Chris@0 71
Chris@66 72 factory = instance("vamp");
Chris@0 73 if (factory) {
Chris@0 74 std::vector<QString> tmp = factory->getPluginIdentifiers();
Chris@0 75 for (size_t i = 0; i < tmp.size(); ++i) {
Chris@0 76 rv.push_back(tmp[i]);
Chris@0 77 }
Chris@0 78 }
Chris@0 79
Chris@0 80 // Plugins can change the locale, revert it to default.
Chris@0 81 setlocale(LC_ALL, "C");
Chris@0 82 return rv;
Chris@0 83 }
Chris@0 84
Chris@0 85 std::vector<QString>
Chris@0 86 FeatureExtractionPluginFactory::getPluginIdentifiers()
Chris@0 87 {
Chris@0 88 std::vector<QString> rv;
Chris@66 89 std::vector<QString> path = getPluginPath();
Chris@66 90
Chris@66 91 for (std::vector<QString>::iterator i = path.begin(); i != path.end(); ++i) {
Chris@66 92
Chris@117 93 // std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << i->toStdString() << std::endl;
Chris@66 94
Chris@66 95 QDir pluginDir(*i, PLUGIN_GLOB,
Chris@66 96 QDir::Name | QDir::IgnoreCase,
Chris@66 97 QDir::Files | QDir::Readable);
Chris@66 98
Chris@66 99 for (unsigned int j = 0; j < pluginDir.count(); ++j) {
Chris@66 100
Chris@66 101 QString soname = pluginDir.filePath(pluginDir[j]);
Chris@66 102
Chris@66 103 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
Chris@66 104
Chris@66 105 if (!libraryHandle) {
Chris@71 106 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl;
Chris@66 107 continue;
Chris@66 108 }
Chris@66 109
Chris@66 110 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 111 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 112
Chris@66 113 if (!fn) {
Chris@66 114 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname.toStdString() << std::endl;
Chris@66 115 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 116 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 117 }
Chris@66 118 continue;
Chris@66 119 }
Chris@66 120
Chris@66 121 const VampPluginDescriptor *descriptor = 0;
Chris@66 122 int index = 0;
Chris@66 123
Chris@239 124 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@82 125 QString id = PluginIdentifier::createIdentifier
Chris@238 126 ("vamp", soname, descriptor->identifier);
Chris@66 127 rv.push_back(id);
Chris@241 128 // std::cerr << "Found id " << id.toStdString() << std::endl;
Chris@66 129 ++index;
Chris@66 130 }
Chris@66 131
Chris@66 132 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 133 std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 134 }
Chris@66 135 }
Chris@66 136 }
Chris@66 137
Chris@165 138 generateTaxonomy();
Chris@165 139
Chris@0 140 return rv;
Chris@0 141 }
Chris@0 142
Chris@66 143 QString
Chris@66 144 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir)
Chris@66 145 {
Chris@66 146 QString file = "";
Chris@66 147
Chris@66 148 if (inDir != "") {
Chris@66 149
Chris@66 150 QDir dir(inDir, PLUGIN_GLOB,
Chris@66 151 QDir::Name | QDir::IgnoreCase,
Chris@66 152 QDir::Files | QDir::Readable);
Chris@66 153 if (!dir.exists()) return "";
Chris@66 154
Chris@66 155 file = dir.filePath(QFileInfo(soname).fileName());
Chris@66 156 if (QFileInfo(file).exists()) {
Chris@66 157 return file;
Chris@66 158 }
Chris@66 159
Chris@66 160 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@66 161 file = dir.filePath(dir[j]);
Chris@66 162 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) {
Chris@66 163 return file;
Chris@66 164 }
Chris@66 165 }
Chris@66 166
Chris@66 167 return "";
Chris@66 168
Chris@66 169 } else {
Chris@66 170
Chris@66 171 QFileInfo fi(soname);
Chris@66 172 if (fi.exists()) return soname;
Chris@66 173
Chris@66 174 if (fi.isAbsolute() && fi.absolutePath() != "") {
Chris@66 175 file = findPluginFile(soname, fi.absolutePath());
Chris@66 176 if (file != "") return file;
Chris@66 177 }
Chris@66 178
Chris@66 179 std::vector<QString> path = getPluginPath();
Chris@66 180 for (std::vector<QString>::iterator i = path.begin();
Chris@66 181 i != path.end(); ++i) {
Chris@66 182 if (*i != "") {
Chris@66 183 file = findPluginFile(soname, *i);
Chris@66 184 if (file != "") return file;
Chris@66 185 }
Chris@66 186 }
Chris@66 187
Chris@66 188 return "";
Chris@66 189 }
Chris@66 190 }
Chris@66 191
Chris@66 192 Vamp::Plugin *
Chris@0 193 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier,
Chris@0 194 float inputSampleRate)
Chris@0 195 {
Chris@66 196 Vamp::Plugin *rv = 0;
Chris@66 197
Chris@66 198 const VampPluginDescriptor *descriptor = 0;
Chris@66 199 int index = 0;
Chris@66 200
Chris@66 201 QString type, soname, label;
Chris@66 202 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@71 203 if (type != "vamp") {
Chris@0 204 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type.toStdString() << std::endl;
Chris@0 205 return 0;
Chris@0 206 }
Chris@0 207
Chris@66 208 QString found = findPluginFile(soname);
Chris@66 209
Chris@66 210 if (found == "") {
Chris@66 211 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname.toStdString() << std::endl;
Chris@117 212 return 0;
Chris@66 213 } else if (found != soname) {
Chris@117 214 // std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: WARNING: Given library name was " << soname.toStdString() << ", found at " << found.toStdString() << std::endl;
Chris@117 215 // std::cerr << soname.toStdString() << " -> " << found.toStdString() << std::endl;
Chris@0 216 }
Chris@0 217
Chris@66 218 soname = found;
Chris@66 219
Chris@66 220 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
Chris@66 221
Chris@66 222 if (!libraryHandle) {
Chris@71 223 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl;
Chris@66 224 return 0;
Chris@19 225 }
Chris@19 226
Chris@66 227 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
Chris@66 228 DLSYM(libraryHandle, "vampGetPluginDescriptor");
Chris@66 229
Chris@66 230 if (!fn) {
Chris@66 231 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname.toStdString() << std::endl;
Chris@66 232 goto done;
Chris@0 233 }
Chris@0 234
Chris@239 235 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@238 236 if (label == descriptor->identifier) break;
Chris@66 237 ++index;
Chris@47 238 }
Chris@47 239
Chris@66 240 if (!descriptor) {
Chris@66 241 std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label.toStdString() << "\" in library " << soname.toStdString() << std::endl;
Chris@66 242 goto done;
Martin@37 243 }
Martin@37 244
Chris@66 245 rv = new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
Chris@66 246
Chris@117 247 // std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << std::endl;
Chris@79 248
Chris@66 249 //!!! need to dlclose() when plugins from a given library are unloaded
Chris@66 250
Chris@66 251 done:
Chris@66 252 if (!rv) {
Chris@66 253 if (DLCLOSE(libraryHandle) != 0) {
Chris@66 254 std::cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname.toStdString() << std::endl;
Chris@66 255 }
Chris@66 256 }
Chris@73 257
Chris@73 258 // 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 259
Chris@66 260 return rv;
Chris@0 261 }
Chris@0 262
Chris@165 263 QString
Chris@165 264 FeatureExtractionPluginFactory::getPluginCategory(QString identifier)
Chris@165 265 {
Chris@165 266 return m_taxonomy[identifier];
Chris@165 267 }
Chris@165 268
Chris@165 269 void
Chris@165 270 FeatureExtractionPluginFactory::generateTaxonomy()
Chris@165 271 {
Chris@165 272 std::vector<QString> pluginPath = getPluginPath();
Chris@165 273 std::vector<QString> path;
Chris@165 274
Chris@165 275 for (size_t i = 0; i < pluginPath.size(); ++i) {
Chris@165 276 if (pluginPath[i].contains("/lib/")) {
Chris@165 277 QString p(pluginPath[i]);
Chris@165 278 path.push_back(p);
Chris@165 279 p.replace("/lib/", "/share/");
Chris@165 280 path.push_back(p);
Chris@165 281 }
Chris@165 282 path.push_back(pluginPath[i]);
Chris@165 283 }
Chris@165 284
Chris@165 285 for (size_t i = 0; i < path.size(); ++i) {
Chris@165 286
Chris@165 287 QDir dir(path[i], "*.cat");
Chris@165 288
Chris@165 289 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i].toStdString() << " has " << dir.count() << " .cat files" << std::endl;
Chris@165 290 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@165 291
Chris@165 292 QFile file(path[i] + "/" + dir[j]);
Chris@165 293
Chris@165 294 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i].toStdString() + "/" + dir[j].toStdString()) << std::endl;
Chris@165 295
Chris@165 296 if (file.open(QIODevice::ReadOnly)) {
Chris@165 297 // std::cerr << "...opened" << std::endl;
Chris@165 298 QTextStream stream(&file);
Chris@165 299 QString line;
Chris@165 300
Chris@165 301 while (!stream.atEnd()) {
Chris@165 302 line = stream.readLine();
Chris@165 303 // std::cerr << "line is: \"" << line.toStdString() << "\"" << std::endl;
Chris@165 304 QString id = PluginIdentifier::canonicalise
Chris@165 305 (line.section("::", 0, 0));
Chris@165 306 QString cat = line.section("::", 1, 1);
Chris@165 307 m_taxonomy[id] = cat;
Chris@165 308 // std::cerr << "FeatureExtractionPluginFactory: set id \"" << id.toStdString() << "\" to cat \"" << cat.toStdString() << "\"" << std::endl;
Chris@165 309 }
Chris@165 310 }
Chris@165 311 }
Chris@165 312 }
Chris@165 313 }