changeset 133:74a7c2a8d6b6

Merge from branch listargs
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 04 Nov 2016 10:43:49 +0000
parents 2004ec2b653e (current diff) d04958b5d3ad (diff)
children 3dcf0394971d 9da826f812cb
files
diffstat 13 files changed, 341 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/test/test-server.sh	Fri Oct 28 14:31:58 2016 +0100
+++ b/test/test-server.sh	Fri Nov 04 10:43:49 2016 +0000
@@ -44,6 +44,8 @@
 
 cat > "$input" <<EOF
 {"method":"list"}
+{"method":"list","params": {"from":["vamp-example-plugins","something-nonexistent"]}}
+{"method":"list","params": {"from":["something-nonexistent"]}}
 {"method":"load","id":6,"params": {"key":"vamp-example-plugins:percussiononsets","inputSampleRate":44100,"adapterFlags":["AdaptInputDomain","AdaptBufferSize"]}}
 {"method":"configure","id":"weevil","params":{"handle":1,"configuration":{"blockSize": 8, "channelCount": 1, "parameterValues": {"sensitivity": 40, "threshold": 3}, "stepSize": 8}}}
 {"method":"process","params": {"handle": 1, "processInput": { "timestamp": {"s": 0, "n": 0}, "inputBuffers": [ [1,2,3,4,5,6,7,8] ]}}}
@@ -63,7 +65,7 @@
 # (converting to JSON using piper-convert) and once with it directly
 # in JSON mode
 
-for format in capnp json ; do
+for format in json capnp ; do
 
     ( export VAMP_PATH="$vampsdkdir"/examples ;
       while read request ; do
@@ -83,8 +85,8 @@
           done
     ) < "$input"
 
-    # Skip plugin list
-    tail -n +2 "$allrespfile" > "$obtained"
+    # Skip plugin lists
+    tail -n +4 "$allrespfile" > "$obtained"
 
     echo "Checking response contents against expected contents..."
     if ! cmp "$obtained" "$expected"; then
@@ -93,6 +95,41 @@
         echo "OK"
     fi
 
+    echo "Checking plugin counts from list responses..."
+    
+    # Now check the plugin lists, but as the descriptions etc are
+    # probably a bit fragile, let's just count the number of plugins
+
+    # First, with no "from" arg to the list call
+    list_no_from=$(head -n +1 "$allrespfile" | fmt -1 | grep '"key"' | wc -l)
+
+    # Now with a "from" arg that includes the library that exists
+    list_with_good_from=$(tail -n +2 "$allrespfile" | head -n +1 | fmt -1 |
+                              grep '"key"' | wc -l)
+    
+    # Now with a "from" arg that doesn't include any real library
+    list_with_bad_from=$(tail -n +3 "$allrespfile" | head -n +1 | fmt -1 |
+                             grep '"key"' | wc -l)
+
+    if [ "$list_no_from" != "6" ]; then
+        echo "Wrong number of plugins from list response without \"from\" arg"
+        echo "Expected 6, obtained $list_no_from"
+        false
+    fi
+    if [ "$list_with_good_from" != "6" ]; then
+        echo "Wrong number of plugins from list response with good \"from\" arg"
+        echo "Expected 6, obtained $list_with_good_from"
+        false
+    fi
+    if [ "$list_with_bad_from" != "0" ]; then
+        echo "Wrong number of plugins from list response with bad \"from\" arg"
+        echo "Expected 0, obtained $list_with_bad_from"
+        false
+    fi
+    echo OK
+    
     rm "$allrespfile"
 
 done
+
+echo "Tests succeeded"  # set -e at top should ensure we don't get here otherwise
--- a/vamp-capnp/VampnProto.h	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-capnp/VampnProto.h	Fri Nov 04 10:43:49 2016 +0000
@@ -495,7 +495,38 @@
         c.stepSize = r.getStepSize();
         c.blockSize = r.getBlockSize();
     }
+    
+    static void
+    buildListRequest(piper::ListRequest::Builder &r,
+                     const ListRequest &resp) {
 
+        auto p = r.initFrom(unsigned(resp.from.size()));
+        for (int i = 0; i < int(resp.from.size()); ++i) {
+            p.set(i, resp.from[i]);
+        }
+    }
+    
+    static void
+    readListRequest(ListRequest &lr,
+                    const piper::ListRequest::Reader &r) {
+
+        lr.from.clear();
+        for (auto f: r.getFrom()) {
+            lr.from.push_back(f);
+        }
+    }
+
+    static void
+    buildListResponse(piper::ListResponse::Builder &r,
+                      const ListResponse &resp) {
+        
+        auto p = r.initAvailable(unsigned(resp.available.size()));
+        for (int i = 0; i < int(resp.available.size()); ++i) {
+            auto pd = p[i];
+            buildExtractorStaticData(pd, resp.available[i]);
+        }
+    }
+    
     static void
     readListResponse(ListResponse &lr,
                      const piper::ListResponse::Reader &r) {
@@ -728,8 +759,10 @@
     }
 
     static void
