Mercurial > hg > svcore
view plugin/PiperVampPluginFactory.cpp @ 1375:da5f4d37988d dev/refactor-piper-related
Invert control, injecting a server path on construction. Also add initializer_list constructor for multiple servers.
author | Lucas Thompson <lucas.thompson@qmul.ac.uk> |
---|---|
date | Thu, 09 Feb 2017 14:32:07 +0000 |
parents | 54fabf5aceb8 |
children | d9511f9e04d7 |
line wrap: on
line source
/* -*- 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-2016 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. */ #ifdef HAVE_PIPER #include "PiperVampPluginFactory.h" #include "PluginIdentifier.h" #include "system/System.h" #include "PluginScan.h" #ifdef _WIN32 #undef VOID #undef ERROR #define CAPNP_LITE 1 #endif #include "vamp-client/qt/AutoPlugin.h" #include "vamp-client/qt/ProcessQtTransport.h" #include "vamp-client/CapnpRRClient.h" #include <QDir> #include <QFile> #include <QFileInfo> #include <QTextStream> #include <QCoreApplication> #include <iostream> #include "base/Profiler.h" #include "base/HelperExecPath.h" using namespace std; //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 class PiperVampPluginFactory::Logger : public piper_vamp::client::LogCallback { protected: void log(std::string message) const override { SVDEBUG << "PiperVampPluginFactory: " << message << endl; } }; PiperVampPluginFactory::PiperVampPluginFactory(std::initializer_list<QString> servers) : m_logger(new Logger) { HelperExecPath hep(HelperExecPath::AllInstalled); for (auto server: servers) { for (auto platformHelper: hep.getHelperExecutables(server)) m_servers.push_back(platformHelper); } for (auto n: m_servers) { SVDEBUG << "NOTE: PiperVampPluginFactory: Found server: " << n.executable << endl; } if (m_servers.empty()) { SVDEBUG << "NOTE: No Piper Vamp servers found in installation;" << " found none of the following:" << endl; for (auto serverName: servers) for (auto d: hep.getHelperCandidatePaths(serverName)) { SVDEBUG << "NOTE: " << d << endl; } } } PiperVampPluginFactory::PiperVampPluginFactory() : PiperVampPluginFactory({"piper-vamp-simple-server"}) {} PiperVampPluginFactory::~PiperVampPluginFactory() { delete m_logger; } vector<QString> PiperVampPluginFactory::getPluginIdentifiers(QString &errorMessage) { Profiler profiler("PiperVampPluginFactory::getPluginIdentifiers"); QMutexLocker locker(&m_mutex); if (m_servers.empty()) { errorMessage = QObject::tr("External plugin host executable does not appear to be installed"); return {}; } if (m_pluginData.empty()) { populate(errorMessage); } vector<QString> rv; for (const auto &d: m_pluginData) { rv.push_back(QString("vamp:") + QString::fromStdString(d.second.pluginKey)); } return rv; } Vamp::Plugin * PiperVampPluginFactory::instantiatePlugin(QString identifier, sv_samplerate_t inputSampleRate) { Profiler profiler("PiperVampPluginFactory::instantiatePlugin"); if (m_origins.find(identifier) == m_origins.end()) { cerr << "ERROR: No known server for identifier " << identifier << endl; SVDEBUG << "ERROR: No known server for identifier " << identifier << endl; return 0; } auto psd = getPluginStaticData(identifier); if (psd.pluginKey == "") { return 0; } SVDEBUG << "PiperVampPluginFactory: Creating Piper AutoPlugin for server " << m_origins[identifier] << ", identifier " << identifier << endl; auto ap = new piper_vamp::client::AutoPlugin (m_origins[identifier].toStdString(), psd.pluginKey, float(inputSampleRate), 0, m_logger); if (!ap->isOK()) { delete ap; return 0; } return ap; } piper_vamp::PluginStaticData PiperVampPluginFactory::getPluginStaticData(QString identifier) { if (m_pluginData.find(identifier) != m_pluginData.end()) { return m_pluginData[identifier]; } else { return {}; } } QString PiperVampPluginFactory::getPluginCategory(QString identifier) { if (m_taxonomy.find(identifier) != m_taxonomy.end()) { return m_taxonomy[identifier]; } else { return {}; } } void PiperVampPluginFactory::populate(QString &errorMessage) { QString someError; for (auto s: m_servers) { populateFrom(s, someError); if (someError != "" && errorMessage == "") { errorMessage = someError; } } } void PiperVampPluginFactory::populateFrom(const HelperExecPath::HelperExec &server, QString &errorMessage) { QString tag = server.tag; string executable = server.executable.toStdString(); PluginScan *scan = PluginScan::getInstance(); auto candidateLibraries = scan->getCandidateLibrariesFor(PluginScan::VampPlugin); SVDEBUG << "PiperVampPluginFactory: Populating from " << executable << endl; SVDEBUG << "INFO: Have " << candidateLibraries.size() << " candidate Vamp plugin libraries from scanner" << endl; vector<string> from; for (const auto &c: candidateLibraries) { if (c.helperTag == tag) { string soname = QFileInfo(c.libraryPath).baseName().toStdString(); SVDEBUG << "INFO: For tag \"" << tag << "\" giving library " << soname << endl; from.push_back(soname); } } if (from.empty()) { SVDEBUG << "PiperVampPluginFactory: No candidate libraries for tag \"" << tag << "\""; if (scan->scanSucceeded()) { // we have to assume that they all failed to load (i.e. we // exclude them all) rather than sending an empty list // (which would mean no exclusions) SVDEBUG << ", skipping" << endl; return; } else { SVDEBUG << ", but it seems the scan failed, so bumbling on anyway" << endl; } } piper_vamp::client::ProcessQtTransport transport(executable, "capnp", m_logger); if (!transport.isOK()) { SVDEBUG << "PiperVampPluginFactory: Failed to start Piper process transport" << endl; errorMessage = QObject::tr("Could not start external plugin host"); return; } piper_vamp::client::CapnpRRClient client(&transport, m_logger); piper_vamp::ListRequest req; req.from = from; piper_vamp::ListResponse resp; try { resp = client.listPluginData(req); } catch (piper_vamp::client::ServerCrashed) { SVDEBUG << "PiperVampPluginFactory: Piper server crashed" << endl; errorMessage = QObject::tr ("External plugin host exited unexpectedly while listing plugins"); return; } catch (const std::exception &e) { SVDEBUG << "PiperVampPluginFactory: Exception caught: " << e.what() << endl; errorMessage = QObject::tr("External plugin host invocation failed: %1") .arg(e.what()); return; } SVDEBUG << "PiperVampPluginFactory: server \"" << executable << "\" lists " << resp.available.size() << " plugin(s)" << endl; for (const auto &pd: resp.available) { QString identifier = QString("vamp:") + QString::fromStdString(pd.pluginKey); if (m_origins.find(identifier) != m_origins.end()) { // have it already, from a higher-priority server // (e.g. 64-bit instead of 32-bit) continue; } m_origins[identifier] = server.executable; m_pluginData[identifier] = pd; QStringList catlist; for (const auto &cs: pd.category) { catlist.push_back(QString::fromStdString(cs)); } m_taxonomy[identifier] = catlist.join(" > "); } } #endif