changeset 214:0906984b9496

Merge pull request #5 from piper-audio/dev/rename-pluginstub Dev/rename pluginstub
author Chris Cannam <cannam@all-day-breakfast.com>
date Thu, 09 Feb 2017 14:41:29 +0000
parents 8183c3be5592 (current diff) a69724686f0b (diff)
children 8dff3213f77c
files vamp-client/PluginStub.h vamp-client/qt/AutoPlugin.h
diffstat 11 files changed, 688 insertions(+), 685 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Thu Feb 09 14:19:38 2017 +0000
+++ b/Makefile	Thu Feb 09 14:41:29 2017 +0000
@@ -110,17 +110,19 @@
 test/vamp-client/tst_PluginStub.o: vamp-support/PluginConfiguration.h
 test/vamp-client/tst_PluginStub.o: vamp-client/PluginClient.h
 test/vamp-client/tst_PluginStub.o: vamp-support/PluginConfiguration.h
-test/vamp-client/tst_PluginStub.o: vamp-client/PluginStub.h
+test/vamp-client/tst_PluginStub.o: vamp-client/PiperVampPlugin.h
 test/vamp-client/tst_PluginStub.o: vamp-support/PluginStaticData.h
 test/vamp-client/tst_PluginStub.o: vamp-client/PluginClient.h
 vamp-client/qt/test.o: vamp-client/qt/ProcessQtTransport.h
 vamp-client/qt/test.o: vamp-client/SynchronousTransport.h
-vamp-client/qt/test.o: vamp-client/Exceptions.h vamp-client/qt/AutoPlugin.h
+vamp-client/qt/test.o: vamp-client/Exceptions.h
+vamp-client/qt/test.o: vamp-client/qt/PiperAutoPlugin.h
 vamp-client/qt/test.o: vamp-client/CapnpRRClient.h vamp-client/Loader.h
 vamp-client/qt/test.o: vamp-support/RequestResponse.h
 vamp-client/qt/test.o: vamp-support/PluginStaticData.h
 vamp-client/qt/test.o: vamp-support/PluginConfiguration.h
-vamp-client/qt/test.o: vamp-client/PluginClient.h vamp-client/PluginStub.h
+vamp-client/qt/test.o: vamp-client/PluginClient.h
+vamp-client/qt/test.o: vamp-client/PiperVampPlugin.h
 vamp-client/qt/test.o: vamp-support/PluginStaticData.h
 vamp-client/qt/test.o: vamp-support/PluginConfiguration.h
 vamp-client/qt/test.o: vamp-client/SynchronousTransport.h
--- a/test/vamp-client/tst_PluginStub.cpp	Thu Feb 09 14:19:38 2017 +0000
+++ b/test/vamp-client/tst_PluginStub.cpp	Thu Feb 09 14:41:29 2017 +0000
@@ -1,7 +1,7 @@
 #include "catch/catch.hpp"
 #include "vamp-client/Loader.h"
 #include "vamp-client/PluginClient.h"
-#include "vamp-client/PluginStub.h"
+#include "vamp-client/PiperVampPlugin.h"
 #include "vamp-support/RequestResponse.h"
 #include <vector>
 
@@ -11,14 +11,14 @@
 
 // This stub fakes the interaction with a Piper server
 // Here we only need to implement the configure method 
