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