changeset 49:f3f7561233d6

Begin plugin output id / index mapping for use in feature sets
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 16 Sep 2016 14:13:21 +0100
parents ce6cb3308bd7
children 12e3b396544c
files bits/PluginOutputIdMapper.h capnproto/VampnProto.h capnproto/vamp.capnp json/VampJson.h
diffstat 4 files changed, 196 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bits/PluginOutputIdMapper.h	Fri Sep 16 14:13:21 2016 +0100
@@ -0,0 +1,88 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Vampipe
+
+    Centre for Digital Music, Queen Mary, University of London.
+    Copyright 2006-2016 Chris Cannam and QMUL.
+  
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+    Except as contained in this notice, the names of the Centre for
+    Digital Music; Queen Mary, University of London; and Chris Cannam
+    shall not be used in advertising or otherwise to promote the sale,
+    use or other dealings in this Software without prior written
+    authorization.
+*/
+
+#ifndef VAMPIPE_PLUGIN_ID_MAPPER_H
+#define VAMPIPE_PLUGIN_ID_MAPPER_H
+
+#include <vamp-hostsdk/Plugin.h>
+
+#include <map>
+#include <string>
+
+namespace vampipe {
+
+class PluginOutputIdMapper
+{
+// NB not threadsafe. Does this matter?
+
+//!!! simplify. A single vector is almost certainly faster.
+    
+public:
+    PluginOutputIdMapper(Vamp::Plugin *p) : m_plugin(p) { }
+
+    class NotFound : virtual public std::runtime_error {
+    public:
+        NotFound() : runtime_error("output id or index not found in mapper") { }
+    };
+
+    int idToIndex(std::string outputId) const {
+	if (m_idIndexMap.empty()) populate();
+	auto i = m_idIndexMap.find(outputId);
+	if (i == m_idIndexMap.end()) throw NotFound();
+	return i->second;
+    }
+
+    std::string indexToId(int index) const {
+	if (m_ids.empty()) populate();
+	if (index < 0 || size_t(index) >= m_ids.size()) throw NotFound();
+	return m_ids[index];
+    }
+
+private:
+    Vamp::Plugin *m_plugin;
+    mutable std::vector<std::string> m_ids;
+    mutable std::map<std::string, int> m_idIndexMap;
+
+    void populate() const {
+	Vamp::Plugin::OutputList outputs = m_plugin->getOutputDescriptors();
+	for (const auto &d: outputs) {
+	    m_idIndexMap[d.identifier] = m_ids.size();
+	    m_ids.push_back(d.identifier);
+	}
+    }
+};
+
+}
+
+#endif
--- a/capnproto/VampnProto.h	Wed Sep 14 14:43:37 2016 +0100
+++ b/capnproto/VampnProto.h	Fri Sep 16 14:13:21 2016 +0100
@@ -42,6 +42,7 @@
 #include <vamp-hostsdk/PluginStaticData.h>
 
 #include "bits/PluginHandleMapper.h"
+#include "bits/PluginOutputIdMapper.h"
 #include "bits/RequestResponseType.h"
 
 namespace vampipe
