changeset 84:db9a6ab618bc

Client builds; does not run
author Chris Cannam <c.cannam@qmul.ac.uk>
date Wed, 12 Oct 2016 11:59:57 +0100
parents 154e94ea84d4
children 1b7c11bc5a88
files vamp-client/Makefile vamp-client/client.cpp vamp-client/client.pro vamp-client/stub.h vamp-support/AssignedPluginHandleMapper.h vamp-support/CountingPluginHandleMapper.h
diffstat 6 files changed, 228 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/vamp-client/Makefile	Tue Oct 11 17:08:31 2016 +0100
+++ b/vamp-client/Makefile	Wed Oct 12 11:59:57 2016 +0100
@@ -36,7 +36,7 @@
 DISTDIR = /home/cannam/code/piper-cpp/o/client1.0.0
 LINK          = g++
 LFLAGS        = -Wl,-O1 -Wl,-O1,--sort-common,--as-needed,-z,relro
-LIBS          = $(SUBLIBS) -lQt5Core -lpthread 
+LIBS          = $(SUBLIBS) -lcapnp -lkj -lvamp-hostsdk -lQt5Core -lpthread 
 AR            = ar cqs
 RANLIB        = 
 SED           = sed
@@ -48,8 +48,10 @@
 
 ####### Files
 
-SOURCES       = client.cpp 
-OBJECTS       = ../o/client.o
+SOURCES       = client.cpp \
+		../vamp-capnp/piper.capnp.c++ 
+OBJECTS       = ../o/client.o \
+		../o/piper.capnp.o
 DIST          = /usr/lib/qt/mkspecs/features/spec_pre.prf \
 		/usr/lib/qt/mkspecs/common/unix.conf \
 		/usr/lib/qt/mkspecs/common/linux.conf \
@@ -203,7 +205,8 @@
 		/usr/lib/qt/mkspecs/features/testcase_targets.prf \
 		/usr/lib/qt/mkspecs/features/yacc.prf \
 		/usr/lib/qt/mkspecs/features/lex.prf \
-		client.pro  client.cpp
+		client.pro  client.cpp \
+		../vamp-capnp/piper.capnp.c++
 QMAKE_TARGET  = client
 DESTDIR       = 
 TARGET        = client
@@ -540,7 +543,7 @@
 distdir: FORCE
 	@test -d $(DISTDIR) || mkdir -p $(DISTDIR)
 	$(COPY_FILE) --parents $(DIST) $(DISTDIR)/
-	$(COPY_FILE) --parents client.cpp $(DISTDIR)/
+	$(COPY_FILE) --parents client.cpp ../vamp-capnp/piper.capnp.c++ $(DISTDIR)/
 
 
 clean: compiler_clean 
@@ -583,6 +586,9 @@
 ../o/client.o: client.cpp stub.h
 	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ../o/client.o client.cpp
 
+../o/piper.capnp.o: ../vamp-capnp/piper.capnp.c++ ../vamp-capnp/piper.capnp.h
+	$(CC) -c $(CFLAGS) $(INCPATH) -o ../o/piper.capnp.o ../vamp-capnp/piper.capnp.c++
+
 ####### Install
 
 install:  FORCE
--- a/vamp-client/client.cpp	Tue Oct 11 17:08:31 2016 +0100
+++ b/vamp-client/client.cpp	Wed Oct 12 11:59:57 2016 +0100
@@ -59,7 +59,7 @@
     }
 
     //!!! obviously, factor out all repetitive guff
