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