c@5: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ c@5: c@5: #ifndef VAMP_JSON_H c@5: #define VAMP_JSON_H c@5: c@5: #include c@5: #include c@5: #include c@5: #include c@5: c@5: #include c@5: #include c@5: c@5: #include c@5: #include c@5: c@10: #include "bits/PluginHandleMapper.h" c@10: c@10: namespace vampipe { c@10: c@6: /** c@6: * Convert the structures laid out in the Vamp SDK classes into JSON c@6: * (and back again) following the schema in the vamp-json-schema c@6: * project repo. c@6: */ c@5: class VampJson c@5: { c@5: public: c@5: class Failure : virtual public std::runtime_error { c@5: public: c@5: Failure(std::string s) : runtime_error(s) { } c@5: }; c@5: c@5: template c@5: static json11::Json c@5: fromBasicDescriptor(const T &t) { c@5: return json11::Json::object { c@5: { "identifier", t.identifier }, c@5: { "name", t.name }, c@5: { "description", t.description } c@5: }; c@5: } c@5: c@5: template c@5: static void c@5: toBasicDescriptor(json11::Json j, T &t) { c@5: if (!j.is_object()) { c@5: throw Failure("object expected for basic descriptor content"); c@5: } c@5: if (!j["identifier"].is_string()) { c@5: throw Failure("string expected for identifier"); c@5: } c@5: t.identifier = j["identifier"].string_value(); c@5: t.name = j["name"].string_value(); c@5: t.description = j["description"].string_value(); c@5: } c@5: c@5: template c@5: static json11::Json c@5: fromValueExtents(const T &t) { c@5: return json11::Json::object { c@5: { "min", t.minValue }, c@5: { "max", t.maxValue } c@5: }; c@5: } c@5: c@5: template c@5: static bool c@5: toValueExtents(json11::Json j, T &t) { c@5: if (j["extents"].is_null()) { c@5: return false; c@5: } else if (j["extents"].is_object()) { c@5: if (j["extents"]["min"].is_number() && c@5: j["extents"]["max"].is_number()) { c@5: t.minValue = j["extents"]["min"].number_value(); c@5: t.maxValue = j["extents"]["max"].number_value(); c@5: return true; c@5: } else { c@5: throw Failure("numbers expected for min and max"); c@5: } c@5: } else { c@5: throw Failure("object expected for extents (if present)"); c@5: } c@5: } c@5: c@5: static json11::Json c@5: fromRealTime(const Vamp::RealTime &r) { c@5: return json11::Json::object { c@5: { "s", r.sec }, c@5: { "n", r.nsec } c@5: }; c@5: } c@5: c@5: static Vamp::RealTime c@5: toRealTime(json11::Json j) { c@5: json11::Json sec = j["s"]; c@5: json11::Json nsec = j["n"]; c@5: if (!sec.is_number() || !nsec.is_number()) { c@5: throw Failure("invalid Vamp::RealTime object " + j.dump()); c@5: } c@5: return Vamp::RealTime(sec.int_value(), nsec.int_value()); c@5: } c@5: c@5: static std::string c@5: fromSampleType(Vamp::Plugin::OutputDescriptor::SampleType type) { c@5: switch (type) { c@5: case Vamp::Plugin::OutputDescriptor::OneSamplePerStep: c@5: return "OneSamplePerStep"; c@5: case Vamp::Plugin::OutputDescriptor::FixedSampleRate: c@5: return "FixedSampleRate"; c@5: case Vamp::Plugin::OutputDescriptor::VariableSampleRate: c@5: return "VariableSampleRate"; c@5: } c@5: return ""; c@5: } c@5: c@5: static Vamp::Plugin::OutputDescriptor::SampleType c@5: toSampleType(std::string text) { c@5: if (text == "OneSamplePerStep") { c@5: return Vamp::Plugin::OutputDescriptor::OneSamplePerStep; c@5: } else if (text == "FixedSampleRate") { c@5: return Vamp::Plugin::OutputDescriptor::FixedSampleRate; c@5: } else if (text == "VariableSampleRate") { c@5: return Vamp::Plugin::OutputDescriptor::VariableSampleRate; c@5: } else { c@5: throw Failure("invalid sample type string: " + text); c@5: } c@5: } c@5: c@5: static json11::Json c@5: fromOutputDescriptor(const Vamp::Plugin::OutputDescriptor &desc) { c@5: json11::Json::object jo { c@5: { "basic", fromBasicDescriptor(desc) }, c@5: { "unit", desc.unit }, c@5: { "sampleType", fromSampleType(desc.sampleType) }, c@5: { "sampleRate", desc.sampleRate }, c@5: { "hasDuration", desc.hasDuration } c@5: }; c@5: if (desc.hasFixedBinCount) { c@5: jo["binCount"] = int(desc.binCount); c@5: jo["binNames"] = json11::Json::array c@5: (desc.binNames.begin(), desc.binNames.end()); c@5: } c@5: if (desc.hasKnownExtents) { c@5: jo["extents"] = fromValueExtents(desc); c@5: } c@5: if (desc.isQuantized) { c@5: jo["quantizeStep"] = desc.quantizeStep; c@5: } c@5: return json11::Json(jo); c@5: } c@12: c@5: static Vamp::Plugin::OutputDescriptor c@5: toOutputDescriptor(json11::Json j) { c@5: c@5: Vamp::Plugin::OutputDescriptor od; c@5: if (!j.is_object()) { c@5: throw Failure("object expected for output descriptor"); c@5: } c@5: c@5: toBasicDescriptor(j["basic"], od); c@5: c@5: od.unit = j["unit"].string_value(); c@5: c@5: od.sampleType = toSampleType(j["sampleType"].string_value()); c@5: c@5: if (!j["sampleRate"].is_number()) { c@5: throw Failure("number expected for sample rate"); c@5: } c@5: od.sampleRate = j["sampleRate"].number_value(); c@5: od.hasDuration = j["hasDuration"].bool_value(); c@5: c@5: if (j["binCount"].is_number() && j["binCount"].int_value() > 0) { c@5: od.hasFixedBinCount = true; c@5: od.binCount = j["binCount"].int_value(); c@5: for (auto &n: j["binNames"].array_items()) { c@5: if (!n.is_string()) { c@5: throw Failure("string expected for bin name"); c@5: } c@5: od.binNames.push_back(n.string_value()); c@5: } c@5: } else { c@5: od.hasFixedBinCount = false; c@5: } c@5: c@5: bool extentsPresent = toValueExtents(j, od); c@5: od.hasKnownExtents = extentsPresent; c@5: c@5: if (j["quantizeStep"].is_number()) { c@5: od.isQuantized = true; c@5: od.quantizeStep = j["quantizeStep"].number_value(); c@5: } else { c@5: od.isQuantized = false; c@5: } c@5: c@5: return od; c@5: } c@5: c@5: static json11::Json c@5: fromParameterDescriptor(const Vamp::PluginBase::ParameterDescriptor &desc) { c@5: c@5: json11::Json::object jo { c@5: { "basic", fromBasicDescriptor(desc) }, c@5: { "unit", desc.unit }, c@5: { "extents", fromValueExtents(desc) }, c@5: { "defaultValue", desc.defaultValue }, c@5: { "valueNames", json11::Json::array c@5: (desc.valueNames.begin(), desc.valueNames.end()) } c@5: }; c@5: if (desc.isQuantized) { c@5: jo["quantizeStep"] = desc.quantizeStep; c@5: } c@5: return json11::Json(jo); c@5: } c@5: c@5: static Vamp::PluginBase::ParameterDescriptor c@5: toParameterDescriptor(json11::Json j) { c@5: c@5: Vamp::PluginBase::ParameterDescriptor pd; c@5: if (!j.is_object()) { c@5: throw Failure("object expected for parameter descriptor"); c@5: } c@5: c@5: toBasicDescriptor(j["basic"], pd); c@5: c@5: pd.unit = j["unit"].string_value(); c@5: c@5: bool extentsPresent = toValueExtents(j, pd); c@5: if (!extentsPresent) { c@5: throw Failure("extents must be present in parameter descriptor"); c@5: } c@5: c@5: if (!j["defaultValue"].is_number()) { c@5: throw Failure("number expected for default value"); c@5: } c@5: c@5: pd.defaultValue = j["defaultValue"].number_value(); c@5: c@5: pd.valueNames.clear(); c@5: for (auto &n: j["valueNames"].array_items()) { c@5: if (!n.is_string()) { c@5: throw Failure("string expected for value name"); c@5: } c@5: pd.valueNames.push_back(n.string_value()); c@5: } c@5: c@5: if (j["quantizeStep"].is_number()) { c@5: pd.isQuantized = true; c@5: pd.quantizeStep = j["quantizeStep"].number_value(); c@5: } else { c@5: pd.isQuantized = false; c@5: } c@5: c@5: return pd; c@5: } c@5: c@5: static std::string c@5: fromFloatBuffer(const float *buffer, size_t nfloats) { c@5: // must use char pointers, otherwise the converter will only c@5: // encode every 4th byte (as it will count up in float* steps) c@5: const char *start = reinterpret_cast(buffer); c@5: const char *end = reinterpret_cast(buffer + nfloats); c@5: std::string encoded; c@5: bn::encode_b64(start, end, back_inserter(encoded)); c@5: return encoded; c@5: } c@5: c@5: static std::vector c@5: toFloatBuffer(std::string encoded) { c@5: std::string decoded; c@5: bn::decode_b64(encoded.begin(), encoded.end(), back_inserter(decoded)); c@5: const float *buffer = reinterpret_cast(decoded.c_str()); c@5: size_t n = decoded.size() / sizeof(float); c@5: return std::vector(buffer, buffer + n); c@5: } c@5: c@5: static json11::Json c@5: fromFeature(const Vamp::Plugin::Feature &f) { c@5: c@5: json11::Json::object jo; c@5: if (f.values.size() > 0) { c@5: jo["b64values"] = fromFloatBuffer(f.values.data(), f.values.size()); c@5: } c@5: if (f.label != "") { c@5: jo["label"] = f.label; c@5: } c@5: if (f.hasTimestamp) { c@5: jo["timestamp"] = fromRealTime(f.timestamp); c@5: } c@5: if (f.hasDuration) { c@5: jo["duration"] = fromRealTime(f.duration); c@5: } c@5: return json11::Json(jo); c@5: } c@5: c@5: static Vamp::Plugin::Feature c@5: toFeature(json11::Json j) { c@5: c@5: Vamp::Plugin::Feature f; c@5: if (!j.is_object()) { c@5: throw Failure("object expected for feature"); c@5: } c@5: if (j["timestamp"].is_object()) { c@5: f.timestamp = toRealTime(j["timestamp"]); c@5: f.hasTimestamp = true; c@5: } c@5: if (j["duration"].is_object()) { c@5: f.duration = toRealTime(j["duration"]); c@5: f.hasDuration = true; c@5: } c@5: if (j["b64values"].is_string()) { c@5: f.values = toFloatBuffer(j["b64values"].string_value()); c@5: } else if (j["values"].is_array()) { c@5: for (auto v : j["values"].array_items()) { c@5: f.values.push_back(v.number_value()); c@5: } c@5: } c@5: f.label = j["label"].string_value(); c@5: return f; c@5: } c@5: c@5: static json11::Json c@5: fromFeatureSet(const Vamp::Plugin::FeatureSet &fs) { c@5: c@5: json11::Json::object jo; c@5: for (const auto &fsi : fs) { c@5: std::vector fj; c@5: for (const Vamp::Plugin::Feature &f: fsi.second) { c@5: fj.push_back(fromFeature(f)); c@5: } c@5: std::stringstream sstr; c@5: sstr << fsi.first; c@5: std::string n = sstr.str(); c@5: jo[n] = fj; c@5: } c@5: return json11::Json(jo); c@5: } c@5: c@5: static Vamp::Plugin::FeatureList c@5: toFeatureList(json11::Json j) { c@5: c@5: Vamp::Plugin::FeatureList fl; c@5: if (!j.is_array()) { c@5: throw Failure("array expected for feature list"); c@5: } c@5: for (const json11::Json &fj : j.array_items()) { c@5: fl.push_back(toFeature(fj)); c@5: } c@5: return fl; c@5: } c@5: c@5: static Vamp::Plugin::FeatureSet c@5: toFeatureSet(json11::Json j) { c@5: c@5: Vamp::Plugin::FeatureSet fs; c@5: if (!j.is_object()) { c@5: throw Failure("object expected for feature set"); c@5: } c@5: for (auto &entry : j.object_items()) { c@5: std::string nstr = entry.first; c@5: size_t count = 0; c@5: int n = stoi(nstr, &count); c@5: if (n < 0 || fs.find(n) != fs.end() || count < nstr.size()) { c@5: throw Failure("invalid or duplicate numerical index for output"); c@5: } c@5: fs[n] = toFeatureList(entry.second); c@5: } c@5: return fs; c@5: } c@5: c@5: static std::string c@5: fromInputDomain(Vamp::Plugin::InputDomain domain) { c@5: c@5: switch (domain) { c@5: case Vamp::Plugin::TimeDomain: c@5: return "TimeDomain"; c@5: case Vamp::Plugin::FrequencyDomain: c@5: return "FrequencyDomain"; c@5: } c@5: return ""; c@5: } c@5: c@5: static Vamp::Plugin::InputDomain c@5: toInputDomain(std::string text) { c@5: c@5: if (text == "TimeDomain") { c@5: return Vamp::Plugin::TimeDomain; c@5: } else if (text == "FrequencyDomain") { c@5: return Vamp::Plugin::FrequencyDomain; c@5: } else { c@5: throw Failure("invalid input domain string: " + text); c@5: } c@5: } c@5: c@5: static json11::Json c@5: fromPluginStaticData(const Vamp::HostExt::PluginStaticData &d) { c@5: c@5: json11::Json::object jo; c@5: jo["pluginKey"] = d.pluginKey; c@5: jo["basic"] = fromBasicDescriptor(d.basic); c@5: jo["maker"] = d.maker; c@5: jo["copyright"] = d.copyright; c@5: jo["pluginVersion"] = d.pluginVersion; c@5: c@5: json11::Json::array cat; c@5: for (const std::string &c: d.category) cat.push_back(c); c@5: jo["category"] = cat; c@5: c@5: jo["minChannelCount"] = d.minChannelCount; c@5: jo["maxChannelCount"] = d.maxChannelCount; c@5: c@5: json11::Json::array params; c@5: Vamp::PluginBase::ParameterList vparams = d.parameters; c@5: for (auto &p: vparams) params.push_back(fromParameterDescriptor(p)); c@5: jo["parameters"] = params; c@5: c@5: json11::Json::array progs; c@5: Vamp::PluginBase::ProgramList vprogs = d.programs; c@5: for (auto &p: vprogs) progs.push_back(p); c@5: jo["programs"] = progs; c@5: c@5: jo["inputDomain"] = fromInputDomain(d.inputDomain); c@5: c@5: json11::Json::array outinfo; c@5: auto vouts = d.basicOutputInfo; c@5: for (auto &o: vouts) outinfo.push_back(fromBasicDescriptor(o)); c@5: jo["basicOutputInfo"] = outinfo; c@5: c@5: return json11::Json(jo); c@5: } c@5: c@5: static Vamp::HostExt::PluginStaticData c@5: toPluginStaticData(json11::Json j) { c@5: c@5: std::string err; c@5: if (!j.has_shape({ c@5: { "pluginKey", json11::Json::STRING }, c@5: { "pluginVersion", json11::Json::NUMBER }, c@5: { "minChannelCount", json11::Json::NUMBER }, c@5: { "maxChannelCount", json11::Json::NUMBER }, c@5: { "inputDomain", json11::Json::STRING }}, err)) { c@5: throw Failure("malformed plugin static data: " + err); c@5: } c@5: c@5: if (!j["basicOutputInfo"].is_array()) { c@5: throw Failure("array expected for basic output info"); c@5: } c@5: c@5: if (!j["maker"].is_null() && c@5: !j["maker"].is_string()) { c@5: throw Failure("string expected for maker"); c@5: } c@5: c@5: if (!j["copyright"].is_null() && c@5: !j["copyright"].is_string()) { c@5: throw Failure("string expected for copyright"); c@5: } c@5: c@5: if (!j["category"].is_null() && c@5: !j["category"].is_array()) { c@5: throw Failure("array expected for category"); c@5: } c@5: c@5: if (!j["parameters"].is_null() && c@5: !j["parameters"].is_array()) { c@5: throw Failure("array expected for parameters"); c@5: } c@5: c@5: if (!j["programs"].is_null() && c@5: !j["programs"].is_array()) { c@5: throw Failure("array expected for programs"); c@5: } c@5: c@5: if (!j["inputDomain"].is_null() && c@5: !j["inputDomain"].is_string()) { c@5: throw Failure("string expected for inputDomain"); c@5: } c@5: c@5: if (!j["basicOutputInfo"].is_null() && c@5: !j["basicOutputInfo"].is_array()) { c@5: throw Failure("array expected for basicOutputInfo"); c@5: } c@5: c@5: Vamp::HostExt::PluginStaticData psd; c@5: c@5: psd.pluginKey = j["pluginKey"].string_value(); c@5: c@5: toBasicDescriptor(j["basic"], psd.basic); c@5: c@5: psd.maker = j["maker"].string_value(); c@5: psd.copyright = j["copyright"].string_value(); c@5: psd.pluginVersion = j["pluginVersion"].int_value(); c@5: c@5: for (const auto &c : j["category"].array_items()) { c@5: if (!c.is_string()) { c@5: throw Failure("strings expected in category array"); c@5: } c@5: psd.category.push_back(c.string_value()); c@5: } c@5: c@5: psd.minChannelCount = j["minChannelCount"].int_value(); c@5: psd.maxChannelCount = j["maxChannelCount"].int_value(); c@5: c@5: for (const auto &p : j["parameters"].array_items()) { c@5: auto pd = toParameterDescriptor(p); c@5: psd.parameters.push_back(pd); c@5: } c@5: c@5: for (const auto &p : j["programs"].array_items()) { c@5: if (!p.is_string()) { c@5: throw Failure("strings expected in programs array"); c@5: } c@5: psd.programs.push_back(p.string_value()); c@5: } c@5: c@5: psd.inputDomain = toInputDomain(j["inputDomain"].string_value()); c@5: c@5: for (const auto &bo : j["basicOutputInfo"].array_items()) { c@5: Vamp::HostExt::PluginStaticData::Basic b; c@5: toBasicDescriptor(bo, b); c@5: psd.basicOutputInfo.push_back(b); c@5: } c@5: c@5: return psd; c@5: } c@5: c@5: static json11::Json c@5: fromPluginConfiguration(const Vamp::HostExt::PluginConfiguration &c) { c@5: c@5: json11::Json::object jo; c@5: c@5: json11::Json::object paramValues; c@5: for (auto &vp: c.parameterValues) { c@5: paramValues[vp.first] = vp.second; c@5: } c@5: jo["parameterValues"] = paramValues; c@5: c@5: if (c.currentProgram != "") { c@5: jo["currentProgram"] = c.currentProgram; c@5: } c@5: c@5: jo["channelCount"] = c.channelCount; c@5: jo["stepSize"] = c.stepSize; c@5: jo["blockSize"] = c.blockSize; c@5: c@5: return json11::Json(jo); c@5: } c@5: c@5: static Vamp::HostExt::PluginConfiguration c@5: toPluginConfiguration(json11::Json j) { c@5: c@5: std::string err; c@5: if (!j.has_shape({ c@5: { "channelCount", json11::Json::NUMBER }, c@5: { "stepSize", json11::Json::NUMBER }, c@5: { "blockSize", json11::Json::NUMBER } }, err)) { c@5: throw Failure("malformed plugin configuration: " + err); c@5: } c@5: c@5: if (!j["parameterValues"].is_null() && c@5: !j["parameterValues"].is_object()) { c@5: throw Failure("object expected for parameter values"); c@5: } c@5: c@5: for (auto &pv : j["parameterValues"].object_items()) { c@5: if (!pv.second.is_number()) { c@5: throw Failure("number expected for parameter value"); c@5: } c@5: } c@5: c@5: if (!j["currentProgram"].is_null() && c@5: !j["currentProgram"].is_string()) { c@5: throw Failure("string expected for program name"); c@5: } c@5: c@5: Vamp::HostExt::PluginConfiguration config; c@5: c@5: config.channelCount = j["channelCount"].number_value(); c@5: config.stepSize = j["stepSize"].number_value(); c@5: config.blockSize = j["blockSize"].number_value(); c@5: c@5: for (auto &pv : j["parameterValues"].object_items()) { c@5: config.parameterValues[pv.first] = pv.second.number_value(); c@5: } c@5: c@5: if (j["currentProgram"].is_string()) { c@5: config.currentProgram = j["currentProgram"].string_value(); c@5: } c@5: c@5: return config; c@5: } c@5: c@5: static json11::Json c@5: fromAdapterFlags(int flags) { c@5: c@5: json11::Json::array arr; c@5: c@5: if (flags & Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN) { c@5: arr.push_back("AdaptInputDomain"); c@5: } c@5: if (flags & Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT) { c@5: arr.push_back("AdaptChannelCount"); c@5: } c@5: if (flags & Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE) { c@5: arr.push_back("AdaptBufferSize"); c@5: } c@5: c@5: return json11::Json(arr); c@5: } c@5: c@5: static Vamp::HostExt::PluginLoader::AdapterFlags c@5: toAdapterFlags(json11::Json j) { c@5: c@5: if (!j.is_array()) { c@5: throw Failure("array expected for adapter flags"); c@5: } c@5: int flags = 0x0; c@5: c@5: for (auto &jj: j.array_items()) { c@5: if (!jj.is_string()) { c@5: throw Failure("string expected for adapter flag"); c@5: } c@5: std::string text = jj.string_value(); c@5: if (text == "AdaptInputDomain") { c@5: flags |= Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN; c@5: } else if (text == "AdaptChannelCount") { c@5: flags |= Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT; c@5: } else if (text == "AdaptBufferSize") { c@5: flags |= Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE; c@5: } else if (text == "AdaptAllSafe") { c@5: flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL_SAFE; c@5: } else if (text == "AdaptAll") { c@5: flags |= Vamp::HostExt::PluginLoader::ADAPT_ALL; c@5: } else { c@5: throw Failure("invalid adapter flag string: " + text); c@5: } c@5: } c@5: c@5: return Vamp::HostExt::PluginLoader::AdapterFlags(flags); c@5: } c@5: c@5: static json11::Json c@5: fromLoadRequest(Vamp::HostExt::LoadRequest req) { c@5: c@5: json11::Json::object jo; c@5: jo["pluginKey"] = req.pluginKey; c@5: jo["inputSampleRate"] = req.inputSampleRate; c@5: jo["adapterFlags"] = fromAdapterFlags(req.adapterFlags); c@5: return json11::Json(jo); c@5: } c@5: c@5: static Vamp::HostExt::LoadRequest c@5: toLoadRequest(json11::Json j) { c@5: c@5: std::string err; c@5: c@5: if (!j.has_shape({ c@5: { "pluginKey", json11::Json::STRING }, c@5: { "inputSampleRate", json11::Json::NUMBER }, c@5: { "adapterFlags", json11::Json::ARRAY } }, err)) { c@12: throw Failure("malformed load request: " + err); c@5: } c@5: c@5: Vamp::HostExt::LoadRequest req; c@5: req.pluginKey = j["pluginKey"].string_value(); c@5: req.inputSampleRate = j["inputSampleRate"].number_value(); c@5: req.adapterFlags = toAdapterFlags(j["adapterFlags"]); c@5: return req; c@5: } c@10: c@10: static json11::Json c@10: fromLoadResponse(Vamp::HostExt::LoadResponse resp, c@10: PluginHandleMapper &mapper) { c@10: c@10: json11::Json::object jo; c@10: jo["pluginHandle"] = double(mapper.pluginToHandle(resp.plugin)); c@10: jo["staticData"] = fromPluginStaticData(resp.staticData); c@10: jo["defaultConfiguration"] = c@10: fromPluginConfiguration(resp.defaultConfiguration); c@10: return json11::Json(jo); c@10: } c@10: c@10: static Vamp::HostExt::LoadResponse c@10: toLoadResponse(json11::Json j, c@10: PluginHandleMapper &mapper) { c@10: c@10: std::string err; c@10: c@10: if (!j.has_shape({ c@10: { "pluginHandle", json11::Json::NUMBER }, c@10: { "staticData", json11::Json::OBJECT }, c@10: { "defaultConfiguration", json11::Json::OBJECT } }, err)) { c@12: throw Failure("malformed load response: " + err); c@10: } c@10: c@10: Vamp::HostExt::LoadResponse resp; c@10: resp.plugin = mapper.handleToPlugin(j["pluginHandle"].int_value()); c@10: resp.staticData = toPluginStaticData(j["staticData"]); c@10: resp.defaultConfiguration = toPluginConfiguration(j["defaultConfiguration"]); c@10: return resp; c@10: } c@12: c@12: static json11::Json c@13: fromConfigurationRequest(const Vamp::HostExt::ConfigurationRequest &cr, c@13: PluginHandleMapper &mapper) { c@13: c@13: json11::Json::object jo; c@13: c@13: jo["pluginHandle"] = mapper.pluginToHandle(cr.plugin); c@13: jo["configuration"] = fromPluginConfiguration(cr.configuration); c@13: c@13: return json11::Json(jo); c@13: } c@13: c@13: static Vamp::HostExt::ConfigurationRequest c@13: toConfigurationRequest(json11::Json j, c@13: PluginHandleMapper &mapper) { c@13: c@13: std::string err; c@13: c@13: if (!j.has_shape({ c@13: { "pluginHandle", json11::Json::NUMBER }, c@13: { "configuration", json11::Json::OBJECT } }, err)) { c@13: throw Failure("malformed configuration request: " + err); c@13: } c@13: c@13: Vamp::HostExt::ConfigurationRequest cr; c@13: cr.plugin = mapper.handleToPlugin(j["pluginHandle"].int_value()); c@13: cr.configuration = toPluginConfiguration(j["configuration"]); c@13: return cr; c@13: } c@13: c@13: static json11::Json c@12: fromConfigurationResponse(const Vamp::HostExt::ConfigurationResponse &cr) { c@12: c@13: json11::Json::object jo; c@12: c@12: json11::Json::array outs; c@12: for (auto &d: cr.outputs) { c@12: outs.push_back(fromOutputDescriptor(d)); c@12: } c@13: jo["outputList"] = outs; c@12: c@13: return json11::Json(jo); c@12: } c@12: c@13: static Vamp::HostExt::ConfigurationResponse c@13: toConfigurationResponse(json11::Json j) { c@13: c@12: Vamp::HostExt::ConfigurationResponse cr; c@12: c@12: if (!j["outputList"].is_array()) { c@12: throw Failure("array expected for output list"); c@12: } c@12: c@12: for (const auto &o: j["outputList"].array_items()) { c@12: cr.outputs.push_back(toOutputDescriptor(o)); c@12: } c@12: c@12: return cr; c@12: } c@5: }; c@5: c@10: } c@5: c@5: #endif