# HG changeset patch # User Chris Cannam # Date 1460733975 -3600 # Node ID a1f410f895d3edf8008067a57d86f92b5da278de # Parent 4018fc0189bc46bf36ce1961ae558377afff2c6e# Parent 2f628dc9a0b0ac0ccd3d8333e8bdbc541e88e0b2 Merge from branch pluginscan diff -r 4018fc0189bc -r a1f410f895d3 config.pri.in --- a/config.pri.in Fri Mar 18 14:25:05 2016 +0000 +++ b/config.pri.in Fri Apr 15 16:26:15 2016 +0100 @@ -10,7 +10,7 @@ QMAKE_CXXFLAGS += @CXXFLAGS@ QMAKE_LFLAGS += @LDFLAGS@ -linux*:LIBS += -lasound +linux*:LIBS += -lasound -ldl macx*:DEFINES += HAVE_COREAUDIO MACOSX_DEPLOYMENT_TARGET=1060 diff -r 4018fc0189bc -r a1f410f895d3 data/fileio/test/test.pro --- a/data/fileio/test/test.pro Fri Mar 18 14:25:05 2016 +0000 +++ b/data/fileio/test/test.pro Fri Apr 15 16:26:15 2016 +0100 @@ -36,6 +36,9 @@ DEFINES += HAVE_COREAUDIO LIBS += -framework CoreAudio -framework CoreMidi -framework AudioUnit -framework AudioToolbox -framework CoreFoundation -framework CoreServices -framework Accelerate } + linux* { + LIBS += -ldl + } } CONFIG += qt thread warn_on stl rtti exceptions console c++11 diff -r 4018fc0189bc -r a1f410f895d3 plugin/DSSIPluginFactory.h --- a/plugin/DSSIPluginFactory.h Fri Mar 18 14:25:05 2016 +0000 +++ b/plugin/DSSIPluginFactory.h Fri Apr 15 16:26:15 2016 +0100 @@ -48,6 +48,10 @@ DSSIPluginFactory(); friend class RealTimePluginFactory; + virtual PluginScan::PluginType getPluginType() const { + return PluginScan::DSSIPlugin; + } + virtual std::vector getPluginPath(); virtual std::vector getLRDFPath(QString &baseUri); diff -r 4018fc0189bc -r a1f410f895d3 plugin/FeatureExtractionPluginFactory.cpp --- a/plugin/FeatureExtractionPluginFactory.cpp Fri Mar 18 14:25:05 2016 +0000 +++ b/plugin/FeatureExtractionPluginFactory.cpp Fri Apr 15 16:26:15 2016 +0100 @@ -21,6 +21,8 @@ #include "system/System.h" +#include "PluginScan.h" + #include #include #include @@ -111,87 +113,14 @@ } vector -FeatureExtractionPluginFactory::getPluginCandidateFiles() -{ - vector path = getPluginPath(); - vector candidates; - - for (QString dirname : path) { - -#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE - cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << dirname << endl; -#endif - - QDir pluginDir(dirname, 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]); - candidates.push_back(soname); - } - } - - return candidates; -} - -vector -FeatureExtractionPluginFactory::winnowPluginCandidates(vector candidates, - QString &warningMessage) -{ - vector good, bad; - vector badStatuses; - - for (QString c: candidates) { - - PluginLoadStatus status = - TestPluginLoadability(c, "vampGetPluginDescriptor"); - - if (status == PluginLoadOK) { - good.push_back(c); - } else if (status == UnknownPluginLoadStatus) { - cerr << "WARNING: Unknown load status for plugin candidate \"" - << c << "\", continuing" << endl; - good.push_back(c); - } else { - bad.push_back(c); - badStatuses.push_back(status); - } - } - - if (!bad.empty()) { - warningMessage = - QObject::tr("Failed to load plugins" - "

Failed to load one or more plugin libraries:

\n"); - warningMessage += "
    "; - for (int i = 0; in_range_for(bad, i); ++i) { - QString m; - if (badStatuses[i] == PluginLoadFailedToLoadLibrary) { - m = QObject::tr("Failed to load library"); - } else if (badStatuses[i] == PluginLoadFailedToFindDescriptor) { - m = QObject::tr("Failed to query plugins from library after loading"); - } else if (badStatuses[i] == PluginLoadFailedElsewhere) { - m = QObject::tr("Unknown failure"); - } else { - m = QObject::tr("Success: internal error?"); - } - warningMessage += QString("
  • %1 (%2)
  • \n") - .arg(bad[i]) - .arg(m); - } - warningMessage += "