-    buildRpcRequest_List(piper::RpcRequest::Builder &b) {
-        b.getRequest().initList();
+    buildRpcRequest_List(piper::RpcRequest::Builder &b,
+                         const ListRequest &req) {
+        auto r = b.getRequest().initList();
+        buildListRequest(r, req);
     }
 
     static void
@@ -737,11 +770,7 @@
                           const ListResponse &resp) {
 
         auto r = b.getResponse().initList();
-        auto p = r.initAvailable(unsigned(resp.available.size()));
-        for (int i = 0; i < int(resp.available.size()); ++i) {
-            auto pd = p[i];
-            buildExtractorStaticData(pd, resp.available[i]);
-        }
+        buildListResponse(r, resp);
     }
     
     static void
@@ -904,10 +933,12 @@
     }
         
     static void
-    readRpcRequest_List(const piper::RpcRequest::Reader &r) {
+    readRpcRequest_List(ListRequest &req,
+                        const piper::RpcRequest::Reader &r) {
         if (getRequestResponseType(r) != RRType::List) {
             throw std::logic_error("not a list request");
         }
+        readListRequest(req, r.getRequest().getList());
     }
 
     static void
--- a/vamp-capnp/piper.capnp.c++	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-capnp/piper.capnp.c++	Fri Nov 04 10:43:49 2016 +0000
@@ -1538,29 +1538,51 @@
   0, 0, nullptr, nullptr, nullptr, { &s_eb49b9892c5b9b83, nullptr, nullptr, 0, 0, nullptr }
 };
 #endif  // !CAPNP_LITE
-static const ::capnp::_::AlignedData<16> b_b54ff18dabd0d4e1 = {
+static const ::capnp::_::AlignedData<36> b_b54ff18dabd0d4e1 = {
   {   0,   0,   0,   0,   5,   0,   6,   0,
     225, 212, 208, 171, 141, 241,  79, 181,
      12,   0,   0,   0,   1,   0,   0,   0,
       6, 146, 153,  76, 196, 198, 177, 196,
-      0,   0,   7,   0,   0,   0,   0,   0,
+      1,   0,   7,   0,   0,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
      21,   0,   0,   0, 194,   0,   0,   0,
      29,   0,   0,   0,   7,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
-      0,   0,   0,   0,   0,   0,   0,   0,
+     25,   0,   0,   0,  63,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
       0,   0,   0,   0,   0,   0,   0,   0,
     112, 105, 112, 101, 114,  46,  99,  97,
     112, 110, 112,  58,  76, 105, 115, 116,
      82, 101, 113, 117, 101, 115, 116,   0,
-      0,   0,   0,   0,   1,   0,   1,   0, }
+      0,   0,   0,   0,   1,   0,   1,   0,
+      4,   0,   0,   0,   3,   0,   4,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   1,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     13,   0,   0,   0,  42,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      8,   0,   0,   0,   3,   0,   1,   0,
+     36,   0,   0,   0,   2,   0,   1,   0,
+    102, 114, 111, 109,   0,   0,   0,   0,
+     14,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   3,   0,   1,   0,
+     12,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     14,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0, }
 };
 ::capnp::word const* const bp_b54ff18dabd0d4e1 = b_b54ff18dabd0d4e1.words;
 #if !CAPNP_LITE