-    
+
     Vamp::Plugin *
     load(std::string key, float inputSampleRate, int adapterFlags) {
 
@@ -72,7 +72,7 @@
         request.inputSampleRate = inputSampleRate;
         request.adapterFlags = adapterFlags;
 
-        ::capnp::MallocMessageBuilder message;
+        capnp::MallocMessageBuilder message;
         RpcRequest::Builder builder = message.initRoot<RpcRequest>();
 
         VampnProto::buildRpcRequest_Load(builder, request);
@@ -82,7 +82,32 @@
         auto arr = messageToFlatArray(message);
         m_process->write(arr.asChars().begin(), arr.asChars().size());
 
-        ///.... read...
+        //!!! ... --> will also need some way to kill this process
+        //!!! (from another thread)
+
+        QByteArray buffer = readResponseBuffer();
+        capnp::FlatArrayMessageReader responseMessage(toArrayPtr(buffer));
+        RpcResponse::Reader reader = responseMessage.getRoot<RpcResponse>();
+
+        //!!! handle (explicit) error case
+
+        checkResponseType(reader, RpcResponse::Response::Which::LOAD, id);
+        
+        const LoadResponse::Reader &lr = reader.getResponse().getLoad();
+
+        Vamp::HostExt::PluginStaticData psd;
+        Vamp::HostExt::PluginConfiguration defaultConfig;
+        VampnProto::readExtractorStaticData(psd, lr.getStaticData());
+        VampnProto::readConfiguration(defaultConfig, lr.getDefaultConfiguration());
+        
+        Vamp::Plugin *plugin = new PiperStubPlugin(this,
+                                                   inputSampleRate,
+                                                   psd,
+                                                   defaultConfig);
+
+        m_mapper.addPlugin(lr.getHandle(), plugin);
+
+        return plugin;
     };     
     
     virtual
@@ -98,35 +123,202 @@
         request.plugin = plugin;
         request.configuration = config;
 
-        ::capnp::MallocMessageBuilder message;
+        capnp::MallocMessageBuilder message;
         RpcRequest::Builder builder = message.initRoot<RpcRequest>();
 
         VampnProto::buildRpcRequest_Configure(builder, request, m_mapper);
         ReqId id = getId();
         builder.getId().setNumber(id);
+        
+        auto arr = messageToFlatArray(message);
+        m_process->write(arr.asChars().begin(), arr.asChars().size());
+        
+        QByteArray buffer = readResponseBuffer();
+        capnp::FlatArrayMessageReader responseMessage(toArrayPtr(buffer));
+        RpcResponse::Reader reader = responseMessage.getRoot<RpcResponse>();
 
-        //!!! now what?
+        //!!! handle (explicit) error case
+
+        checkResponseType(reader, RpcResponse::Response::Which::CONFIGURE, id);
+
+        Vamp::HostExt::ConfigurationResponse cr;
+        VampnProto::readConfigurationResponse(cr,
+                                              reader.getResponse().getConfigure(),
+                                              m_mapper);
+
+        return cr.outputs;
     };
     
-    
     virtual
     Vamp::Plugin::FeatureSet
     process(PiperStubPlugin *plugin,
-            const float *const *inputBuffers,
-            Vamp::RealTime timestamp) = 0;
+            std::vector<std::vector<float> > inputBuffers,
+            Vamp::RealTime timestamp) {
+
+        if (!m_process) {
+            throw std::runtime_error("Piper server failed to start");
+        }
+
+        Vamp::HostExt::ProcessRequest request;
+        request.plugin = plugin;
+        request.inputBuffers = inputBuffers;
+        request.timestamp = timestamp;
+        
+        capnp::MallocMessageBuilder message;
+        RpcRequest::Builder builder = message.initRoot<RpcRequest>();
+
+        VampnProto::buildRpcRequest_Process(builder, request, m_mapper);
+        ReqId id = getId();
+        builder.getId().setNumber(id);
+        
+        auto arr = messageToFlatArray(message);
+        m_process->write(arr.asChars().begin(), arr.asChars().size());
+        
+        QByteArray buffer = readResponseBuffer();
+        capnp::FlatArrayMessageReader responseMessage(toArrayPtr(buffer));
+        RpcResponse::Reader reader = responseMessage.getRoot<RpcResponse>();
+
+        //!!! handle (explicit) error case
+
+        checkResponseType(reader, RpcResponse::Response::Which::PROCESS, id);
+
+        Vamp::HostExt::ProcessResponse pr;
+        VampnProto::readProcessResponse(pr,
+                                        reader.getResponse().getProcess(),
+                                        m_mapper);
+
+        return pr.features;
+    }
 
     virtual Vamp::Plugin::FeatureSet