-// due to testing only the initialise implemention of PluginStub
+// due to testing only the initialise implemention of PiperVampPlugin
 class StubClient : public PluginClient
 {
 public:
     StubClient(PluginStaticData staticData) : m_staticData(staticData) {}
     
     ConfigurationResponse
-    configure(PluginStub* plugin,
+    configure(PiperVampPlugin* plugin,
               PluginConfiguration config) override
     {
         const float scale = plugin->getParameter("framing-scale");
@@ -42,7 +42,7 @@
     }
     
     Vamp::Plugin::FeatureSet
-    process(PluginStub* /*plugin*/,
+    process(PiperVampPlugin* /*plugin*/,
             AudioBuffer /*channels*/,
             Vamp::RealTime /*timestamp*/) override
     {
@@ -50,13 +50,13 @@
     }
     
     Vamp::Plugin::FeatureSet
-    finish(PluginStub* /*plugin*/) override
+    finish(PiperVampPlugin* /*plugin*/) override
     {
         return {};
     }
     
     void
-    reset(PluginStub* /*plugin*/, PluginConfiguration /*config*/) override
+    reset(PiperVampPlugin* /*plugin*/, PluginConfiguration /*config*/) override
     {}
 private:
     PluginStaticData m_staticData;
@@ -93,7 +93,7 @@
 
     StubClient stub {staticData};
     
-    PluginStub vampPiperAdapter {
+    PiperVampPlugin vampPiperAdapter {
         &stub, 
         "stub", // plugin key
         44100.0, // sample rate
--- a/vamp-client/CapnpRRClient.h	Thu Feb 09 14:19:38 2017 +0000
+++ b/vamp-client/CapnpRRClient.h	Thu Feb 09 14:41:29 2017 +0000
@@ -38,7 +38,7 @@
 
 #include "Loader.h"
 #include "PluginClient.h"
-#include "PluginStub.h"
+#include "PiperVampPlugin.h"
 #include "SynchronousTransport.h"
 
 #include "vamp-support/AssignedPluginHandleMapper.h"
@@ -149,7 +149,7 @@
     // Loader methods:
 
     ListResponse
-    listPluginData(const ListRequest &req) override {
+    list(const ListRequest &req) override {
 
         LOG_E("CapnpRRClient::listPluginData called");
         
@@ -177,7 +177,7 @@
     }
     
     LoadResponse
-    loadPlugin(const LoadRequest &req) override {
+    load(const LoadRequest &req) override {
 
         LOG_E("CapnpRRClient::loadPlugin called");
         
@@ -190,12 +190,12 @@
                                                        resp.staticData,
                                                        resp.defaultConfiguration);
 
-        Vamp::Plugin *plugin = new PluginStub(this,
-                                              req.pluginKey,
-                                              req.inputSampleRate,
-                                              req.adapterFlags,
-                                              resp.staticData,
-                                              resp.defaultConfiguration);
+        Vamp::Plugin *plugin = new PiperVampPlugin(this,
+                                                   req.pluginKey,
+                                                   req.inputSampleRate,
+                                                   req.adapterFlags,
+                                                   resp.staticData,
+                                                   resp.defaultConfiguration);
 
         m_mapper.addPlugin(handle, plugin);
 
@@ -210,7 +210,7 @@
     
     virtual
     ConfigurationResponse
-    configure(PluginStub *plugin,
+    configure(PiperVampPlugin *plugin,
               PluginConfiguration config) override {
 
         LOG_E("CapnpRRClient::configure called");
@@ -247,7 +247,7 @@
     
     virtual
     Vamp::Plugin::FeatureSet
-    process(PluginStub *plugin,
+    process(PiperVampPlugin *plugin,
             std::vector<std::vector<float> > inputBuffers,
             Vamp::RealTime timestamp) override {
 
@@ -284,7 +284,7 @@
     }
 
     virtual Vamp::Plugin::FeatureSet
-    finish(PluginStub *plugin) override {
+    finish(PiperVampPlugin *plugin) override {
 
         LOG_E("CapnpRRClient::finish called");
         
@@ -323,7 +323,7 @@
     }
 
     virtual void
-    reset(PluginStub *plugin,
+    reset(PiperVampPlugin *plugin,
           PluginConfiguration config) override {
 
         // Reload the plugin on the server side, and configure it as requested
--- a/vamp-client/Loader.h	Thu Feb 09 14:19:38 2017 +0000
+++ b/vamp-client/Loader.h	Thu Feb 09 14:41:29 2017 +0000
@@ -44,8 +44,8 @@
 class Loader
 {
 public:
-    virtual ListResponse listPluginData(const ListRequest &) = 0;
-    virtual LoadResponse loadPlugin(const LoadRequest &) = 0;
+    virtual ListResponse list(const ListRequest &) = 0;
+    virtual LoadResponse load(const LoadRequest &) = 0;
 };
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-client/PiperVampPlugin.h	Thu Feb 09 14:41:29 2017 +0000
@@ -0,0 +1,413 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+/*
+  Piper C++
+
+  An API for audio analysis and feature extraction plugins.
+
+  Centre for Digital Music, Queen Mary, University of London.
+  Copyright 2006-2017 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 PIPER_VAMP_PLUGIN_H
+#define PIPER_VAMP_PLUGIN_H
+
+#include <vamp-hostsdk/Plugin.h>
+#include <vamp-hostsdk/PluginLoader.h>
+
+#include "vamp-support/PluginStaticData.h"
+#include "vamp-support/PluginConfiguration.h"
+
+#include "PluginClient.h"
+
+#include <cstdint>
+#include <iostream>
+
+namespace piper_vamp {
+namespace client {
+
+/**
+ * PiperVampPlugin presents a Piper feature extractor in the form of a
+ * Vamp plugin.
+ */
+class PiperVampPlugin : public Vamp::Plugin
+{
+    enum State {
+        /**
+         * The plugin's corresponding Piper feature extractor has been
+         * loaded but no subsequent state change has happened. This is
+         * the initial state of PiperVampPlugin on construction, since
+         * it is associated with a pre-loaded handle.
+         */
+        Loaded,
+        
+        /**
+         * The plugin has been configured, and the step and block size
+         * received from the host in its last call to initialise()
+         * match those that were returned in the configuration
+         * response (i.e. the server's desired step and block
+         * size). Our m_config record reflects these correct
+         * values. The plugin is ready to process.
+         */
+        Configured,
+
+        /**
+         * The plugin has been configured, but the step and block size
+         * received from the host in its last call to initialise()
+         * differ from those returned by the server in the
+         * configuration response. Our initialise() call therefore
+         * returned false, and the plugin cannot be used until the
+         * host calls initialise() again with the "correct" step and
+         * block size. Our m_config record reflects these correct
+         * values, so the host can retrieve them through
+         * getPreferredStepSize and getPreferredBlockSize.
+         */
+        Misconfigured,
+
+        /**
+         * The finish() function has been called and the plugin
+         * unloaded. No further plugin activity is possible.
+         */
+        Finished,
+
+        /** 
+         * A call has failed unrecoverably. No further plugin activity
+         * is possible.
+         */
+        Failed
+    };
+    
+public:
+    PiperVampPlugin(PluginClient *client,
+                    std::string pluginKey,
+                    float inputSampleRate,
+                    int adapterFlags,
+                    PluginStaticData psd,
+                    PluginConfiguration defaultConfig) :
+        Plugin(inputSampleRate),
+        m_client(client),
+        m_key(pluginKey),
+        m_adapterFlags(adapterFlags),
+        m_state(Loaded),
+        m_psd(psd),
+        m_defaultConfig(defaultConfig),
+        m_config(defaultConfig)
+    { }
+
+    virtual ~PiperVampPlugin() {
+        if (m_state != Finished && m_state != Failed) {
+            try {
+                (void)m_client->finish(this);
+            } catch (const std::exception &e) {
+                // Finish can throw, but our destructor must not
+                std::cerr << "WARNING: PiperVampPlugin::~PiperVampPlugin: caught exception from finish(): " << e.what() << std::endl;
+            }
+        }
+    }
+    
+    virtual std::string getIdentifier() const {
+        return m_psd.basic.identifier;
+    }
+
+    virtual std::string getName() const {
+        return m_psd.basic.name;
+    }
+
+    virtual std::string getDescription() const {
+        return m_psd.basic.description;
+    }
+
+    virtual std::string getMaker() const {
+        return m_psd.maker;
+    }
+
+    virtual std::string getCopyright() const {
+        return m_psd.copyright;
+    }
+
+    virtual int getPluginVersion() const {
+        return m_psd.pluginVersion;
+    }
+
+    virtual ParameterList getParameterDescriptors() const {
+        return m_psd.parameters;
+    }
+
+    virtual float getParameter(std::string name) const {
+        if (m_config.parameterValues.find(name) != m_config.parameterValues.end()) {
+            return m_config.parameterValues.at(name);
+        } else {
+            return 0.f;
+        }
+    }
+
+    virtual void setParameter(std::string name, float value) {
+        if (m_state == Failed) {
+            throw std::logic_error("Plugin is in failed state");
+        }
+        if (m_state != Loaded) {
+            m_state = Failed;
+            throw std::logic_error("Can't set parameter after plugin initialised");
+        }
+        m_config.parameterValues[name] = value;
+    }
+
+    virtual ProgramList getPrograms() const {
+        return m_psd.programs;
+    }
+
+    virtual std::string getCurrentProgram() const {
+        return m_config.currentProgram;
+    }
+    
+    virtual void selectProgram(std::string program) {
+        if (m_state == Failed) {
+            throw std::logic_error("Plugin is in failed state");
+        }
+        if (m_state != Loaded) {
+            m_state = Failed;
+            throw std::logic_error("Can't select program after plugin initialised");
+        }
+        m_config.currentProgram = program;
+    }
+
+    virtual bool initialise(size_t inputChannels,
+                            size_t stepSize,
+                            size_t blockSize) {
+
+        if (m_state == Failed) {
+            throw std::logic_error("Plugin is in failed state");
+        }
+
+        if (m_state == Misconfigured) {
+            if (int(stepSize) == m_config.framing.stepSize &&
+                int(blockSize) == m_config.framing.blockSize) {
+                m_state = Configured;
+                return true;
+            } else {
+                return false;
+            }
+        }
+        
+        if (m_state != Loaded) {
+            m_state = Failed;
+            throw std::logic_error("Plugin has already been initialised");
+        }
+        
+        m_config.channelCount = int(inputChannels);
+        m_config.framing.stepSize = int(stepSize);
+        m_config.framing.blockSize = int(blockSize);
+
+        try {
+            auto response = m_client->configure(this, m_config);
+            m_outputs = response.outputs;
+            
+            // Update with the new preferred step and block size now
+            // that the plugin has taken into account its parameter
+            // settings. If the values passed in to initialise()
+            // weren't suitable, then this ensures that a subsequent
+            // call to getPreferredStepSize/BlockSize on this plugin
+            // object will at least get acceptable values from now on
+            m_config.framing = response.framing;
+
+            // And if they didn't match up with the passed-in ones,
+            // lodge ourselves in Misconfigured state and report
+            // failure so as to provoke the host to call initialise()
+            // again before any processing.
+            if (m_config.framing.stepSize != int(stepSize) ||
+                m_config.framing.blockSize != int(blockSize)) {
+                m_state = Misconfigured;
+                return false;
+            }
+            
+        } catch (const std::exception &e) {
+            m_state = Failed;
+            throw;
+        }
+
+        if (!m_outputs.empty()) {
+            m_state = Configured;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    virtual void reset() {
+        
+        if (m_state == Failed) {
+            throw std::logic_error("Plugin is in failed state");
+        }
+        if (m_state == Loaded || m_state == Misconfigured) {
+            // reset is a no-op if the plugin hasn't been initialised yet
+            return;
+        }
+
+        try {
+            m_client->reset(this, m_config);
+        } catch (const std::exception &e) {
+            m_state = Failed;
+            throw;
+        }
+
+        m_state = Configured;
+    }
+
+    virtual InputDomain getInputDomain() const {
+        return m_psd.inputDomain;
+    }
+
+    virtual size_t getPreferredBlockSize() const {
+        // Return this from m_config instead of m_defaultConfig, so
+        // that it gets updated in the event of an initialise() call
+        // that fails for the wrong value
+        return m_config.framing.blockSize;
+    }
+
+    virtual size_t getPreferredStepSize() const {
+        // Return this from m_config instead of m_defaultConfig, so
+        // that it gets updated in the event of an initialise() call
+        // that fails for the wrong value
+        return m_config.framing.stepSize;
+    }
+
+    virtual size_t getMinChannelCount() const {
+        return m_psd.minChannelCount;
+    }
+
+    virtual size_t getMaxChannelCount() const {
+        return m_psd.maxChannelCount;
+    }
+
+    virtual OutputList getOutputDescriptors() const {
+
+        if (m_state == Failed) {
+            throw std::logic_error("Plugin is in failed state");
+        }
+        if (m_state == Configured) {
+            return m_outputs;
+        }
+
+        //!!! todo: figure out for which hosts (and adapters?) it may
+        //!!! be a problem that the output descriptors are incomplete
+        //!!! here. Any such hosts/adapters are broken, but I bet they
+        //!!! exist
+        
+        OutputList staticOutputs;
+        for (const auto &o: m_psd.basicOutputInfo) {
+            OutputDescriptor od;
+            od.identifier = o.identifier;
+            od.name = o.name;
+            od.description = o.description;
+            staticOutputs.push_back(od);
+        }
+        return staticOutputs;
+    }
+
+    virtual FeatureSet process(const float *const *inputBuffers,
+                               Vamp::RealTime timestamp) {
+
+        if (m_state == Failed) {
+            throw std::logic_error("Plugin is in failed state");
+        }
+        if (m_state == Loaded || m_state == Misconfigured) {
+            m_state = Failed;
+            throw std::logic_error("Plugin has not been initialised");
+        }
+        if (m_state == Finished) {
+            m_state = Failed;
+            throw std::logic_error("Plugin has already been disposed of");
+        }
+
+        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.framing.blockSize));
+        }
+
+        try {
+            return m_client->process(this, vecbuf, timestamp);
+        } catch (const std::exception &e) {
+            m_state = Failed;
+            throw;
+        }
+    }
+
+    virtual FeatureSet getRemainingFeatures() {
+
+        if (m_state == Failed) {
+            throw std::logic_error("Plugin is in failed state");
+        }
+        if (m_state == Loaded || m_state == Misconfigured) {
+            m_state = Failed;
+            throw std::logic_error("Plugin has not been configured");
+        }
+        if (m_state == Finished) {
+            m_state = Failed;
+            throw std::logic_error("Plugin has already been disposed of");
+        }
+
+        m_state = Finished;
+
+        try {
+            return m_client->finish(this);
+        } catch (const std::exception &e) {
+            m_state = Failed;
+            throw;
+        }
+    }
+
+    // Not Plugin methods, but needed by the PluginClient to support reloads:
+    
+    virtual float getInputSampleRate() const {
+        return m_inputSampleRate;
+    }
+
+    virtual std::string getPluginKey() const {
+        return m_key;
+    }
+
+    virtual int getAdapterFlags() const {
+        return m_adapterFlags;
+    }
+    
+private:
+    PluginClient *m_client;
+    std::string m_key;
+    int m_adapterFlags;
+    State m_state;
+    PluginStaticData m_psd;
+    OutputList m_outputs;
+    PluginConfiguration m_defaultConfig;
+    PluginConfiguration m_config;
+};
+
+}
+}
+
+#endif
--- a/vamp-client/PluginClient.h	Thu Feb 09 14:19:38 2017 +0000
+++ b/vamp-client/PluginClient.h	Thu Feb 09 14:41:29 2017 +0000
@@ -41,7 +41,7 @@
 namespace piper_vamp {
 namespace client {
 
-class PluginStub;
+class PiperVampPlugin;
 
 /**
  * Interface for a client that accepts Vamp-like structures (Plugin
@@ -54,22 +54,22 @@
 public:
     virtual
     ConfigurationResponse
-    configure(PluginStub *plugin,
+    configure(PiperVampPlugin *plugin,
               PluginConfiguration config) = 0;
     
     virtual
     Vamp::Plugin::FeatureSet
-    process(PluginStub *plugin,
+    process(PiperVampPlugin *plugin,
             std::vector<std::vector<float> > inputBuffers,
             Vamp::RealTime timestamp) = 0;
 
     virtual
     Vamp::Plugin::FeatureSet
-    finish(PluginStub *plugin) = 0;
+    finish(PiperVampPlugin *plugin) = 0;
 
     virtual
     void
-    reset(PluginStub *plugin,
+    reset(PiperVampPlugin *plugin,
           PluginConfiguration config) = 0;
 };
 
--- a/vamp-client/PluginStub.h	Thu Feb 09 14:19:38 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,412 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
-/*
-  Piper C++
-
-  An API for audio analysis and feature extraction plugins.
-
-  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 PIPER_PLUGIN_STUB_H
-#define PIPER_PLUGIN_STUB_H
-
-#include <vamp-hostsdk/Plugin.h>
-#include <vamp-hostsdk/PluginLoader.h>
-
-#include "vamp-support/PluginStaticData.h"
-#include "vamp-support/PluginConfiguration.h"
-
-#include "PluginClient.h"
-
-#include <cstdint>
-#include <iostream>
-
-namespace piper_vamp {
-namespace client {
-
-/**
- * PluginStub presents a Piper feature extractor in the form of a Vamp plugin.
- */
-class PluginStub : public Vamp::Plugin
-{
-    enum State {
-        /**
-         * The plugin's corresponding Piper feature extractor has been
-         * loaded but no subsequent state change has happened. This is
-         * the initial state of PluginStub on construction, since it
-         * is associated with a pre-loaded handle.
-         */
-        Loaded,
-        
-        /**
-         * The plugin has been configured, and the step and block size
-         * received from the host in its last call to initialise()
-         * match those that were returned in the configuration
-         * response (i.e. the server's desired step and block
-         * size). Our m_config record reflects these correct
-         * values. The plugin is ready to process.
-         */
-        Configured,
-
-        /**
-         * The plugin has been configured, but the step and block size
-         * received from the host in its last call to initialise()
-         * differ from those returned by the server in the
-         * configuration response. Our initialise() call therefore
-         * returned false, and the plugin cannot be used until the
-         * host calls initialise() again with the "correct" step and
-         * block size. Our m_config record reflects these correct
-         * values, so the host can retrieve them through
-         * getPreferredStepSize and getPreferredBlockSize.
-         */
-        Misconfigured,
-
-        /**
-         * The finish() function has been called and the plugin
-         * unloaded. No further plugin activity is possible.
-         */
-        Finished,
-
-        /** 
-         * A call has failed unrecoverably. No further plugin activity
-         * is possible.
-         */
-        Failed
-    };
-    
-public:
-    PluginStub(PluginClient *client,
-               std::string pluginKey,
-               float inputSampleRate,
-               int adapterFlags,
-               PluginStaticData psd,
-               PluginConfiguration defaultConfig) :
-        Plugin(inputSampleRate),
-        m_client(client),
-        m_key(pluginKey),
-        m_adapterFlags(adapterFlags),
-        m_state(Loaded),
-        m_psd(psd),
-        m_defaultConfig(defaultConfig),
-        m_config(defaultConfig)
-    { }
-
-    virtual ~PluginStub() {
-        if (m_state != Finished && m_state != Failed) {
-            try {
-                (void)m_client->finish(this);
-            } catch (const std::exception &e) {
-                // Finish can throw, but our destructor must not
-                std::cerr << "WARNING: PluginStub::~PluginStub: caught exception from finish(): " << e.what() << std::endl;
-            }
-        }
-    }
-    
-    virtual std::string getIdentifier() const {
-        return m_psd.basic.identifier;
-    }
-
-    virtual std::string getName() const {
-        return m_psd.basic.name;
-    }
-
-    virtual std::string getDescription() const {
-        return m_psd.basic.description;
-    }
-
-    virtual std::string getMaker() const {
-        return m_psd.maker;
-    }
-
-    virtual std::string getCopyright() const {
-        return m_psd.copyright;
-    }
-
-    virtual int getPluginVersion() const {
-        return m_psd.pluginVersion;
-    }
-
-    virtual ParameterList getParameterDescriptors() const {
-        return m_psd.parameters;
-    }
-
-    virtual float getParameter(std::string name) const {
-        if (m_config.parameterValues.find(name) != m_config.parameterValues.end()) {
-            return m_config.parameterValues.at(name);
-        } else {
-            return 0.f;
-        }
-    }
-
-    virtual void setParameter(std::string name, float value) {
-        if (m_state == Failed) {
-            throw std::logic_error("Plugin is in failed state");
-        }
-        if (m_state != Loaded) {
-            m_state = Failed;
-            throw std::logic_error("Can't set parameter after plugin initialised");
-        }
-        m_config.parameterValues[name] = value;
-    }
-
-    virtual ProgramList getPrograms() const {
-        return m_psd.programs;
-    }
-
-    virtual std::string getCurrentProgram() const {
-        return m_config.currentProgram;
-    }
-    
-    virtual void selectProgram(std::string program) {
-        if (m_state == Failed) {
-            throw std::logic_error("Plugin is in failed state");
-        }
-        if (m_state != Loaded) {
-            m_state = Failed;
-            throw std::logic_error("Can't select program after plugin initialised");
-        }
-        m_config.currentProgram = program;
-    }
-
-    virtual bool initialise(size_t inputChannels,
-                            size_t stepSize,
-                            size_t blockSize) {
-
-        if (m_state == Failed) {
-            throw std::logic_error("Plugin is in failed state");
-        }
-
-        if (m_state == Misconfigured) {
-            if (int(stepSize) == m_config.framing.stepSize &&
-                int(blockSize) == m_config.framing.blockSize) {
-                m_state = Configured;
-                return true;
-            } else {
-                return false;
-            }
-        }
-        
-        if (m_state != Loaded) {
-            m_state = Failed;
-            throw std::logic_error("Plugin has already been initialised");
-        }
-        
-        m_config.channelCount = int(inputChannels);
-        m_config.framing.stepSize = int(stepSize);
-        m_config.framing.blockSize = int(blockSize);
-
-        try {
-            auto response = m_client->configure(this, m_config);
-            m_outputs = response.outputs;
-            
-            // Update with the new preferred step and block size now
-            // that the plugin has taken into account its parameter
-            // settings. If the values passed in to initialise()
-            // weren't suitable, then this ensures that a subsequent
-            // call to getPreferredStepSize/BlockSize on this plugin
-            // object will at least get acceptable values from now on
-            m_config.framing = response.framing;
-
-            // And if they didn't match up with the passed-in ones,
-            // lodge ourselves in Misconfigured state and report
-            // failure so as to provoke the host to call initialise()
-            // again before any processing.
-            if (m_config.framing.stepSize != int(stepSize) ||
-                m_config.framing.blockSize != int(blockSize)) {
-                m_state = Misconfigured;
-                return false;
-            }
-            
-        } catch (const std::exception &e) {
-            m_state = Failed;
-            throw;
-        }
-
-        if (!m_outputs.empty()) {
-            m_state = Configured;
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    virtual void reset() {
-        
-        if (m_state == Failed) {
-            throw std::logic_error("Plugin is in failed state");
-        }
-        if (m_state == Loaded || m_state == Misconfigured) {
-            // reset is a no-op if the plugin hasn't been initialised yet
-            return;
-        }
-
-        try {
-            m_client->reset(this, m_config);
-        } catch (const std::exception &e) {
-            m_state = Failed;
-            throw;
-        }
-
-        m_state = Configured;
-    }
-
-    virtual InputDomain getInputDomain() const {
-        return m_psd.inputDomain;
-    }
-
-    virtual size_t getPreferredBlockSize() const {
-        // Return this from m_config instead of m_defaultConfig, so
-        // that it gets updated in the event of an initialise() call
-        // that fails for the wrong value
-        return m_config.framing.blockSize;
-    }
-
-    virtual size_t getPreferredStepSize() const {
-        // Return this from m_config instead of m_defaultConfig, so
-        // that it gets updated in the event of an initialise() call
-        // that fails for the wrong value
-        return m_config.framing.stepSize;
-    }
-
-    virtual size_t getMinChannelCount() const {
-        return m_psd.minChannelCount;
-    }
-
-    virtual size_t getMaxChannelCount() const {
-        return m_psd.maxChannelCount;
-    }
-
-    virtual OutputList getOutputDescriptors() const {
-
-        if (m_state == Failed) {
-            throw std::logic_error("Plugin is in failed state");
-        }
-        if (m_state == Configured) {
-            return m_outputs;
-        }
-
-        //!!! todo: figure out for which hosts (and adapters?) it may
-        //!!! be a problem that the output descriptors are incomplete
-        //!!! here. Any such hosts/adapters are broken, but I bet they
-        //!!! exist
-        
-        OutputList staticOutputs;
-        for (const auto &o: m_psd.basicOutputInfo) {
-            OutputDescriptor od;
-            od.identifier = o.identifier;
-            od.name = o.name;
-            od.description = o.description;
-            staticOutputs.push_back(od);
-        }
-        return staticOutputs;
-    }
-
-    virtual FeatureSet process(const float *const *inputBuffers,
-                               Vamp::RealTime timestamp) {
-
-        if (m_state == Failed) {
-            throw std::logic_error("Plugin is in failed state");
-        }
-        if (m_state == Loaded || m_state == Misconfigured) {
-            m_state = Failed;
-            throw std::logic_error("Plugin has not been initialised");
-        }
-        if (m_state == Finished) {
-            m_state = Failed;
-            throw std::logic_error("Plugin has already been disposed of");
-        }
-
-        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.framing.blockSize));
-        }
-
-        try {
-            return m_client->process(this, vecbuf, timestamp);
-        } catch (const std::exception &e) {
-            m_state = Failed;
-            throw;
-        }
-    }
-
-    virtual FeatureSet getRemainingFeatures() {
-
-        if (m_state == Failed) {
-            throw std::logic_error("Plugin is in failed state");
-        }
-        if (m_state == Loaded || m_state == Misconfigured) {
-            m_state = Failed;
-            throw std::logic_error("Plugin has not been configured");
-        }
-        if (m_state == Finished) {
-            m_state = Failed;
-            throw std::logic_error("Plugin has already been disposed of");
-        }
-
-        m_state = Finished;
-
-        try {
-            return m_client->finish(this);
-        } catch (const std::exception &e) {
-            m_state = Failed;
-            throw;
-        }
-    }
-
-    // Not Plugin methods, but needed by the PluginClient to support reloads:
-    
-    virtual float getInputSampleRate() const {
-        return m_inputSampleRate;
-    }
-
-    virtual std::string getPluginKey() const {
-        return m_key;
-    }
-
-    virtual int getAdapterFlags() const {
-        return m_adapterFlags;
-    }
-    
-private:
-    PluginClient *m_client;
-    std::string m_key;
-    int m_adapterFlags;
-    State m_state;
-    PluginStaticData m_psd;
-    OutputList m_outputs;
-    PluginConfiguration m_defaultConfig;
-    PluginConfiguration m_config;
-};
-
-}
-}
-
-#endif
--- a/vamp-client/qt/AutoPlugin.h	Thu Feb 09 14:19:38 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,235 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
-/*
-  Piper C++
-
-  An API for audio analysis and feature extraction plugins.
-
-  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 PIPER_AUTO_PLUGIN_H
-#define PIPER_AUTO_PLUGIN_H
-
-#include "ProcessQtTransport.h"
-#include "../CapnpRRClient.h"
-#include "../Exceptions.h"
-
-#include <cstdint>
-
-namespace piper_vamp {
-namespace client {
-
-/**
- * AutoPlugin presents a Piper feature extractor in the form of a Vamp
- * plugin, managing its own single-use server instance. That is, the
- * distinguishing quality of AutoPlugin (in comparison with
- * PluginStub) is that it runs and terminates its own Piper server,
- * whose lifetime matches that of the plugin.
- *
- * Example usage:
- *
- *    Vamp::Plugin *plugin = 
- *        new AutoPlugin("piper-server-name.exe",
- *                       "vamp-example-plugins:zerocrossing",
- *                       44100.0f,
- *                       Vamp::HostExt::PluginLoader::ADAPT_ALL_SAFE,
- *                       nullptr);
- *    plugin->initialise(...);
- *    plugin->process(...);       <-- in the normal way for a Vamp plugin
- *    delete plugin;              <-- causes the server to exit
- *
- * AutoPlugin makes use of the Loader and PluginClient interfaces,
- * providing them its own transport layer object for its single server.
- *
- * Note that any method may throw ServerCrashed, RequestTimedOut or
- * ProtocolError exceptions.
- */
-class AutoPlugin : public Vamp::Plugin
-{
-public:
-    /**
-     * Construct an AutoPlugin that runs an instance of the Piper
-     * server with the given server name (executable path), requesting
-     * the given plugin key from the server.
-     *
-     * \param adapterFlags a bitwise OR of the values in the
-     * Vamp::HostExt::PluginLoader::AdapterFlags enumeration
-     *
-     * \param logger an optional callback for log messages. Pass a
-     * null pointer to use cerr instead.
-     */
-    AutoPlugin(std::string serverName,
-               std::string pluginKey,
-               float inputSampleRate,
-               int adapterFlags,
-               LogCallback *logger) :
-        Vamp::Plugin(inputSampleRate),
-        m_logger(logger),
-        m_transport(serverName, "capnp", logger),
-        m_client(&m_transport, logger)
-    {
-        LoadRequest req;
-        req.pluginKey = pluginKey;
-        req.inputSampleRate = inputSampleRate;
-        req.adapterFlags = adapterFlags;
-        try {
-            LoadResponse resp = m_client.loadPlugin(req);
-            m_plugin = resp.plugin;
-        } catch (ServerCrashed c) {
-            log(std::string("AutoPlugin: Server crashed: ") + c.what());
-            m_plugin = 0;
-        }
-    }
-
-    virtual ~AutoPlugin() {
-        delete m_plugin;
-        // The transport is a plain data member and will be deleted
-        // here, which will have the effect of terminating the server
-    }
-
-    bool isOK() const {
-        return (m_plugin != nullptr);
-    }
-    
-    virtual std::string getIdentifier() const {
-        return getPlugin()->getIdentifier();
-    }
-
-    virtual std::string getName() const {
-        return getPlugin()->getName();
-    }
-
-    virtual std::string getDescription() const {
-        return getPlugin()->getDescription();
-    }
-
-    virtual std::string getMaker() const {
-        return getPlugin()->getMaker();
-    }
-
-    virtual std::string getCopyright() const {
-        return getPlugin()->getCopyright();
-    }
-
-    virtual int getPluginVersion() const {
-        return getPlugin()->getPluginVersion();
-    }
-
-    virtual ParameterList getParameterDescriptors() const {
-        return getPlugin()->getParameterDescriptors();
-    }
-
-    virtual float getParameter(std::string name) const {
-        return getPlugin()->getParameter(name);
-    }
-
-    virtual void setParameter(std::string name, float value) {
-        getPlugin()->setParameter(name, value);
-    }
-
-    virtual ProgramList getPrograms() const {
-        return getPlugin()->getPrograms();
-    }
-
-    virtual std::string getCurrentProgram() const {
-        return getPlugin()->getCurrentProgram();
-    }
-    
-    virtual void selectProgram(std::string program) {
-        getPlugin()->selectProgram(program);
-    }
-
-    virtual bool initialise(size_t inputChannels,
-                            size_t stepSize,
-                            size_t blockSize) {
-        return getPlugin()->initialise(inputChannels, stepSize, blockSize);
-    }
-
-    virtual void reset() {
-        getPlugin()->reset();
-    }
-
-    virtual InputDomain getInputDomain() const {
-        return getPlugin()->getInputDomain();
-    }
-
-    virtual size_t getPreferredBlockSize() const {
-        return getPlugin()->getPreferredBlockSize();
-    }
-
-    virtual size_t getPreferredStepSize() const {
-        return getPlugin()->getPreferredStepSize();
-    }
-
-    virtual size_t getMinChannelCount() const {
-        return getPlugin()->getMinChannelCount();
-    }
-
-    virtual size_t getMaxChannelCount() const {
-        return getPlugin()->getMaxChannelCount();
-    }
-
-    virtual OutputList getOutputDescriptors() const {
-        return getPlugin()->getOutputDescriptors();
-    }
-
-    virtual FeatureSet process(const float *const *inputBuffers,
-                               Vamp::RealTime timestamp) {
-        return getPlugin()->process(inputBuffers, timestamp);
-    }
-
-    virtual FeatureSet getRemainingFeatures() {
-        return getPlugin()->getRemainingFeatures();
-    }
-
-private:
-    LogCallback *m_logger;
-    ProcessQtTransport m_transport;
-    CapnpRRClient m_client;
-    Vamp::Plugin *m_plugin;
-    Vamp::Plugin *getPlugin() const {
-        if (!m_plugin) {
-            log("AutoPlugin: getPlugin() failed (caller should have called AutoPlugin::isOK)");
-            throw std::logic_error("Plugin load failed");
-        }
-        return m_plugin;
-    }
-
-    void log(std::string message) const {
-        if (m_logger) m_logger->log(message);
-        else std::cerr << message << std::endl;
-    }
-};
-
-}
-}
-
-#endif
-
-    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-client/qt/PiperAutoPlugin.h	Thu Feb 09 14:41:29 2017 +0000
@@ -0,0 +1,235 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+/*
+  Piper C++
+
+  An API for audio analysis and feature extraction plugins.
+
+  Centre for Digital Music, Queen Mary, University of London.
+  Copyright 2006-2017 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 PIPER_AUTO_PLUGIN_H
+#define PIPER_AUTO_PLUGIN_H
+
+#include "ProcessQtTransport.h"
+#include "../CapnpRRClient.h"
+#include "../Exceptions.h"
+
+#include <cstdint>
+
+namespace piper_vamp {
+namespace client {
+
+/**
+ * AutoPlugin presents a Piper feature extractor in the form of a Vamp
+ * plugin, managing its own single-use server instance. That is, the
+ * distinguishing quality of AutoPlugin (in comparison with
+ * PluginStub) is that it runs and terminates its own Piper server,
+ * whose lifetime matches that of the plugin.
+ *
+ * Example usage:
+ *
+ *    Vamp::Plugin *plugin = 
+ *        new AutoPlugin("piper-server-name.exe",
+ *                       "vamp-example-plugins:zerocrossing",
+ *                       44100.0f,
+ *                       Vamp::HostExt::PluginLoader::ADAPT_ALL_SAFE,
+ *                       nullptr);
+ *    plugin->initialise(...);
+ *    plugin->process(...);       <-- in the normal way for a Vamp plugin
+ *    delete plugin;              <-- causes the server to exit
+ *
+ * AutoPlugin makes use of the Loader and PluginClient interfaces,
+ * providing them its own transport layer object for its single server.
+ *
+ * Note that any method may throw ServerCrashed, RequestTimedOut or
+ * ProtocolError exceptions.
+ */
+class PiperAutoPlugin : public Vamp::Plugin
+{
+public:
+    /**
+     * Construct a PiperAutoPlugin that runs an instance of the Piper
+     * server with the given server name (executable path), requesting
+     * the given plugin key from the server.
+     *
+     * \param adapterFlags a bitwise OR of the values in the
+     * Vamp::HostExt::PluginLoader::AdapterFlags enumeration
+     *
+     * \param logger an optional callback for log messages. Pass a
+     * null pointer to use cerr instead.
+     */
+    PiperAutoPlugin(std::string serverName,
+                    std::string pluginKey,
+                    float inputSampleRate,
+                    int adapterFlags,
+                    LogCallback *logger) : // logger may be nullptr for cerr
+        Vamp::Plugin(inputSampleRate),
+        m_logger(logger),
+        m_transport(serverName, "capnp", logger),
+        m_client(&m_transport, logger)
+    {
+        LoadRequest req;
+        req.pluginKey = pluginKey;
+        req.inputSampleRate = inputSampleRate;
+        req.adapterFlags = adapterFlags;
+        try {
+            LoadResponse resp = m_client.load(req);
+            m_plugin = resp.plugin;
+        } catch (ServerCrashed c) {
+            log(std::string("PiperAutoPlugin: Server crashed: ") + c.what());
+            m_plugin = 0;
+        }
+    }
+
+    virtual ~PiperAutoPlugin() {
+        delete m_plugin;
+        // The transport is a plain data member and will be deleted
+        // here, which will have the effect of terminating the server
+    }
+
+    bool isOK() const {
+        return (m_plugin != nullptr);
+    }
+    
+    virtual std::string getIdentifier() const {
+        return getPlugin()->getIdentifier();
+    }
+
+    virtual std::string getName() const {
+        return getPlugin()->getName();
+    }
+
+    virtual std::string getDescription() const {
+        return getPlugin()->getDescription();
+    }
+
+    virtual std::string getMaker() const {
+        return getPlugin()->getMaker();
+    }
+
+    virtual std::string getCopyright() const {
+        return getPlugin()->getCopyright();
+    }
+
+    virtual int getPluginVersion() const {
+        return getPlugin()->getPluginVersion();
+    }
+
+    virtual ParameterList getParameterDescriptors() const {
+        return getPlugin()->getParameterDescriptors();
+    }
+
+    virtual float getParameter(std::string name) const {
+        return getPlugin()->getParameter(name);
+    }
+
+    virtual void setParameter(std::string name, float value) {
+        getPlugin()->setParameter(name, value);
+    }
+
+    virtual ProgramList getPrograms() const {
+        return getPlugin()->getPrograms();
+    }
+
+    virtual std::string getCurrentProgram() const {
+        return getPlugin()->getCurrentProgram();
+    }
+    
+    virtual void selectProgram(std::string program) {
+        getPlugin()->selectProgram(program);
+    }
+
+    virtual bool initialise(size_t inputChannels,
+                            size_t stepSize,
+                            size_t blockSize) {
+        return getPlugin()->initialise(inputChannels, stepSize, blockSize);
+    }
+
+    virtual void reset() {
+        getPlugin()->reset();
+    }
+
+    virtual InputDomain getInputDomain() const {
+        return getPlugin()->getInputDomain();
+    }
+
+    virtual size_t getPreferredBlockSize() const {
+        return getPlugin()->getPreferredBlockSize();
+    }
+
+    virtual size_t getPreferredStepSize() const {
+        return getPlugin()->getPreferredStepSize();
+    }
+
+    virtual size_t getMinChannelCount() const {
+        return getPlugin()->getMinChannelCount();
+    }
+
+    virtual size_t getMaxChannelCount() const {
+        return getPlugin()->getMaxChannelCount();
+    }
+
+    virtual OutputList getOutputDescriptors() const {
+        return getPlugin()->getOutputDescriptors();
+    }
+
+    virtual FeatureSet process(const float *const *inputBuffers,
+                               Vamp::RealTime timestamp) {
+        return getPlugin()->process(inputBuffers, timestamp);
+    }
+
+    virtual FeatureSet getRemainingFeatures() {
+        return getPlugin()->getRemainingFeatures();
+    }
+
+private:
+    LogCallback *m_logger;
+    ProcessQtTransport m_transport;
+    CapnpRRClient m_client;
+    Vamp::Plugin *m_plugin;
+    Vamp::Plugin *getPlugin() const {
+        if (!m_plugin) {
+            log("PiperAutoPlugin: getPlugin() failed (caller should have called PiperAutoPlugin::isOK)");
+            throw std::logic_error("Plugin load failed");
+        }
+        return m_plugin;
+    }
+
+    void log(std::string message) const {
+        if (m_logger) m_logger->log(message);
+        else std::cerr << message << std::endl;
+    }
+};
+
+}
+}
+
+#endif
+
+    
--- a/vamp-client/qt/test.cpp	Thu Feb 09 14:19:38 2017 +0000
+++ b/vamp-client/qt/test.cpp	Thu Feb 09 14:41:29 2017 +0000
@@ -35,7 +35,7 @@
 
 #include "ProcessQtTransport.h"
 #include "CapnpRRClient.h"
-#include "AutoPlugin.h"
+#include "PiperAutoPlugin.h"
 
 #include <stdexcept>
 
@@ -60,7 +60,7 @@
             
         piper_vamp::client::CapnpRRClient client(&transport, nullptr);
 
-        piper_vamp::ListResponse lr = client.listPluginData({});
+        piper_vamp::ListResponse lr = client.list({});
         cerr << "Plugins available:" << endl;
         int i = 1;
         for (const auto &p: lr.available) {
@@ -70,7 +70,7 @@
         piper_vamp::LoadRequest req;
         req.pluginKey = "vamp-example-plugins:zerocrossing";
         req.inputSampleRate = 16;
-        piper_vamp::LoadResponse resp = client.loadPlugin(req);
+        piper_vamp::LoadResponse resp = client.load(req);
         Vamp::Plugin *plugin = resp.plugin;
     
         if (!plugin->initialise(1, 4, 4)) {
@@ -107,13 +107,13 @@
 
         delete plugin;
 
-        // Let's try a crazy AutoPlugin
+        // Let's try a crazy PiperAutoPlugin
 
-        piper_vamp::client::AutoPlugin ap
+        piper_vamp::client::PiperAutoPlugin ap
             (argv[1], "vamp-example-plugins:zerocrossing", 16, 0, nullptr);
     
         if (!ap.isOK()) {
-            cerr << "AutoPlugin creation failed" << endl;
+            cerr << "PiperAutoPlugin creation failed" << endl;
         } else {
             if (!ap.initialise(1, 4, 4)) {
                 cerr << "initialisation failed" << endl;
--- a/vamp-client/qt/test.pro	Thu Feb 09 14:19:38 2017 +0000
+++ b/vamp-client/qt/test.pro	Thu Feb 09 14:41:29 2017 +0000
@@ -32,11 +32,11 @@
         
 HEADERS += \
         ProcessQtTransport.h \
-        AutoPlugin.h \
+        PiperAutoPlugin.h \
         ../CapnpRRClient.h \
         ../Loader.h \
         ../PluginClient.h \
-        ../PluginStub.h \
+        ../PiperVampPlugin.h \
         ../SynchronousTransport.h