annotate plugin/PiperVampPluginFactory.cpp @ 1290:fa574c909c3d 3.0-integration

Add MAD_BUFFER_GUARD padding at end of mp3 buffer, in order to ensure last frame is decoded successfully (otherwise the decoded audio is truncated). Another thing learned from madplay.
author Chris Cannam
date Thu, 24 Nov 2016 17:06:31 +0000
parents a99641535e02
children 54fabf5aceb8
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@1264 51 class PiperVampPluginFactory::Logger : public piper_vamp::client::LogCallback {
Chris@1264 52 protected:
Chris@1264 53 void log(std::string message) const override {
Chris@1264 54 SVDEBUG << "PiperVampPluginFactory: " << message << endl;
Chris@1264 55 }
Chris@1264 56 };
Chris@1264 57
Chris@1264 58 PiperVampPluginFactory::PiperVampPluginFactory() :
Chris@1264 59 m_logger(new Logger)
Chris@66 60 {
Chris@1241 61 QString serverName = "piper-vamp-simple-server";
Chris@1240 62
Chris@1246 63 HelperExecPath hep(HelperExecPath::AllInstalled);
Chris@1246 64 m_servers = hep.getHelperExecutables(serverName);
Chris@1240 65
Chris@1246 66 for (auto n: m_servers) {
Chris@1247 67 SVDEBUG << "NOTE: PiperVampPluginFactory: Found server: "
Chris@1247 68 << n.executable << endl;
Chris@1246 69 }
Chris@1246 70
Chris@1240 71 if (m_servers.empty()) {
Chris@1247 72 SVDEBUG << "NOTE: No Piper Vamp servers found in installation;"
Chris@1247 73 << " found none of the following:" << endl;
Chris@1246 74 for (auto d: hep.getHelperCandidatePaths(serverName)) {
Chris@1247 75 SVDEBUG << "NOTE: " << d << endl;
Chris@1241 76 }
Chris@1240 77 }
Chris@1240 78 }
Chris@1240 79
Chris@1264 80 PiperVampPluginFactory::~PiperVampPluginFactory()
Chris@1264 81 {
Chris@1264 82 delete m_logger;
Chris@1264 83 }
Chris@1264 84
Chris@1164 85 vector<QString>
Chris@1227 86 PiperVampPluginFactory::getPluginIdentifiers(QString &errorMessage)
Chris@0 87 {
Chris@1225 88 Profiler profiler("PiperVampPluginFactory::getPluginIdentifiers");
Chris@408 89
Chris@1209 90 QMutexLocker locker(&m_mutex);
Chris@1209 91
Chris@1240 92 if (m_servers.empty()) {
Chris@1227 93 errorMessage = QObject::tr("External plugin host executable does not appear to be installed");
Chris@1227 94 return {};
Chris@1227 95 }
Chris@1227 96
Chris@1209 97 if (m_pluginData.empty()) {
Chris@1227 98 populate(errorMessage);
Chris@1209 99 }
Chris@1209 100
Chris@1164 101 vector<QString> rv;
Chris@1179 102
Chris@1209 103 for (const auto &d: m_pluginData) {
Chris@1225 104 rv.push_back(QString("vamp:") + QString::fromStdString(d.second.pluginKey));
Chris@66 105 }
Chris@66 106
Chris@0 107 return rv;
Chris@0 108 }
Chris@0 109
Chris@66 110 Vamp::Plugin *
Chris@1225 111 PiperVampPluginFactory::instantiatePlugin(QString identifier,
Chris@1225 112 sv_samplerate_t inputSampleRate)
Chris@0 113 {
Chris@1225 114 Profiler profiler("PiperVampPluginFactory::instantiatePlugin");
Chris@1225 115
Chris@1240 116 if (m_origins.find(identifier) == m_origins.end()) {
Chris@1240 117 cerr << "ERROR: No known server for identifier " << identifier << endl;
Chris@1247 118 SVDEBUG << "ERROR: No known server for identifier " << identifier << endl;
Chris@1240 119 return 0;
Chris@1240 120 }
Chris@1240 121
Chris@1225 122 auto psd = getPluginStaticData(identifier);
Chris@1225 123 if (psd.pluginKey == "") {
Chris@1225 124 return 0;
Chris@1225 125 }
Chris@1264 126
Chris@1264 127 SVDEBUG << "PiperVampPluginFactory: Creating Piper AutoPlugin for server "
Chris@1264 128 << m_origins[identifier] << ", identifier " << identifier << endl;
Chris@1210 129
Chris@1210 130 auto ap = new piper_vamp::client::AutoPlugin
Chris@1240 131 (m_origins[identifier].toStdString(),
Chris@1264 132 psd.pluginKey,
Chris@1264 133 float(inputSampleRate),
Chris@1264 134 0,
Chris@1264 135 m_logger);
Chris@1240 136
Chris@1210 137 if (!ap->isOK()) {
Chris@1210 138 delete ap;
Chris@1210 139 return 0;
Chris@1225 140 }
Chris@1225 141
Chris@1225 142 return ap;
Chris@1225 143 }
Chris@1225 144
Chris@1225 145 piper_vamp::PluginStaticData
Chris@1225 146 PiperVampPluginFactory::getPluginStaticData(QString identifier)
Chris@1225 147 {
Chris@1225 148 if (m_pluginData.find(identifier) != m_pluginData.end()) {
Chris@1225 149 return m_pluginData[identifier];
Chris@1210 150 } else {
Chris@1225 151 return {};
Chris@1210 152 }
Chris@298 153 }
Chris@298 154
Chris@165 155 QString
Chris@1225 156 PiperVampPluginFactory::getPluginCategory(QString identifier)
Chris@165 157 {
Chris@1223 158 if (m_taxonomy.find(identifier) != m_taxonomy.end()) {
Chris@1223 159 return m_taxonomy[identifier];
Chris@1223 160 } else {
Chris@1223 161 return {};
Chris@1223 162 }
Chris@165 163 }
Chris@165 164
Chris@165 165 void
Chris@1227 166 PiperVampPluginFactory::populate(QString &errorMessage)
Chris@165 167 {
Chris@1240 168 QString someError;
Chris@1227 169
Chris@1246 170 for (auto s: m_servers) {
Chris@1240 171
Chris@1240 172 populateFrom(s, someError);
Chris@1240 173
Chris@1240 174 if (someError != "" && errorMessage == "") {
Chris@1240 175 errorMessage = someError;
Chris@1240 176 }
Chris@1240 177 }
Chris@1240 178 }
Chris@1240 179
Chris@1240 180 void
Chris@1246 181 PiperVampPluginFactory::populateFrom(const HelperExecPath::HelperExec &server,
Chris@1246 182 QString &errorMessage)
Chris@1240 183 {
Chris@1246 184 QString tag = server.tag;
Chris@1246 185 string executable = server.executable.toStdString();
Chris@1246 186
Chris@1246 187 PluginScan *scan = PluginScan::getInstance();
Chris@1246 188 auto candidateLibraries =
Chris@1246 189 scan->getCandidateLibrariesFor(PluginScan::VampPlugin);
Chris@1246 190
Chris@1264 191 SVDEBUG << "PiperVampPluginFactory: Populating from " << executable << endl;
Chris@1250 192 SVDEBUG << "INFO: Have " << candidateLibraries.size()
Chris@1264 193 << " candidate Vamp plugin libraries from scanner" << endl;
Chris@1249 194
Chris@1246 195 vector<string> from;
Chris@1246 196 for (const auto &c: candidateLibraries) {
Chris@1246 197 if (c.helperTag == tag) {
Chris@1246 198 string soname = QFileInfo(c.libraryPath).baseName().toStdString();
Chris@1247 199 SVDEBUG << "INFO: For tag \"" << tag << "\" giving library " << soname << endl;
Chris@1246 200 from.push_back(soname);
Chris@1246 201 }
Chris@1246 202 }
Chris@1246 203
Chris@1246 204 if (from.empty()) {
Chris@1247 205 SVDEBUG << "PiperVampPluginFactory: No candidate libraries for tag \""
Chris@1246 206 << tag << "\"";
Chris@1246 207 if (scan->scanSucceeded()) {
Chris@1246 208 // we have to assume that they all failed to load (i.e. we
Chris@1246 209 // exclude them all) rather than sending an empty list
Chris@1246 210 // (which would mean no exclusions)
Chris@1247 211 SVDEBUG << ", skipping" << endl;
Chris@1246 212 return;
Chris@1246 213 } else {
Chris@1247 214 SVDEBUG << ", but it seems the scan failed, so bumbling on anyway" << endl;
Chris@1246 215 }
Chris@1246 216 }
Chris@1246 217
Chris@1264 218 piper_vamp::client::ProcessQtTransport transport(executable, "capnp", m_logger);
Chris@1227 219 if (!transport.isOK()) {
Chris@1264 220 SVDEBUG << "PiperVampPluginFactory: Failed to start Piper process transport" << endl;
Chris@1227 221 errorMessage = QObject::tr("Could not start external plugin host");
Chris@1227 222 return;
Chris@1227 223 }
Chris@1234 224
Chris@1264 225 piper_vamp::client::CapnpRRClient client(&transport, m_logger);
Chris@1248 226
Chris@1248 227 piper_vamp::ListRequest req;
Chris@1248 228 req.from = from;
Chris@1248 229
Chris@1248 230 piper_vamp::ListResponse resp;
Chris@1234 231
Chris@1234 232 try {
Chris@1248 233 resp = client.listPluginData(req);
Chris@1234 234 } catch (piper_vamp::client::ServerCrashed) {
Chris@1264 235 SVDEBUG << "PiperVampPluginFactory: Piper server crashed" << endl;
Chris@1234 236 errorMessage = QObject::tr
Chris@1234 237 ("External plugin host exited unexpectedly while listing plugins");
Chris@1234 238 return;
Chris@1235 239 } catch (const std::exception &e) {
Chris@1264 240 SVDEBUG << "PiperVampPluginFactory: Exception caught: " << e.what() << endl;
Chris@1235 241 errorMessage = QObject::tr("External plugin host invocation failed: %1")
Chris@1235 242 .arg(e.what());
Chris@1235 243 return;
Chris@1234 244 }
Chris@1213 245
Chris@1247 246 SVDEBUG << "PiperVampPluginFactory: server \"" << executable << "\" lists "
Chris@1248 247 << resp.available.size() << " plugin(s)" << endl;
Chris@1244 248
Chris@1248 249 for (const auto &pd: resp.available) {
Chris@1240 250
Chris@1213 251 QString identifier =
Chris@1213 252 QString("vamp:") + QString::fromStdString(pd.pluginKey);
Chris@1213 253
Chris@1240 254 if (m_origins.find(identifier) != m_origins.end()) {
Chris@1240 255 // have it already, from a higher-priority server
Chris@1240 256 // (e.g. 64-bit instead of 32-bit)
Chris@1240 257 continue;
Chris@1240 258 }
Chris@1240 259
Chris@1246 260 m_origins[identifier] = server.executable;
Chris@1240 261
Chris@1225 262 m_pluginData[identifier] = pd;
Chris@1225 263
Chris@1213 264 QStringList catlist;
Chris@1213 265 for (const auto &cs: pd.category) {
Chris@1213 266 catlist.push_back(QString::fromStdString(cs));
Chris@1213 267 }
Chris@1223 268
Chris@1213 269 m_taxonomy[identifier] = catlist.join(" > ");
Chris@1213 270 }
Chris@1209 271 }
Chris@165 272
Chris@1249 273 #endif