"; - } - return good; -} - -vector FeatureExtractionPluginFactory::getPluginIdentifiers() { Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers"); vector rv; - vector candidates = winnowPluginCandidates(getPluginCandidateFiles(), - m_pluginScanError); + + QStringList candidates = PluginScan::getInstance()->getCandidateLibrariesFor + (PluginScan::VampPlugin); for (QString soname : candidates) { diff -r 4018fc0189bc -r a1f410f895d3 plugin/FeatureExtractionPluginFactory.h --- a/plugin/FeatureExtractionPluginFactory.h Fri Mar 18 14:25:05 2016 +0000 +++ b/plugin/FeatureExtractionPluginFactory.h Fri Apr 15 16:26:15 2016 +0100 @@ -37,14 +37,6 @@ virtual std::vector getPluginPath(); virtual std::vector getPluginIdentifiers(); - - /** - * Return any error message arising from the initial plugin - * scan. The return value will either be an empty string (nothing - * to report) or an HTML string suitable for dropping into a - * dialog and showing the user. - */ - virtual QString getPluginPopulationWarning() { return m_pluginScanError; } virtual QString findPluginFile(QString soname, QString inDir = ""); @@ -66,13 +58,7 @@ void pluginDeleted(Vamp::Plugin *); std::map m_handleMap; - std::vector getPluginCandidateFiles(); - std::vector winnowPluginCandidates(std::vector candidates, - QString &warningMessage); - void generateTaxonomy(); - - QString m_pluginScanError; }; #endif diff -r 4018fc0189bc -r a1f410f895d3 plugin/LADSPAPluginFactory.cpp --- a/plugin/LADSPAPluginFactory.cpp Fri Mar 18 14:25:05 2016 +0000 +++ b/plugin/LADSPAPluginFactory.cpp Fri Apr 15 16:26:15 2016 +0100 @@ -668,14 +668,11 @@ generateFallbackCategories(); - for (std::vector::iterator i = pathList.begin(); - i != pathList.end(); ++i) { + QStringList candidates = + PluginScan::getInstance()->getCandidateLibrariesFor(getPluginType()); - QDir pluginDir(*i, PLUGIN_GLOB); - - for (unsigned int j = 0; j < pluginDir.count(); ++j) { - discoverPluginsFrom(QString("%1/%2").arg(*i).arg(pluginDir[j])); - } + for (QString c: candidates) { + discoverPluginsFrom(c); } } diff -r 4018fc0189bc -r a1f410f895d3 plugin/LADSPAPluginFactory.h --- a/plugin/LADSPAPluginFactory.h Fri Mar 18 14:25:05 2016 +0000 +++ b/plugin/LADSPAPluginFactory.h Fri Apr 15 16:26:15 2016 +0100 @@ -24,6 +24,8 @@ #include "RealTimePluginFactory.h" #include "api/ladspa.h" +#include "PluginScan.h" + #include #include #include @@ -63,6 +65,10 @@ LADSPAPluginFactory(); friend class RealTimePluginFactory; + virtual PluginScan::PluginType getPluginType() const { + return PluginScan::LADSPAPlugin; + } + virtual std::vector getPluginPath(); virtual std::vector getLRDFPath(QString &baseUri); diff -r 4018fc0189bc -r a1f410f895d3 plugin/PluginScan.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/PluginScan.cpp Fri Apr 15 16:26:15 2016 +0100 @@ -0,0 +1,112 @@ +/* -*- 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 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 "PluginScan.h" + +#include "base/Debug.h" + +#include "checker/knownplugins.h" + +#include +#include + +using std::string; + +class PluginScan::Logger : public PluginCandidates::LogCallback +{ +protected: + void log(std::string message) { + SVDEBUG << "PluginScan: " << message; + } +}; + +PluginScan *PluginScan::getInstance() +{ + static QMutex mutex; + static PluginScan *m_instance = 0; + mutex.lock(); + if (!m_instance) m_instance = new PluginScan(); + mutex.unlock(); + return m_instance; +} + +PluginScan::PluginScan() : m_kp(0), m_succeeded(false), m_logger(new Logger) { +} + +PluginScan::~PluginScan() { + delete m_kp; + delete m_logger; +} + +void +PluginScan::scan(QString helperExecutablePath) +{ + delete m_kp; + m_succeeded = false; + try { + m_kp = new KnownPlugins(helperExecutablePath.toStdString(), m_logger); + m_succeeded = true; + } catch (const std::exception &e) { + cerr << "ERROR: PluginScan::scan: " << e.what() << endl; + m_kp = 0; + } +} + +QStringList +PluginScan::getCandidateLibrariesFor(PluginType type) const +{ + KnownPlugins::PluginType kpt; + switch (type) { + case VampPlugin: kpt = KnownPlugins::VampPlugin; break; + case LADSPAPlugin: kpt = KnownPlugins::LADSPAPlugin; break; + case DSSIPlugin: kpt = KnownPlugins::DSSIPlugin; break; + default: throw std::logic_error("Inconsistency in plugin type enums"); + } + + QStringList candidates; + if (!m_kp) return candidates; + auto c = m_kp->getCandidateLibrariesFor(kpt); + for (auto s: c) candidates.push_back(s.c_str()); + return candidates; +} + +QString +PluginScan::getStartupFailureReport() const +{ + if (!m_succeeded) { + return QObject::tr("Failed to scan for plugins" + "