-    finish(PiperStubPlugin *plugin) = 0;
+    finish(PiperStubPlugin *plugin) {
+
+        if (!m_process) {
+            throw std::runtime_error("Piper server failed to start");
+        }
+
+        Vamp::HostExt::FinishRequest request;
+        request.plugin = plugin;
+        
+        capnp::MallocMessageBuilder message;
+        RpcRequest::Builder builder = message.initRoot<RpcRequest>();
+
+        VampnProto::buildRpcRequest_Finish(builder, request, m_mapper);
+        ReqId id = getId();
+        builder.getId().setNumber(id);
+        
+        auto arr = messageToFlatArray(message);
+        m_process->write(arr.asChars().begin(), arr.asChars().size());
+        
+        QByteArray buffer = readResponseBuffer();
+        capnp::FlatArrayMessageReader responseMessage(toArrayPtr(buffer));
+        RpcResponse::Reader reader = responseMessage.getRoot<RpcResponse>();
+
+        //!!! handle (explicit) error case
+
+        checkResponseType(reader, RpcResponse::Response::Which::FINISH, id);
+
+        Vamp::HostExt::ProcessResponse pr;
+        VampnProto::readFinishResponse(pr,
+                                       reader.getResponse().getFinish(),
+                                       m_mapper);
+
+        m_mapper.removePlugin(m_mapper.pluginToHandle(plugin));
+        delete plugin;
+        
+        return pr.features;
+    }
 
 private:
     QProcess *m_process;
     AssignedPluginHandleMapper m_mapper;
-    int getId() {
+    ReqId getId() {
         //!!! todo: mutex
         static ReqId m_nextId = 0;
         return m_nextId++;
     }
+
+    kj::ArrayPtr<const capnp::word>
+    toArrayPtr(QByteArray arr) {
+        size_t wordSize = sizeof(capnp::word);
+        capnp::word *dptr = reinterpret_cast<capnp::word *>(arr.data());
+        kj::ArrayPtr<const capnp::word> kptr(dptr, arr.size() / wordSize);
+        return kptr;
+    }
+
+    QByteArray
+    readResponseBuffer() { 
+        
+        QByteArray buffer;
+        size_t wordSize = sizeof(capnp::word);
+        bool complete = false;
+        
+        while (!complete) {
+
+            m_process->waitForReadyRead(1000);
+            qint64 byteCount = m_process->bytesAvailable();
+            qint64 wordCount = byteCount / wordSize;
+
+            if (!wordCount) {
+                if (m_process->state() == QProcess::NotRunning) {
+                    cerr << "ERROR: Subprocess exited: Load failed" << endl;
+                    throw std::runtime_error("Piper server exited unexpectedly");
+                }
+            } else {
+                buffer.append(m_process->read(wordCount * wordSize));
+                size_t haveWords = buffer.size() / wordSize;
+                size_t expectedWords =
+                    capnp::expectedSizeInWordsFromPrefix(toArrayPtr(buffer));
+
+                cerr << "haveWords = " << haveWords << ", expectedWords = " << expectedWords << endl;
+                
+                if (haveWords >= expectedWords) {
+                    if (haveWords > expectedWords) {
+                        cerr << "WARNING: obtained more data than expected ("
+                             << haveWords << " words, expected " << expectedWords
+                             << ")" << endl;
+                    }
+                    complete = true;
+                }
+            }
+        }
+
+        return buffer;
+    }
+
+    void
+    checkResponseType(const RpcResponse::Reader &r,
+                      RpcResponse::Response::Which type,
+                      ReqId id) {
+        
+        if (r.getResponse().which() != type) {
+            throw std::runtime_error("Wrong response type");
+        }
+        if (ReqId(r.getId().getNumber()) != id) {
+            throw std::runtime_error("Wrong response id");
+        }
+    }
 };
     
 }
 
