Mercurial > hg > easaier-soundaccess
diff plugin/FeatureExtractionPluginFactory.cpp @ 0:fc9323a41f5a
start base : Sonic Visualiser sv1-1.0rc1
author | lbajardsilogic |
---|---|
date | Fri, 11 May 2007 09:08:14 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/FeatureExtractionPluginFactory.cpp Fri May 11 09:08:14 2007 +0000 @@ -0,0 +1,399 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam and QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "FeatureExtractionPluginFactory.h" +#include "PluginIdentifier.h" + +#include "vamp/vamp.h" +#include "vamp-sdk/PluginHostAdapter.h" + +#include "system/System.h" + +#include <QDir> +#include <QFile> +#include <QFileInfo> +#include <QTextStream> + +#include <iostream> + +//#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 + +static FeatureExtractionPluginFactory *_nativeInstance = 0; + +FeatureExtractionPluginFactory * +FeatureExtractionPluginFactory::instance(QString pluginType) +{ + if (pluginType == "vamp") { + if (!_nativeInstance) { +// std::cerr << "FeatureExtractionPluginFactory::instance(" << pluginType.toStdString() +// << "): creating new FeatureExtractionPluginFactory" << std::endl; + _nativeInstance = new FeatureExtractionPluginFactory(); + } + return _nativeInstance; + } + + else return 0; +} + +FeatureExtractionPluginFactory * +FeatureExtractionPluginFactory::instanceFor(QString identifier) +{ + QString type, soName, label; + PluginIdentifier::parseIdentifier(identifier, type, soName, label); + return instance(type); +} + +std::vector<QString> +FeatureExtractionPluginFactory::getPluginPath() +{ + if (!m_pluginPath.empty()) return m_pluginPath; + + std::vector<std::string> p = Vamp::PluginHostAdapter::getPluginPath(); + for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str()); + return m_pluginPath; +} + +std::vector<QString> +FeatureExtractionPluginFactory::getAllPluginIdentifiers() +{ + FeatureExtractionPluginFactory *factory; + std::vector<QString> rv; + + factory = instance("vamp"); + if (factory) { + std::vector<QString> tmp = factory->getPluginIdentifiers(); + for (size_t i = 0; i < tmp.size(); ++i) { + rv.push_back(tmp[i]); + } + } + + // Plugins can change the locale, revert it to default. + setlocale(LC_ALL, "C"); + return rv; +} + +std::vector<QString> +FeatureExtractionPluginFactory::getPluginIdentifiers() +{ + std::vector<QString> rv; + std::vector<QString> path = getPluginPath(); + + for (std::vector<QString>::iterator i = path.begin(); i != path.end(); ++i) { + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << i->toStdString() << std::endl; +#endif + + QDir pluginDir(*i, PLUGIN_GLOB, + QDir::Name | QDir::IgnoreCase, + QDir::Files | QDir::Readable); + + for (unsigned int j = 0; j < pluginDir.count(); ++j) { + + QString soname = pluginDir.filePath(pluginDir[j]); + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: trying potential library " << soname.toStdString() << std::endl; +#endif + + void *libraryHandle = DLOPEN(soname, RTLD_LAZY); + + if (!libraryHandle) { + std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl; + continue; + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: It's a library all right, checking for descriptor" << std::endl; +#endif + + VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) + DLSYM(libraryHandle, "vampGetPluginDescriptor"); + + if (!fn) { + std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname.toStdString() << std::endl; + if (DLCLOSE(libraryHandle) != 0) { + std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl; + } + continue; + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << std::endl; +#endif + + const VampPluginDescriptor *descriptor = 0; + int index = 0; + + std::map<std::string, int> known; + bool ok = true; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + + if (known.find(descriptor->identifier) != known.end()) { + std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library " + << soname.toStdString() + << " returns the same plugin identifier \"" + << descriptor->identifier << "\" at indices " + << known[descriptor->identifier] << " and " + << index << std::endl; + std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << std::endl; + ok = false; + break; + } else { + known[descriptor->identifier] = index; + } + + ++index; + } + + if (ok) { + + index = 0; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + + QString id = PluginIdentifier::createIdentifier + ("vamp", soname, descriptor->identifier); + rv.push_back(id); +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id.toStdString() << " at index " << index << std::endl; +#endif + ++index; + } + } + + if (DLCLOSE(libraryHandle) != 0) { + std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl; + } + } + } + + generateTaxonomy(); + + return rv; +} + +QString +FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir) +{ + QString file = ""; + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::findPluginFile(\"" + << soname.toStdString() << "\", \"" << inDir.toStdString() << "\")" + << std::endl; +#endif + + if (inDir != "") { + + QDir dir(inDir, PLUGIN_GLOB, + QDir::Name | QDir::IgnoreCase, + QDir::Files | QDir::Readable); + if (!dir.exists()) return ""; + + file = dir.filePath(QFileInfo(soname).fileName()); + + if (QFileInfo(file).exists() && QFileInfo(file).isFile()) { + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::findPluginFile: " + << "found trivially at " << file.toStdString() << std::endl; +#endif + + return file; + } + + for (unsigned int j = 0; j < dir.count(); ++j) { + file = dir.filePath(dir[j]); + if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) { + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::findPluginFile: " + << "found at " << file.toStdString() << std::endl; +#endif + + return file; + } + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::findPluginFile (with dir): " + << "not found" << std::endl; +#endif + + return ""; + + } else { + + QFileInfo fi(soname); + + if (fi.isAbsolute() && fi.exists() && fi.isFile()) { +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::findPluginFile: " + << "found trivially at " << soname.toStdString() << std::endl; +#endif + return soname; + } + + if (fi.isAbsolute() && fi.absolutePath() != "") { + file = findPluginFile(soname, fi.absolutePath()); + if (file != "") return file; + } + + std::vector<QString> path = getPluginPath(); + for (std::vector<QString>::iterator i = path.begin(); + i != path.end(); ++i) { + if (*i != "") { + file = findPluginFile(soname, *i); + if (file != "") return file; + } + } + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::findPluginFile: " + << "not found" << std::endl; +#endif + + return ""; + } +} + +Vamp::Plugin * +FeatureExtractionPluginFactory::instantiatePlugin(QString identifier, + float inputSampleRate) +{ + Vamp::Plugin *rv = 0; + + const VampPluginDescriptor *descriptor = 0; + int index = 0; + + QString type, soname, label; + PluginIdentifier::parseIdentifier(identifier, type, soname, label); + if (type != "vamp") { + std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type.toStdString() << std::endl; + return 0; + } + + QString found = findPluginFile(soname); + + if (found == "") { + std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname.toStdString() << std::endl; + return 0; + } else if (found != soname) { + +#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE + std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Given library name was " << soname.toStdString() << ", found at " << found.toStdString() << std::endl; + std::cerr << soname.toStdString() << " -> " << found.toStdString() << std::endl; +#endif + + } + + soname = found; + + void *libraryHandle = DLOPEN(soname, RTLD_LAZY); + + if (!libraryHandle) { + std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl; + return 0; + } + + VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) + DLSYM(libraryHandle, "vampGetPluginDescriptor"); + + if (!fn) { + std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname.toStdString() << std::endl; + goto done; + } + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + if (label == descriptor->identifier) break; + ++index; + } + + if (!descriptor) { + std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label.toStdString() << "\" in library " << soname.toStdString() << std::endl; + goto done; + } + + rv = new Vamp::PluginHostAdapter(descriptor, inputSampleRate); + +// std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << std::endl; + + //!!! need to dlclose() when plugins from a given library are unloaded + +done: + if (!rv) { + if (DLCLOSE(libraryHandle) != 0) { + std::cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname.toStdString() << std::endl; + } + } + +// 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; + + return rv; +} + +QString +FeatureExtractionPluginFactory::getPluginCategory(QString identifier) +{ + return m_taxonomy[identifier]; +} + +void +FeatureExtractionPluginFactory::generateTaxonomy() +{ + std::vector<QString> pluginPath = getPluginPath(); + std::vector<QString> path; + + for (size_t i = 0; i < pluginPath.size(); ++i) { + if (pluginPath[i].contains("/lib/")) { + QString p(pluginPath[i]); + path.push_back(p); + p.replace("/lib/", "/share/"); + path.push_back(p); + } + path.push_back(pluginPath[i]); + } + + for (size_t i = 0; i < path.size(); ++i) { + + QDir dir(path[i], "*.cat"); + +// std::cerr << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i].toStdString() << " has " << dir.count() << " .cat files" << std::endl; + for (unsigned int j = 0; j < dir.count(); ++j) { + + QFile file(path[i] + "/" + dir[j]); + +// std::cerr << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i].toStdString() + "/" + dir[j].toStdString()) << std::endl; + + if (file.open(QIODevice::ReadOnly)) { +// std::cerr << "...opened" << std::endl; + QTextStream stream(&file); + QString line; + + while (!stream.atEnd()) { + line = stream.readLine(); +// std::cerr << "line is: \"" << line.toStdString() << "\"" << std::endl; + QString id = PluginIdentifier::canonicalise + (line.section("::", 0, 0)); + QString cat = line.section("::", 1, 1); + m_taxonomy[id] = cat; +// std::cerr << "FeatureExtractionPluginFactory: set id \"" << id.toStdString() << "\" to cat \"" << cat.toStdString() << "\"" << std::endl; + } + } + } + } +}