+static const uint16_t m_b54ff18dabd0d4e1[] = {0};
+static const uint16_t i_b54ff18dabd0d4e1[] = {0};
 const ::capnp::_::RawSchema s_b54ff18dabd0d4e1 = {
-  0xb54ff18dabd0d4e1, b_b54ff18dabd0d4e1.words, 16, nullptr, nullptr,
-  0, 0, nullptr, nullptr, nullptr, { &s_b54ff18dabd0d4e1, nullptr, nullptr, 0, 0, nullptr }
+  0xb54ff18dabd0d4e1, b_b54ff18dabd0d4e1.words, 36, nullptr, m_b54ff18dabd0d4e1,
+  0, 1, i_b54ff18dabd0d4e1, nullptr, nullptr, { &s_b54ff18dabd0d4e1, nullptr, nullptr, 0, 0, nullptr }
 };
 #endif  // !CAPNP_LITE
 static const ::capnp::_::AlignedData<38> b_c8b36e8e9e8d6f15 = {
@@ -2698,8 +2720,10 @@
 namespace piper {
 
 // Basic
+#ifndef _MSC_VER
 constexpr uint16_t Basic::_capnpPrivate::dataWordSize;
 constexpr uint16_t Basic::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind Basic::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* Basic::_capnpPrivate::schema;
@@ -2707,8 +2731,10 @@
 #endif  // !CAPNP_LITE
 
 // ParameterDescriptor
+#ifndef _MSC_VER
 constexpr uint16_t ParameterDescriptor::_capnpPrivate::dataWordSize;
 constexpr uint16_t ParameterDescriptor::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind ParameterDescriptor::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* ParameterDescriptor::_capnpPrivate::schema;
@@ -2716,8 +2742,10 @@
 #endif  // !CAPNP_LITE
 
 // ConfiguredOutputDescriptor
+#ifndef _MSC_VER
 constexpr uint16_t ConfiguredOutputDescriptor::_capnpPrivate::dataWordSize;
 constexpr uint16_t ConfiguredOutputDescriptor::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind ConfiguredOutputDescriptor::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* ConfiguredOutputDescriptor::_capnpPrivate::schema;
@@ -2725,8 +2753,10 @@
 #endif  // !CAPNP_LITE
 
 // OutputDescriptor
+#ifndef _MSC_VER
 constexpr uint16_t OutputDescriptor::_capnpPrivate::dataWordSize;
 constexpr uint16_t OutputDescriptor::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind OutputDescriptor::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* OutputDescriptor::_capnpPrivate::schema;
@@ -2734,8 +2764,10 @@
 #endif  // !CAPNP_LITE
 
 // ExtractorStaticData
+#ifndef _MSC_VER
 constexpr uint16_t ExtractorStaticData::_capnpPrivate::dataWordSize;
 constexpr uint16_t ExtractorStaticData::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind ExtractorStaticData::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* ExtractorStaticData::_capnpPrivate::schema;
@@ -2743,8 +2775,10 @@
 #endif  // !CAPNP_LITE
 
 // RealTime
+#ifndef _MSC_VER
 constexpr uint16_t RealTime::_capnpPrivate::dataWordSize;
 constexpr uint16_t RealTime::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind RealTime::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* RealTime::_capnpPrivate::schema;
@@ -2752,8 +2786,10 @@
 #endif  // !CAPNP_LITE
 
 // ProcessInput
+#ifndef _MSC_VER
 constexpr uint16_t ProcessInput::_capnpPrivate::dataWordSize;
 constexpr uint16_t ProcessInput::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind ProcessInput::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* ProcessInput::_capnpPrivate::schema;
@@ -2761,8 +2797,10 @@
 #endif  // !CAPNP_LITE
 
 // Feature
+#ifndef _MSC_VER
 constexpr uint16_t Feature::_capnpPrivate::dataWordSize;
 constexpr uint16_t Feature::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind Feature::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* Feature::_capnpPrivate::schema;
@@ -2770,8 +2808,10 @@
 #endif  // !CAPNP_LITE
 
 // FeatureSet
+#ifndef _MSC_VER
 constexpr uint16_t FeatureSet::_capnpPrivate::dataWordSize;
 constexpr uint16_t FeatureSet::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind FeatureSet::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* FeatureSet::_capnpPrivate::schema;
@@ -2779,8 +2819,10 @@
 #endif  // !CAPNP_LITE
 
 // FeatureSet::FSPair
+#ifndef _MSC_VER
 constexpr uint16_t FeatureSet::FSPair::_capnpPrivate::dataWordSize;
 constexpr uint16_t FeatureSet::FSPair::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind FeatureSet::FSPair::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* FeatureSet::FSPair::_capnpPrivate::schema;
@@ -2788,8 +2830,10 @@
 #endif  // !CAPNP_LITE
 
 // Configuration
+#ifndef _MSC_VER
 constexpr uint16_t Configuration::_capnpPrivate::dataWordSize;
 constexpr uint16_t Configuration::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind Configuration::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* Configuration::_capnpPrivate::schema;
@@ -2797,8 +2841,10 @@
 #endif  // !CAPNP_LITE
 
 // Configuration::PVPair
+#ifndef _MSC_VER
 constexpr uint16_t Configuration::PVPair::_capnpPrivate::dataWordSize;
 constexpr uint16_t Configuration::PVPair::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind Configuration::PVPair::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* Configuration::PVPair::_capnpPrivate::schema;
@@ -2808,8 +2854,10 @@
 const ::capnp::_::ConstList< ::piper::AdapterFlag> ADAPT_ALL_SAFE(::capnp::schemas::b_9ed58097be8bc6f3.words + 27);
 const ::capnp::_::ConstList< ::piper::AdapterFlag> ADAPT_ALL(::capnp::schemas::b_eb49b9892c5b9b83.words + 26);
 // ListRequest
+#ifndef _MSC_VER
 constexpr uint16_t ListRequest::_capnpPrivate::dataWordSize;
 constexpr uint16_t ListRequest::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind ListRequest::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* ListRequest::_capnpPrivate::schema;
@@ -2817,8 +2865,10 @@
 #endif  // !CAPNP_LITE
 
 // ListResponse
+#ifndef _MSC_VER
 constexpr uint16_t ListResponse::_capnpPrivate::dataWordSize;
 constexpr uint16_t ListResponse::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind ListResponse::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* ListResponse::_capnpPrivate::schema;
@@ -2826,8 +2876,10 @@
 #endif  // !CAPNP_LITE
 
 // LoadRequest
+#ifndef _MSC_VER
 constexpr uint16_t LoadRequest::_capnpPrivate::dataWordSize;
 constexpr uint16_t LoadRequest::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind LoadRequest::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* LoadRequest::_capnpPrivate::schema;
@@ -2835,8 +2887,10 @@
 #endif  // !CAPNP_LITE
 
 // LoadResponse
+#ifndef _MSC_VER
 constexpr uint16_t LoadResponse::_capnpPrivate::dataWordSize;
 constexpr uint16_t LoadResponse::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind LoadResponse::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* LoadResponse::_capnpPrivate::schema;
@@ -2844,8 +2898,10 @@
 #endif  // !CAPNP_LITE
 
 // ConfigurationRequest
+#ifndef _MSC_VER
 constexpr uint16_t ConfigurationRequest::_capnpPrivate::dataWordSize;
 constexpr uint16_t ConfigurationRequest::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind ConfigurationRequest::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* ConfigurationRequest::_capnpPrivate::schema;
@@ -2853,8 +2909,10 @@
 #endif  // !CAPNP_LITE
 
 // ConfigurationResponse
+#ifndef _MSC_VER
 constexpr uint16_t ConfigurationResponse::_capnpPrivate::dataWordSize;
 constexpr uint16_t ConfigurationResponse::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind ConfigurationResponse::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* ConfigurationResponse::_capnpPrivate::schema;
@@ -2862,8 +2920,10 @@
 #endif  // !CAPNP_LITE
 
 // ProcessRequest
+#ifndef _MSC_VER
 constexpr uint16_t ProcessRequest::_capnpPrivate::dataWordSize;
 constexpr uint16_t ProcessRequest::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind ProcessRequest::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* ProcessRequest::_capnpPrivate::schema;
@@ -2871,8 +2931,10 @@
 #endif  // !CAPNP_LITE
 
 // ProcessResponse
+#ifndef _MSC_VER
 constexpr uint16_t ProcessResponse::_capnpPrivate::dataWordSize;
 constexpr uint16_t ProcessResponse::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind ProcessResponse::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* ProcessResponse::_capnpPrivate::schema;
@@ -2880,8 +2942,10 @@
 #endif  // !CAPNP_LITE
 
 // FinishRequest
+#ifndef _MSC_VER
 constexpr uint16_t FinishRequest::_capnpPrivate::dataWordSize;
 constexpr uint16_t FinishRequest::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind FinishRequest::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* FinishRequest::_capnpPrivate::schema;
@@ -2889,8 +2953,10 @@
 #endif  // !CAPNP_LITE
 
 // FinishResponse
+#ifndef _MSC_VER
 constexpr uint16_t FinishResponse::_capnpPrivate::dataWordSize;
 constexpr uint16_t FinishResponse::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind FinishResponse::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* FinishResponse::_capnpPrivate::schema;
@@ -2898,8 +2964,10 @@
 #endif  // !CAPNP_LITE
 
 // Error
+#ifndef _MSC_VER
 constexpr uint16_t Error::_capnpPrivate::dataWordSize;
 constexpr uint16_t Error::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind Error::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* Error::_capnpPrivate::schema;
@@ -2907,8 +2975,10 @@
 #endif  // !CAPNP_LITE
 
 // RpcRequest
+#ifndef _MSC_VER
 constexpr uint16_t RpcRequest::_capnpPrivate::dataWordSize;
 constexpr uint16_t RpcRequest::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind RpcRequest::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* RpcRequest::_capnpPrivate::schema;
@@ -2916,8 +2986,10 @@
 #endif  // !CAPNP_LITE
 
 // RpcRequest::Id
+#ifndef _MSC_VER
 constexpr uint16_t RpcRequest::Id::_capnpPrivate::dataWordSize;
 constexpr uint16_t RpcRequest::Id::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind RpcRequest::Id::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* RpcRequest::Id::_capnpPrivate::schema;
@@ -2925,8 +2997,10 @@
 #endif  // !CAPNP_LITE
 
 // RpcRequest::Request
+#ifndef _MSC_VER
 constexpr uint16_t RpcRequest::Request::_capnpPrivate::dataWordSize;
 constexpr uint16_t RpcRequest::Request::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind RpcRequest::Request::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* RpcRequest::Request::_capnpPrivate::schema;
@@ -2934,8 +3008,10 @@
 #endif  // !CAPNP_LITE
 
 // RpcResponse
+#ifndef _MSC_VER
 constexpr uint16_t RpcResponse::_capnpPrivate::dataWordSize;
 constexpr uint16_t RpcResponse::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind RpcResponse::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* RpcResponse::_capnpPrivate::schema;
@@ -2943,8 +3019,10 @@
 #endif  // !CAPNP_LITE
 
 // RpcResponse::Id
+#ifndef _MSC_VER
 constexpr uint16_t RpcResponse::Id::_capnpPrivate::dataWordSize;
 constexpr uint16_t RpcResponse::Id::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind RpcResponse::Id::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* RpcResponse::Id::_capnpPrivate::schema;
@@ -2952,8 +3030,10 @@
 #endif  // !CAPNP_LITE
 
 // RpcResponse::Response
+#ifndef _MSC_VER
 constexpr uint16_t RpcResponse::Response::_capnpPrivate::dataWordSize;
 constexpr uint16_t RpcResponse::Response::_capnpPrivate::pointerCount;
+#endif
 #if !CAPNP_LITE
 constexpr ::capnp::Kind RpcResponse::Response::_capnpPrivate::kind;
 constexpr ::capnp::_::RawSchema const* RpcResponse::Response::_capnpPrivate::schema;
--- a/vamp-capnp/piper.capnp.h	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-capnp/piper.capnp.h	Fri Nov 04 10:43:49 2016 +0000
@@ -269,7 +269,7 @@
   class Pipeline;
 
   struct _capnpPrivate {
-    CAPNP_DECLARE_STRUCT_HEADER(b54ff18dabd0d4e1, 0, 0)
+    CAPNP_DECLARE_STRUCT_HEADER(b54ff18dabd0d4e1, 0, 1)
     #if !CAPNP_LITE
     static constexpr ::capnp::_::RawBrandedSchema const* brand = &schema->defaultBrand;
     #endif  // !CAPNP_LITE
@@ -1864,6 +1864,9 @@
   }
 #endif  // !CAPNP_LITE
 
+  inline bool hasFrom() const;
+  inline  ::capnp::List< ::capnp::Text>::Reader getFrom() const;
+
 private:
   ::capnp::_::StructReader _reader;
   template <typename, ::capnp::Kind>
@@ -1892,6 +1895,14 @@
   inline ::kj::StringTree toString() const { return asReader().toString(); }
 #endif  // !CAPNP_LITE
 
+  inline bool hasFrom();
+  inline  ::capnp::List< ::capnp::Text>::Builder getFrom();
+  inline void setFrom( ::capnp::List< ::capnp::Text>::Reader value);
+  inline void setFrom(::kj::ArrayPtr<const  ::capnp::Text::Reader> value);
+  inline  ::capnp::List< ::capnp::Text>::Builder initFrom(unsigned int size);
+  inline void adoptFrom(::capnp::Orphan< ::capnp::List< ::capnp::Text>>&& value);
+  inline ::capnp::Orphan< ::capnp::List< ::capnp::Text>> disownFrom();
+
 private:
   ::capnp::_::StructBuilder _builder;
   template <typename, ::capnp::Kind>
@@ -4839,6 +4850,42 @@
       0 * ::capnp::ELEMENTS, value);
 }
 
