cannam@232
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@232
|
2 /*
|
cannam@232
|
3 Piper C++
|
cannam@232
|
4
|
cannam@232
|
5 An API for audio analysis and feature extraction plugins.
|
cannam@232
|
6
|
cannam@232
|
7 Centre for Digital Music, Queen Mary, University of London.
|
cannam@232
|
8 Copyright 2006-2016 Chris Cannam and QMUL.
|
cannam@232
|
9
|
cannam@232
|
10 Permission is hereby granted, free of charge, to any person
|
cannam@232
|
11 obtaining a copy of this software and associated documentation
|
cannam@232
|
12 files (the "Software"), to deal in the Software without
|
cannam@232
|
13 restriction, including without limitation the rights to use, copy,
|
cannam@232
|
14 modify, merge, publish, distribute, sublicense, and/or sell copies
|
cannam@232
|
15 of the Software, and to permit persons to whom the Software is
|
cannam@232
|
16 furnished to do so, subject to the following conditions:
|
cannam@232
|
17
|
cannam@232
|
18 The above copyright notice and this permission notice shall be
|
cannam@232
|
19 included in all copies or substantial portions of the Software.
|
cannam@232
|
20
|
cannam@232
|
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
cannam@232
|
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
cannam@232
|
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
cannam@232
|
24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
cannam@232
|
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
cannam@232
|
26 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
cannam@232
|
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
cannam@232
|
28
|
cannam@232
|
29 Except as contained in this notice, the names of the Centre for
|
cannam@232
|
30 Digital Music; Queen Mary, University of London; and Chris Cannam
|
cannam@232
|
31 shall not be used in advertising or otherwise to promote the sale,
|
cannam@232
|
32 use or other dealings in this Software without prior written
|
cannam@232
|
33 authorization.
|
cannam@232
|
34 */
|
cannam@232
|
35
|
cannam@232
|
36 #include "vamp-json/VampJson.h"
|
cannam@232
|
37 #include "vamp-support/RequestOrResponse.h"
|
cannam@232
|
38 #include "vamp-support/LoaderRequests.h"
|
cannam@232
|
39 #include "vamp-support/RdfTypes.h"
|
cannam@232
|
40
|
cannam@232
|
41 #include <iostream>
|
cannam@232
|
42 #include <sstream>
|
cannam@232
|
43 #include <stdexcept>
|
cannam@232
|
44
|
cannam@232
|
45 #include <map>
|
cannam@232
|
46 #include <set>
|
cannam@232
|
47
|
cannam@232
|
48 // for _setmode stuff and _dup
|
cannam@232
|
49 #ifdef _WIN32
|
cannam@232
|
50 #include <io.h>
|
cannam@232
|
51 #include <fcntl.h>
|
cannam@232
|
52 #endif
|
cannam@232
|
53
|
cannam@232
|
54 // for dup, open etc
|
cannam@232
|
55 #ifndef _WIN32
|
cannam@232
|
56 #include <fcntl.h>
|
cannam@232
|
57 #include <unistd.h>
|
cannam@232
|
58 #endif
|
cannam@232
|
59
|
cannam@232
|
60 using namespace std;
|
cannam@232
|
61 using namespace json11;
|
cannam@232
|
62 using namespace piper_vamp;
|
cannam@232
|
63 using namespace Vamp;
|
cannam@232
|
64
|
cannam@232
|
65 static string myname = "piper-vamp-simple-server";
|
cannam@232
|
66
|
cannam@232
|
67 static void version()
|
cannam@232
|
68 {
|
cannam@232
|
69 cout << "1.0" << endl;
|
cannam@232
|
70 exit(0);
|
cannam@232
|
71 }
|
cannam@232
|
72
|
cannam@232
|
73 static void usage(bool successful = false)
|
cannam@232
|
74 {
|
cannam@232
|
75 cerr << "\n" << myname <<
|
cannam@232
|
76 ": Emit stub version of main code\nfor a Piper Adapter implementation of a Vamp plugin library\n\n"
|
cannam@232
|
77 " Usage: " << myname << " [-d] <soname>\n"
|
cannam@232
|
78 " " << myname << " -v\n"
|
cannam@232
|
79 " " << myname << " -h\n\n"
|
cannam@232
|
80 " where\n"
|
cannam@232
|
81 " <soname>: the Vamp plugin library name to emit stub conversion code for\n"
|
cannam@232
|
82 " -d: also print debug information to stderr\n"
|
cannam@232
|
83 " -v: print version number to stdout and exit\n"
|
cannam@232
|
84 " -h: print this text to stderr and exit\n\n";
|
cannam@232
|
85 if (successful) exit(0);
|
cannam@232
|
86 else exit(2);
|
cannam@232
|
87 }
|
cannam@232
|
88
|
cannam@232
|
89 // We write our output to stdout, but want to ensure that the plugin
|
cannam@232
|
90 // doesn't write anything itself. To do this we open a null file
|
cannam@232
|
91 // descriptor and dup2() it into place of stdout in the gaps between
|
cannam@232
|
92 // our own output activity.
|
cannam@232
|
93
|
cannam@232
|
94 static int normalFd = -1;
|
cannam@232
|
95 static int suspendedFd = -1;
|
cannam@232
|
96
|
cannam@232
|
97 static void initFds(bool binary)
|
cannam@232
|
98 {
|
cannam@232
|
99 #ifdef _WIN32
|
cannam@232
|
100 if (binary) {
|
cannam@232
|
101 int result = _setmode(0, _O_BINARY);
|
cannam@232
|
102 if (result == -1) {
|
cannam@232
|
103 throw runtime_error("Failed to set binary mode on stdin");
|
cannam@232
|
104 }
|
cannam@232
|
105 result = _setmode(1, _O_BINARY);
|
cannam@232
|
106 if (result == -1) {
|
cannam@232
|
107 throw runtime_error("Failed to set binary mode on stdout");
|
cannam@232
|
108 }
|
cannam@232
|
109 }
|
cannam@232
|
110 normalFd = _dup(1);
|
cannam@232
|
111 suspendedFd = _open("NUL", _O_WRONLY);
|
cannam@232
|
112 #else
|
cannam@232
|
113 (void)binary;
|
cannam@232
|
114 normalFd = dup(1);
|
cannam@232
|
115 suspendedFd = open("/dev/null", O_WRONLY);
|
cannam@232
|
116 #endif
|
cannam@232
|
117
|
cannam@232
|
118 if (normalFd < 0 || suspendedFd < 0) {
|
cannam@232
|
119 throw runtime_error("Failed to initialise fds for stdio suspend/resume");
|
cannam@232
|
120 }
|
cannam@232
|
121 }
|
cannam@232
|
122
|
cannam@232
|
123 static void suspendOutput()
|
cannam@232
|
124 {
|
cannam@232
|
125 #ifdef _WIN32
|
cannam@232
|
126 _dup2(suspendedFd, 1);
|
cannam@232
|
127 #else
|
cannam@232
|
128 dup2(suspendedFd, 1);
|
cannam@232
|
129 #endif
|
cannam@232
|
130 }
|
cannam@232
|
131
|
cannam@232
|
132 static void resumeOutput()
|
cannam@232
|
133 {
|
cannam@232
|
134 #ifdef _WIN32
|
cannam@232
|
135 _dup2(normalFd, 1);
|
cannam@232
|
136 #else
|
cannam@232
|
137 dup2(normalFd, 1);
|
cannam@232
|
138 #endif
|
cannam@232
|
139 }
|
cannam@232
|
140
|
cannam@232
|
141 ListResponse
|
cannam@232
|
142 makeRequest(string soname, bool debug)
|
cannam@232
|
143 {
|
cannam@232
|
144 ListRequest req;
|
cannam@232
|
145 req.from.push_back(soname);
|
cannam@232
|
146 return LoaderRequests().listPluginData(req);
|
cannam@232
|
147 }
|
cannam@232
|
148
|
cannam@232
|
149 struct PlausibleMetadata
|
cannam@232
|
150 {
|
cannam@232
|
151 string className;
|
cannam@232
|
152 string adapterName;
|
cannam@232
|
153 };
|
cannam@232
|
154
|
cannam@232
|
155 PlausibleMetadata
|
cannam@232
|
156 inventPlausibleMetadata(string key)
|
cannam@232
|
157 {
|
cannam@232
|
158 PlausibleMetadata pm;
|
cannam@232
|
159 pm.className = "MyPlugin";//!!!
|
cannam@232
|
160 pm.adapterName = "myPluginAdapter";//!!!
|
cannam@232
|
161 return pm;
|
cannam@232
|
162 }
|
cannam@232
|
163
|
cannam@232
|
164 void
|
cannam@232
|
165 emitFor(string soname, const ListResponse &resp, bool debug)
|
cannam@232
|
166 {
|
cannam@232
|
167 cout <<
|
cannam@232
|
168 "\n#include \"PiperExport.h\"\n"
|
cannam@232
|
169 "\n"
|
cannam@232
|
170 "// #include your own plugin headers here\n"
|
cannam@232
|
171 "\n"
|
cannam@232
|
172 "using piper_vamp_js::PiperAdapter;\n"
|
cannam@232
|
173 "using piper_vamp_js::PiperPluginLibrary;\n"
|
cannam@232
|
174 "\n"
|
cannam@232
|
175 "static std::string soname(\"" << soname << "\");\n"
|
cannam@232
|
176 "\n";
|
cannam@232
|
177
|
cannam@237
|
178 // The same plugin key may appear more than once in the available
|
cannam@237
|
179 // list, if the same plugin is installed in more than one location
|
cannam@237
|
180 // on the Vamp path. To avoid emitting its wrapper definition
|
cannam@237
|
181 // multiple times, we need to keep a record of which ones we've
|
cannam@237
|
182 // emitted for each stage
|
cannam@237
|
183 set<string> emitted;
|
cannam@232
|
184
|
cannam@232
|
185 for (const auto &plugin: resp.available) {
|
cannam@237
|
186
|
cannam@237
|
187 string key = plugin.pluginKey;
|
cannam@237
|
188 if (emitted.find(key) != emitted.end()) {
|
cannam@237
|
189 continue;
|
cannam@237
|
190 }
|
cannam@237
|
191
|
cannam@237
|
192 PlausibleMetadata pm = inventPlausibleMetadata(key);
|
cannam@232
|
193 cout << "static PiperAdapter<"
|
cannam@232
|
194 << pm.className
|
cannam@232
|
195 << "> // replace with the actual Vamp plugin class name for \""
|
cannam@232
|
196 << plugin.basic.identifier << "\" plugin\n" << pm.adapterName
|
cannam@232
|
197 << "(\n soname,\n ";
|
cannam@232
|
198
|
cannam@232
|
199 string catString = "{ ";
|
cannam@237
|
200 bool first = true;
|
cannam@232
|
201 for (auto c: plugin.category) {
|
cannam@232
|
202 if (!first) catString += ", ";
|
cannam@232
|
203 catString += "\"" + c + "\"";
|
cannam@232
|
204 first = false;
|
cannam@232
|
205 }
|
cannam@232
|
206 catString += " }";
|
cannam@232
|
207 cout << catString << ",\n ";
|
cannam@232
|
208
|
cannam@232
|
209 cout << "{\n ";
|
cannam@232
|
210 first = true;
|
cannam@232
|
211 for (auto o: plugin.staticOutputInfo) {
|
cannam@232
|
212 if (!first) {
|
cannam@232
|
213 cout << ",\n ";
|
cannam@232
|
214 }
|
cannam@232
|
215 cout << " ";
|
cannam@232
|
216 string outputId = o.first;
|
cannam@232
|
217 const StaticOutputDescriptor &desc = o.second;
|
cannam@235
|
218 cout << "{ \"" << outputId << "\",\n { \""
|
cannam@235
|
219 << desc.typeURI << "\" }\n }";
|
cannam@232
|
220 first = false;
|
cannam@232
|
221 }
|
cannam@232
|
222 cout << "\n }\n";
|
cannam@232
|
223 cout << " );\n\n";
|
cannam@237
|
224 emitted.insert(key);
|
cannam@232
|
225 }
|
cannam@232
|
226
|
cannam@232
|
227 cout << "static PiperPluginLibrary library({\n ";
|
cannam@237
|
228 emitted.clear();
|
cannam@232
|
229 for (const auto &plugin: resp.available) {
|
cannam@237
|
230
|
cannam@237
|
231 string key = plugin.pluginKey;
|
cannam@237
|
232 if (emitted.find(key) != emitted.end()) {
|
cannam@237
|
233 continue;
|
cannam@237
|
234 }
|
cannam@237
|
235
|
cannam@237
|
236 PlausibleMetadata pm = inventPlausibleMetadata(key);
|
cannam@237
|
237 if (!emitted.empty()) {
|
cannam@232
|
238 cout << ",\n ";
|
cannam@232
|
239 }
|
cannam@232
|
240 cout << "&" << pm.adapterName;
|
cannam@237
|
241 emitted.insert(key);
|
cannam@232
|
242 }
|
cannam@232
|
243 cout << "\n});\n\n";
|
cannam@232
|
244 cout << "PIPER_EXPORT_LIBRARY(library);\n" << endl;
|
cannam@232
|
245 }
|
cannam@232
|
246
|
cannam@232
|
247 int main(int argc, char **argv)
|
cannam@232
|
248 {
|
cannam@232
|
249 if (argc != 2 && argc != 3) {
|
cannam@232
|
250 usage();
|
cannam@232
|
251 }
|
cannam@232
|
252
|
cannam@232
|
253 bool debug = false;
|
cannam@232
|
254
|
cannam@232
|
255 string arg = argv[1];
|
cannam@232
|
256 if (arg == "-h") {
|
cannam@232
|
257 if (argc == 2) {
|
cannam@232
|
258 usage(true);
|
cannam@232
|
259 } else {
|
cannam@232
|
260 usage();
|
cannam@232
|
261 }
|
cannam@232
|
262 } else if (arg == "-v") {
|
cannam@232
|
263 if (argc == 2) {
|
cannam@232
|
264 version();
|
cannam@232
|
265 } else {
|
cannam@232
|
266 usage();
|
cannam@232
|
267 }
|
cannam@232
|
268 } else if (arg == "-d") {
|
cannam@232
|
269 if (argc == 2) {
|
cannam@232
|
270 usage();
|
cannam@232
|
271 } else {
|
cannam@232
|
272 debug = true;
|
cannam@232
|
273 arg = argv[2];
|
cannam@232
|
274 }
|
cannam@232
|
275 }
|
cannam@232
|
276
|
cannam@232
|
277 string soname = arg;
|
cannam@232
|
278
|
cannam@232
|
279 try {
|
cannam@232
|
280 initFds(false);
|
cannam@232
|
281 } catch (exception &e) {
|
cannam@232
|
282 cerr << "ERROR: " << e.what() << endl;
|
cannam@232
|
283 exit(1);
|
cannam@232
|
284 }
|
cannam@232
|
285
|
cannam@232
|
286 suspendOutput();
|
cannam@232
|
287
|
cannam@232
|
288 ListResponse resp = makeRequest(soname, debug);
|
cannam@232
|
289
|
cannam@232
|
290 resumeOutput();
|
cannam@232
|
291
|
cannam@232
|
292 emitFor(soname, resp, debug);
|
cannam@232
|
293
|
cannam@232
|
294 exit(0);
|
cannam@232
|
295 }
|