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
|