changeset 23:d678cd00e593

Begin vampipe-convert
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 20 May 2016 18:05:02 +0100
parents b0fc4eb51547
children 533ca5ca3404
files Makefile capnproto/VampnProto.h capnproto/vamp.capnp utilities/json-to-capnp.cpp utilities/vampipe-convert.cpp
diffstat 5 files changed, 302 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Fri May 20 17:07:04 2016 +0100
+++ b/Makefile	Fri May 20 18:05:02 2016 +0100
@@ -3,7 +3,10 @@
 INCFLAGS	:= -Ivamp-plugin-sdk -Ijson -Icapnproto -I.
 LDFLAGS		:= -Lvamp-plugin-sdk -Wl,-Bstatic -lvamp-hostsdk -Wl,-Bdynamic -lcapnp -lkj -ldl
 
-all:	bin/vamp-json-cli bin/vamp-json-to-capnp
+all:	bin/vamp-json-cli bin/vamp-json-to-capnp bin/vampipe-convert
+
+bin/vampipe-convert: utilities/vampipe-convert.o json/json11/json11.o
+	c++ $(CXXFLAGS) $^ -o $@ $(LDFLAGS)
 
 bin/vamp-json-to-capnp:	utilities/json-to-capnp.o json/json11/json11.o
 	c++ $(CXXFLAGS) $^ -o $@ $(LDFLAGS)
@@ -14,6 +17,9 @@
 capnproto/vamp.capnp.h:	capnproto/vamp.capnp
 	capnp compile $< -oc++
 
+utilities/vampipe-convert.o:	utilities/vampipe-convert.cpp capnproto/vamp.capnp.h capnproto/VampnProto.h json/VampJson.h
+	c++ $(CXXFLAGS) $(INCFLAGS) -c $< -o $@
+
 utilities/json-to-capnp.o:	utilities/json-to-capnp.cpp capnproto/vamp.capnp.h capnproto/VampnProto.h json/VampJson.h
 	c++ $(CXXFLAGS) $(INCFLAGS) -c $< -o $@
 
--- a/capnproto/VampnProto.h	Fri May 20 17:07:04 2016 +0100
+++ b/capnproto/VampnProto.h	Fri May 20 18:05:02 2016 +0100
@@ -709,7 +709,7 @@
     
     static void
     buildVampResponse_Process(VampResponse::Builder &b,
-                                const Vamp::HostExt::ProcessResponse &pr) {
+                              const Vamp::HostExt::ProcessResponse &pr) {
         b.setSuccess(true);
         b.setErrorText("");
         auto u = b.getResponse().initProcess();
@@ -717,9 +717,12 @@
     }
     
     static void
-    buildVampRequest_Finish(VampRequest::Builder &b) {
+    buildVampRequest_Finish(VampRequest::Builder &b,
+                            Vamp::Plugin *p,
+                            PluginHandleMapper &mapper) {
 
-        b.getRequest().setFinish();
+        auto u = b.getRequest().initFinish();
+        u.setPluginHandle(mapper.pluginToHandle(p));
     }
     
     static void
--- a/capnproto/vamp.capnp	Fri May 20 17:07:04 2016 +0100
+++ b/capnproto/vamp.capnp	Fri May 20 18:05:02 2016 +0100
@@ -140,6 +140,10 @@
     input              @1  :ProcessInput;
 }
 
+struct FinishRequest {
+    pluginHandle       @0  :Int32;
+}
+
 struct ProcessResponse {
     features           @0  :FeatureSet;
 }
@@ -150,7 +154,7 @@
 	load           @1  :LoadRequest;
 	configure      @2  :ConfigurationRequest;
 	process        @3  :ProcessRequest;
-	finish         @4  :Void;        # getRemainingFeatures and unload plugin
+	finish         @4  :FinishRequest;     # getRemainingFeatures and unload
     }
 }
 
--- a/utilities/json-to-capnp.cpp	Fri May 20 17:07:04 2016 +0100
+++ b/utilities/json-to-capnp.cpp	Fri May 20 18:05:02 2016 +0100
@@ -65,10 +65,7 @@
     string type = j["type"].string_value();
     Json payload = j["payload"];
 
