annotate plugin/PiperVampPluginFactory.cpp @ 1249:d45a16c232bd piper

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