Failed to scan for plugins at startup. Possibly " + "the plugin checker helper program was not correctly " + "installed alongside %1?

") + .arg(QCoreApplication::applicationName()); + } + if (!m_kp) { + return QObject::tr("Did not scan for plugins" + "

Apparently no scan for plugins was attempted " + "(internal error?)

"); + } + + string report = m_kp->getFailureReport(); + if (report == "") { + return QString(report.c_str()); + } + + return QObject::tr("Failed to load plugins" + "

Failed to load one or more plugin libraries:

") + + QString(report.c_str()) + + QObject::tr("

These plugins may be incompatible with the system, " + "and will be ignored during this run of %1.

") + .arg(QCoreApplication::applicationName()); +} + diff -r 4018fc0189bc -r a1f410f895d3 plugin/PluginScan.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/PluginScan.h Fri Apr 15 16:26:15 2016 +0100 @@ -0,0 +1,50 @@ +/* -*- 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 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. +*/ + +#ifndef PLUGIN_SCAN_H +#define PLUGIN_SCAN_H + +#include + +class KnownPlugins; + +class PluginScan +{ +public: + static PluginScan *getInstance(); + + void scan(QString helperExecutablePath); + + bool scanSucceeded() const; + + enum PluginType { + VampPlugin, + LADSPAPlugin, + DSSIPlugin + }; + QStringList getCandidateLibrariesFor(PluginType) const; + + QString getStartupFailureReport() const; + +private: + PluginScan(); + ~PluginScan(); + KnownPlugins *m_kp; + bool m_succeeded; + + class Logger; + Logger *m_logger; +}; + +#endif diff -r 4018fc0189bc -r a1f410f895d3 svcore.pro --- a/svcore.pro Fri Mar 18 14:25:05 2016 +0000 +++ b/svcore.pro Fri Apr 15 16:26:15 2016 +0100 @@ -39,7 +39,7 @@ TARGET = svcore DEPENDPATH += . data plugin plugin/api/alsa -INCLUDEPATH += . data plugin plugin/api/alsa ../dataquay +INCLUDEPATH += . data plugin plugin/api/alsa ../dataquay ../checker OBJECTS_DIR = o MOC_DIR = o @@ -223,7 +223,8 @@ data/osc/OSCMessage.cpp \ data/osc/OSCQueue.cpp -HEADERS += plugin/DSSIPluginFactory.h \ +HEADERS += plugin/PluginScan.h \ + plugin/DSSIPluginFactory.h \ plugin/DSSIPluginInstance.h \ plugin/FeatureExtractionPluginFactory.h \ plugin/LADSPAPluginFactory.h \ @@ -243,7 +244,8 @@ plugin/api/alsa/sound/asequencer.h -SOURCES += plugin/DSSIPluginFactory.cpp \ +SOURCES += plugin/PluginScan.cpp \ + plugin/DSSIPluginFactory.cpp \ plugin/DSSIPluginInstance.cpp \ plugin/FeatureExtractionPluginFactory.cpp \ plugin/LADSPAPluginFactory.cpp \ diff -r 4018fc0189bc -r a1f410f895d3 system/System.cpp --- a/system/System.cpp Fri Mar 18 14:25:05 2016 +0000 +++ b/system/System.cpp Fri Apr 15 16:26:15 2016 +0100 @@ -325,66 +325,3 @@ double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; } float princargf(float a) { return float(princarg(a)); } -#ifndef _WIN32 - -#include -#include - -PluginLoadStatus -TestPluginLoadability(QString soname, QString descriptorFn) -{ - //!!! This is POSIX only, no equivalent on Windows, where we'll - //!!! have to do something completely different - - pid_t pid = fork(); - - if (pid < 0) { - return UnknownPluginLoadStatus; // fork failed - } - - if (pid == 0) { // the child process - - void *handle = DLOPEN(soname, RTLD_NOW | RTLD_LOCAL); - if (!handle) { - cerr << "isPluginLibraryLoadable: Failed to open plugin library \"" - << soname << "\": " << dlerror() << "\n"; - cerr << "exiting with status 1" << endl; - exit(1); - } - - void *fn = DLSYM(handle, descriptorFn.toLocal8Bit().data()); - if (!fn) { - cerr << "isPluginLibraryLoadable: Failed to find plugin descriptor function \"" << descriptorFn << "\" in library \"" << soname << "\": " << dlerror() << "\n"; - exit(2); - } - -// cerr << "isPluginLibraryLoadable: Successfully loaded library \"" << soname << "\" and retrieved descriptor function" << endl; - - exit(0); - - } else { // the parent process - - int status = 0; - - do { - waitpid(pid, &status, 0); - } while (WIFSTOPPED(status)); - - if (WIFEXITED(status)) { - switch (WEXITSTATUS(status)) { - case 0: return PluginLoadOK; // success - case 1: return PluginLoadFailedToLoadLibrary; - case 2: return PluginLoadFailedToFindDescriptor; - default: return PluginLoadFailedElsewhere; - } - } - - if (WIFSIGNALED(status)) { - return PluginLoadFailedElsewhere; - } - - return UnknownPluginLoadStatus; - } -} - -#endif diff -r 4018fc0189bc -r a1f410f895d3 system/System.h --- a/system/System.h Fri Mar 18 14:25:05 2016 +0000 +++ b/system/System.h Fri Apr 15 16:26:15 2016 +0100 @@ -154,21 +154,6 @@ extern void StoreStartupLocale(); extern void RestoreStartupLocale(); -enum PluginLoadStatus { - UnknownPluginLoadStatus, - PluginLoadOK, - PluginLoadFailedToLoadLibrary, - PluginLoadFailedToFindDescriptor, - PluginLoadFailedElsewhere -}; - -// Check whether a plugin library is loadable without crashing (may -// need to spawn an external process to do it). Descriptor fn is the -// name of a LADSPA/DSSI/Vamp-style descriptor function to try -// calling; may be an empty string if the plugin doesn't follow that -// convention. -PluginLoadStatus TestPluginLoadability(QString soname, QString descriptorFn); - #include #ifndef M_PI diff -r 4018fc0189bc -r a1f410f895d3 transform/TransformFactory.cpp --- a/transform/TransformFactory.cpp Fri Mar 18 14:25:05 2016 +0000 +++ b/transform/TransformFactory.cpp Fri Apr 15 16:26:15 2016 +0100 @@ -399,18 +399,6 @@ m_transformsPopulated = true; } -QString -TransformFactory::getPluginPopulationWarning() -{ - FeatureExtractionPluginFactory *vfactory = - FeatureExtractionPluginFactory::instance("vamp"); - QString warningMessage; - if (vfactory) { - warningMessage = vfactory->getPluginPopulationWarning(); - } - return warningMessage; -} - void TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms) { diff -r 4018fc0189bc -r a1f410f895d3 transform/TransformFactory.h --- a/transform/TransformFactory.h Fri Mar 18 14:25:05 2016 +0000 +++ b/transform/TransformFactory.h Fri Apr 15 16:26:15 2016 +0100 @@ -195,14 +195,6 @@ */ void setParametersFromPluginConfigurationXml(Transform &transform, QString xml); - - /** - * Return any error message arising from the initial plugin - * scan. The return value will either be an empty string (nothing - * to report) or an HTML string suitable for dropping into a - * dialog and showing the user. - */ - QString getPluginPopulationWarning(); protected: typedef std::map TransformDescriptionMap;