Chris@49: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@52: Sonic Visualiser Chris@52: An audio file viewer and annotation editor. Chris@52: Centre for Digital Music, Queen Mary, University of London. Chris@52: This file copyright 2006 Chris Cannam. Chris@0: Chris@52: This program is free software; you can redistribute it and/or Chris@52: modify it under the terms of the GNU General Public License as Chris@52: published by the Free Software Foundation; either version 2 of the Chris@52: License, or (at your option) any later version. See the file Chris@52: COPYING included with this distribution for more information. Chris@0: */ Chris@0: Chris@0: #include "FeatureExtractionPluginFactory.h" Chris@0: #include "PluginIdentifier.h" Chris@0: Chris@66: #include "vamp/vamp.h" Chris@66: #include "vamp-sdk/PluginHostAdapter.h" Chris@66: Chris@150: #include "system/System.h" Chris@66: Chris@66: #include Chris@66: #include Chris@66: #include Chris@165: #include Chris@66: Chris@0: #include Chris@0: Chris@0: static FeatureExtractionPluginFactory *_nativeInstance = 0; Chris@0: Chris@0: FeatureExtractionPluginFactory * Chris@0: FeatureExtractionPluginFactory::instance(QString pluginType) Chris@0: { Chris@71: if (pluginType == "vamp") { Chris@0: if (!_nativeInstance) { Chris@0: std::cerr << "FeatureExtractionPluginFactory::instance(" << pluginType.toStdString() Chris@0: << "): creating new FeatureExtractionPluginFactory" << std::endl; Chris@0: _nativeInstance = new FeatureExtractionPluginFactory(); Chris@0: } Chris@0: return _nativeInstance; Chris@0: } Chris@0: Chris@0: else return 0; Chris@0: } Chris@0: Chris@0: FeatureExtractionPluginFactory * Chris@0: FeatureExtractionPluginFactory::instanceFor(QString identifier) Chris@0: { Chris@0: QString type, soName, label; Chris@0: PluginIdentifier::parseIdentifier(identifier, type, soName, label); Chris@0: return instance(type); Chris@0: } Chris@0: Chris@0: std::vector Chris@66: FeatureExtractionPluginFactory::getPluginPath() Chris@66: { Chris@117: if (!m_pluginPath.empty()) return m_pluginPath; Chris@117: Chris@66: std::vector path; Chris@66: std::string envPath; Chris@66: Chris@78: char *cpath = getenv("VAMP_PATH"); Chris@66: if (cpath) envPath = cpath; Chris@66: Chris@66: if (envPath == "") { Chris@78: envPath = DEFAULT_VAMP_PATH; Chris@66: char *chome = getenv("HOME"); Chris@66: if (chome) { Chris@78: std::string home(chome); Chris@78: int f; Chris@78: while ((f = envPath.find("$HOME")) >= 0 && f < envPath.length()) { Chris@78: envPath.replace(f, 5, home); Chris@78: } Chris@66: } Chris@83: #ifdef Q_WS_WIN32 Chris@83: char *cpfiles = getenv("ProgramFiles"); Chris@83: if (!cpfiles) cpfiles = "C:\\Program Files"; Chris@83: std::string pfiles(cpfiles); Chris@83: int f; Chris@83: while ((f = envPath.find("%ProgramFiles%")) >= 0 && f < envPath.length()) { Chris@83: envPath.replace(f, 14, pfiles); Chris@83: } Chris@83: #endif Chris@66: } Chris@66: Chris@78: std::cerr << "VAMP path is: \"" << envPath << "\"" << std::endl; Chris@78: Chris@66: std::string::size_type index = 0, newindex = 0; Chris@66: Chris@78: while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) { Chris@66: path.push_back(envPath.substr(index, newindex - index).c_str()); Chris@66: index = newindex + 1; Chris@66: } Chris@66: Chris@66: path.push_back(envPath.substr(index).c_str()); Chris@66: Chris@117: m_pluginPath = path; Chris@66: return path; Chris@66: } Chris@66: Chris@66: std::vector Chris@0: FeatureExtractionPluginFactory::getAllPluginIdentifiers() Chris@0: { Chris@0: FeatureExtractionPluginFactory *factory; Chris@0: std::vector rv; Chris@0: Chris@66: factory = instance("vamp"); Chris@0: if (factory) { Chris@0: std::vector tmp = factory->getPluginIdentifiers(); Chris@0: for (size_t i = 0; i < tmp.size(); ++i) { Chris@0: rv.push_back(tmp[i]); Chris@0: } Chris@0: } Chris@0: Chris@0: // Plugins can change the locale, revert it to default. Chris@0: setlocale(LC_ALL, "C"); Chris@0: return rv; Chris@0: } Chris@0: Chris@0: std::vector Chris@0: FeatureExtractionPluginFactory::getPluginIdentifiers() Chris@0: { Chris@0: std::vector rv; Chris@66: std::vector path = getPluginPath(); Chris@66: Chris@66: for (std::vector::iterator i = path.begin(); i != path.end(); ++i) { Chris@66: Chris@117: // std::cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << i->toStdString() << std::endl; Chris@66: Chris@66: QDir pluginDir(*i, PLUGIN_GLOB, Chris@66: QDir::Name | QDir::IgnoreCase, Chris@66: QDir::Files | QDir::Readable); Chris@66: Chris@66: for (unsigned int j = 0; j < pluginDir.count(); ++j) { Chris@66: Chris@66: QString soname = pluginDir.filePath(pluginDir[j]); Chris@66: Chris@66: void *libraryHandle = DLOPEN(soname, RTLD_LAZY); Chris@66: Chris@66: if (!libraryHandle) { Chris@71: std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl; Chris@66: continue; Chris@66: } Chris@66: Chris@66: VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) Chris@66: DLSYM(libraryHandle, "vampGetPluginDescriptor"); Chris@66: Chris@66: if (!fn) { Chris@66: std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname.toStdString() << std::endl; Chris@66: if (DLCLOSE(libraryHandle) != 0) { Chris@66: std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl; Chris@66: } Chris@66: continue; Chris@66: } Chris@66: Chris@66: const VampPluginDescriptor *descriptor = 0; Chris@66: int index = 0; Chris@66: Chris@66: while ((descriptor = fn(index))) { Chris@82: QString id = PluginIdentifier::createIdentifier Chris@82: ("vamp", soname, descriptor->name); Chris@66: rv.push_back(id); Chris@66: std::cerr << "Found id " << id.toStdString() << std::endl; Chris@66: ++index; Chris@66: } Chris@66: Chris@66: if (DLCLOSE(libraryHandle) != 0) { Chris@66: std::cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname.toStdString() << std::endl; Chris@66: } Chris@66: } Chris@66: } Chris@66: Chris@165: generateTaxonomy(); Chris@165: Chris@0: return rv; Chris@0: } Chris@0: Chris@66: QString Chris@66: FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir) Chris@66: { Chris@66: QString file = ""; Chris@66: Chris@66: if (inDir != "") { Chris@66: Chris@66: QDir dir(inDir, PLUGIN_GLOB, Chris@66: QDir::Name | QDir::IgnoreCase, Chris@66: QDir::Files | QDir::Readable); Chris@66: if (!dir.exists()) return ""; Chris@66: Chris@66: file = dir.filePath(QFileInfo(soname).fileName()); Chris@66: if (QFileInfo(file).exists()) { Chris@66: return file; Chris@66: } Chris@66: Chris@66: for (unsigned int j = 0; j < dir.count(); ++j) { Chris@66: file = dir.filePath(dir[j]); Chris@66: if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) { Chris@66: return file; Chris@66: } Chris@66: } Chris@66: Chris@66: return ""; Chris@66: Chris@66: } else { Chris@66: Chris@66: QFileInfo fi(soname); Chris@66: if (fi.exists()) return soname; Chris@66: Chris@66: if (fi.isAbsolute() && fi.absolutePath() != "") { Chris@66: file = findPluginFile(soname, fi.absolutePath()); Chris@66: if (file != "") return file; Chris@66: } Chris@66: Chris@66: std::vector path = getPluginPath(); Chris@66: for (std::vector::iterator i = path.begin(); Chris@66: i != path.end(); ++i) { Chris@66: if (*i != "") { Chris@66: file = findPluginFile(soname, *i); Chris@66: if (file != "") return file; Chris@66: } Chris@66: } Chris@66: Chris@66: return ""; Chris@66: } Chris@66: } Chris@66: Chris@66: Vamp::Plugin * Chris@0: FeatureExtractionPluginFactory::instantiatePlugin(QString identifier, Chris@0: float inputSampleRate) Chris@0: { Chris@66: Vamp::Plugin *rv = 0; Chris@66: Chris@66: const VampPluginDescriptor *descriptor = 0; Chris@66: int index = 0; Chris@66: Chris@66: QString type, soname, label; Chris@66: PluginIdentifier::parseIdentifier(identifier, type, soname, label); Chris@71: if (type != "vamp") { Chris@0: std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type.toStdString() << std::endl; Chris@0: return 0; Chris@0: } Chris@0: Chris@66: QString found = findPluginFile(soname); Chris@66: Chris@66: if (found == "") { Chris@66: std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname.toStdString() << std::endl; Chris@117: return 0; Chris@66: } else if (found != soname) { Chris@117: // std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: WARNING: Given library name was " << soname.toStdString() << ", found at " << found.toStdString() << std::endl; Chris@117: // std::cerr << soname.toStdString() << " -> " << found.toStdString() << std::endl; Chris@0: } Chris@0: Chris@66: soname = found; Chris@66: Chris@66: void *libraryHandle = DLOPEN(soname, RTLD_LAZY); Chris@66: Chris@66: if (!libraryHandle) { Chris@71: std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname.toStdString() << ": " << DLERROR() << std::endl; Chris@66: return 0; Chris@19: } Chris@19: Chris@66: VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) Chris@66: DLSYM(libraryHandle, "vampGetPluginDescriptor"); Chris@66: Chris@66: if (!fn) { Chris@66: std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname.toStdString() << std::endl; Chris@66: goto done; Chris@0: } Chris@0: Chris@66: while ((descriptor = fn(index))) { Chris@66: if (label == descriptor->name) break; Chris@66: ++index; Chris@47: } Chris@47: Chris@66: if (!descriptor) { Chris@66: std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label.toStdString() << "\" in library " << soname.toStdString() << std::endl; Chris@66: goto done; Martin@37: } Martin@37: Chris@66: rv = new Vamp::PluginHostAdapter(descriptor, inputSampleRate); Chris@66: Chris@117: // std::cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << std::endl; Chris@79: Chris@66: //!!! need to dlclose() when plugins from a given library are unloaded Chris@66: Chris@66: done: Chris@66: if (!rv) { Chris@66: if (DLCLOSE(libraryHandle) != 0) { Chris@66: std::cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname.toStdString() << std::endl; Chris@66: } Chris@66: } Chris@73: Chris@73: // 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: Chris@66: return rv; Chris@0: } Chris@0: Chris@165: QString Chris@165: FeatureExtractionPluginFactory::getPluginCategory(QString identifier) Chris@165: { Chris@165: return m_taxonomy[identifier]; Chris@165: } Chris@165: Chris@165: void Chris@165: FeatureExtractionPluginFactory::generateTaxonomy() Chris@165: { Chris@165: std::vector pluginPath = getPluginPath(); Chris@165: std::vector path; Chris@165: Chris@165: for (size_t i = 0; i < pluginPath.size(); ++i) { Chris@165: if (pluginPath[i].contains("/lib/")) { Chris@165: QString p(pluginPath[i]); Chris@165: path.push_back(p); Chris@165: p.replace("/lib/", "/share/"); Chris@165: path.push_back(p); Chris@165: } Chris@165: path.push_back(pluginPath[i]); Chris@165: } Chris@165: Chris@165: for (size_t i = 0; i < path.size(); ++i) { Chris@165: Chris@165: QDir dir(path[i], "*.cat"); Chris@165: Chris@165: // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i].toStdString() << " has " << dir.count() << " .cat files" << std::endl; Chris@165: for (unsigned int j = 0; j < dir.count(); ++j) { Chris@165: Chris@165: QFile file(path[i] + "/" + dir[j]); Chris@165: Chris@165: // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i].toStdString() + "/" + dir[j].toStdString()) << std::endl; Chris@165: Chris@165: if (file.open(QIODevice::ReadOnly)) { Chris@165: // std::cerr << "...opened" << std::endl; Chris@165: QTextStream stream(&file); Chris@165: QString line; Chris@165: Chris@165: while (!stream.atEnd()) { Chris@165: line = stream.readLine(); Chris@165: // std::cerr << "line is: \"" << line.toStdString() << "\"" << std::endl; Chris@165: QString id = PluginIdentifier::canonicalise Chris@165: (line.section("::", 0, 0)); Chris@165: QString cat = line.section("::", 1, 1); Chris@165: m_taxonomy[id] = cat; Chris@165: // std::cerr << "FeatureExtractionPluginFactory: set id \"" << id.toStdString() << "\" to cat \"" << cat.toStdString() << "\"" << std::endl; Chris@165: } Chris@165: } Chris@165: } Chris@165: } Chris@165: }