annotate plugin/PiperVampPluginFactory.cpp @ 1248:58dd6a6fe414 piper

Update to use listargs variant of Piper stuff (so that the plugin winnowing feature from the penultimate commit actually works)
author Chris Cannam
date Thu, 03 Nov 2016 15:38:17 +0000
parents 8f076d02569a
children d45a16c232bd
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1241 7 This file copyright 2006-2016 Chris Cannam and QMUL.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@1225 16 #include "PiperVampPluginFactory.h"
Chris@0 17 #include "PluginIdentifier.h"
Chris@0 18
Chris@150 19 #include "system/System.h"
Chris@66 20
Chris@1179 21 #include "PluginScan.h"
Chris@1179 22
Chris@1224 23 #ifdef _WIN32
Chris@1224 24 #undef VOID
Chris@1224 25 #undef ERROR
Chris@1224 26 #define CAPNP_LITE 1
Chris@1224 27 #endif
Chris@1225 28
Chris@1210 29 #include "vamp-client/AutoPlugin.h"
Chris@1210 30
Chris@66 31 #include <QDir>
Chris@66 32 #include <QFile>
Chris@66 33 #include <QFileInfo>
Chris@165 34 #include <QTextStream>
Chris@1227 35 #include <QCoreApplication>
Chris@66 36
Chris@0 37 #include <iostream>
Chris@0 38
Chris@408 39 #include "base/Profiler.h"
Chris@1241 40 #include "base/HelperExecPath.h"
Chris@408 41
Chris@1223 42 #include "vamp-client/ProcessQtTransport.h"
Chris@1223 43 #include "vamp-client/CapnpRRClient.h"
Chris@1223 44
Chris@1164 45 using namespace std;
Chris@1164 46
Chris@249 47 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1
Chris@249 48
Chris@1240 49 PiperVampPluginFactory::PiperVampPluginFactory()
Chris@66 50 {
Chris@1241 51 QString serverName = "piper-vamp-simple-server";
Chris@1240 52
Chris@1246 53 HelperExecPath hep(HelperExecPath::AllInstalled);
Chris@1246 54 m_servers = hep.getHelperExecutables(serverName);
Chris@1240 55
Chris@1246 56 for (auto n: m_servers) {
Chris@1247 57 SVDEBUG << "NOTE: PiperVampPluginFactory: Found server: "
Chris@1247 58 << n.executable << endl;
Chris@1246 59 }
Chris@1246 60
Chris@1240 61 if (m_servers.empty()) {
Chris@1247 62 SVDEBUG << "NOTE: No Piper Vamp servers found in installation;"
Chris@1247 63 << " found none of the following:" << endl;
Chris@1246 64 for (auto d: hep.getHelperCandidatePaths(serverName)) {
Chris@1247 65 SVDEBUG << "NOTE: " << d << endl;
Chris@1241 66 }
Chris@1240 67 }
Chris@1240 68 }
Chris@1240 69
Chris@1164 70 vector<QString>
Chris@1227 71 PiperVampPluginFactory::getPluginIdentifiers(QString &errorMessage)
Chris@0 72 {
Chris@1225 73 Profiler profiler("PiperVampPluginFactory::getPluginIdentifiers");
Chris@408 74
Chris@1209 75 QMutexLocker locker(&m_mutex);
Chris@1209 76
Chris@1240 77 if (m_servers.empty()) {
Chris@1227 78 errorMessage = QObject::tr("External plugin host executable does not appear to be installed");
Chris@1227 79 return {};
Chris@1227 80 }
Chris@1227 81
Chris@1209 82 if (m_pluginData.empty()) {
Chris@1227 83 populate(errorMessage);
Chris@1209 84 }
Chris@1209 85
Chris@1164 86 vector<QString> rv;
Chris@1179 87
Chris@1209 88 for (const auto &d: m_pluginData) {
Chris@1225 89 rv.push_back(QString("vamp:") + QString::fromStdString(d.second.pluginKey));
Chris@66 90 }
Chris@66 91
Chris@0 92 return rv;
Chris@0 93 }
Chris@0 94
Chris@66 95 Vamp::Plugin *
Chris@1225 96 PiperVampPluginFactory::instantiatePlugin(QString identifier,
Chris@1225 97 sv_samplerate_t inputSampleRate)
Chris@0 98 {
Chris@1225 99 Profiler profiler("PiperVampPluginFactory::instantiatePlugin");
Chris@1225 100
Chris@1240 101 if (m_origins.find(identifier) == m_origins.end()) {
Chris@1240 102 cerr << "ERROR: No known server for identifier " << identifier << endl;
Chris@1247 103 SVDEBUG << "ERROR: No known server for identifier " << identifier << endl;
Chris@1240 104 return 0;
Chris@1240 105 }
Chris@1240 106
Chris@1225 107 auto psd = getPluginStaticData(identifier);
Chris@1225 108 if (psd.pluginKey == "") {
Chris@1225 109 return 0;
Chris@1225 110 }
Chris@1210 111
Chris@1210 112 auto ap = new piper_vamp::client::AutoPlugin
Chris@1240 113 (m_origins[identifier].toStdString(),
Chris@1240 114 psd.pluginKey, float(inputSampleRate), 0);
Chris@1240 115
Chris@1210 116 if (!ap->isOK()) {
Chris@1210 117 delete ap;
Chris@1210 118 return 0;
Chris@1225 119 }
Chris@1225 120
Chris@1225 121 return ap;
Chris@1225 122 }
Chris@1225 123
Chris@1225 124 piper_vamp::PluginStaticData
Chris@1225 125 PiperVampPluginFactory::getPluginStaticData(QString identifier)
Chris@1225 126 {
Chris@1225 127 if (m_pluginData.find(identifier) != m_pluginData.end()) {
Chris@1225 128 return m_pluginData[identifier];
Chris@1210 129 } else {
Chris@1225 130 return {};
Chris@1210 131 }
Chris@298 132 }
Chris@298 133
Chris@165 134 QString
Chris@1225 135 PiperVampPluginFactory::getPluginCategory(QString identifier)
Chris@165 136 {
Chris@1223 137 if (m_taxonomy.find(identifier) != m_taxonomy.end()) {
Chris@1223 138 return m_taxonomy[identifier];
Chris@1223 139 } else {
Chris@1223 140 return {};
Chris@1223 141 }
Chris@165 142 }
Chris@165 143
Chris@165 144 void
Chris@1227 145 PiperVampPluginFactory::populate(QString &errorMessage)
Chris@165 146 {
Chris@1240 147 QString someError;
Chris@1227 148
Chris@1246 149 for (auto s: m_servers) {
Chris@1240 150
Chris@1240 151 populateFrom(s, someError);
Chris@1240 152
Chris@1240 153 if (someError != "" && errorMessage == "") {
Chris@1240 154 errorMessage = someError;
Chris@1240 155 }
Chris@1240 156 }
Chris@1240 157 }
Chris@1240 158
Chris@1240 159 void
Chris@1246 160 PiperVampPluginFactory::populateFrom(const HelperExecPath::HelperExec &server,
Chris@1246 161 QString &errorMessage)
Chris@1240 162 {
Chris@1246 163 QString tag = server.tag;
Chris@1246 164 string executable = server.executable.toStdString();
Chris@1246 165
Chris@1246 166 PluginScan *scan = PluginScan::getInstance();
Chris@1246 167 auto candidateLibraries =
Chris@1246 168 scan->getCandidateLibrariesFor(PluginScan::VampPlugin);
Chris@1246 169
Chris@1246 170 vector<string> from;
Chris@1246 171 for (const auto &c: candidateLibraries) {
Chris@1246 172 if (c.helperTag == tag) {
Chris@1246 173 string soname = QFileInfo(c.libraryPath).baseName().toStdString();
Chris@1247 174 SVDEBUG << "INFO: For tag \"" << tag << "\" giving library " << soname << endl;
Chris@1246 175 from.push_back(soname);
Chris@1246 176 }
Chris@1246 177 }
Chris@1246 178
Chris@1246 179 if (from.empty()) {
Chris@1247 180 SVDEBUG << "PiperVampPluginFactory: No candidate libraries for tag \""
Chris@1246 181 << tag << "\"";
Chris@1246 182 if (scan->scanSucceeded()) {
Chris@1246 183 // we have to assume that they all failed to load (i.e. we
Chris@1246 184 // exclude them all) rather than sending an empty list
Chris@1246 185 // (which would mean no exclusions)
Chris@1247 186 SVDEBUG << ", skipping" << endl;
Chris@1246 187 return;
Chris@1246 188 } else {
Chris@1247 189 SVDEBUG << ", but it seems the scan failed, so bumbling on anyway" << endl;
Chris@1246 190 }
Chris@1246 191 }
Chris@1246 192
Chris@1246 193 piper_vamp::client::ProcessQtTransport transport(executable, "capnp");
Chris@1227 194 if (!transport.isOK()) {
Chris@1227 195 errorMessage = QObject::tr("Could not start external plugin host");
Chris@1227 196 return;
Chris@1227 197 }
Chris@1234 198
Chris@1223 199 piper_vamp::client::CapnpRRClient client(&transport);
Chris@1248 200
Chris@1248 201 piper_vamp::ListRequest req;
Chris@1248 202 req.from = from;
Chris@1248 203
Chris@1248 204 piper_vamp::ListResponse resp;
Chris@1234 205
Chris@1234 206 try {
Chris@1248 207 resp = client.listPluginData(req);
Chris@1234 208 } catch (piper_vamp::client::ServerCrashed) {
Chris@1234 209 errorMessage = QObject::tr
Chris@1234 210 ("External plugin host exited unexpectedly while listing plugins");
Chris@1234 211 return;
Chris@1235 212 } catch (const std::exception &e) {
Chris@1235 213 errorMessage = QObject::tr("External plugin host invocation failed: %1")
Chris@1235 214 .arg(e.what());
Chris@1235 215 return;
Chris@1234 216 }
Chris@1213 217
Chris@1247 218 SVDEBUG << "PiperVampPluginFactory: server \"" << executable << "\" lists "
Chris@1248 219 << resp.available.size() << " plugin(s)" << endl;
Chris@1244 220
Chris@1248 221 for (const auto &pd: resp.available) {
Chris@1240 222
Chris@1213 223 QString identifier =
Chris@1213 224 QString("vamp:") + QString::fromStdString(pd.pluginKey);
Chris@1213 225
Chris@1240 226 if (m_origins.find(identifier) != m_origins.end()) {
Chris@1240 227 // have it already, from a higher-priority server
Chris@1240 228 // (e.g. 64-bit instead of 32-bit)
Chris@1240 229 continue;
Chris@1240 230 }
Chris@1240 231
Chris@1246 232 m_origins[identifier] = server.executable;
Chris@1240 233
Chris@1225 234 m_pluginData[identifier] = pd;
Chris@1225 235
Chris@1213 236 QStringList catlist;
Chris@1213 237 for (const auto &cs: pd.category) {
Chris@1213 238 catlist.push_back(QString::fromStdString(cs));
Chris@1213 239 }
Chris@1223 240
Chris@1213 241 m_taxonomy[identifier] = catlist.join(" > ");
Chris@1213 242 }
Chris@1209 243 }
Chris@165 244