@@ -294,13 +295,14 @@
     
     static void
     buildFeatureSet(FeatureSet::Builder &b,
-                    const Vamp::Plugin::FeatureSet &fs) {
+                    const Vamp::Plugin::FeatureSet &fs,
+                    const PluginOutputIdMapper &omapper) {
 
         auto featureset = b.initFeaturePairs(fs.size());
         int ix = 0;
         for (const auto &fsi : fs) {
             auto fspair = featureset[ix];
-            fspair.setOutput(fsi.first);
+            fspair.setOutput(omapper.indexToId(fsi.first));
             auto featurelist = fspair.initFeatures(fsi.second.size());
             for (size_t j = 0; j < fsi.second.size(); ++j) {
                 auto feature = featurelist[j];
@@ -312,7 +314,8 @@
 
     static void
     readFeatureSet(Vamp::Plugin::FeatureSet &fs,
-                   const FeatureSet::Reader &r) {
+                   const FeatureSet::Reader &r,
+                   const PluginOutputIdMapper &omapper) {
 
         fs.clear();
         auto pp = r.getFeaturePairs();
@@ -324,7 +327,7 @@
                 readFeature(vf, f);
                 vfl.push_back(vf);
             }
-            fs[p.getOutput()] = vfl;
+            fs[omapper.idToIndex(p.getOutput())] = vfl;
         }
     }
     
@@ -526,9 +529,9 @@
     static void
     buildLoadResponse(LoadResponse::Builder &b,
                       const Vamp::HostExt::LoadResponse &resp,
-                      PluginHandleMapper &mapper) {
+                      PluginHandleMapper &pmapper) {
 
-        b.setPluginHandle(mapper.pluginToHandle(resp.plugin));
+        b.setPluginHandle(pmapper.pluginToHandle(resp.plugin));
         auto sd = b.initStaticData();
         buildPluginStaticData(sd, resp.staticData);
         auto conf = b.initDefaultConfiguration();
@@ -538,9 +541,9 @@
     static void
     readLoadResponse(Vamp::HostExt::LoadResponse &resp,
                      const LoadResponse::Reader &r,
-                     PluginHandleMapper &mapper) {
+                     PluginHandleMapper &pmapper) {
 
-        resp.plugin = mapper.handleToPlugin(r.getPluginHandle());
+        resp.plugin = pmapper.handleToPlugin(r.getPluginHandle());
         readPluginStaticData(resp.staticData, r.getStaticData());
         readPluginConfiguration(resp.defaultConfiguration,
                                 r.getDefaultConfiguration());
@@ -549,9 +552,9 @@
     static void
     buildConfigurationRequest(ConfigurationRequest::Builder &b,
                               const Vamp::HostExt::ConfigurationRequest &cr,
-                              PluginHandleMapper &mapper) {
+                              PluginHandleMapper &pmapper) {
 
-        b.setPluginHandle(mapper.pluginToHandle(cr.plugin));
+        b.setPluginHandle(pmapper.pluginToHandle(cr.plugin));
         auto c = b.initConfiguration();
         buildPluginConfiguration(c, cr.configuration);
     }
@@ -559,10 +562,10 @@
     static void
     readConfigurationRequest(Vamp::HostExt::ConfigurationRequest &cr,
                              const ConfigurationRequest::Reader &r,
-                             PluginHandleMapper &mapper) {
+                             PluginHandleMapper &pmapper) {
 
         auto h = r.getPluginHandle();
-        cr.plugin = mapper.handleToPlugin(h);
+        cr.plugin = pmapper.handleToPlugin(h);
         auto c = r.getConfiguration();
         readPluginConfiguration(cr.configuration, c);
     }
@@ -629,9 +632,9 @@
     static void
     buildProcessRequest(ProcessRequest::Builder &b,
                         const Vamp::HostExt::ProcessRequest &pr,
-                        PluginHandleMapper &mapper) {
+                        PluginHandleMapper &pmapper) {
 
-        b.setPluginHandle(mapper.pluginToHandle(pr.plugin));
+        b.setPluginHandle(pmapper.pluginToHandle(pr.plugin));
         auto input = b.initInput();
         buildProcessInput(input, pr.timestamp, pr.inputBuffers);
     }
@@ -639,26 +642,28 @@
     static void
     readProcessRequest(Vamp::HostExt::ProcessRequest &pr,
                        const ProcessRequest::Reader &r,
-                       PluginHandleMapper &mapper) {
+                       PluginHandleMapper &pmapper) {
 
         auto h = r.getPluginHandle();
-        pr.plugin = mapper.handleToPlugin(h);
+        pr.plugin = pmapper.handleToPlugin(h);
         readProcessInput(pr.timestamp, pr.inputBuffers, r.getInput());
     }
 
     static void
     buildProcessResponse(ProcessResponse::Builder &b,
-                         const Vamp::HostExt::ProcessResponse &pr) {
+                         const Vamp::HostExt::ProcessResponse &pr,
+                         const PluginOutputIdMapper &omapper) {
 
         auto f = b.initFeatures();
-        buildFeatureSet(f, pr.features);
+        buildFeatureSet(f, pr.features, omapper);
     }
     
     static void
     readProcessResponse(Vamp::HostExt::ProcessResponse &pr,
-                        const ProcessResponse::Reader &r) {
+                        const ProcessResponse::Reader &r,
+                        const PluginOutputIdMapper &omapper) {
 
-        readFeatureSet(pr.features, r.getFeatures());
+        readFeatureSet(pr.features, r.getFeatures(), omapper);
     }
 
     static void
@@ -690,19 +695,19 @@
     static void
     buildVampResponse_Load(VampResponse::Builder &b,
                            const Vamp::HostExt::LoadResponse &resp,
-                           PluginHandleMapper &mapper) {
+                           PluginHandleMapper &pmapper) {
         b.setSuccess(resp.plugin != 0);
         b.setErrorText("");
         auto u = b.getResponse().initLoad();
-        buildLoadResponse(u, resp, mapper);
+        buildLoadResponse(u, resp, pmapper);
     }
 
     static void
     buildVampRequest_Configure(VampRequest::Builder &b,
                                const Vamp::HostExt::ConfigurationRequest &cr,
-                               PluginHandleMapper &mapper) {
+                               PluginHandleMapper &pmapper) {
         auto u = b.getRequest().initConfigure();
-        buildConfigurationRequest(u, cr, mapper);
+        buildConfigurationRequest(u, cr, pmapper);
     }
 
     static void
@@ -717,34 +722,36 @@
     static void
     buildVampRequest_Process(VampRequest::Builder &b,
                              const Vamp::HostExt::ProcessRequest &pr,
-                             PluginHandleMapper &mapper) {
+                             PluginHandleMapper &pmapper) {
         auto u = b.getRequest().initProcess();
-        buildProcessRequest(u, pr, mapper);
+        buildProcessRequest(u, pr, pmapper);
     }
     
     static void
     buildVampResponse_Process(VampResponse::Builder &b,
-                              const Vamp::HostExt::ProcessResponse &pr) {
+                              const Vamp::HostExt::ProcessResponse &pr,
+                              const PluginOutputIdMapper &omapper) {
         b.setSuccess(true);
         b.setErrorText("");
         auto u = b.getResponse().initProcess();
-        buildProcessResponse(u, pr);
+        buildProcessResponse(u, pr, omapper);
     }
     
     static void
     buildVampRequest_Finish(VampRequest::Builder &b,
                             Vamp::Plugin *p,
-                            PluginHandleMapper &mapper) {
+                            PluginHandleMapper &pmapper) {
 
         auto u = b.getRequest().initFinish();
-        u.setPluginHandle(mapper.pluginToHandle(p));
+        u.setPluginHandle(pmapper.pluginToHandle(p));
     }
     
     static void
     buildVampResponse_Finish(VampResponse::Builder &b,
-                             const Vamp::HostExt::ProcessResponse &pr) {
+                             const Vamp::HostExt::ProcessResponse &pr,
+                             const PluginOutputIdMapper &omapper) {
 
-        buildVampResponse_Process(b, pr);
+        buildVampResponse_Process(b, pr, omapper);
     }
 
     static RRType
@@ -817,24 +824,24 @@
     static void
     readVampResponse_Load(Vamp::HostExt::LoadResponse &resp,
                           const VampResponse::Reader &r,
-                          PluginHandleMapper &mapper) {
+                          PluginHandleMapper &pmapper) {
         if (getRequestResponseType(r) != RRType::Load) {
             throw std::logic_error("not a load response");
         }
         resp = {};
         if (r.getSuccess()) {
-            readLoadResponse(resp, r.getResponse().getLoad(), mapper);
+            readLoadResponse(resp, r.getResponse().getLoad(), pmapper);
         }
     }
     
     static void
     readVampRequest_Configure(Vamp::HostExt::ConfigurationRequest &req,
                               const VampRequest::Reader &r,
-                              PluginHandleMapper &mapper) {
+                              PluginHandleMapper &pmapper) {
         if (getRequestResponseType(r) != RRType::Configure) {
             throw std::logic_error("not a configuration request");
         }
-        readConfigurationRequest(req, r.getRequest().getConfigure(), mapper);
+        readConfigurationRequest(req, r.getRequest().getConfigure(), pmapper);
     }
 
     static void
@@ -852,45 +859,47 @@
     static void
     readVampRequest_Process(Vamp::HostExt::ProcessRequest &req,
                             const VampRequest::Reader &r,
-                            PluginHandleMapper &mapper) {
+                            PluginHandleMapper &pmapper) {
         if (getRequestResponseType(r) != RRType::Process) {
             throw std::logic_error("not a process request");
         }
-        readProcessRequest(req, r.getRequest().getProcess(), mapper);
+        readProcessRequest(req, r.getRequest().getProcess(), pmapper);
     }
 
     static void
     readVampResponse_Process(Vamp::HostExt::ProcessResponse &resp,
-                             const VampResponse::Reader &r) {
+                             const VampResponse::Reader &r,
+                             const PluginOutputIdMapper &omapper) {
         if (getRequestResponseType(r) != RRType::Process) {
             throw std::logic_error("not a process response");
         }
         resp = {};
         if (r.getSuccess()) {
-            readProcessResponse(resp, r.getResponse().getProcess());
+            readProcessResponse(resp, r.getResponse().getProcess(), omapper);
         }
     }
     
     static void
     readVampRequest_Finish(Vamp::Plugin *&finishPlugin,
                            const VampRequest::Reader &r,
-                           PluginHandleMapper &mapper) {
+                           PluginHandleMapper &pmapper) {
         if (getRequestResponseType(r) != RRType::Finish) {
             throw std::logic_error("not a finish request");
         }
-        finishPlugin = mapper.handleToPlugin
+        finishPlugin = pmapper.handleToPlugin
             (r.getRequest().getFinish().getPluginHandle());
     }
 
     static void
     readVampResponse_Finish(Vamp::HostExt::ProcessResponse &resp,
-                            const VampResponse::Reader &r) {
+                            const VampResponse::Reader &r,
+                            const PluginOutputIdMapper &omapper) {
         if (getRequestResponseType(r) != RRType::Finish) {
             throw std::logic_error("not a finish response");
         }
         resp = {};
         if (r.getSuccess()) {
-            readProcessResponse(resp, r.getResponse().getFinish());
+            readProcessResponse(resp, r.getResponse().getFinish(), omapper);
         }
     }
 };
--- a/capnproto/vamp.capnp	Wed Sep 14 14:43:37 2016 +0100
+++ b/capnproto/vamp.capnp	Fri Sep 16 14:13:21 2016 +0100
@@ -96,7 +96,7 @@
 
 struct FeatureSet {
     struct FSPair {
-        output         @0  :Int32;
+        output         @0  :Text;
         features       @1  :List(Feature) = [];
     }
     featurePairs       @0  :List(FSPair);
@@ -144,14 +144,15 @@
     input              @1  :ProcessInput;
 }
 
+struct ProcessResponse {
+    pluginHandle       @0  :Int32;
+    features           @1  :FeatureSet;
+}
+
 struct FinishRequest {
     pluginHandle       @0  :Int32;
 }
 
-struct ProcessResponse {
-    features           @0  :FeatureSet;
-}
-
 struct VampRequest {
     request :union {
 	list           @0  :Void;
--- a/json/VampJson.h	Wed Sep 14 14:43:37 2016 +0100
+++ b/json/VampJson.h	Fri Sep 16 14:13:21 2016 +0100
@@ -47,6 +47,7 @@
 #include <vamp-hostsdk/PluginLoader.h>
 
 #include "bits/PluginHandleMapper.h"
+#include "bits/PluginOutputIdMapper.h"
 #include "bits/RequestResponseType.h"
 
 namespace vampipe {
@@ -392,6 +393,7 @@
 
     static json11::Json
     fromFeatureSet(const Vamp::Plugin::FeatureSet &fs,
+                   const PluginOutputIdMapper &omapper,
                    BufferSerialisation serialisation) {
 
         json11::Json::object jo;
@@ -400,10 +402,7 @@
             for (const Vamp::Plugin::Feature &f: fsi.second) {
                 fj.push_back(fromFeature(f, serialisation));
             }
-            std::stringstream sstr;
-            sstr << fsi.first;
-            std::string n = sstr.str();
-            jo[n] = fj;
+            jo[omapper.indexToId(fsi.first)] = fj;
         }
         return json11::Json(jo);
     }
@@ -423,18 +422,18 @@
     }
 
     static Vamp::Plugin::FeatureSet
-    toFeatureSet(json11::Json j, BufferSerialisation &serialisation) {
+    toFeatureSet(json11::Json j,
+                 const PluginOutputIdMapper &omapper,
+                 BufferSerialisation &serialisation) {
 
         Vamp::Plugin::FeatureSet fs;
         if (!j.is_object()) {
             throw Failure("object expected for feature set");
         }
         for (auto &entry : j.object_items()) {
-            std::string nstr = entry.first;
-            size_t count = 0;
-            int n = stoi(nstr, &count);
-            if (n < 0 || fs.find(n) != fs.end() || count < nstr.size()) {
-                throw Failure("invalid or duplicate numerical index for output");
+            int n = omapper.idToIndex(entry.first);
+            if (fs.find(n) != fs.end()) {
+                throw Failure("duplicate numerical index for output");
             }
             fs[n] = toFeatureList(entry.second, serialisation);
         }
@@ -744,10 +743,10 @@
 
     static json11::Json
     fromLoadResponse(const Vamp::HostExt::LoadResponse &resp,
-                     const PluginHandleMapper &mapper) {
+                     const PluginHandleMapper &pmapper) {
 
         json11::Json::object jo;
-        jo["pluginHandle"] = double(mapper.pluginToHandle(resp.plugin));
+        jo["pluginHandle"] = double(pmapper.pluginToHandle(resp.plugin));
         jo["staticData"] = fromPluginStaticData(resp.staticData);
         jo["defaultConfiguration"] =
             fromPluginConfiguration(resp.defaultConfiguration);
@@ -756,7 +755,7 @@
 
     static Vamp::HostExt::LoadResponse
     toLoadResponse(json11::Json j,
-                   const PluginHandleMapper &mapper) {
+                   const PluginHandleMapper &pmapper) {
 
         std::string err;
 
@@ -768,7 +767,7 @@
         }
 
         Vamp::HostExt::LoadResponse resp;
-        resp.plugin = mapper.handleToPlugin(j["pluginHandle"].int_value());
+        resp.plugin = pmapper.handleToPlugin(j["pluginHandle"].int_value());
         resp.staticData = toPluginStaticData(j["staticData"]);
         resp.defaultConfiguration = toPluginConfiguration(j["defaultConfiguration"]);
         return resp;
@@ -776,11 +775,11 @@
 
     static json11::Json
     fromConfigurationRequest(const Vamp::HostExt::ConfigurationRequest &cr,
-                             const PluginHandleMapper &mapper) {
+                             const PluginHandleMapper &pmapper) {
 
         json11::Json::object jo;
 
-        jo["pluginHandle"] = mapper.pluginToHandle(cr.plugin);
+        jo["pluginHandle"] = pmapper.pluginToHandle(cr.plugin);
         jo["configuration"] = fromPluginConfiguration(cr.configuration);
         
         return json11::Json(jo);
@@ -788,7 +787,7 @@
 
     static Vamp::HostExt::ConfigurationRequest
     toConfigurationRequest(json11::Json j,
-                           const PluginHandleMapper &mapper) {
+                           const PluginHandleMapper &pmapper) {
 
         std::string err;
 
@@ -799,7 +798,7 @@
         }
 
         Vamp::HostExt::ConfigurationRequest cr;
-        cr.plugin = mapper.handleToPlugin(j["pluginHandle"].int_value());
+        cr.plugin = pmapper.handleToPlugin(j["pluginHandle"].int_value());
         cr.configuration = toPluginConfiguration(j["configuration"]);
         return cr;
     }
@@ -836,11 +835,11 @@
 
     static json11::Json
     fromProcessRequest(const Vamp::HostExt::ProcessRequest &r,
-                       const PluginHandleMapper &mapper,
+                       const PluginHandleMapper &pmapper,
                        BufferSerialisation serialisation) {
 
         json11::Json::object jo;
-        jo["pluginHandle"] = mapper.pluginToHandle(r.plugin);
+        jo["pluginHandle"] = pmapper.pluginToHandle(r.plugin);
 
         json11::Json::object io;
         io["timestamp"] = fromRealTime(r.timestamp);
@@ -865,7 +864,7 @@
 
     static Vamp::HostExt::ProcessRequest
     toProcessRequest(json11::Json j,
-                     const PluginHandleMapper &mapper,
+                     const PluginHandleMapper &pmapper,
                      BufferSerialisation &serialisation) {
 
         std::string err;
@@ -885,7 +884,7 @@
         }
 
         Vamp::HostExt::ProcessRequest r;
-        r.plugin = mapper.handleToPlugin(j["pluginHandle"].int_value());
+        r.plugin = pmapper.handleToPlugin(j["pluginHandle"].int_value());
 
         r.timestamp = toRealTime(input["timestamp"]);
 
@@ -951,23 +950,23 @@
 
     static json11::Json
     fromVampResponse_Load(const Vamp::HostExt::LoadResponse &resp,
-                          const PluginHandleMapper &mapper) {
+                          const PluginHandleMapper &pmapper) {
 
         json11::Json::object jo;
         jo["type"] = "load";
         jo["success"] = (resp.plugin != 0);
         jo["errorText"] = "";
-        jo["content"] = fromLoadResponse(resp, mapper);
+        jo["content"] = fromLoadResponse(resp, pmapper);
         return json11::Json(jo);
     }
 
     static json11::Json
     fromVampRequest_Configure(const Vamp::HostExt::ConfigurationRequest &req,
-                              const PluginHandleMapper &mapper) {
+                              const PluginHandleMapper &pmapper) {
 
         json11::Json::object jo;
         jo["type"] = "configure";
-        jo["content"] = fromConfigurationRequest(req, mapper);
+        jo["content"] = fromConfigurationRequest(req, pmapper);
         return json11::Json(jo);
     }    
 
@@ -984,48 +983,50 @@
     
     static json11::Json
     fromVampRequest_Process(const Vamp::HostExt::ProcessRequest &req,
-                            const PluginHandleMapper &mapper,
+                            const PluginHandleMapper &pmapper,
                             BufferSerialisation serialisation) {
 
         json11::Json::object jo;
         jo["type"] = "process";
-        jo["content"] = fromProcessRequest(req, mapper, serialisation);
+        jo["content"] = fromProcessRequest(req, pmapper, serialisation);
         return json11::Json(jo);
     }    
 
     static json11::Json
     fromVampResponse_Process(const Vamp::HostExt::ProcessResponse &resp,
+                             const PluginOutputIdMapper &omapper,
                              BufferSerialisation serialisation) {
         
         json11::Json::object jo;
         jo["type"] = "process";
         jo["success"] = true;
         jo["errorText"] = "";
-        jo["content"] = fromFeatureSet(resp.features, serialisation);
+        jo["content"] = fromFeatureSet(resp.features, omapper, serialisation);
         return json11::Json(jo);
     }
     
     static json11::Json
     fromVampRequest_Finish(Vamp::Plugin *p,
-                           const PluginHandleMapper &mapper) {
+                           const PluginHandleMapper &pmapper) {
 
         json11::Json::object jo;
         jo["type"] = "finish";
         json11::Json::object fo;
-        fo["pluginHandle"] = mapper.pluginToHandle(p);
+        fo["pluginHandle"] = pmapper.pluginToHandle(p);
         jo["content"] = fo;
         return json11::Json(jo);
     }    
     
     static json11::Json
     fromVampResponse_Finish(const Vamp::HostExt::ProcessResponse &resp,
+                            const PluginOutputIdMapper &omapper,
                             BufferSerialisation serialisation) {
 
         json11::Json::object jo;
         jo["type"] = "finish";
         jo["success"] = true;
         jo["errorText"] = "";
-        jo["content"] = fromFeatureSet(resp.features, serialisation);
+        jo["content"] = fromFeatureSet(resp.features, omapper, serialisation);
         return json11::Json(jo);
     }
 
@@ -1116,20 +1117,20 @@
     }
     
     static Vamp::HostExt::LoadResponse
-    toVampResponse_Load(json11::Json j, const PluginHandleMapper &mapper) {
+    toVampResponse_Load(json11::Json j, const PluginHandleMapper &pmapper) {
         
         Vamp::HostExt::LoadResponse resp;
         if (successful(j)) {
-            resp = toLoadResponse(j["content"], mapper);
+            resp = toLoadResponse(j["content"], pmapper);
         }
         return resp;
     }
     
     static Vamp::HostExt::ConfigurationRequest
-    toVampRequest_Configure(json11::Json j, const PluginHandleMapper &mapper) {
+    toVampRequest_Configure(json11::Json j, const PluginHandleMapper &pmapper) {
         
         checkTypeField(j, "configure");
-        return toConfigurationRequest(j["content"], mapper);
+        return toConfigurationRequest(j["content"], pmapper);
     }
     
     static Vamp::HostExt::ConfigurationResponse
@@ -1143,36 +1144,40 @@
     }
     
     static Vamp::HostExt::ProcessRequest
-    toVampRequest_Process(json11::Json j, const PluginHandleMapper &mapper,
+    toVampRequest_Process(json11::Json j, const PluginHandleMapper &pmapper,
                           BufferSerialisation &serialisation) {
         
         checkTypeField(j, "process");
-        return toProcessRequest(j["content"], mapper, serialisation);
+        return toProcessRequest(j["content"], pmapper, serialisation);
     }
     
     static Vamp::HostExt::ProcessResponse
-    toVampResponse_Process(json11::Json j, BufferSerialisation &serialisation) {
+    toVampResponse_Process(json11::Json j,
+                           const PluginOutputIdMapper &omapper,
+                           BufferSerialisation &serialisation) {
         
         Vamp::HostExt::ProcessResponse resp;
         if (successful(j)) {
-            resp.features = toFeatureSet(j["content"], serialisation);
+            resp.features = toFeatureSet(j["content"], omapper, serialisation);
         }
         return resp;
     }
     
     static Vamp::Plugin *
-    toVampRequest_Finish(json11::Json j, const PluginHandleMapper &mapper) {
+    toVampRequest_Finish(json11::Json j, const PluginHandleMapper &pmapper) {
         
         checkTypeField(j, "finish");
-        return mapper.handleToPlugin(j["content"]["pluginHandle"].int_value());
+        return pmapper.handleToPlugin(j["content"]["pluginHandle"].int_value());
     }
     
     static Vamp::HostExt::ProcessResponse
-    toVampResponse_Finish(json11::Json j, BufferSerialisation &serialisation) {
+    toVampResponse_Finish(json11::Json j,
+                          const PluginOutputIdMapper &omapper,
+                          BufferSerialisation &serialisation) {
         
         Vamp::HostExt::ProcessResponse resp;
         if (successful(j)) {
-            resp.features = toFeatureSet(j["content"], serialisation);
+            resp.features = toFeatureSet(j["content"], omapper, serialisation);
         }
         return resp;
     }