c@5
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
c@5
|
2
|
c@18
|
3 /*
|
c@18
|
4 VamPipe
|
c@18
|
5
|
c@18
|
6 Centre for Digital Music, Queen Mary, University of London.
|
c@18
|
7 Copyright 2015-2016 QMUL.
|
c@18
|
8
|
c@18
|
9 Permission is hereby granted, free of charge, to any person
|
c@18
|
10 obtaining a copy of this software and associated documentation
|
c@18
|
11 files (the "Software"), to deal in the Software without
|
c@18
|
12 restriction, including without limitation the rights to use, copy,
|
c@18
|
13 modify, merge, publish, distribute, sublicense, and/or sell copies
|
c@18
|
14 of the Software, and to permit persons to whom the Software is
|
c@18
|
15 furnished to do so, subject to the following conditions:
|
c@18
|
16
|
c@18
|
17 The above copyright notice and this permission notice shall be
|
c@18
|
18 included in all copies or substantial portions of the Software.
|
c@18
|
19
|
c@18
|
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
c@18
|
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
c@18
|
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
c@18
|
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
c@18
|
24 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
c@18
|
25 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
c@18
|
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
c@18
|
27
|
c@18
|
28 Except as contained in this notice, the names of the Centre for
|
c@18
|
29 Digital Music; Queen Mary, University of London; and Chris Cannam
|
c@18
|
30 shall not be used in advertising or otherwise to promote the sale,
|
c@18
|
31 use or other dealings in this Software without prior written
|
c@18
|
32 authorization.
|
c@18
|
33 */
|
c@18
|
34
|
c@5
|
35 #ifndef VAMP_JSON_H
|
c@5
|
36 #define VAMP_JSON_H
|
c@5
|
37
|
c@5
|
38 #include <vector>
|
c@5
|
39 #include <string>
|
c@5
|
40 #include <sstream>
|
c@5
|
41
|
c@5
|
42 #include <json11/json11.hpp>
|
c@5
|
43 #include <base-n/include/basen.hpp>
|
c@5
|
44
|
c@5
|
45 #include <vamp-hostsdk/Plugin.h>
|
c@5
|
46 #include <vamp-hostsdk/PluginLoader.h>
|
c@5
|
47
|
c@10
|
48 #include "bits/PluginHandleMapper.h"
|
c@49
|
49 #include "bits/PluginOutputIdMapper.h"
|
c@25
|
50 #include "bits/RequestResponseType.h"
|
c@10
|
51
|
c@10
|
52 namespace vampipe {
|
c@10
|
53
|
c@6
|
54 /**
|
c@6
|
55 * Convert the structures laid out in the Vamp SDK classes into JSON
|
c@6
|
56 * (and back again) following the schema in the vamp-json-schema
|
c@6
|
57 * project repo.
|
c@60
|
58 *
|
c@60
|
59 * Functions with names starting "from" convert from a Vamp SDK object
|
c@60
|
60 * to JSON output. Most of them return a json11::Json object, with a
|
c@60
|
61 * few exceptions for low-level utilities that return a string. These
|
c@60
|
62 * functions succeed all of the time.
|
c@60
|
63 *
|
c@60
|
64 * Functions with names starting "to" convert to a Vamp SDK object
|
c@60
|
65 * from JSON input. These functions all accept a json11::Json object
|
c@60
|
66 * as first argument, with a few exceptions for low-level utilities
|
c@60
|
67 * that accept a string. These functions all accept a string reference
|
c@60
|
68 * as a final argument and return an error string through it if the
|
c@60
|
69 * conversion fails. If conversion fails the return value is
|
c@60
|
70 * undefined, and any returned object may be incomplete or
|
c@60
|
71 * invalid. Callers should check for an empty error string (indicating
|
c@60
|
72 * success) before using the returned value.
|
c@6
|
73 */
|
c@60
|
74
|
c@60
|
75 //!!! todo: convert pmapper to err style
|
c@60
|
76
|
c@5
|
77 class VampJson
|
c@5
|
78 {
|
c@5
|
79 public:
|
c@45
|
80 /** Serialisation format for arrays of floats (process input and
|
c@66
|
81 * feature values). Wherever such an array appears, it may
|
c@66
|
82 * alternatively be replaced by a single string containing a
|
c@66
|
83 * base-64 encoding of the IEEE float buffer. When parsing, if a
|
c@66
|
84 * string is found instead of an array in this case, it will be
|
c@66
|
85 * interpreted as a base-64 encoded buffer. Only array or base-64
|
c@66
|
86 * encoding may be provided, not both.
|
c@45
|
87 */
|
c@44
|
88 enum class BufferSerialisation {
|
c@45
|
89
|
c@45
|
90 /** Default JSON serialisation of values in array form. This
|
c@45
|
91 * is relatively slow to parse and serialise, and can take a
|
c@45
|
92 * lot of space.
|
c@45
|
93 */
|
c@66
|
94 Array,
|
c@45
|
95
|
c@66
|
96 /** Base64-encoded string of the raw data as packed
|
c@66
|
97 * little-endian IEEE 32-bit floats. Faster and more compact
|
c@66
|
98 * than the text encoding but more complicated to
|
c@66
|
99 * provide. Note that Base64 serialisations produced by this
|
c@45
|
100 * library do not including padding characters and so are not
|
c@45
|
101 * necessarily multiples of 4 characters long. You will need
|
c@45
|
102 * to pad them yourself if concatenating them or supplying to
|
c@45
|
103 * a consumer that expects padding.
|
c@45
|
104 */
|
c@45
|
105 Base64
|
c@44
|
106 };
|
c@44
|
107
|
c@60
|
108 static bool failed(const std::string &err) {
|
c@60
|
109 return err != "";
|
c@60
|
110 }
|
c@5
|
111
|
c@5
|
112 template <typename T>
|
c@5
|
113 static json11::Json
|
c@5
|
114 fromBasicDescriptor(const T &t) {
|
c@5
|
115 return json11::Json::object {
|
c@5
|
116 { "identifier", t.identifier },
|
c@5
|
117 { "name", t.name },
|
c@5
|
118 { "description", t.description }
|
c@5
|
119 };
|
c@5
|
120 }
|
c@5
|
121
|
c@5
|
122 template <typename T>
|
c@5
|
123 static void
|
c@60
|
124 toBasicDescriptor(json11::Json j, T &t, std::string &err) {
|
c@5
|
125 if (!j.is_object()) {
|
c@60
|
126 err = "object expected for basic descriptor content";
|
c@60
|
127 return;
|
c@5
|
128 }
|
c@5
|
129 if (!j["identifier"].is_string()) {
|
c@60
|
130 err = "string expected for identifier";
|
c@60
|
131 return;
|
c@5
|
132 }
|
c@5
|
133 t.identifier = j["identifier"].string_value();
|
c@5
|
134 t.name = j["name"].string_value();
|
c@5
|
135 t.description = j["description"].string_value();
|
c@5
|
136 }
|
c@5
|
137
|
c@5
|
138 template <typename T>
|
c@5
|
139 static json11::Json
|
c@5
|
140 fromValueExtents(const T &t) {
|
c@5
|
141 return json11::Json::object {
|
c@5
|
142 { "min", t.minValue },
|
c@5
|
143 { "max", t.maxValue }
|
c@5
|
144 };
|
c@5
|
145 }
|
c@5
|
146
|
c@5
|
147 template <typename T>
|
c@5
|
148 static bool
|
c@60
|
149 toValueExtents(json11::Json j, T &t, std::string &err) {
|
c@5
|
150 if (j["extents"].is_null()) {
|
c@5
|
151 return false;
|
c@5
|
152 } else if (j["extents"].is_object()) {
|
c@5
|
153 if (j["extents"]["min"].is_number() &&
|
c@5
|
154 j["extents"]["max"].is_number()) {
|
c@5
|
155 t.minValue = j["extents"]["min"].number_value();
|
c@5
|
156 t.maxValue = j["extents"]["max"].number_value();
|
c@5
|
157 return true;
|
c@5
|
158 } else {
|
c@60
|
159 err = "numbers expected for min and max";
|
c@60
|
160 return false;
|
c@5
|
161 }
|
c@5
|
162 } else {
|
c@60
|
163 err = "object expected for extents (if present)";
|
c@60
|
164 return false;
|
c@5
|
165 }
|
c@5
|
166 }
|
c@5
|
167
|
c@5
|
168 static json11::Json
|
c@5
|
169 fromRealTime(const Vamp::RealTime &r) {
|
c@5
|
170 return json11::Json::object {
|
c@5
|
171 { "s", r.sec },
|
c@5
|
172 { "n", r.nsec }
|
c@5
|
173 };
|
c@5
|
174 }
|
c@5
|
175
|
c@5
|
176 static Vamp::RealTime
|
c@60
|
177 toRealTime(json11::Json j, std::string &err) {
|
c@5
|
178 json11::Json sec = j["s"];
|
c@5
|
179 json11::Json nsec = j["n"];
|
c@5
|
180 if (!sec.is_number() || !nsec.is_number()) {
|
c@60
|
181 err = "invalid Vamp::RealTime object " + j.dump();
|
c@60
|
182 return {};
|
c@5
|
183 }
|
c@5
|
184 return Vamp::RealTime(sec.int_value(), nsec.int_value());
|
c@5
|
185 }
|
c@5
|
186
|
c@5
|
187 static std::string
|
c@5
|
188 fromSampleType(Vamp::Plugin::OutputDescriptor::SampleType type) {
|
c@5
|
189 switch (type) {
|
c@5
|
190 case Vamp::Plugin::OutputDescriptor::OneSamplePerStep:
|
c@5
|
191 return "OneSamplePerStep";
|
c@5
|
192 case Vamp::Plugin::OutputDescriptor::FixedSampleRate:
|
c@5
|
193 return "FixedSampleRate";
|
c@5
|
194 case Vamp::Plugin::OutputDescriptor::VariableSampleRate:
|
c@5
|
195 return "VariableSampleRate";
|
c@5
|
196 }
|
c@5
|
197 return "";
|
c@5
|
198 }
|
c@5
|
199
|
c@5
|
200 static Vamp::Plugin::OutputDescriptor::SampleType
|
c@60
|
201 toSampleType(std::string text, std::string &err) {
|
c@5
|
202 if (text == "OneSamplePerStep") {
|
c@5
|
203 return Vamp::Plugin::OutputDescriptor::OneSamplePerStep;
|
c@5
|
204 } else if (text == "FixedSampleRate") {
|
c@5
|
205 return Vamp::Plugin::OutputDescriptor::FixedSampleRate;
|
c@5
|
206 } else if (text == "VariableSampleRate") {
|
c@5
|
207 return Vamp::Plugin::OutputDescriptor::VariableSampleRate;
|
c@5
|
208 } else {
|
c@60
|
209 err = "invalid sample type string: " + text;
|
c@60
|
210 return Vamp::Plugin::OutputDescriptor::OneSamplePerStep;
|
c@5
|
211 }
|
c@5
|
212 }
|
c@5
|
213
|
c@5
|
214 static json11::Json
|
c@64
|
215 fromConfiguredOutputDescriptor(const Vamp::Plugin::OutputDescriptor &desc) {
|
c@5
|
216 json11::Json::object jo {
|
c@5
|
217 { "unit", desc.unit },
|
c@5
|
218 { "sampleType", fromSampleType(desc.sampleType) },
|
c@5
|
219 { "sampleRate", desc.sampleRate },
|
c@5
|
220 { "hasDuration", desc.hasDuration }
|
c@5
|
221 };
|
c@5
|
222 if (desc.hasFixedBinCount) {
|
c@5
|
223 jo["binCount"] = int(desc.binCount);
|
c@5
|
224 jo["binNames"] = json11::Json::array
|
c@5
|
225 (desc.binNames.begin(), desc.binNames.end());
|
c@5
|
226 }
|
c@5
|
227 if (desc.hasKnownExtents) {
|
c@5
|
228 jo["extents"] = fromValueExtents(desc);
|
c@5
|
229 }
|
c@5
|
230 if (desc.isQuantized) {
|
c@5
|
231 jo["quantizeStep"] = desc.quantizeStep;
|
c@5
|
232 }
|
c@5
|
233 return json11::Json(jo);
|
c@5
|
234 }
|
c@12
|
235
|
c@64
|
236 static json11::Json
|
c@64
|
237 fromOutputDescriptor(const Vamp::Plugin::OutputDescriptor &desc) {
|
c@64
|
238 json11::Json::object jo {
|
c@64
|
239 { "basic", fromBasicDescriptor(desc) },
|
c@64
|
240 { "configured", fromConfiguredOutputDescriptor(desc) }
|
c@64
|
241 };
|
c@64
|
242 return json11::Json(jo);
|
c@64
|
243 }
|
c@64
|
244
|
c@5
|
245 static Vamp::Plugin::OutputDescriptor
|
c@65
|
246 toConfiguredOutputDescriptor(json11::Json j, std::string &err) {
|
c@5
|
247
|
c@5
|
248 Vamp::Plugin::OutputDescriptor od;
|
c@5
|
249 if (!j.is_object()) {
|
c@60
|
250 err = "object expected for output descriptor";
|
c@60
|
251 return {};
|
c@5
|
252 }
|
c@5
|
253
|
c@5
|
254 od.unit = j["unit"].string_value();
|
c@5
|
255
|
c@60
|
256 od.sampleType = toSampleType(j["sampleType"].string_value(), err);
|
c@60
|
257 if (failed(err)) return {};
|
c@5
|
258
|
c@5
|
259 if (!j["sampleRate"].is_number()) {
|
c@60
|
260 err = "number expected for sample rate";
|
c@60
|
261 return {};
|
c@5
|
262 }
|
c@5
|
263 od.sampleRate = j["sampleRate"].number_value();
|
c@5
|
264 od.hasDuration = j["hasDuration"].bool_value();
|
c@5
|
265
|
c@5
|
266 if (j["binCount"].is_number() && j["binCount"].int_value() > 0) {
|
c@5
|
267 od.hasFixedBinCount = true;
|
c@5
|
268 od.binCount = j["binCount"].int_value();
|
c@5
|
269 for (auto &n: j["binNames"].array_items()) {
|
c@5
|
270 if (!n.is_string()) {
|
c@60
|
271 err = "string expected for bin name";
|
c@60
|
272 return {};
|
c@5
|
273 }
|
c@5
|
274 od.binNames.push_back(n.string_value());
|
c@5
|
275 }
|
c@5
|
276 } else {
|
c@5
|
277 od.hasFixedBinCount = false;
|
c@5
|
278 }
|
c@5
|
279
|
c@60
|
280 bool extentsPresent = toValueExtents(j, od, err);
|
c@60
|
281 if (failed(err)) return {};
|
c@60
|
282
|
c@5
|
283 od.hasKnownExtents = extentsPresent;
|
c@5
|
284
|
c@5
|
285 if (j["quantizeStep"].is_number()) {
|
c@5
|
286 od.isQuantized = true;
|
c@5
|
287 od.quantizeStep = j["quantizeStep"].number_value();
|
c@5
|
288 } else {
|
c@5
|
289 od.isQuantized = false;
|
c@5
|
290 }
|
c@5
|
291
|
c@5
|
292 return od;
|
c@5
|
293 }
|
c@64
|
294
|
c@64
|
295 static Vamp::Plugin::OutputDescriptor
|
c@65
|
296 toOutputDescriptor(json11::Json j, std::string &err) {
|
c@64
|
297
|
c@64
|
298 Vamp::Plugin::OutputDescriptor od;
|
c@64
|
299 if (!j.is_object()) {
|
c@65
|
300 err = "object expected for output descriptor";
|
c@65
|
301 return {};
|
c@64
|
302 }
|
c@64
|
303
|
c@65
|
304 od = toConfiguredOutputDescriptor(j, err);
|
c@65
|
305 if (failed(err)) return {};
|
c@64
|
306
|
c@65
|
307 toBasicDescriptor(j["basic"], od, err);
|
c@65
|
308 if (failed(err)) return {};
|
c@64
|
309
|
c@64
|
310 return od;
|
c@64
|
311 }
|
c@5
|
312
|
c@5
|
313 static json11::Json
|
c@5
|
314 fromParameterDescriptor(const Vamp::PluginBase::ParameterDescriptor &desc) {
|
c@5
|
315
|
c@5
|
316 json11::Json::object jo {
|
c@5
|
317 { "basic", fromBasicDescriptor(desc) },
|
c@5
|
318 { "unit", desc.unit },
|
c@5
|
319 { "extents", fromValueExtents(desc) },
|
c@5
|
320 { "defaultValue", desc.defaultValue },
|
c@5
|
321 { "valueNames", json11::Json::array
|
c@5
|
322 (desc.valueNames.begin(), desc.valueNames.end()) }
|
c@5
|
323 };
|
c@5
|
324 if (desc.isQuantized) {
|
c@5
|
325 jo["quantizeStep"] = desc.quantizeStep;
|
c@5
|
326 }
|
c@5
|
327 return json11::Json(jo);
|
c@5
|
328 }
|
c@5
|
329
|
c@5
|
330 static Vamp::PluginBase::ParameterDescriptor
|
c@60
|
331 toParameterDescriptor(json11::Json j, std::string &err) {
|
c@5
|
332
|
c@5
|
333 Vamp::PluginBase::ParameterDescriptor pd;
|
c@5
|
334 if (!j.is_object()) {
|
c@60
|
335 err = "object expected for parameter descriptor";
|
c@60
|
336 return {};
|
c@5
|
337 }
|
c@5
|
338
|
c@60
|
339 toBasicDescriptor(j["basic"], pd, err);
|
c@60
|
340 if (failed(err)) return {};
|
c@5
|
341
|
c@5
|
342 pd.unit = j["unit"].string_value();
|
c@5
|
343
|
c@60
|
344 bool extentsPresent = toValueExtents(j, pd, err);
|
c@60
|
345 if (failed(err)) return {};
|
c@5
|
346 if (!extentsPresent) {
|
c@60
|
347 err = "extents must be present in parameter descriptor";
|
c@60
|
348 return {};
|
c@5
|
349 }
|
c@5
|
350
|
c@5
|
351 if (!j["defaultValue"].is_number()) {
|
c@60
|
352 err = "number expected for default value";
|
c@60
|
353 return {};
|
c@5
|
354 }
|
c@5
|
355
|
c@5
|
356 pd.defaultValue = j["defaultValue"].number_value();
|
c@5
|
357
|
c@5
|
358 pd.valueNames.clear();
|
c@5
|
359 for (auto &n: j["valueNames"].array_items()) {
|
c@5
|
360 if (!n.is_string()) {
|
c@60
|
361 err = "string expected for value name";
|
c@60
|
362 return {};
|
c@5
|
363 }
|
c@5
|
364 pd.valueNames.push_back(n.string_value());
|
c@5
|
365 }
|
c@5
|
366
|
c@5
|
367 if (j["quantizeStep"].is_number()) {
|
c@5
|
368 pd.isQuantized = true;
|
c@5
|
369 pd.quantizeStep = j["quantizeStep"].number_value();
|
c@5
|
370 } else {
|
c@5
|
371 pd.isQuantized = false;
|
c@5
|
372 }
|
c@5
|
373
|
c@5
|
374 return pd;
|
c@5
|
375 }
|
c@5
|
376
|
c@5
|
377 static std::string
|
c@5
|
378 fromFloatBuffer(const float *buffer, size_t nfloats) {
|
c@5
|
379 // must use char pointers, otherwise the converter will only
|
c@5
|
380 // encode every 4th byte (as it will count up in float* steps)
|
c@5
|
381 const char *start = reinterpret_cast<const char *>(buffer);
|
c@5
|
382 const char *end = reinterpret_cast<const char *>(buffer + nfloats);
|
c@5
|
383 std::string encoded;
|
c@5
|
384 bn::encode_b64(start, end, back_inserter(encoded));
|
c@5
|
385 return encoded;
|
c@5
|
386 }
|
c@5
|
387
|
c@5
|
388 static std::vector<float>
|
c@60
|
389 toFloatBuffer(std::string encoded, std::string & /* err */) {
|
c@5
|
390 std::string decoded;
|
c@5
|
391 bn::decode_b64(encoded.begin(), encoded.end(), back_inserter(decoded));
|
c@5
|
392 const float *buffer = reinterpret_cast<const float *>(decoded.c_str());
|
c@5
|
393 size_t n = decoded.size() / sizeof(float);
|
c@47
|
394 return std::vector<float>(buffer, buffer + n);
|
c@5
|
395 }
|
c@5
|
396
|
c@5
|
397 static json11::Json
|
c@44
|
398 fromFeature(const Vamp::Plugin::Feature &f,
|
c@44
|
399 BufferSerialisation serialisation) {
|
c@5
|
400
|
c@5
|
401 json11::Json::object jo;
|
c@5
|
402 if (f.values.size() > 0) {
|
c@66
|
403 if (serialisation == BufferSerialisation::Array) {
|
c@66
|
404 jo["featureValues"] = json11::Json::array(f.values.begin(),
|
c@66
|
405 f.values.end());
|
c@35
|
406 } else {
|
c@66
|
407 jo["featureValues"] = fromFloatBuffer(f.values.data(),
|
c@66
|
408 f.values.size());
|
c@35
|
409 }
|
c@5
|
410 }
|
c@5
|
411 if (f.label != "") {
|
c@5
|
412 jo["label"] = f.label;
|
c@5
|
413 }
|
c@5
|
414 if (f.hasTimestamp) {
|
c@5
|
415 jo["timestamp"] = fromRealTime(f.timestamp);
|
c@5
|
416 }
|
c@5
|
417 if (f.hasDuration) {
|
c@5
|
418 jo["duration"] = fromRealTime(f.duration);
|
c@5
|
419 }
|
c@5
|
420 return json11::Json(jo);
|
c@5
|
421 }
|
c@5
|
422
|
c@5
|
423 static Vamp::Plugin::Feature
|
c@60
|
424 toFeature(json11::Json j, BufferSerialisation &serialisation, std::string &err) {
|
c@5
|
425
|
c@5
|
426 Vamp::Plugin::Feature f;
|
c@5
|
427 if (!j.is_object()) {
|
c@60
|
428 err = "object expected for feature";
|
c@60
|
429 return {};
|
c@5
|
430 }
|
c@5
|
431 if (j["timestamp"].is_object()) {
|
c@60
|
432 f.timestamp = toRealTime(j["timestamp"], err);
|
c@60
|
433 if (failed(err)) return {};
|
c@5
|
434 f.hasTimestamp = true;
|
c@5
|
435 }
|
c@5
|
436 if (j["duration"].is_object()) {
|
c@60
|
437 f.duration = toRealTime(j["duration"], err);
|
c@60
|
438 if (failed(err)) return {};
|
c@5
|
439 f.hasDuration = true;
|
c@5
|
440 }
|
c@66
|
441 if (j["featureValues"].is_string()) {
|
c@66
|
442 f.values = toFloatBuffer(j["featureValues"].string_value(), err);
|
c@60
|
443 if (failed(err)) return {};
|
c@44
|
444 serialisation = BufferSerialisation::Base64;
|
c@66
|
445 } else if (j["featureValues"].is_array()) {
|
c@66
|
446 for (auto v : j["featureValues"].array_items()) {
|
c@5
|
447 f.values.push_back(v.number_value());
|
c@5
|
448 }
|
c@66
|
449 serialisation = BufferSerialisation::Array;
|
c@5
|
450 }
|
c@5
|
451 f.label = j["label"].string_value();
|
c@5
|
452 return f;
|
c@5
|
453 }
|
c@5
|
454
|
c@5
|
455 static json11::Json
|
c@44
|
456 fromFeatureSet(const Vamp::Plugin::FeatureSet &fs,
|
c@49
|
457 const PluginOutputIdMapper &omapper,
|
c@44
|
458 BufferSerialisation serialisation) {
|
c@5
|
459
|
c@5
|
460 json11::Json::object jo;
|
c@5
|
461 for (const auto &fsi : fs) {
|
c@5
|
462 std::vector<json11::Json> fj;
|
c@5
|
463 for (const Vamp::Plugin::Feature &f: fsi.second) {
|
c@44
|
464 fj.push_back(fromFeature(f, serialisation));
|
c@5
|
465 }
|
c@49
|
466 jo[omapper.indexToId(fsi.first)] = fj;
|
c@5
|
467 }
|
c@5
|
468 return json11::Json(jo);
|
c@5
|
469 }
|
c@5
|
470
|
c@5
|
471 static Vamp::Plugin::FeatureList
|
c@44
|
472 toFeatureList(json11::Json j,
|
c@60
|
473 BufferSerialisation &serialisation, std::string &err) {
|
c@5
|
474
|
c@5
|
475 Vamp::Plugin::FeatureList fl;
|
c@5
|
476 if (!j.is_array()) {
|
c@60
|
477 err = "array expected for feature list";
|
c@60
|
478 return {};
|
c@5
|
479 }
|
c@5
|
480 for (const json11::Json &fj : j.array_items()) {
|
c@60
|
481 fl.push_back(toFeature(fj, serialisation, err));
|
c@60
|
482 if (failed(err)) return {};
|
c@5
|
483 }
|
c@5
|
484 return fl;
|
c@5
|
485 }
|
c@5
|
486
|
c@5
|
487 static Vamp::Plugin::FeatureSet
|
c@49
|
488 toFeatureSet(json11::Json j,
|
c@49
|
489 const PluginOutputIdMapper &omapper,
|
c@60
|
490 BufferSerialisation &serialisation,
|
c@60
|
491 std::string &err) {
|
c@5
|
492
|
c@5
|
493 Vamp::Plugin::FeatureSet fs;
|
c@5
|
494 if (!j.is_object()) {
|
c@60
|
495 err = "object expected for feature set";
|
c@60
|
496 return {};
|
c@5
|
497 }
|
c@5
|
498 for (auto &entry : j.object_items()) {
|
c@49
|
499 int n = omapper.idToIndex(entry.first);
|
c@49
|
500 if (fs.find(n) != fs.end()) {
|
c@60
|
501 err = "duplicate numerical index for output";
|
c@60
|
502 return {};
|
c@5
|
503 }
|
c@60
|
504 fs[n] = toFeatureList(entry.second, serialisation, err);
|
c@60
|
505 if (failed(err)) return {};
|
c@5
|
506 }
|
c@5
|
507 return fs;
|
c@5
|
508 }
|
c@5
|
509
|
c@5
|
510 static std::string
|
c@5
|
511 fromInputDomain(Vamp::Plugin::InputDomain domain) {
|
c@5
|
512
|
c@5
|
513 switch (domain) {
|
c@5
|
514 case Vamp::Plugin::TimeDomain:
|
c@5
|
515 return "TimeDomain";
|
c@5
|
516 case Vamp::Plugin::FrequencyDomain:
|
c@5
|
517 return "FrequencyDomain";
|
c@5
|
518 }
|
c@5
|
519 return "";
|
c@5
|
520 }
|
c@5
|
521
|
c@5
|
522 static Vamp::Plugin::InputDomain
|
c@60
|
523 toInputDomain(std::string text, std::string &err) {
|
c@5
|
524
|
c@5
|
525 if (text == "TimeDomain") {
|
c@5
|
526 return Vamp::Plugin::TimeDomain;
|
c@5
|
527 } else if (text == "FrequencyDomain") {
|
c@5
|
528 return Vamp::Plugin::FrequencyDomain;
|
c@5
|
529 } else {
|
c@60
|
530 err = "invalid input domain string: " + text;
|
c@60
|
531 return {};
|
c@5
|
532 }
|
c@5
|
533 }
|
c@5
|
534
|
c@5
|
535 static json11::Json
|
c@5
|
536 fromPluginStaticData(const Vamp::HostExt::PluginStaticData &d) {
|
c@5
|
537
|
c@5
|
538 json11::Json::object jo;
|
c@5
|
539 jo["pluginKey"] = d.pluginKey;
|
c@5
|
540 jo["basic"] = fromBasicDescriptor(d.basic);
|
c@5
|
541 jo["maker"] = d.maker;
|
c@5
|
542 jo["copyright"] = d.copyright;
|
c@5
|
543 jo["pluginVersion"] = d.pluginVersion;
|
c@5
|
544
|
c@5
|
545 json11::Json::array cat;
|
c@5
|
546 for (const std::string &c: d.category) cat.push_back(c);
|
c@5
|
547 jo["category"] = cat;
|
c@5
|
548
|
c@5
|
549 jo["minChannelCount"] = d.minChannelCount;
|
c@5
|
550 jo["maxChannelCount"] = d.maxChannelCount;
|
c@5
|
551
|
c@5
|
552 json11::Json::array params;
|
c@5
|
553 Vamp::PluginBase::ParameterList vparams = d.parameters;
|
c@5
|
554 for (auto &p: vparams) params.push_back(fromParameterDescriptor(p));
|
c@5
|
555 jo["parameters"] = params;
|
c@5
|
556
|
c@5
|
557 json11::Json::array progs;
|
c@5
|
558 Vamp::PluginBase::ProgramList vprogs = d.programs;
|
c@5
|
559 for (auto &p: vprogs) progs.push_back(p);
|
c@5
|
560 jo["programs"] = progs;
|
c@5
|
561
|
c@5
|
562 jo["inputDomain"] = fromInputDomain(d.inputDomain);
|
c@5
|
563
|
c@5
|
564 json11::Json::array outinfo;
|
c@5
|
565 auto vouts = d.basicOutputInfo;
|
c@5
|
566 for (auto &o: vouts) outinfo.push_back(fromBasicDescriptor(o));
|
c@5
|
567 jo["basicOutputInfo"] = outinfo;
|
c@5
|
568
|
c@5
|
569 return json11::Json(jo);
|
c@5
|
570 }
|
c@5
|
571
|
c@5
|
572 static Vamp::HostExt::PluginStaticData
|
c@60
|
573 toPluginStaticData(json11::Json j, std::string &err) {
|
c@5
|
574
|
c@5
|
575 if (!j.has_shape({
|
c@5
|
576 { "pluginKey", json11::Json::STRING },
|
c@5
|
577 { "pluginVersion", json11::Json::NUMBER },
|
c@5
|
578 { "minChannelCount", json11::Json::NUMBER },
|
c@5
|
579 { "maxChannelCount", json11::Json::NUMBER },
|
c@5
|
580 { "inputDomain", json11::Json::STRING }}, err)) {
|
c@60
|
581
|
c@60
|
582 err = "malformed plugin static data: " + err;
|
c@60
|
583
|
c@60
|
584 } else if (!j["basicOutputInfo"].is_array()) {
|
c@60
|
585
|
c@60
|
586 err = "array expected for basic output info";
|
c@60
|
587
|
c@60
|
588 } else if (!j["maker"].is_null() &&
|
c@60
|
589 !j["maker"].is_string()) {
|
c@60
|
590
|
c@60
|
591 err = "string expected for maker";
|
c@60
|
592
|
c@60
|
593 } else if (!j["copyright"].is_null() &&
|
c@60
|
594 !j["copyright"].is_string()) {
|
c@60
|
595 err = "string expected for copyright";
|
c@60
|
596
|
c@60
|
597 } else if (!j["category"].is_null() &&
|
c@60
|
598 !j["category"].is_array()) {
|
c@60
|
599
|
c@60
|
600 err = "array expected for category";
|
c@60
|
601
|
c@60
|
602 } else if (!j["parameters"].is_null() &&
|
c@60
|
603 !j["parameters"].is_array()) {
|
c@60
|
604
|
c@60
|
605 err = "array expected for parameters";
|
c@60
|
606
|
c@60
|
607 } else if (!j["programs"].is_null() &&
|
c@60
|
608 !j["programs"].is_array()) {
|
c@60
|
609
|
c@60
|
610 err = "array expected for programs";
|
c@60
|
611
|
c@60
|
612 } else if (!j["inputDomain"].is_null() &&
|
c@60
|
613 !j["inputDomain"].is_string()) {
|
c@60
|
614
|
c@60
|
615 err = "string expected for inputDomain";
|
c@60
|
616
|
c@60
|
617 } else if (!j["basicOutputInfo"].is_null() &&
|
c@60
|
618 !j["basicOutputInfo"].is_array()) {
|
c@60
|
619
|
c@60
|
620 err = "array expected for basicOutputInfo";
|
c@60
|
621
|
c@60
|
622 } else {
|
c@60
|
623
|
c@60
|
624 Vamp::HostExt::PluginStaticData psd;
|
c@60
|
625
|
c@60
|
626 psd.pluginKey = j["pluginKey"].string_value();
|
c@60
|
627
|
c@60
|
628 toBasicDescriptor(j["basic"], psd.basic, err);
|
c@60
|
629 if (failed(err)) return {};
|
c@60
|
630
|
c@60
|
631 psd.maker = j["maker"].string_value();
|
c@60
|
632 psd.copyright = j["copyright"].string_value();
|
c@60
|
633 psd.pluginVersion = j["pluginVersion"].int_value();
|
c@60
|
634
|
c@60
|
635 for (const auto &c : j["category"].array_items()) {
|
c@60
|
636 if (!c.is_string()) {
|
c@60
|
637 err = "strings expected in category array";
|
c@60
|
638 return {};
|
c@60
|
639 }
|
c@60
|
640 psd.category.push_back(c.string_value());
|
c@60
|
641 }
|
c@60
|
642
|
c@60
|
643 psd.minChannelCount = j["minChannelCount"].int_value();
|
c@60
|
644 psd.maxChannelCount = j["maxChannelCount"].int_value();
|
c@60
|
645
|
c@60
|
646 for (const auto &p : j["parameters"].array_items()) {
|
c@60
|
647 auto pd = toParameterDescriptor(p, err);
|
c@60
|
648 if (failed(err)) return {};
|
c@60
|
649 psd.parameters.push_back(pd);
|
c@60
|
650 }
|
c@60
|
651
|
c@60
|
652 for (const auto &p : j["programs"].array_items()) {
|
c@60
|
653 if (!p.is_string()) {
|
c@60
|
654 err = "strings expected in programs array";
|
c@60
|
655 return {};
|
c@60
|
656 }
|
c@60
|
657 psd.programs.push_back(p.string_value());
|
c@60
|
658 }
|
c@60
|
659
|
c@60
|
660 psd.inputDomain = toInputDomain(j["inputDomain"].string_value(), err);
|
c@60
|
661 if (failed(err)) return {};
|
c@60
|
662
|
c@60
|
663 for (const auto &bo : j["basicOutputInfo"].array_items()) {
|
c@60
|
664 Vamp::HostExt::PluginStaticData::Basic b;
|
c@60
|
665 toBasicDescriptor(bo, b, err);
|
c@60
|
666 if (failed(err)) return {};
|
c@60
|
667 psd.basicOutputInfo.push_back(b);
|
c@60
|
668 }
|
c@60
|
669
|
c@60
|
670 return psd;
|
c@5
|
671 }
|
c@5
|
672
|
c@60
|
673 // fallthrough error case
|
c@60
|
674 return {};
|
c@5
|
675 }
|
c@5
|
676
|
c@5
|
677 static json11::Json
|
c@5
|
678 fromPluginConfiguration(const Vamp::HostExt::PluginConfiguration &c) {
|
c@5
|
679
|
c@5
|
680 json11::Json::object jo;
|
c@5
|
681
|
c@5
|
682 json11::Json::object paramValues;
|
c@5
|
683 for (auto &vp: c.parameterValues) {
|
c@5
|
684 paramValues[vp.first] = vp.second;
|
c@5
|
685 }
|
c@5
|
686 jo["parameterValues"] = paramValues;
|
c@5
|
687
|
c@5
|
688 if (c.currentProgram != "") {
|
c@5
|
689 jo["currentProgram"] = c.currentProgram;
|
c@5
|
690 }
|
c@5
|
691
|
c@5
|
692 jo["channelCount"] = c.channelCount;
|
c@5
|
693 jo["stepSize"] = c.stepSize;
|
c@5
|
694 jo["blockSize"] = c.blockSize;
|
c@5
|
695
|
c@5
|
696 return json11::Json(jo);
|
c@5
|
697 }
|
c@5
|
698
|
c@5
|
699 static Vamp::HostExt::PluginConfiguration
|
c@60
|
700 toPluginConfiguration(json11::Json j, std::string &err) {
|
c@5
|
701
|
c@5
|
702 if (!j.has_shape({
|
c@5
|
703 { "channelCount", json11::Json::NUMBER },
|
c@5
|
704 { "stepSize", json11::Json::NUMBER },
|
c@5
|
705 { "blockSize", json11::Json::NUMBER } }, err)) {
|
c@60
|
706 err = "malformed plugin configuration: " + err;
|
c@60
|
707 return {};
|
c@5
|
708 }
|
c@5
|
709
|
c@5
|
710 if (!j["parameterValues"].is_null() &&
|
c@5
|
711 !j["parameterValues"].is_object()) {
|
c@60
|
712 err = "object expected for parameter values";
|
c@60
|
713 return {};
|
c@5
|
714 }
|
c@5
|
715
|
c@5
|
716 for (auto &pv : j["parameterValues"].object_items()) {
|
c@5
|
717 if (!pv.second.is_number()) {
|
c@60
|
718 err = "number expected for parameter value";
|
c@60
|
719 return {};
|
c@5
|
720 }
|
c@5
|
721 }
|
c@5
|
722
|
c@5
|
723 if (!j["currentProgram"].is_null() &&
|
c@5
|
724 !j["currentProgram"].is_string()) {
|
c@60
|
725 err = "string expected for program name";
|
c@60
|
726 return {};
|
c@5
|
727 }
|
c@5
|
728
|
c@5
|
729 Vamp::HostExt::PluginConfiguration config;
|
c@5
|
730
|
c@5
|
731 config.channelCount = j["channelCount"].number_value();
|
c@5
|
732 config.stepSize = j["stepSize"].number_value();
|
c@5
|
733 config.blockSize = j["blockSize"].number_value();
|
c@5
|
734
|
c@5
|
735 for (auto &pv : j["parameterValues"].object_items()) {
|
c@5
|
736 config.parameterValues[pv.first] = pv.second.number_value();
|
c@5
|
737 }
|
c@5
|
738
|
c@5
|
739 if (j["currentProgram"].is_string()) {
|
c@5
|
740 config.currentProgram = j["currentProgram"].string_value();
|
c@5
|
741 }
|
c@5
|
742
|
c@5
|
743 return config;
|
c@5
|
744 }
|
c@5
|
745
|
c@5
|
746 static json11::Json
|
c@5
|
747 fromAdapterFlags(int flags) {
|
c@5
|
748
|
c@5
|
749 json11::Json::array arr;
|
c@5
|
750
|
c@5
|
751 if (flags & Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN) {
|
c@5
|
752 arr.push_back("AdaptInputDomain");
|
c@5
|
753 }
|
c@5
|
754 if (flags & Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT) {
|
c@5
|
755 arr.push_back("AdaptChannelCount");
|
c@5
|
756 }
|
c@5
|
757 if (flags & Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE) {
|
c@5
|
758 arr.push_back("AdaptBufferSize");
|
c@5
|
759 }
|
c@5
|
760
|
c@5
|
761 return json11::Json(arr);
|
c@5
|
762 }
|
c@5
|
763
|
c@5
|
764 static Vamp::HostExt::PluginLoader::AdapterFlags
|
c@60
|
765 toAdapterFlags(json11::Json j, std::string &err) {
|
c@60
|
766
|
c@60
|
767 int flags = 0x0;
|
c@5
|
768
|
c@5
|
769 if (!j.is_array()) {
|
c@5
|
770
|
c@60
|
771 err = "array expected for adapter flags";
|
c@60
|
772
|
c@60
|
773 } else {
|
c@60
|
774
|
c@60
|
775 for (auto &jj: j.array_items()) {
|
c@60
|
776 if (!jj.is_string()) {
|
c@60
|
777 err = "string expected for adapter flag";
|
c@60
|
778 break;
|
c@60
|
779 }
|
c@60
|
780 std::string text = jj.string_value();
|
c@60
|
781 if (text == "AdaptInputDomain") {
|
c@60
|
782 flags |= Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN;
|
c@60
|
783 } else if (text == "AdaptChannelCount") {
|
c@60
|
784 flags |= Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT;
|
c@60
|
785 } else if (text == "AdaptBufferSize") {
|
c@60
|
786 flags |= Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE;
|
c@60
|
787 } else if (text == "AdaptAllSafe") {
|
c@60
|
788 flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL_SAFE;
|
c@60
|
789 } else if (text == "AdaptAll") {
|
c@60
|
790 flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL;
|
c@60
|
791 } else {
|
c@60
|
792 err = "invalid adapter flag string: " + text;
|
c@60
|
793 break;
|
c@60
|
794 }
|
c@5
|
795 }
|
c@5
|
796 }
|
c@5
|
797
|
c@5
|
798 return Vamp::HostExt::PluginLoader::AdapterFlags(flags);
|
c@5
|
799 }
|
c@5
|
800
|
c@5
|
801 static json11::Json
|
c@17
|
802 fromLoadRequest(const Vamp::HostExt::LoadRequest &req) {
|
c@5
|
803
|
c@5
|
804 json11::Json::object jo;
|
c@5
|
805 jo["pluginKey"] = req.pluginKey;
|
c@5
|
806 jo["inputSampleRate"] = req.inputSampleRate;
|
c@5
|
807 jo["adapterFlags"] = fromAdapterFlags(req.adapterFlags);
|
c@5
|
808 return json11::Json(jo);
|
c@5
|
809 }
|
c@5
|
810
|
c@5
|
811 static Vamp::HostExt::LoadRequest
|
c@60
|
812 toLoadRequest(json11::Json j, std::string &err) {
|
c@5
|
813
|
c@5
|
814 if (!j.has_shape({
|
c@5
|
815 { "pluginKey", json11::Json::STRING },
|
c@32
|
816 { "inputSampleRate", json11::Json::NUMBER } }, err)) {
|
c@60
|
817 err = "malformed load request: " + err;
|
c@60
|
818 return {};
|
c@5
|
819 }
|
c@5
|
820
|
c@5
|
821 Vamp::HostExt::LoadRequest req;
|
c@5
|
822 req.pluginKey = j["pluginKey"].string_value();
|
c@5
|
823 req.inputSampleRate = j["inputSampleRate"].number_value();
|
c@32
|
824 if (!j["adapterFlags"].is_null()) {
|
c@60
|
825 req.adapterFlags = toAdapterFlags(j["adapterFlags"], err);
|
c@60
|
826 if (failed(err)) return {};
|
c@32
|
827 }
|
c@5
|
828 return req;
|
c@5
|
829 }
|
c@10
|
830
|
c@10
|
831 static json11::Json
|
c@17
|
832 fromLoadResponse(const Vamp::HostExt::LoadResponse &resp,
|
c@49
|
833 const PluginHandleMapper &pmapper) {
|
c@10
|
834
|
c@10
|
835 json11::Json::object jo;
|
c@49
|
836 jo["pluginHandle"] = double(pmapper.pluginToHandle(resp.plugin));
|
c@10
|
837 jo["staticData"] = fromPluginStaticData(resp.staticData);
|
c@10
|
838 jo["defaultConfiguration"] =
|
c@10
|
839 fromPluginConfiguration(resp.defaultConfiguration);
|
c@10
|
840 return json11::Json(jo);
|
c@10
|
841 }
|
c@10
|
842
|
c@10
|
843 static Vamp::HostExt::LoadResponse
|
c@10
|
844 toLoadResponse(json11::Json j,
|
c@60
|
845 const PluginHandleMapper &pmapper, std::string &err) {
|
c@10
|
846
|
c@10
|
847 if (!j.has_shape({
|
c@10
|
848 { "pluginHandle", json11::Json::NUMBER },
|
c@10
|
849 { "staticData", json11::Json::OBJECT },
|
c@10
|
850 { "defaultConfiguration", json11::Json::OBJECT } }, err)) {
|
c@60
|
851 err = "malformed load response: " + err;
|
c@60
|
852 return {};
|
c@10
|
853 }
|
c@10
|
854
|
c@10
|
855 Vamp::HostExt::LoadResponse resp;
|
c@49
|
856 resp.plugin = pmapper.handleToPlugin(j["pluginHandle"].int_value());
|
c@60
|
857 resp.staticData = toPluginStaticData(j["staticData"], err);
|
c@60
|
858 if (failed(err)) return {};
|
c@60
|
859 resp.defaultConfiguration = toPluginConfiguration(j["defaultConfiguration"],
|
c@60
|
860 err);
|
c@60
|
861 if (failed(err)) return {};
|
c@10
|
862 return resp;
|
c@10
|
863 }
|
c@12
|
864
|
c@12
|
865 static json11::Json
|
c@13
|
866 fromConfigurationRequest(const Vamp::HostExt::ConfigurationRequest &cr,
|
c@49
|
867 const PluginHandleMapper &pmapper) {
|
c@13
|
868
|
c@13
|
869 json11::Json::object jo;
|
c@13
|
870
|
c@49
|
871 jo["pluginHandle"] = pmapper.pluginToHandle(cr.plugin);
|
c@13
|
872 jo["configuration"] = fromPluginConfiguration(cr.configuration);
|
c@13
|
873
|
c@13
|
874 return json11::Json(jo);
|
c@13
|
875 }
|
c@13
|
876
|
c@13
|
877 static Vamp::HostExt::ConfigurationRequest
|
c@13
|
878 toConfigurationRequest(json11::Json j,
|
c@60
|
879 const PluginHandleMapper &pmapper, std::string &err) {
|
c@13
|
880
|
c@13
|
881 if (!j.has_shape({
|
c@13
|
882 { "pluginHandle", json11::Json::NUMBER },
|
c@13
|
883 { "configuration", json11::Json::OBJECT } }, err)) {
|
c@60
|
884 err = "malformed configuration request: " + err;
|
c@60
|
885 return {};
|
c@13
|
886 }
|
c@13
|
887
|
c@13
|
888 Vamp::HostExt::ConfigurationRequest cr;
|
c@49
|
889 cr.plugin = pmapper.handleToPlugin(j["pluginHandle"].int_value());
|
c@60
|
890 cr.configuration = toPluginConfiguration(j["configuration"], err);
|
c@60
|
891 if (failed(err)) return {};
|
c@13
|
892 return cr;
|
c@13
|
893 }
|
c@13
|
894
|
c@13
|
895 static json11::Json
|
c@55
|
896 fromConfigurationResponse(const Vamp::HostExt::ConfigurationResponse &cr,
|
c@55
|
897 const PluginHandleMapper &pmapper) {
|
c@12
|
898
|
c@13
|
899 json11::Json::object jo;
|
c@55
|
900
|
c@55
|
901 jo["pluginHandle"] = pmapper.pluginToHandle(cr.plugin);
|
c@12
|
902
|
c@12
|
903 json11::Json::array outs;
|
c@12
|
904 for (auto &d: cr.outputs) {
|
c@12
|
905 outs.push_back(fromOutputDescriptor(d));
|
c@12
|
906 }
|
c@13
|
907 jo["outputList"] = outs;
|
c@12
|
908
|
c@13
|
909 return json11::Json(jo);
|
c@12
|
910 }
|
c@12
|
911
|
c@13
|
912 static Vamp::HostExt::ConfigurationResponse
|
c@55
|
913 toConfigurationResponse(json11::Json j,
|
c@60
|
914 const PluginHandleMapper &pmapper, std::string &err) {
|
c@13
|
915
|
c@12
|
916 Vamp::HostExt::ConfigurationResponse cr;
|
c@12
|
917
|
c@55
|
918 cr.plugin = pmapper.handleToPlugin(j["pluginHandle"].int_value());
|
c@55
|
919
|
c@12
|
920 if (!j["outputList"].is_array()) {
|
c@60
|
921 err = "array expected for output list";
|
c@60
|
922 return {};
|
c@12
|
923 }
|
c@12
|
924
|
c@12
|
925 for (const auto &o: j["outputList"].array_items()) {
|
c@60
|
926 cr.outputs.push_back(toOutputDescriptor(o, err));
|
c@60
|
927 if (failed(err)) return {};
|
c@12
|
928 }
|
c@12
|
929
|
c@12
|
930 return cr;
|
c@12
|
931 }
|
c@16
|
932
|
c@16
|
933 static json11::Json
|
c@16
|
934 fromProcessRequest(const Vamp::HostExt::ProcessRequest &r,
|
c@49
|
935 const PluginHandleMapper &pmapper,
|
c@44
|
936 BufferSerialisation serialisation) {
|
c@16
|
937
|
c@16
|
938 json11::Json::object jo;
|
c@49
|
939 jo["pluginHandle"] = pmapper.pluginToHandle(r.plugin);
|
c@16
|
940
|
c@16
|
941 json11::Json::object io;
|
c@16
|
942 io["timestamp"] = fromRealTime(r.timestamp);
|
c@16
|
943
|
c@16
|
944 json11::Json::array chans;
|
c@16
|
945 for (size_t i = 0; i < r.inputBuffers.size(); ++i) {
|
c@66
|
946 if (serialisation == BufferSerialisation::Array) {
|
c@66
|
947 chans.push_back(json11::Json::array(r.inputBuffers[i].begin(),
|
c@66
|
948 r.inputBuffers[i].end()));
|
c@44
|
949 } else {
|
c@66
|
950 chans.push_back(fromFloatBuffer(r.inputBuffers[i].data(),
|
c@66
|
951 r.inputBuffers[i].size()));
|
c@44
|
952 }
|
c@16
|
953 }
|
c@16
|
954 io["inputBuffers"] = chans;
|
c@16
|
955
|
c@16
|
956 jo["processInput"] = io;
|
c@16
|
957 return json11::Json(jo);
|
c@16
|
958 }
|
c@17
|
959
|
c@17
|
960 static Vamp::HostExt::ProcessRequest
|
c@44
|
961 toProcessRequest(json11::Json j,
|
c@49
|
962 const PluginHandleMapper &pmapper,
|
c@60
|
963 BufferSerialisation &serialisation, std::string &err) {
|
c@17
|
964
|
c@17
|
965 if (!j.has_shape({
|
c@17
|
966 { "pluginHandle", json11::Json::NUMBER },
|
c@17
|
967 { "processInput", json11::Json::OBJECT } }, err)) {
|
c@60
|
968 err = "malformed process request: " + err;
|
c@60
|
969 return {};
|
c@17
|
970 }
|
c@17
|
971
|
c@17
|
972 auto input = j["processInput"];
|
c@17
|
973
|
c@17
|
974 if (!input.has_shape({
|
c@17
|
975 { "timestamp", json11::Json::OBJECT },
|
c@17
|
976 { "inputBuffers", json11::Json::ARRAY } }, err)) {
|
c@60
|
977 err = "malformed process request: " + err;
|
c@60
|
978 return {};
|
c@17
|
979 }
|
c@17
|
980
|
c@17
|
981 Vamp::HostExt::ProcessRequest r;
|
c@49
|
982 r.plugin = pmapper.handleToPlugin(j["pluginHandle"].int_value());
|
c@17
|
983
|
c@60
|
984 r.timestamp = toRealTime(input["timestamp"], err);
|
c@60
|
985 if (failed(err)) return {};
|
c@17
|
986
|
c@66
|
987 for (const auto &a: input["inputBuffers"].array_items()) {
|
c@44
|
988
|
c@66
|
989 if (a.is_string()) {
|
c@66
|
990 std::vector<float> buf = toFloatBuffer(a.string_value(),
|
c@60
|
991 err);
|
c@60
|
992 if (failed(err)) return {};
|
c@44
|
993 r.inputBuffers.push_back(buf);
|
c@44
|
994 serialisation = BufferSerialisation::Base64;
|
c@44
|
995
|
c@66
|
996 } else if (a.is_array()) {
|
c@17
|
997 std::vector<float> buf;
|
c@66
|
998 for (auto v : a.array_items()) {
|
c@17
|
999 buf.push_back(v.number_value());
|
c@17
|
1000 }
|
c@17
|
1001 r.inputBuffers.push_back(buf);
|
c@66
|
1002 serialisation = BufferSerialisation::Array;
|
c@44
|
1003
|
c@17
|
1004 } else {
|
c@66
|
1005 err = "expected arrays or strings in inputBuffers array";
|
c@60
|
1006 return {};
|
c@17
|
1007 }
|
c@17
|
1008 }
|
c@17
|
1009
|
c@17
|
1010 return r;
|
c@17
|
1011 }
|
c@17
|
1012
|
c@17
|
1013 static json11::Json
|
c@17
|
1014 fromVampRequest_List() {
|
c@17
|
1015
|
c@17
|
1016 json11::Json::object jo;
|
c@17
|
1017 jo["type"] = "list";
|
c@17
|
1018 return json11::Json(jo);
|
c@17
|
1019 }
|
c@17
|
1020
|
c@17
|
1021 static json11::Json
|
c@59
|
1022 fromVampResponse_List(const Vamp::HostExt::ListResponse &resp) {
|
c@17
|
1023
|
c@17
|
1024 json11::Json::object jo;
|
c@24
|
1025 jo["type"] = "list";
|
c@59
|
1026 jo["success"] = true;
|
c@17
|
1027
|
c@17
|
1028 json11::Json::array arr;
|
c@64
|
1029 for (const auto &a: resp.plugins) {
|
c@17
|
1030 arr.push_back(fromPluginStaticData(a));
|
c@17
|
1031 }
|
c@24
|
1032 json11::Json::object po;
|
c@24
|
1033 po["plugins"] = arr;
|
c@24
|
1034
|
c@24
|
1035 jo["content"] = po;
|
c@17
|
1036 return json11::Json(jo);
|
c@17
|
1037 }
|
c@17
|
1038
|
c@17
|
1039 static json11::Json
|
c@17
|
1040 fromVampRequest_Load(const Vamp::HostExt::LoadRequest &req) {
|
c@17
|
1041
|
c@17
|
1042 json11::Json::object jo;
|
c@17
|
1043 jo["type"] = "load";
|
c@17
|
1044 jo["content"] = fromLoadRequest(req);
|
c@17
|
1045 return json11::Json(jo);
|
c@17
|
1046 }
|
c@17
|
1047
|
c@17
|
1048 static json11::Json
|
c@17
|
1049 fromVampResponse_Load(const Vamp::HostExt::LoadResponse &resp,
|
c@49
|
1050 const PluginHandleMapper &pmapper) {
|
c@17
|
1051
|
c@17
|
1052 json11::Json::object jo;
|
c@24
|
1053 jo["type"] = "load";
|
c@17
|
1054 jo["success"] = (resp.plugin != 0);
|
c@17
|
1055 jo["errorText"] = "";
|
c@49
|
1056 jo["content"] = fromLoadResponse(resp, pmapper);
|
c@17
|
1057 return json11::Json(jo);
|
c@17
|
1058 }
|
c@17
|
1059
|
c@17
|
1060 static json11::Json
|
c@17
|
1061 fromVampRequest_Configure(const Vamp::HostExt::ConfigurationRequest &req,
|
c@49
|
1062 const PluginHandleMapper &pmapper) {
|
c@17
|
1063
|
c@17
|
1064 json11::Json::object jo;
|
c@17
|
1065 jo["type"] = "configure";
|
c@49
|
1066 jo["content"] = fromConfigurationRequest(req, pmapper);
|
c@17
|
1067 return json11::Json(jo);
|
c@17
|
1068 }
|
c@17
|
1069
|
c@17
|
1070 static json11::Json
|
c@55
|
1071 fromVampResponse_Configure(const Vamp::HostExt::ConfigurationResponse &resp,
|
c@55
|
1072 const PluginHandleMapper &pmapper) {
|
c@17
|
1073
|
c@17
|
1074 json11::Json::object jo;
|
c@24
|
1075 jo["type"] = "configure";
|
c@17
|
1076 jo["success"] = (!resp.outputs.empty());
|
c@17
|
1077 jo["errorText"] = "";
|
c@55
|
1078 jo["content"] = fromConfigurationResponse(resp, pmapper);
|
c@17
|
1079 return json11::Json(jo);
|
c@17
|
1080 }
|
c@17
|
1081
|
c@17
|
1082 static json11::Json
|
c@17
|
1083 fromVampRequest_Process(const Vamp::HostExt::ProcessRequest &req,
|
c@49
|
1084 const PluginHandleMapper &pmapper,
|
c@44
|
1085 BufferSerialisation serialisation) {
|
c@17
|
1086
|
c@17
|
1087 json11::Json::object jo;
|
c@17
|
1088 jo["type"] = "process";
|
c@49
|
1089 jo["content"] = fromProcessRequest(req, pmapper, serialisation);
|
c@17
|
1090 return json11::Json(jo);
|
c@17
|
1091 }
|
c@17
|
1092
|
c@17
|
1093 static json11::Json
|
c@44
|
1094 fromVampResponse_Process(const Vamp::HostExt::ProcessResponse &resp,
|
c@51
|
1095 const PluginHandleMapper &pmapper,
|
c@44
|
1096 BufferSerialisation serialisation) {
|
c@17
|
1097
|
c@17
|
1098 json11::Json::object jo;
|
c@24
|
1099 jo["type"] = "process";
|
c@17
|
1100 jo["success"] = true;
|
c@17
|
1101 jo["errorText"] = "";
|
c@52
|
1102 json11::Json::object po;
|
c@52
|
1103 po["pluginHandle"] = pmapper.pluginToHandle(resp.plugin);
|
c@52
|
1104 po["features"] = fromFeatureSet(resp.features,
|
c@57
|
1105 *pmapper.pluginToOutputIdMapper(resp.plugin),
|
c@52
|
1106 serialisation);
|
c@52
|
1107 jo["content"] = po;
|
c@17
|
1108 return json11::Json(jo);
|
c@17
|
1109 }
|
c@17
|
1110
|
c@17
|
1111 static json11::Json
|
c@55
|
1112 fromVampRequest_Finish(const Vamp::HostExt::FinishRequest &req,
|
c@49
|
1113 const PluginHandleMapper &pmapper) {
|
c@17
|
1114
|
c@17
|
1115 json11::Json::object jo;
|
c@17
|
1116 jo["type"] = "finish";
|
c@24
|
1117 json11::Json::object fo;
|
c@55
|
1118 fo["pluginHandle"] = pmapper.pluginToHandle(req.plugin);
|
c@24
|
1119 jo["content"] = fo;
|
c@17
|
1120 return json11::Json(jo);
|
c@17
|
1121 }
|
c@17
|
1122
|
c@17
|
1123 static json11::Json
|
c@44
|
1124 fromVampResponse_Finish(const Vamp::HostExt::ProcessResponse &resp,
|
c@51
|
1125 const PluginHandleMapper &pmapper,
|
c@44
|
1126 BufferSerialisation serialisation) {
|
c@17
|
1127
|
c@17
|
1128 json11::Json::object jo;
|
c@24
|
1129 jo["type"] = "finish";
|
c@17
|
1130 jo["success"] = true;
|
c@17
|
1131 jo["errorText"] = "";
|
c@52
|
1132 json11::Json::object po;
|
c@52
|
1133 po["pluginHandle"] = pmapper.pluginToHandle(resp.plugin);
|
c@52
|
1134 po["features"] = fromFeatureSet(resp.features,
|
c@57
|
1135 *pmapper.pluginToOutputIdMapper(resp.plugin),
|
c@52
|
1136 serialisation);
|
c@52
|
1137 jo["content"] = po;
|
c@17
|
1138 return json11::Json(jo);
|
c@17
|
1139 }
|
c@24
|
1140
|
c@41
|
1141 static json11::Json
|
c@52
|
1142 fromError(std::string errorText, RRType responseType) {
|
c@41
|
1143
|
c@41
|
1144 json11::Json::object jo;
|
c@43
|
1145 std::string type;
|
c@41
|
1146
|
c@43
|
1147 if (responseType == RRType::List) type = "list";
|
c@43
|
1148 else if (responseType == RRType::Load) type = "load";
|
c@43
|
1149 else if (responseType == RRType::Configure) type = "configure";
|
c@43
|
1150 else if (responseType == RRType::Process) type = "process";
|
c@43
|
1151 else if (responseType == RRType::Finish) type = "finish";
|
c@43
|
1152 else type = "invalid";
|
c@41
|
1153
|
c@43
|
1154 jo["type"] = type;
|
c@41
|
1155 jo["success"] = false;
|
c@52
|
1156 jo["errorText"] = std::string("error in ") + type + " request: " + errorText;
|
c@41
|
1157 return json11::Json(jo);
|
c@41
|
1158 }
|
c@41
|
1159
|
c@24
|
1160 private: // go private briefly for a couple of helper functions
|
c@24
|
1161
|
c@24
|
1162 static void
|
c@60
|
1163 checkTypeField(json11::Json j, std::string expected, std::string &err) {
|
c@24
|
1164 if (!j["type"].is_string()) {
|
c@60
|
1165 err = "string expected for type";
|
c@60
|
1166 return;
|
c@24
|
1167 }
|
c@24
|
1168 if (j["type"].string_value() != expected) {
|
c@60
|
1169 err = "expected value \"" + expected + "\" for type";
|
c@60
|
1170 return;
|
c@24
|
1171 }
|
c@24
|
1172 }
|
c@24
|
1173
|
c@24
|
1174 static bool
|
c@60
|
1175 successful(json11::Json j, std::string &err) {
|
c@24
|
1176 if (!j["success"].is_bool()) {
|
c@60
|
1177 err = "bool expected for success";
|
c@60
|
1178 return false;
|
c@24
|
1179 }
|
c@24
|
1180 return j["success"].bool_value();
|
c@24
|
1181 }
|
c@24
|
1182
|
c@24
|
1183 public:
|
c@25
|
1184 static RRType
|
c@60
|
1185 getRequestResponseType(json11::Json j, std::string &err) {
|
c@25
|
1186
|
c@25
|
1187 if (!j["type"].is_string()) {
|
c@60
|
1188 err = "string expected for type";
|
c@60
|
1189 return RRType::NotValid;
|
c@25
|
1190 }
|
c@25
|
1191
|
c@25
|
1192 std::string type = j["type"].string_value();
|
c@25
|
1193
|
c@25
|
1194 if (type == "list") return RRType::List;
|
c@25
|
1195 else if (type == "load") return RRType::Load;
|
c@25
|
1196 else if (type == "configure") return RRType::Configure;
|
c@25
|
1197 else if (type == "process") return RRType::Process;
|
c@25
|
1198 else if (type == "finish") return RRType::Finish;
|
c@60
|
1199 else if (type == "invalid") return RRType::NotValid;
|
c@25
|
1200 else {
|
c@60
|
1201 err = "unknown or unexpected request/response type \"" + type + "\"";
|
c@60
|
1202 return RRType::NotValid;
|
c@25
|
1203 }
|
c@25
|
1204 }
|
c@44
|
1205
|
c@24
|
1206 static void
|
c@60
|
1207 toVampRequest_List(json11::Json j, std::string &err) {
|
c@60
|
1208 checkTypeField(j, "list", err);
|
c@24
|
1209 }
|
c@24
|
1210
|
c@56
|
1211 static Vamp::HostExt::ListResponse
|
c@60
|
1212 toVampResponse_List(json11::Json j, std::string &err) {
|
c@24
|
1213
|
c@56
|
1214 Vamp::HostExt::ListResponse resp;
|
c@60
|
1215 if (successful(j, err) && !failed(err)) {
|
c@24
|
1216 for (const auto &a: j["content"]["plugins"].array_items()) {
|
c@65
|
1217 resp.plugins.push_back(toPluginStaticData(a, err));
|
c@60
|
1218 if (failed(err)) return {};
|
c@24
|
1219 }
|
c@24
|
1220 }
|
c@60
|
1221
|
c@56
|
1222 return resp;
|
c@24
|
1223 }
|
c@24
|
1224
|
c@24
|
1225 static Vamp::HostExt::LoadRequest
|
c@60
|
1226 toVampRequest_Load(json11::Json j, std::string &err) {
|
c@24
|
1227
|
c@60
|
1228 checkTypeField(j, "load", err);
|
c@60
|
1229 if (failed(err)) return {};
|
c@60
|
1230 return toLoadRequest(j["content"], err);
|
c@24
|
1231 }
|
c@24
|
1232
|
c@24
|
1233 static Vamp::HostExt::LoadResponse
|
c@60
|
1234 toVampResponse_Load(json11::Json j,
|
c@60
|
1235 const PluginHandleMapper &pmapper,
|
c@60
|
1236 std::string &err) {
|
c@24
|
1237
|
c@24
|
1238 Vamp::HostExt::LoadResponse resp;
|
c@60
|
1239 if (successful(j, err) && !failed(err)) {
|
c@60
|
1240 resp = toLoadResponse(j["content"], pmapper, err);
|
c@24
|
1241 }
|
c@24
|
1242 return resp;
|
c@24
|
1243 }
|
c@24
|
1244
|
c@24
|
1245 static Vamp::HostExt::ConfigurationRequest
|
c@60
|
1246 toVampRequest_Configure(json11::Json j,
|
c@60
|
1247 const PluginHandleMapper &pmapper,
|
c@60
|
1248 std::string &err) {
|
c@24
|
1249
|
c@60
|
1250 checkTypeField(j, "configure", err);
|
c@60
|
1251 if (failed(err)) return {};
|
c@60
|
1252 return toConfigurationRequest(j["content"], pmapper, err);
|
c@24
|
1253 }
|
c@24
|
1254
|
c@24
|
1255 static Vamp::HostExt::ConfigurationResponse
|
c@60
|
1256 toVampResponse_Configure(json11::Json j,
|
c@60
|
1257 const PluginHandleMapper &pmapper,
|
c@60
|
1258 std::string &err) {
|
c@24
|
1259
|
c@24
|
1260 Vamp::HostExt::ConfigurationResponse resp;
|
c@60
|
1261 if (successful(j, err) && !failed(err)) {
|
c@60
|
1262 resp = toConfigurationResponse(j["content"], pmapper, err);
|
c@24
|
1263 }
|
c@24
|
1264 return resp;
|
c@24
|
1265 }
|
c@24
|
1266
|
c@24
|
1267 static Vamp::HostExt::ProcessRequest
|
c@49
|
1268 toVampRequest_Process(json11::Json j, const PluginHandleMapper &pmapper,
|
c@60
|
1269 BufferSerialisation &serialisation, std::string &err) {
|
c@24
|
1270
|
c@60
|
1271 checkTypeField(j, "process", err);
|
c@60
|
1272 if (failed(err)) return {};
|
c@60
|
1273 return toProcessRequest(j["content"], pmapper, serialisation, err);
|
c@24
|
1274 }
|
c@24
|
1275
|
c@24
|
1276 static Vamp::HostExt::ProcessResponse
|
c@49
|
1277 toVampResponse_Process(json11::Json j,
|
c@51
|
1278 const PluginHandleMapper &pmapper,
|
c@60
|
1279 BufferSerialisation &serialisation, std::string &err) {
|
c@24
|
1280
|
c@24
|
1281 Vamp::HostExt::ProcessResponse resp;
|
c@60
|
1282 if (successful(j, err) && !failed(err)) {
|
c@51
|
1283 auto jc = j["content"];
|
c@52
|
1284 auto h = jc["pluginHandle"].int_value();
|
c@52
|
1285 resp.plugin = pmapper.handleToPlugin(h);
|
c@52
|
1286 resp.features = toFeatureSet(jc["features"],
|
c@57
|
1287 *pmapper.handleToOutputIdMapper(h),
|
c@60
|
1288 serialisation, err);
|
c@24
|
1289 }
|
c@24
|
1290 return resp;
|
c@24
|
1291 }
|
c@24
|
1292
|
c@55
|
1293 static Vamp::HostExt::FinishRequest
|
c@60
|
1294 toVampRequest_Finish(json11::Json j, const PluginHandleMapper &pmapper,
|
c@60
|
1295 std::string &err) {
|
c@24
|
1296
|
c@60
|
1297 checkTypeField(j, "finish", err);
|
c@60
|
1298 if (failed(err)) return {};
|
c@55
|
1299 Vamp::HostExt::FinishRequest req;
|
c@55
|
1300 req.plugin = pmapper.handleToPlugin
|
c@55
|
1301 (j["content"]["pluginHandle"].int_value());
|
c@55
|
1302 return req;
|
c@24
|
1303 }
|
c@24
|
1304
|
c@24
|
1305 static Vamp::HostExt::ProcessResponse
|
c@49
|
1306 toVampResponse_Finish(json11::Json j,
|
c@51
|
1307 const PluginHandleMapper &pmapper,
|
c@60
|
1308 BufferSerialisation &serialisation, std::string &err) {
|
c@24
|
1309
|
c@24
|
1310 Vamp::HostExt::ProcessResponse resp;
|
c@60
|
1311 if (successful(j, err) && !failed(err)) {
|
c@51
|
1312 auto jc = j["content"];
|
c@52
|
1313 auto h = jc["pluginHandle"].int_value();
|
c@52
|
1314 resp.plugin = pmapper.handleToPlugin(h);
|
c@52
|
1315 resp.features = toFeatureSet(jc["features"],
|
c@57
|
1316 *pmapper.handleToOutputIdMapper(h),
|
c@60
|
1317 serialisation, err);
|
c@24
|
1318 }
|
c@24
|
1319 return resp;
|
c@24
|
1320 }
|
c@5
|
1321 };
|
c@5
|
1322
|
c@10
|
1323 }
|
c@5
|
1324
|
c@5
|
1325 #endif
|