Mercurial > hg > piper-cpp
comparison json/VampJson.h @ 44:a98ef4c2616b
Make base64/text selectable when serialising process and feature blocks; add base64 version as an output format for vampipe-convert; make VamPipePluginLibrary switch to returning base64 encoding as soon as it is fed any as input
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Thu, 08 Sep 2016 15:27:48 +0100 |
parents | 62c17e143aba |
children | 7668fbdcfb15 |
comparison
equal
deleted
inserted
replaced
43:62c17e143aba | 44:a98ef4c2616b |
---|---|
57 * project repo. | 57 * project repo. |
58 */ | 58 */ |
59 class VampJson | 59 class VampJson |
60 { | 60 { |
61 public: | 61 public: |
62 /// Serialisation format for arrays of floats (process input and feature values) | |
63 enum class BufferSerialisation { | |
64 Text, // default JSON serialisation of values in array form | |
65 Base64 // base64-encoded string of the raw data as packed ieee 32-bit floats | |
66 }; | |
67 | |
62 class Failure : virtual public std::runtime_error { | 68 class Failure : virtual public std::runtime_error { |
63 public: | 69 public: |
64 Failure(std::string s) : runtime_error(s) { } | 70 Failure(std::string s) : runtime_error(s) { } |
65 }; | 71 }; |
66 | 72 |
306 size_t n = decoded.size() / sizeof(float); | 312 size_t n = decoded.size() / sizeof(float); |
307 return std::vector<float>(buffer, buffer + n); | 313 return std::vector<float>(buffer, buffer + n); |
308 } | 314 } |
309 | 315 |
310 static json11::Json | 316 static json11::Json |
311 fromFeature(const Vamp::Plugin::Feature &f, bool asText) { | 317 fromFeature(const Vamp::Plugin::Feature &f, |
318 BufferSerialisation serialisation) { | |
312 | 319 |
313 json11::Json::object jo; | 320 json11::Json::object jo; |
314 if (f.values.size() > 0) { | 321 if (f.values.size() > 0) { |
315 if (asText) { | 322 if (serialisation == BufferSerialisation::Text) { |
316 jo["values"] = json11::Json::array(f.values.begin(), | 323 jo["values"] = json11::Json::array(f.values.begin(), |
317 f.values.end()); | 324 f.values.end()); |
318 } else { | 325 } else { |
319 jo["b64values"] = fromFloatBuffer(f.values.data(), | 326 jo["b64values"] = fromFloatBuffer(f.values.data(), |
320 f.values.size()); | 327 f.values.size()); |
331 } | 338 } |
332 return json11::Json(jo); | 339 return json11::Json(jo); |
333 } | 340 } |
334 | 341 |
335 static Vamp::Plugin::Feature | 342 static Vamp::Plugin::Feature |
336 toFeature(json11::Json j) { | 343 toFeature(json11::Json j, |
344 BufferSerialisation &serialisation) { | |
337 | 345 |
338 Vamp::Plugin::Feature f; | 346 Vamp::Plugin::Feature f; |
339 if (!j.is_object()) { | 347 if (!j.is_object()) { |
340 throw Failure("object expected for feature"); | 348 throw Failure("object expected for feature"); |
341 } | 349 } |
347 f.duration = toRealTime(j["duration"]); | 355 f.duration = toRealTime(j["duration"]); |
348 f.hasDuration = true; | 356 f.hasDuration = true; |
349 } | 357 } |
350 if (j["b64values"].is_string()) { | 358 if (j["b64values"].is_string()) { |
351 f.values = toFloatBuffer(j["b64values"].string_value()); | 359 f.values = toFloatBuffer(j["b64values"].string_value()); |
360 serialisation = BufferSerialisation::Base64; | |
352 } else if (j["values"].is_array()) { | 361 } else if (j["values"].is_array()) { |
353 for (auto v : j["values"].array_items()) { | 362 for (auto v : j["values"].array_items()) { |
354 f.values.push_back(v.number_value()); | 363 f.values.push_back(v.number_value()); |
355 } | 364 } |
365 serialisation = BufferSerialisation::Text; | |
356 } | 366 } |
357 f.label = j["label"].string_value(); | 367 f.label = j["label"].string_value(); |
358 return f; | 368 return f; |
359 } | 369 } |
360 | 370 |
361 static json11::Json | 371 static json11::Json |
362 fromFeatureSet(const Vamp::Plugin::FeatureSet &fs, bool asText) { | 372 fromFeatureSet(const Vamp::Plugin::FeatureSet &fs, |
373 BufferSerialisation serialisation) { | |
363 | 374 |
364 json11::Json::object jo; | 375 json11::Json::object jo; |
365 for (const auto &fsi : fs) { | 376 for (const auto &fsi : fs) { |
366 std::vector<json11::Json> fj; | 377 std::vector<json11::Json> fj; |
367 for (const Vamp::Plugin::Feature &f: fsi.second) { | 378 for (const Vamp::Plugin::Feature &f: fsi.second) { |
368 fj.push_back(fromFeature(f, asText)); | 379 fj.push_back(fromFeature(f, serialisation)); |
369 } | 380 } |
370 std::stringstream sstr; | 381 std::stringstream sstr; |
371 sstr << fsi.first; | 382 sstr << fsi.first; |
372 std::string n = sstr.str(); | 383 std::string n = sstr.str(); |
373 jo[n] = fj; | 384 jo[n] = fj; |
374 } | 385 } |
375 return json11::Json(jo); | 386 return json11::Json(jo); |
376 } | 387 } |
377 | 388 |
378 static Vamp::Plugin::FeatureList | 389 static Vamp::Plugin::FeatureList |
379 toFeatureList(json11::Json j) { | 390 toFeatureList(json11::Json j, |
391 BufferSerialisation &serialisation) { | |
380 | 392 |
381 Vamp::Plugin::FeatureList fl; | 393 Vamp::Plugin::FeatureList fl; |
382 if (!j.is_array()) { | 394 if (!j.is_array()) { |
383 throw Failure("array expected for feature list"); | 395 throw Failure("array expected for feature list"); |
384 } | 396 } |
385 for (const json11::Json &fj : j.array_items()) { | 397 for (const json11::Json &fj : j.array_items()) { |
386 fl.push_back(toFeature(fj)); | 398 fl.push_back(toFeature(fj, serialisation)); |
387 } | 399 } |
388 return fl; | 400 return fl; |
389 } | 401 } |
390 | 402 |
391 static Vamp::Plugin::FeatureSet | 403 static Vamp::Plugin::FeatureSet |
392 toFeatureSet(json11::Json j) { | 404 toFeatureSet(json11::Json j, BufferSerialisation &serialisation) { |
393 | 405 |
394 Vamp::Plugin::FeatureSet fs; | 406 Vamp::Plugin::FeatureSet fs; |
395 if (!j.is_object()) { | 407 if (!j.is_object()) { |
396 throw Failure("object expected for feature set"); | 408 throw Failure("object expected for feature set"); |
397 } | 409 } |
400 size_t count = 0; | 412 size_t count = 0; |
401 int n = stoi(nstr, &count); | 413 int n = stoi(nstr, &count); |
402 if (n < 0 || fs.find(n) != fs.end() || count < nstr.size()) { | 414 if (n < 0 || fs.find(n) != fs.end() || count < nstr.size()) { |
403 throw Failure("invalid or duplicate numerical index for output"); | 415 throw Failure("invalid or duplicate numerical index for output"); |
404 } | 416 } |
405 fs[n] = toFeatureList(entry.second); | 417 fs[n] = toFeatureList(entry.second, serialisation); |
406 } | 418 } |
407 return fs; | 419 return fs; |
408 } | 420 } |
409 | 421 |
410 static std::string | 422 static std::string |
800 return cr; | 812 return cr; |
801 } | 813 } |
802 | 814 |
803 static json11::Json | 815 static json11::Json |
804 fromProcessRequest(const Vamp::HostExt::ProcessRequest &r, | 816 fromProcessRequest(const Vamp::HostExt::ProcessRequest &r, |
805 const PluginHandleMapper &mapper) { | 817 const PluginHandleMapper &mapper, |
818 BufferSerialisation serialisation) { | |
806 | 819 |
807 json11::Json::object jo; | 820 json11::Json::object jo; |
808 jo["pluginHandle"] = mapper.pluginToHandle(r.plugin); | 821 jo["pluginHandle"] = mapper.pluginToHandle(r.plugin); |
809 | 822 |
810 json11::Json::object io; | 823 json11::Json::object io; |
811 io["timestamp"] = fromRealTime(r.timestamp); | 824 io["timestamp"] = fromRealTime(r.timestamp); |
812 | 825 |
813 json11::Json::array chans; | 826 json11::Json::array chans; |
814 for (size_t i = 0; i < r.inputBuffers.size(); ++i) { | 827 for (size_t i = 0; i < r.inputBuffers.size(); ++i) { |
815 json11::Json::object c; | 828 json11::Json::object c; |
816 c["b64values"] = fromFloatBuffer(r.inputBuffers[i].data(), | 829 if (serialisation == BufferSerialisation::Text) { |
817 r.inputBuffers[i].size()); | 830 c["values"] = json11::Json::array(r.inputBuffers[i].begin(), |
831 r.inputBuffers[i].end()); | |
832 } else { | |
833 c["b64values"] = fromFloatBuffer(r.inputBuffers[i].data(), | |
834 r.inputBuffers[i].size()); | |
835 } | |
818 chans.push_back(c); | 836 chans.push_back(c); |
819 } | 837 } |
820 io["inputBuffers"] = chans; | 838 io["inputBuffers"] = chans; |
821 | 839 |
822 jo["processInput"] = io; | 840 jo["processInput"] = io; |
823 return json11::Json(jo); | 841 return json11::Json(jo); |
824 } | 842 } |
825 | 843 |
826 static Vamp::HostExt::ProcessRequest | 844 static Vamp::HostExt::ProcessRequest |
827 toProcessRequest(json11::Json j, const PluginHandleMapper &mapper) { | 845 toProcessRequest(json11::Json j, |
846 const PluginHandleMapper &mapper, | |
847 BufferSerialisation &serialisation) { | |
828 | 848 |
829 std::string err; | 849 std::string err; |
830 | 850 |
831 if (!j.has_shape({ | 851 if (!j.has_shape({ |
832 { "pluginHandle", json11::Json::NUMBER }, | 852 { "pluginHandle", json11::Json::NUMBER }, |
846 r.plugin = mapper.handleToPlugin(j["pluginHandle"].int_value()); | 866 r.plugin = mapper.handleToPlugin(j["pluginHandle"].int_value()); |
847 | 867 |
848 r.timestamp = toRealTime(input["timestamp"]); | 868 r.timestamp = toRealTime(input["timestamp"]); |
849 | 869 |
850 for (auto a: input["inputBuffers"].array_items()) { | 870 for (auto a: input["inputBuffers"].array_items()) { |
871 | |
851 if (a["b64values"].is_string()) { | 872 if (a["b64values"].is_string()) { |
852 r.inputBuffers.push_back(toFloatBuffer | 873 std::vector<float> buf = toFloatBuffer(a["b64values"].string_value()); |
853 (a["b64values"].string_value())); | 874 r.inputBuffers.push_back(buf); |
875 serialisation = BufferSerialisation::Base64; | |
876 | |
854 } else if (a["values"].is_array()) { | 877 } else if (a["values"].is_array()) { |
855 std::vector<float> buf; | 878 std::vector<float> buf; |
856 for (auto v : a["values"].array_items()) { | 879 for (auto v : a["values"].array_items()) { |
857 buf.push_back(v.number_value()); | 880 buf.push_back(v.number_value()); |
858 } | 881 } |
859 r.inputBuffers.push_back(buf); | 882 r.inputBuffers.push_back(buf); |
883 serialisation = BufferSerialisation::Text; | |
884 | |
860 } else { | 885 } else { |
861 throw Failure("expected values or b64values in inputBuffers object"); | 886 throw Failure("expected values or b64values in inputBuffers object"); |
862 } | 887 } |
863 } | 888 } |
864 | 889 |
935 return json11::Json(jo); | 960 return json11::Json(jo); |
936 } | 961 } |
937 | 962 |
938 static json11::Json | 963 static json11::Json |
939 fromVampRequest_Process(const Vamp::HostExt::ProcessRequest &req, | 964 fromVampRequest_Process(const Vamp::HostExt::ProcessRequest &req, |
940 const PluginHandleMapper &mapper) { | 965 const PluginHandleMapper &mapper, |
966 BufferSerialisation serialisation) { | |
941 | 967 |
942 json11::Json::object jo; | 968 json11::Json::object jo; |
943 jo["type"] = "process"; | 969 jo["type"] = "process"; |
944 jo["content"] = fromProcessRequest(req, mapper); | 970 jo["content"] = fromProcessRequest(req, mapper, serialisation); |
945 return json11::Json(jo); | 971 return json11::Json(jo); |
946 } | 972 } |
947 | 973 |
948 static json11::Json | 974 static json11::Json |
949 fromVampResponse_Process(const Vamp::HostExt::ProcessResponse &resp) { | 975 fromVampResponse_Process(const Vamp::HostExt::ProcessResponse &resp, |
976 BufferSerialisation serialisation) { | |
950 | 977 |
951 json11::Json::object jo; | 978 json11::Json::object jo; |
952 jo["type"] = "process"; | 979 jo["type"] = "process"; |
953 jo["success"] = true; | 980 jo["success"] = true; |
954 jo["errorText"] = ""; | 981 jo["errorText"] = ""; |
955 jo["content"] = fromFeatureSet(resp.features, true); | 982 jo["content"] = fromFeatureSet(resp.features, serialisation); |
956 return json11::Json(jo); | 983 return json11::Json(jo); |
957 } | 984 } |
958 | 985 |
959 static json11::Json | 986 static json11::Json |
960 fromVampRequest_Finish(Vamp::Plugin *p, | 987 fromVampRequest_Finish(Vamp::Plugin *p, |
967 jo["content"] = fo; | 994 jo["content"] = fo; |
968 return json11::Json(jo); | 995 return json11::Json(jo); |
969 } | 996 } |
970 | 997 |
971 static json11::Json | 998 static json11::Json |
972 fromVampResponse_Finish(const Vamp::HostExt::ProcessResponse &resp) { | 999 fromVampResponse_Finish(const Vamp::HostExt::ProcessResponse &resp, |
1000 BufferSerialisation serialisation) { | |
973 | 1001 |
974 json11::Json::object jo; | 1002 json11::Json::object jo; |
975 jo["type"] = "finish"; | 1003 jo["type"] = "finish"; |
976 jo["success"] = true; | 1004 jo["success"] = true; |
977 jo["errorText"] = ""; | 1005 jo["errorText"] = ""; |
978 jo["content"] = fromFeatureSet(resp.features, true); | 1006 jo["content"] = fromFeatureSet(resp.features, serialisation); |
979 return json11::Json(jo); | 1007 return json11::Json(jo); |
980 } | 1008 } |
981 | 1009 |
982 static json11::Json | 1010 static json11::Json |
983 fromException(const std::exception &e, RRType responseType) { | 1011 fromException(const std::exception &e, RRType responseType) { |
1037 else { | 1065 else { |
1038 throw Failure("unknown or unexpected request/response type \"" + | 1066 throw Failure("unknown or unexpected request/response type \"" + |
1039 type + "\""); | 1067 type + "\""); |
1040 } | 1068 } |
1041 } | 1069 } |
1042 | 1070 |
1043 static void | 1071 static void |
1044 toVampRequest_List(json11::Json j) { | 1072 toVampRequest_List(json11::Json j) { |
1045 | 1073 |
1046 checkTypeField(j, "list"); | 1074 checkTypeField(j, "list"); |
1047 } | 1075 } |
1091 } | 1119 } |
1092 return resp; | 1120 return resp; |
1093 } | 1121 } |
1094 | 1122 |
1095 static Vamp::HostExt::ProcessRequest | 1123 static Vamp::HostExt::ProcessRequest |
1096 toVampRequest_Process(json11::Json j, const PluginHandleMapper &mapper) { | 1124 toVampRequest_Process(json11::Json j, const PluginHandleMapper &mapper, |
1125 BufferSerialisation &serialisation) { | |
1097 | 1126 |
1098 checkTypeField(j, "process"); | 1127 checkTypeField(j, "process"); |
1099 return toProcessRequest(j["content"], mapper); | 1128 return toProcessRequest(j["content"], mapper, serialisation); |
1100 } | 1129 } |
1101 | 1130 |
1102 static Vamp::HostExt::ProcessResponse | 1131 static Vamp::HostExt::ProcessResponse |
1103 toVampResponse_Process(json11::Json j) { | 1132 toVampResponse_Process(json11::Json j, BufferSerialisation &serialisation) { |
1104 | 1133 |
1105 Vamp::HostExt::ProcessResponse resp; | 1134 Vamp::HostExt::ProcessResponse resp; |
1106 if (successful(j)) { | 1135 if (successful(j)) { |
1107 resp.features = toFeatureSet(j["content"]); | 1136 resp.features = toFeatureSet(j["content"], serialisation); |
1108 } | 1137 } |
1109 return resp; | 1138 return resp; |
1110 } | 1139 } |
1111 | 1140 |
1112 static Vamp::Plugin * | 1141 static Vamp::Plugin * |
1115 checkTypeField(j, "finish"); | 1144 checkTypeField(j, "finish"); |
1116 return mapper.handleToPlugin(j["content"]["pluginHandle"].int_value()); | 1145 return mapper.handleToPlugin(j["content"]["pluginHandle"].int_value()); |
1117 } | 1146 } |
1118 | 1147 |
1119 static Vamp::HostExt::ProcessResponse | 1148 static Vamp::HostExt::ProcessResponse |
1120 toVampResponse_Finish(json11::Json j) { | 1149 toVampResponse_Finish(json11::Json j, BufferSerialisation &serialisation) { |
1121 | 1150 |
1122 Vamp::HostExt::ProcessResponse resp; | 1151 Vamp::HostExt::ProcessResponse resp; |
1123 if (successful(j)) { | 1152 if (successful(j)) { |
1124 resp.features = toFeatureSet(j["content"]); | 1153 resp.features = toFeatureSet(j["content"], serialisation); |
1125 } | 1154 } |
1126 return resp; | 1155 return resp; |
1127 } | 1156 } |
1128 }; | 1157 }; |
1129 | 1158 |