+inline bool ListRequest::Reader::hasFrom() const {
+  return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull();
+}
+inline bool ListRequest::Builder::hasFrom() {
+  return !_builder.getPointerField(0 * ::capnp::POINTERS).isNull();
+}
+inline  ::capnp::List< ::capnp::Text>::Reader ListRequest::Reader::getFrom() const {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::Text>>::get(
+      _reader.getPointerField(0 * ::capnp::POINTERS));
+}
+inline  ::capnp::List< ::capnp::Text>::Builder ListRequest::Builder::getFrom() {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::Text>>::get(
+      _builder.getPointerField(0 * ::capnp::POINTERS));
+}
+inline void ListRequest::Builder::setFrom( ::capnp::List< ::capnp::Text>::Reader value) {
+  ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::Text>>::set(
+      _builder.getPointerField(0 * ::capnp::POINTERS), value);
+}
+inline void ListRequest::Builder::setFrom(::kj::ArrayPtr<const  ::capnp::Text::Reader> value) {
+  ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::Text>>::set(
+      _builder.getPointerField(0 * ::capnp::POINTERS), value);
+}
+inline  ::capnp::List< ::capnp::Text>::Builder ListRequest::Builder::initFrom(unsigned int size) {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::Text>>::init(
+      _builder.getPointerField(0 * ::capnp::POINTERS), size);
+}
+inline void ListRequest::Builder::adoptFrom(
+    ::capnp::Orphan< ::capnp::List< ::capnp::Text>>&& value) {
+  ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::Text>>::adopt(
+      _builder.getPointerField(0 * ::capnp::POINTERS), kj::mv(value));
+}
+inline ::capnp::Orphan< ::capnp::List< ::capnp::Text>> ListRequest::Builder::disownFrom() {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::capnp::Text>>::disown(
+      _builder.getPointerField(0 * ::capnp::POINTERS));
+}
+
 inline bool ListResponse::Reader::hasAvailable() const {
   return !_reader.getPointerField(0 * ::capnp::POINTERS).isNull();
 }
