annotate plugin/PiperVampPluginFactory.cpp @ 1247:8f076d02569a piper

Make SVDEBUG always write to a log file -- formerly this was disabled in NDEBUG builds. I think there's little use to that, it just means that we keep adding more cerr debug output because we aren't getting the log we need. And SVDEBUG logging is not usually used in tight loops, I don't think the performance overhead is too serious. Also update the About box.
author Chris Cannam
date Thu, 03 Nov 2016 14:57:00 +0000
parents 75aefcc9f07d
children 58dd6a6fe414
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@1234 200 piper_vamp::ListResponse lr;
Chris@1234 201
Chris@1234 202 try {
Chris@1234 203 lr = client.listPluginData();
Chris@1234 204 } catch (piper_vamp::client::ServerCrashed) {
Chris@1234 205 errorMessage = QObject::tr
Chris@1234 206 ("External plugin host exited unexpectedly while listing plugins");
Chris@1234 207 return;
Chris@1235 208 } catch (const std::exception &e) {
Chris@1235 209 errorMessage = QObject::tr("External plugin host invocation failed: %1")
Chris@1235 210 .arg(e.what());
Chris@1235 211 return;
Chris@1234 212 }
Chris@1213 213
Chris@1247 214 SVDEBUG << "PiperVampPluginFactory: server \"" << executable << "\" lists "
Chris@1247 215 << lr.available.size() << " plugin(s)" << endl;
Chris@1244 216
Chris@1225 217 for (const auto &pd: lr.available) {
Chris@1240 218
Chris@1213 219 QString identifier =
Chris@1213 220 QString("vamp:") + QString::fromStdString(pd.pluginKey);
Chris@1213 221
Chris@1240 222 if (m_origins.find(identifier) != m_origins.end()) {
Chris@1240 223 // have it already, from a higher-priority server
Chris@1240 224 // (e.g. 64-bit instead of 32-bit)
Chris@1240 225 continue;
Chris@1240 226 }
Chris@1240 227
Chris@1246 228 m_origins[identifier] = server.executable;
Chris@1240 229
Chris@1225 230 m_pluginData[identifier] = pd;
Chris@1225 231
Chris@1213 232 QStringList catlist;
Chris@1213 233 for (const auto &cs: pd.category) {
Chris@1213 234 catlist.push_back(QString::fromStdString(cs));
Chris@1213 235 }
Chris@1223 236
Chris@1213 237 m_taxonomy[identifier] = catlist.join(" > ");
Chris@1213 238 }
Chris@1209 239 }
Chris@165 240