annotate plugin/PiperVampPluginFactory.cpp @ 1246:75aefcc9f07d piper

Use plugin scan results to inform the list requests issued to Piper servers
author Chris Cannam
date Thu, 03 Nov 2016 14:14:09 +0000
parents 604b0b2a58e1
children 8f076d02569a
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@1246 57 cerr << "NOTE: PiperVampPluginFactory: Found server: "
Chris@1246 58 << n.executable << endl;
Chris@1246 59 }
Chris@1246 60
Chris@1240 61 if (m_servers.empty()) {
Chris@1241 62 cerr << "NOTE: No Piper Vamp servers found in installation;"
Chris@1241 63 << " found none of the following:" << endl;
Chris@1246 64 for (auto d: hep.getHelperCandidatePaths(serverName)) {
Chris@1241 65 cerr << "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@1240 103 return 0;
Chris@1240 104 }
Chris@1240 105
Chris@1225 106 auto psd = getPluginStaticData(identifier);
Chris@1225 107 if (psd.pluginKey == "") {
Chris@1225 108 return 0;
Chris@1225 109 }
Chris@1210 110
Chris@1210 111 auto ap = new piper_vamp::client::AutoPlugin
Chris@1240 112 (m_origins[identifier].toStdString(),
Chris@1240 113 psd.pluginKey, float(inputSampleRate), 0);
Chris@1240 114
Chris@1210 115 if (!ap->isOK()) {
Chris@1210 116 delete ap;
Chris@1210 117 return 0;
Chris@1225 118 }
Chris@1225 119
Chris@1225 120 return ap;
Chris@1225 121 }
Chris@1225 122
Chris@1225 123 piper_vamp::PluginStaticData
Chris@1225 124 PiperVampPluginFactory::getPluginStaticData(QString identifier)
Chris@1225 125 {
Chris@1225 126 if (m_pluginData.find(identifier) != m_pluginData.end()) {
Chris@1225 127 return m_pluginData[identifier];
Chris@1210 128 } else {
Chris@1225 129 return {};
Chris@1210 130 }
Chris@298 131 }
Chris@298 132
Chris@165 133 QString
Chris@1225 134 PiperVampPluginFactory::getPluginCategory(QString identifier)
Chris@165 135 {
Chris@1223 136 if (m_taxonomy.find(identifier) != m_taxonomy.end()) {
Chris@1223 137 return m_taxonomy[identifier];
Chris@1223 138 } else {
Chris@1223 139 return {};
Chris@1223 140 }
Chris@165 141 }
Chris@165 142
Chris@165 143 void
Chris@1227 144 PiperVampPluginFactory::populate(QString &errorMessage)
Chris@165 145 {
Chris@1240 146 QString someError;
Chris@1227 147
Chris@1246 148 for (auto s: m_servers) {
Chris@1240 149
Chris@1240 150 populateFrom(s, someError);
Chris@1240 151
Chris@1240 152 if (someError != "" && errorMessage == "") {
Chris@1240 153 errorMessage = someError;
Chris@1240 154 }
Chris@1240 155 }
Chris@1240 156 }
Chris@1240 157
Chris@1240 158 void
Chris@1246 159 PiperVampPluginFactory::populateFrom(const HelperExecPath::HelperExec &server,
Chris@1246 160 QString &errorMessage)
Chris@1240 161 {
Chris@1246 162 QString tag = server.tag;
Chris@1246 163 string executable = server.executable.toStdString();
Chris@1246 164
Chris@1246 165 PluginScan *scan = PluginScan::getInstance();
Chris@1246 166 auto candidateLibraries =
Chris@1246 167 scan->getCandidateLibrariesFor(PluginScan::VampPlugin);
Chris@1246 168
Chris@1246 169 vector<string> from;
Chris@1246 170 for (const auto &c: candidateLibraries) {
Chris@1246 171 if (c.helperTag == tag) {
Chris@1246 172 string soname = QFileInfo(c.libraryPath).baseName().toStdString();
Chris@1246 173 cerr << "INFO: For tag \"" << tag << "\" giving library " << soname << endl;
Chris@1246 174 from.push_back(soname);
Chris@1246 175 }
Chris@1246 176 }
Chris@1246 177
Chris@1246 178 if (from.empty()) {
Chris@1246 179 cerr << "PiperVampPluginFactory: No candidate libraries for tag \""
Chris@1246 180 << tag << "\"";
Chris@1246 181 if (scan->scanSucceeded()) {
Chris@1246 182 // we have to assume that they all failed to load (i.e. we
Chris@1246 183 // exclude them all) rather than sending an empty list
Chris@1246 184 // (which would mean no exclusions)
Chris@1246 185 cerr << ", skipping" << endl;
Chris@1246 186 return;
Chris@1246 187 } else {
Chris@1246 188 cerr << ", but it seems the scan failed, so bumbling on anyway" << endl;
Chris@1246 189 }
Chris@1246 190 }
Chris@1246 191
Chris@1246 192 piper_vamp::client::ProcessQtTransport transport(executable, "capnp");
Chris@1227 193 if (!transport.isOK()) {
Chris@1227 194 errorMessage = QObject::tr("Could not start external plugin host");
Chris@1227 195 return;
Chris@1227 196 }
Chris@1234 197
Chris@1223 198 piper_vamp::client::CapnpRRClient client(&transport);
Chris@1234 199 piper_vamp::ListResponse lr;
Chris@1234 200
Chris@1234 201 try {
Chris@1234 202 lr = client.listPluginData();
Chris@1234 203 } catch (piper_vamp::client::ServerCrashed) {
Chris@1234 204 errorMessage = QObject::tr
Chris@1234 205 ("External plugin host exited unexpectedly while listing plugins");
Chris@1234 206 return;
Chris@1235 207 } catch (const std::exception &e) {
Chris@1235 208 errorMessage = QObject::tr("External plugin host invocation failed: %1")
Chris@1235 209 .arg(e.what());
Chris@1235 210 return;
Chris@1234 211 }
Chris@1213 212
Chris@1246 213 cerr << "PiperVampPluginFactory: server \"" << executable << "\" lists "
Chris@1244 214 << lr.available.size() << " plugin(s)" << endl;
Chris@1244 215
Chris@1225 216 for (const auto &pd: lr.available) {
Chris@1240 217
Chris@1213 218 QString identifier =
Chris@1213 219 QString("vamp:") + QString::fromStdString(pd.pluginKey);
Chris@1213 220
Chris@1240 221 if (m_origins.find(identifier) != m_origins.end()) {
Chris@1240 222 // have it already, from a higher-priority server
Chris@1240 223 // (e.g. 64-bit instead of 32-bit)
Chris@1240 224 continue;
Chris@1240 225 }
Chris@1240 226
Chris@1246 227 m_origins[identifier] = server.executable;
Chris@1240 228
Chris@1225 229 m_pluginData[identifier] = pd;
Chris@1225 230
Chris@1213 231 QStringList catlist;
Chris@1213 232 for (const auto &cs: pd.category) {
Chris@1213 233 catlist.push_back(QString::fromStdString(cs));
Chris@1213 234 }
Chris@1223 235
Chris@1213 236 m_taxonomy[identifier] = catlist.join(" > ");
Chris@1213 237 }
Chris@1209 238 }
Chris@165 239