+int main(int, char **)
+{
+    piper::PiperClient client;
+    Vamp::Plugin *plugin = client.load("vamp-example-plugins:zerocrossing", 16, 0);
+    if (!plugin->initialise(1, 4, 4)) {
+        cerr << "initialisation failed" << endl;
+    } else {
+        std::vector<float> buf = { 1.0, -1.0, 1.0, -1.0 };
+        float *bd = buf.data();
+        Vamp::Plugin::FeatureSet features = plugin->process
+            (&bd, Vamp::RealTime::zeroTime);
+        cerr << "results for output 0:" << endl;
+        auto fl(features[0]);
+        for (const auto &f: fl) {
+            cerr << f.values[0] << endl;
+        }
+    }
+    delete plugin;
+}
+
--- a/vamp-client/client.pro	Tue Oct 11 17:08:31 2016 +0100
+++ b/vamp-client/client.pro	Wed Oct 12 11:59:57 2016 +0100
@@ -16,6 +16,8 @@
 
 QMAKE_CXXFLAGS = -I$$VAMPSDK_DIR -I..
 
+LIBS += -lcapnp -lkj -lvamp-hostsdk
+
 # Using the "console" CONFIG flag above should ensure this happens for
 # normal Windows builds, but this may be necessary when cross-compiling
 win32-x-g++:QMAKE_LFLAGS += -Wl,-subsystem,console
@@ -23,5 +25,5 @@
 TARGET = client
 
 SOURCES += \
-	client.cpp
+	client.cpp ../vamp-capnp/piper.capnp.c++
 
--- a/vamp-client/stub.h	Tue Oct 11 17:08:31 2016 +0100
+++ b/vamp-client/stub.h	Wed Oct 12 11:59:57 2016 +0100
@@ -21,7 +21,7 @@
     virtual
     Vamp::Plugin::FeatureSet
     process(PiperStubPlugin *plugin,
-            const float *const *inputBuffers,
+            std::vector<std::vector<float> > inputBuffers,
             Vamp::RealTime timestamp) = 0;
 
     virtual Vamp::Plugin::FeatureSet
@@ -189,7 +189,15 @@
             throw std::logic_error("Plugin has already been disposed of");
         }
 
-        return m_client->process(this, inputBuffers, timestamp);
+        //!!! ew
+        std::vector<std::vector<float> > vecbuf;
+        for (int c = 0; c < m_config.channelCount; ++c) {
+            vecbuf.push_back(std::vector<float>
+                             (inputBuffers[c],
+                              inputBuffers[c] + m_config.blockSize));
+        }
+        
+        return m_client->process(this, vecbuf, timestamp);
     }
 
     virtual FeatureSet getRemainingFeatures() {
--- a/vamp-support/AssignedPluginHandleMapper.h	Tue Oct 11 17:08:31 2016 +0100
+++ b/vamp-support/AssignedPluginHandleMapper.h	Wed Oct 12 11:59:57 2016 +0100
@@ -50,7 +50,7 @@
 public:
     AssignedPluginHandleMapper() { }
 
-    void addPlugin(Vamp::Plugin *p, Handle h) {
+    void addPlugin(Handle h, Vamp::Plugin *p) {
         if (!p) return;
 	if (m_rplugins.find(p) == m_rplugins.end()) {
             if (m_plugins.find(h) != m_plugins.end()) {
--- a/vamp-support/CountingPluginHandleMapper.h	Tue Oct 11 17:08:31 2016 +0100
+++ b/vamp-support/CountingPluginHandleMapper.h	Wed Oct 12 11:59:57 2016 +0100
@@ -51,7 +51,7 @@
 
     void addPlugin(Vamp::Plugin *p) {
         Handle h = m_nextHandle++;
-        m_sub.addPlugin(p, h);
+        m_sub.addPlugin(h, p);
     }
 
     void removePlugin(Handle h) {