-    if (type == "basic") {
-	throw VampJson::Failure("can't convert Basic block on its own");
-
-    } else if (type == "configurationrequest") {
+    if (type == "configurationrequest") {
 	auto req = message.initRoot<ConfigurationRequest>();
 	PreservingPluginHandleMapper mapper;
 	VampnProto::buildConfigurationRequest
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utilities/vampipe-convert.cpp	Fri May 20 18:05:02 2016 +0100
@@ -0,0 +1,283 @@
+
+#include "VampJson.h"
+#include "VampnProto.h"
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+
+using namespace std;
+using namespace json11;
+using namespace vampipe;
+
+// Accepting JSON objects with two fields, "type" and "payload". The
+// "type" string corresponds to the JSON schema filename
+// (e.g. "outputdescriptor") and the "payload" is the JSON object
+// encoded with that schema.
+
+Json
+json_input(string input)
+{
+    string err;
+    Json j = Json::parse(input, err);
+    if (err != "") {
+	throw VampJson::Failure("invalid json: " + err);
+    }
+    if (!j.is_object()) {
+	throw VampJson::Failure("object expected at top level");
+    }
+    if (!j["type"].is_string()) {
+	throw VampJson::Failure("string expected for type field");
+    }
+    if (!j["payload"].is_object()) {
+	throw VampJson::Failure("object expected for payload field");
+    }
+    return j;
+}
+
+class PreservingPluginHandleMapper : public PluginHandleMapper
+{
+public:
+    PreservingPluginHandleMapper() : m_handle(0), m_plugin(0) { }
+
+    virtual int32_t pluginToHandle(Vamp::Plugin *p) {
+	if (p == m_plugin) return m_handle;
+	else throw NotFound();
+    }
+
+    virtual Vamp::Plugin *handleToPlugin(int32_t h) {
+	m_handle = h;
+	m_plugin = reinterpret_cast<Vamp::Plugin *>(h);
+	return m_plugin;
+    }
+
+private:
+    int32_t m_handle;
+    Vamp::Plugin *m_plugin;
+};
+
+void 
+handle_input(::capnp::MallocMessageBuilder &message, string input)
+{
+    string err;
+
+    Json j = json_input(input);
+    string type = j["type"].string_value();
+    Json payload = j["payload"];
+
+    if (type == "configurationrequest") {
+	auto req = message.initRoot<ConfigurationRequest>();
+	PreservingPluginHandleMapper mapper;
+	VampnProto::buildConfigurationRequest
+	    (req, VampJson::toConfigurationRequest(payload, mapper), mapper);
+
+    } else if (type == "configurationresponse") {
+	auto resp = message.initRoot<ConfigurationResponse>();
+	VampnProto::buildConfigurationResponse
+	    (resp, VampJson::toConfigurationResponse(payload));
+
+    } else if (type == "feature") {
+	auto f = message.initRoot<Feature>();
+	VampnProto::buildFeature
+	    (f, VampJson::toFeature(payload));
+
+    } else if (type == "featureset") {
+	auto fs = message.initRoot<FeatureSet>();
+	VampnProto::buildFeatureSet
+	    (fs, VampJson::toFeatureSet(payload));
+
+    } else if (type == "loadrequest") {
+	auto req = message.initRoot<LoadRequest>();
+	VampnProto::buildLoadRequest
+	    (req, VampJson::toLoadRequest(payload));
+	
+    } else if (type == "loadresponse") {
+	auto resp = message.initRoot<LoadResponse>();
+	PreservingPluginHandleMapper mapper;
+	VampnProto::buildLoadResponse
+	    (resp, VampJson::toLoadResponse(payload, mapper), mapper);
+
+    } else if (type == "outputdescriptor") {
+	auto od = message.initRoot<OutputDescriptor>();
+	VampnProto::buildOutputDescriptor
+	    (od, VampJson::toOutputDescriptor(payload));
+
+    } else if (type == "parameterdescriptor") {
+	auto pd = message.initRoot<ParameterDescriptor>();
+	VampnProto::buildParameterDescriptor
+	    (pd, VampJson::toParameterDescriptor(payload));
+
+    } else if (type == "pluginconfiguration") {
+	auto pc = message.initRoot<PluginConfiguration>();
+	auto config = VampJson::toPluginConfiguration(payload);
+	VampnProto::buildPluginConfiguration(pc, config);
+
+    } else if (type == "pluginstaticdata") {
+	auto pc = message.initRoot<PluginStaticData>();
+	auto sd = VampJson::toPluginStaticData(payload);
+ 	VampnProto::buildPluginStaticData(pc, sd);
+
+    } else if (type == "processrequest") {
+	auto p = message.initRoot<ProcessRequest>();
+	PreservingPluginHandleMapper mapper;
+	VampnProto::buildProcessRequest
+	    (p, VampJson::toProcessRequest(payload, mapper), mapper);
+
+    } else if (type == "realtime") {
+	auto b = message.initRoot<RealTime>();
+	VampnProto::buildRealTime
+	    (b, VampJson::toRealTime(payload));
+	
+    } else {
+	throw VampJson::Failure("unknown or unsupported JSON schema type " +
+				type);
+    }
+}
+
+void usage()
+{
+    string myname = "vampipe-convert";
+    cerr << "\n" << myname <<
+	": Convert Vamp request and response messages between formats\n\n"
+	"    Usage:  " << myname << " -i <informat> -o <outformat>\n\n"
+	"Where <informat> and <outformat> may be \"json\" or \"capnp\".\n"
+	"Messages are read from stdin and written to stdout.\n" << endl;
+    exit(2);
+}
+
+class RequestOrResponse
+{
+public:
+    enum Type {
+	List, Load, Configure, Process, Finish, Eof
+    };
+    RequestOrResponse() : // nothing by default
+	type(Eof),
+	success(false),
+	finishPlugin(0) { }
+
+    Type type;
+    bool success;
+    string errorText;
+
+    PreservingPluginHandleMapper mapper;
+    
+    Vamp::HostExt::LoadRequest loadRequest;
+    Vamp::HostExt::LoadResponse loadResponse;
+    Vamp::HostExt::ConfigurationRequest configurationRequest;
+    Vamp::HostExt::ConfigurationResponse configurationResponse;
+    Vamp::HostExt::ProcessRequest processRequest;
+    Vamp::HostExt::ProcessResponse processResponse;
+    Vamp::Plugin *finishPlugin;
+    Vamp::HostExt::ProcessResponse finishResponse;
+    
+};
+
+RequestOrResponse
+readInputJson()
+{
+    RequestOrResponse rr;
+    string input;
+    if (!getline(cin, input)) {
+	rr.type = RequestOrResponse::Eof;
+	return rr;
+    }
+
+    Json j = json_input(input);
+    string type = j["type"].string_value();
+
+    if (type == "list") {
+	rr.type = RequestOrResponse::List;
+
+    } else if (type == "load") {
+	//!!! ah, we need a way to know whether we're dealing with a request or response here
+	rr.type = RequestOrResponse::Load;
+	rr.loadRequest = VampJson::toLoadRequest(j["content"]);
+
+    } else if (type == "configure") {
+	rr.type = RequestOrResponse::Configure;
+	rr.configurationRequest =
+	    VampJson::toConfigurationRequest(j["content"], rr.mapper);
+
+    } else if (type == "process") {
+	rr.type = RequestOrResponse::Process;
+	rr.processRequest =
+	    VampJson::toProcessRequest(j["content"], rr.mapper);
+
+    } else if (type == "finish") {
+	rr.type = RequestOrResponse::Finish;
+	//!!! VampJsonify
+	rr.finishPlugin = rr.mapper.handleToPlugin(j["content"]["pluginHandle"].int_value());
+
+    } else {
+	throw runtime_error("unknown or unexpected request/response type \"" +
+			    type + "\"");
+    }
+
+    return rr;
+}
+
+RequestOrResponse
+readInput(string format)
+{
+    if (format == "json") {
+	return readInputJson();
+    } else {
+	throw runtime_error("unknown or unimplemented format \"" + format + "\"");
+    }
+}
+
+void
+writeOutput(string format, const RequestOrResponse &rr)
+{
+    throw runtime_error("writeOutput not implemented yet");
+    
+}
+
+int main(int argc, char **argv)
+{
+    if (argc != 5) {
+	usage();
+    }
+
+    string informat, outformat;
+    
+    for (int i = 1; i + 1 < argc; ++i) {
+
+	string arg = argv[i];
+	
+	if (arg == "-i") {
+	    if (informat != "") usage();
+	    else informat = argv[++i];
+
+	} else if (arg == "-o") {
+	    if (outformat != "") usage();
+	    else outformat = argv[++i];
+
+	} else {
+	    usage();
+	}
+    }
+
+    if (informat == "" || outformat == "") {
+	usage();
+    }
+
+    while (true) {
+
+	try {
+
+	    RequestOrResponse rr = readInput(informat);
+	    if (rr.type == RequestOrResponse::Eof) break;
+	    writeOutput(outformat, rr);
+	    
+	} catch (std::exception &e) {
+	    cerr << "Error: " << e.what() << endl;
+	    exit(1);
+	}
+    }
+
+    exit(0);
+}
+
+