--- a/vamp-client/CapnpRRClient.h	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-client/CapnpRRClient.h	Fri Nov 04 10:43:49 2016 +0000
@@ -99,7 +99,7 @@
     // Loader methods:
 
     ListResponse
-    listPluginData() override {
+    listPluginData(const ListRequest &req) override {
 
         if (!m_transport->isOK()) {
             throw std::runtime_error("Piper server crashed or failed to start");
@@ -107,7 +107,7 @@
 
         capnp::MallocMessageBuilder message;
         piper::RpcRequest::Builder builder = message.initRoot<piper::RpcRequest>();
-        VampnProto::buildRpcRequest_List(builder);
+        VampnProto::buildRpcRequest_List(builder, req);
         ReqId id = getId();
         builder.getId().setNumber(id);
 
--- a/vamp-client/Loader.h	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-client/Loader.h	Fri Nov 04 10:43:49 2016 +0000
@@ -44,7 +44,7 @@
 class Loader
 {
 public:
-    virtual ListResponse listPluginData() = 0;
+    virtual ListResponse listPluginData(const ListRequest &) = 0;
     virtual LoadResponse loadPlugin(const LoadRequest &) = 0;
 };
 
--- a/vamp-client/client.cpp	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-client/client.cpp	Fri Nov 04 10:43:49 2016 +0000
@@ -44,11 +44,11 @@
 
 int main(int, char **)
 {
-    piper_vamp::client::ProcessQtTransport transport("../bin/piper-vamp-server",
+    piper_vamp::client::ProcessQtTransport transport("../bin/piper-vamp-simple-server",
                                                      "capnp");
     piper_vamp::client::CapnpRRClient client(&transport);
 
-    piper_vamp::ListResponse lr = client.listPluginData();
+    piper_vamp::ListResponse lr = client.listPluginData({});
     cerr << "Plugins available:" << endl;
     int i = 1;
     for (const auto &p: lr.available) {
@@ -97,7 +97,7 @@
 
     // Let's try a crazy AutoPlugin
 
-    piper_vamp::client::AutoPlugin ap("../bin/piper-vamp-server",
+    piper_vamp::client::AutoPlugin ap("../bin/piper-vamp-simple-server",
                                       "vamp-example-plugins:zerocrossing", 16, 0);
     if (!ap.isOK()) {
         cerr << "AutoPlugin creation failed" << endl;
--- a/vamp-json/VampJson.h	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-json/VampJson.h	Fri Nov 04 10:43:49 2016 +0000
@@ -802,6 +802,60 @@
     }
 
     static json11::Json
+    fromListRequest(const ListRequest &req) {
+        json11::Json::object jo;
+        json11::Json::array arr;
+        for (const auto &f: req.from) {
+            arr.push_back(f);
+        }
+        jo["from"] = arr;
+        return json11::Json(jo);
+    }
+
+    static ListRequest
+    toListRequest(json11::Json j, std::string &err) {
+        
+        ListRequest req;
+        if (!j["from"].is_null() &&
+            !j["from"].is_array()) {
+            err = "array expected for from field";
+            return {};
+        }
+        for (const auto &a: j["from"].array_items()) {
+            if (!a.is_string()) {
+                err = "string expected for element in from array";
+                return {};
+            }
+            req.from.push_back(a.string_value());
+        }
+        return req;
+    }
+
+    static json11::Json
+    fromListResponse(const ListResponse &resp) {
+        
+        json11::Json::array arr;
+        for (const auto &a: resp.available) {
+            arr.push_back(fromPluginStaticData(a));
+        }
+        json11::Json::object jo;
+        jo["available"] = arr;
+
+        return json11::Json(jo);
+    }
+
+    static ListResponse
+    toListResponse(json11::Json j, std::string &err) {
+
+        ListResponse resp;
+        for (const auto &a: j["result"]["available"].array_items()) {
+            resp.available.push_back(toPluginStaticData(a, err));
+            if (failed(err)) return {};
+        }
+        return resp;
+    }
+    
+    static json11::Json
     fromLoadRequest(const LoadRequest &req) {
 
         json11::Json::object jo;
@@ -1016,7 +1070,7 @@
 private: // go private briefly for a couple of helper functions
     
     static void
-    checkTypeField(json11::Json j, std::string expected, std::string &err) {
+    checkRpcRequestType(json11::Json j, std::string expected, std::string &err) {
         if (!j["method"].is_string()) {
             err = "string expected for method";
             return;
@@ -1025,6 +1079,31 @@
             err = "expected value \"" + expected + "\" for type";
             return;
         }
+        if (!j["params"].is_null() &&
+            !j["params"].is_object()) {
+            err = "object expected for params";
+            return;
+        }
+        if (!j["id"].is_null() &&
+            !j["id"].is_number() &&
+            !j["id"].is_string()) {
+            err = "number or string expected for id";
+            return;
+        }
+        if (!j["jsonrpc"].is_null() &&
+            !j["jsonrpc"].is_string()) {
+            err = "string expected for jsonrpc";
+            return;
+        }
+        for (const auto &kv: j.object_items()) {
+            if (kv.first != "method" &&
+                kv.first != "params" &&
+                kv.first != "id" &&
+                kv.first != "jsonrpc") {
+                err = "unexpected field \"" + kv.first + "\" in rpc request object";
+                return;
+            }
+        }
     }
 
     static bool
@@ -1051,12 +1130,14 @@
 public:
 
     static json11::Json
-    fromRpcRequest_List(const json11::Json &id) {
+    fromRpcRequest_List(const ListRequest &req,
+                        const json11::Json &id) {
 
         json11::Json::object jo;
         markRPC(jo);
 
         jo["method"] = "list";
+        jo["params"] = fromListRequest(req);
         addId(jo, id);
         return json11::Json(jo);
     }
@@ -1068,15 +1149,8 @@
         json11::Json::object jo;
         markRPC(jo);
 
-        json11::Json::array arr;
-        for (const auto &a: resp.available) {
-            arr.push_back(fromPluginStaticData(a));
-        }
-        json11::Json::object po;
-        po["available"] = arr;
-
         jo["method"] = "list";
-        jo["result"] = po;
+        jo["result"] = fromListResponse(resp);
         addId(jo, id);
         return json11::Json(jo);
     }
@@ -1270,9 +1344,12 @@
 	}
     }
 
-    static void
+    static ListRequest
     toRpcRequest_List(json11::Json j, std::string &err) {
-        checkTypeField(j, "list", err);
+
+        checkRpcRequestType(j, "list", err);
+        if (failed(err)) return {};
+        return toListRequest(j["params"], err);
     }
 
     static ListResponse
@@ -1280,19 +1357,15 @@
 
         ListResponse resp;
         if (successful(j, err) && !failed(err)) {
-            for (const auto &a: j["result"]["available"].array_items()) {
-                resp.available.push_back(toPluginStaticData(a, err));
-                if (failed(err)) return {};
-            }
+            resp = toListResponse(j["result"], err);
         }
-        
         return resp;
     }
 
     static LoadRequest
     toRpcRequest_Load(json11::Json j, std::string &err) {
         
-        checkTypeField(j, "load", err);
+        checkRpcRequestType(j, "load", err);
         if (failed(err)) return {};
         return toLoadRequest(j["params"], err);
     }
@@ -1314,7 +1387,7 @@
                             const PluginHandleMapper &pmapper,
                             std::string &err) {
         
-        checkTypeField(j, "configure", err);
+        checkRpcRequestType(j, "configure", err);
         if (failed(err)) return {};
         return toConfigurationRequest(j["params"], pmapper, err);
     }
@@ -1335,7 +1408,7 @@
     toRpcRequest_Process(json11::Json j, const PluginHandleMapper &pmapper,
                           BufferSerialisation &serialisation, std::string &err) {
         
-        checkTypeField(j, "process", err);
+        checkRpcRequestType(j, "process", err);
         if (failed(err)) return {};
         return toProcessRequest(j["params"], pmapper, serialisation, err);
     }
@@ -1361,7 +1434,7 @@
     toRpcRequest_Finish(json11::Json j, const PluginHandleMapper &pmapper,
                          std::string &err) {
         
-        checkTypeField(j, "finish", err);
+        checkRpcRequestType(j, "finish", err);
         if (failed(err)) return {};
         FinishRequest req;
         req.plugin = pmapper.handleToPlugin
--- a/vamp-server/convert.cpp	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-server/convert.cpp	Fri Nov 04 10:43:49 2016 +0000
@@ -213,7 +213,7 @@
     switch (rr.type) {
 
     case RRType::List:
-        VampJson::toRpcRequest_List(j, err); // type check only
+        rr.listRequest = VampJson::toRpcRequest_List(j, err);
         break;
     case RRType::Load:
         rr.loadRequest = VampJson::toRpcRequest_Load(j, err);
@@ -249,7 +249,7 @@
     switch (rr.type) {
 
     case RRType::List:
-        j = VampJson::fromRpcRequest_List(id);
+        j = VampJson::fromRpcRequest_List(rr.listRequest, id);
         break;
     case RRType::Load:
         j = VampJson::fromRpcRequest_Load(rr.loadRequest, id);
@@ -383,7 +383,7 @@
     switch (rr.type) {
 
     case RRType::List:
-        VampnProto::readRpcRequest_List(reader); // type check only
+        VampnProto::readRpcRequest_List(rr.listRequest, reader);
         break;
     case RRType::Load:
         VampnProto::readRpcRequest_Load(rr.loadRequest, reader);
@@ -416,7 +416,7 @@
     switch (rr.type) {
 
     case RRType::List:
-        VampnProto::buildRpcRequest_List(builder);
+        VampnProto::buildRpcRequest_List(builder, rr.listRequest);
         break;
     case RRType::Load:
         VampnProto::buildRpcRequest_Load(builder, rr.loadRequest);
--- a/vamp-server/simple-server.cpp	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-server/simple-server.cpp	Fri Nov 04 10:43:49 2016 +0000
@@ -218,7 +218,7 @@
     switch (rr.type) {
 
     case RRType::List:
-        VampJson::toRpcRequest_List(j, err); // type check only
+        rr.listRequest = VampJson::toRpcRequest_List(j, err);
         break;
     case RRType::Load:
         rr.loadRequest = VampJson::toRpcRequest_Load(j, err);
@@ -315,7 +315,7 @@
     switch (rr.type) {
 
     case RRType::List:
-        VampnProto::readRpcRequest_List(reader); // type check only
+        VampnProto::readRpcRequest_List(rr.listRequest, reader);
         break;
     case RRType::Load:
         VampnProto::readRpcRequest_Load(rr.loadRequest, reader);
@@ -396,16 +396,21 @@
     switch (request.type) {
 
     case RRType::List:
-        response.listResponse = LoaderRequests().listPluginData();
+        response.listResponse =
+            LoaderRequests().listPluginData(request.listRequest);
         response.success = true;
         break;
 
     case RRType::Load:
-        response.loadResponse = LoaderRequests().loadPlugin(request.loadRequest);
+        response.loadResponse =
+            LoaderRequests().loadPlugin(request.loadRequest);
         if (response.loadResponse.plugin != nullptr) {
             mapper.addPlugin(response.loadResponse.plugin);
             if (debug) {
-                cerr << "piper-vamp-server " << pid << ": loaded plugin, handle = " << mapper.pluginToHandle(response.loadResponse.plugin) << endl;
+                cerr << "piper-vamp-server " << pid
+                     << ": loaded plugin, handle = "
+                     << mapper.pluginToHandle(response.loadResponse.plugin)
+                     << endl;
             }
             response.success = true;
         }
--- a/vamp-support/LoaderRequests.h	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-support/LoaderRequests.h	Fri Nov 04 10:43:49 2016 +0000
@@ -51,12 +51,18 @@
 {
 public:
     ListResponse
-    listPluginData() {
+    listPluginData(ListRequest req) {
 
 	auto loader = Vamp::HostExt::PluginLoader::getInstance();
-	auto keys = loader->listPlugins();
+        
+        std::vector<std::string> keys;
+        if (req.from.empty()) {
+            keys = loader->listPlugins();
+        } else {
+            keys = loader->listPluginsIn(req.from);
+        }
+
 	ListResponse response;
-
 	for (std::string key: keys) {
 	    Vamp::Plugin *p = loader->loadPlugin(key, 44100, 0);
 	    if (!p) continue;
--- a/vamp-support/RequestOrResponse.h	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-support/RequestOrResponse.h	Fri Nov 04 10:43:49 2016 +0000
@@ -70,6 +70,7 @@
     std::string errorText;
     RpcId id;
 
+    ListRequest listRequest;
     ListResponse listResponse;
     LoadRequest loadRequest;
     LoadResponse loadResponse;
--- a/vamp-support/RequestResponse.h	Fri Oct 28 14:31:58 2016 +0100
+++ b/vamp-support/RequestResponse.h	Fri Nov 04 10:43:49 2016 +0000
@@ -49,12 +49,15 @@
  * \class ListRequest
  * 
  * ListRequest is a structure containing the information needed to
- * list plugins. Currently empty.
+ * list plugins.
  *
  * \see ListResponse
  */
 struct ListRequest
 {
+    ListRequest() { } // no constraints by default
+
+    std::vector<std::string> from;
 };
 
 /**