changeset 57:09a1aac6c362 host-factory-stuff

* add wrapper base * make loader able to look up categories
author cannam
date Wed, 09 May 2007 15:21:37 +0000
parents 4ab6224110ef
children 0284955e31e5
files Makefile host/vamp-simple-host.cpp vamp-hostsdk/PluginInputDomainAdapter.cpp vamp-hostsdk/PluginInputDomainAdapter.h vamp-hostsdk/PluginLoader.cpp vamp-hostsdk/PluginLoader.h vamp-hostsdk/PluginWrapper.cpp vamp-hostsdk/PluginWrapper.h
diffstat 8 files changed, 457 insertions(+), 178 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Fri May 04 15:21:12 2007 +0000
+++ b/Makefile	Wed May 09 15:21:37 2007 +0000
@@ -80,6 +80,7 @@
 		$(HOSTSDKDIR)/PluginHostAdapter.h \
 		$(HOSTSDKDIR)/PluginInputDomainAdapter.h \
 		$(HOSTSDKDIR)/PluginLoader.h \
+		$(HOSTSDKDIR)/PluginWrapper.h \
 		$(SDKDIR)/RealTime.h
 
 SDK_OBJECTS	= \
@@ -90,6 +91,7 @@
 		$(HOSTSDKDIR)/PluginHostAdapter.o \
 		$(HOSTSDKDIR)/PluginInputDomainAdapter.o \
 		$(HOSTSDKDIR)/PluginLoader.o \
+		$(HOSTSDKDIR)/PluginWrapper.o \
 		$(SDKDIR)/RealTime.o
 
 SDK_STATIC	= \
--- a/host/vamp-simple-host.cpp	Fri May 04 15:21:12 2007 +0000
+++ b/host/vamp-simple-host.cpp	Wed May 09 15:21:37 2007 +0000
@@ -376,7 +376,7 @@
     LibraryMap libraryMap;
 
     for (size_t i = 0; i < plugins.size(); ++i) {
-        std::string path = loader.getLibraryPath(plugins[i]);
+        std::string path = loader.getLibraryPathForPlugin(plugins[i]);
         libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
     }
 
@@ -407,6 +407,17 @@
                  << plugin->getIdentifier() << "\"" << " ["
                  << plugin->getMaker() << "]" << endl;
 
+//            cerr << "looking up category for " << key << " ..." << endl;
+            Vamp::PluginLoader::PluginCategoryHierarchy category =
+                loader.getPluginCategory(key);
+            if (!category.empty()) {
+                cerr << "       ";
+                for (size_t ci = 0; ci < category.size(); ++ci) {
+                    cerr << " > " << category[ci];
+                }
+                cerr << endl;
+            }
+
             if (plugin->getDescription() != "") {
                 cerr << "        - " << plugin->getDescription() << endl;
             }
--- a/vamp-hostsdk/PluginInputDomainAdapter.cpp	Fri May 04 15:21:12 2007 +0000
+++ b/vamp-hostsdk/PluginInputDomainAdapter.cpp	Wed May 09 15:21:37 2007 +0000
@@ -41,8 +41,7 @@
 namespace Vamp {
 
 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
-    Plugin(0),
-    m_plugin(plugin),
+    PluginWrapper(plugin),
     m_channels(0),
     m_blockSize(0),
     m_freqbuf(0)
@@ -51,7 +50,6 @@
 
 PluginInputDomainAdapter::~PluginInputDomainAdapter()
 {
-    delete m_plugin;
 }
     
 bool
@@ -87,88 +85,10 @@
     return m_plugin->initialise(channels, stepSize, blockSize);
 }
 
-void
-PluginInputDomainAdapter::reset()
+Plugin::InputDomain
+PluginInputDomainAdapter::getInputDomain() const
 {
-    m_plugin->reset();
-}
-
-unsigned int
-PluginInputDomainAdapter::getVampApiVersion() const
-{
-    return m_plugin->getVampApiVersion();
-}
-
-std::string
-PluginInputDomainAdapter::getIdentifier() const
-{
-    return m_plugin->getIdentifier();
-}
-
-std::string
-PluginInputDomainAdapter::getName() const
-{
-    return m_plugin->getName();
-}
-
-std::string
-PluginInputDomainAdapter::getDescription() const
-{
-    return m_plugin->getDescription();
-}
-
-std::string
-PluginInputDomainAdapter::getMaker() const
-{
-    return m_plugin->getMaker();
-}
-
-int
-PluginInputDomainAdapter::getPluginVersion() const
-{
-    return m_plugin->getPluginVersion();
-}
-
-std::string
-PluginInputDomainAdapter::getCopyright() const
-{
-    return m_plugin->getCopyright();
-}
-
-PluginBase::ParameterList
-PluginInputDomainAdapter::getParameterDescriptors() const
-{
-    return m_plugin->getParameterDescriptors();
-}
-
-float
-PluginInputDomainAdapter::getParameter(std::string parameter) const
-{
-    return m_plugin->getParameter(parameter);
-}
-
-void
-PluginInputDomainAdapter::setParameter(std::string parameter, float value)
-{
-    m_plugin->setParameter(parameter, value);
-}
-
-PluginBase::ProgramList
-PluginInputDomainAdapter::getPrograms() const
-{
-    return m_plugin->getPrograms();
-}
-
-std::string
-PluginInputDomainAdapter::getCurrentProgram() const
-{
-    return m_plugin->getCurrentProgram();
-}
-
-void
-PluginInputDomainAdapter::selectProgram(std::string program)
-{
-    m_plugin->selectProgram(program);
+    return TimeDomain;
 }
 
 size_t
@@ -195,23 +115,6 @@
     return block;
 }
 
-size_t
-PluginInputDomainAdapter::getMinChannelCount() const
-{
-    return m_plugin->getMinChannelCount();
-}
-
-size_t PluginInputDomainAdapter::getMaxChannelCount() const
-{
-    return m_plugin->getMaxChannelCount();
-}
-
-Plugin::OutputList
-PluginInputDomainAdapter::getOutputDescriptors() const
-{
-    return m_plugin->getOutputDescriptors();
-}
-
 Plugin::FeatureSet
 PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
 {
@@ -249,12 +152,6 @@
     return m_plugin->process(m_freqbuf, timestamp);
 }
 
-Plugin::FeatureSet
-PluginInputDomainAdapter::getRemainingFeatures()
-{
-    return m_plugin->getRemainingFeatures();
-}
-
 void
 PluginInputDomainAdapter::fft(unsigned int n, bool inverse,
                               double *ri, double *ii, double *ro, double *io)
--- a/vamp-hostsdk/PluginInputDomainAdapter.h	Fri May 04 15:21:12 2007 +0000
+++ b/vamp-hostsdk/PluginInputDomainAdapter.h	Wed May 09 15:21:37 2007 +0000
@@ -36,7 +36,7 @@
 
 #ifndef _PLUGIN_INPUT_DOMAIN_ADAPTER_H_
 
-#include <vamp-sdk/Plugin.h>
+#include "PluginWrapper.h"
 
 namespace Vamp {
 
@@ -62,45 +62,21 @@
 //delegates all calls through to it; the subclass can then override
 //only the ones it needs to handle.
 
-class PluginInputDomainAdapter : public Plugin
+class PluginInputDomainAdapter : public PluginWrapper
 {
 public:
     PluginInputDomainAdapter(Plugin *plugin); // I take ownership of plugin
     virtual ~PluginInputDomainAdapter();
     
     bool initialise(size_t channels, size_t stepSize, size_t blockSize);
-    void reset();
 
-    InputDomain getInputDomain() const { return Plugin::TimeDomain; }
-
-    unsigned int getVampApiVersion() const;
-    std::string getIdentifier() const;
-    std::string getName() const;
-    std::string getDescription() const;
-    std::string getMaker() const;
-    int getPluginVersion() const;
-    std::string getCopyright() const;
-
-    ParameterList getParameterDescriptors() const;
-    float getParameter(std::string) const;
-    void setParameter(std::string, float);
-
-    ProgramList getPrograms() const;
-    std::string getCurrentProgram() const;
-    void selectProgram(std::string);
+    InputDomain getInputDomain() const;
 
     size_t getPreferredStepSize() const;
     size_t getPreferredBlockSize() const;
 
-    size_t getMinChannelCount() const;
-    size_t getMaxChannelCount() const;
-
-    OutputList getOutputDescriptors() const;
-
     FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
 
-    FeatureSet getRemainingFeatures();
-
 protected:
     Plugin *m_plugin;
     size_t m_channels;
--- a/vamp-hostsdk/PluginLoader.cpp	Fri May 04 15:21:12 2007 +0000
+++ b/vamp-hostsdk/PluginLoader.cpp	Wed May 09 15:21:37 2007 +0000
@@ -39,8 +39,12 @@
 
 #include "system.h"
 
+#include <fstream>
+
 #include <dirent.h> // POSIX directory open and read
 
+using namespace std;
+
 namespace Vamp {
 	
 PluginLoader::PluginLoader()
@@ -51,47 +55,34 @@
 {
 }
 
-std::vector<PluginLoader::PluginKey>
+vector<PluginLoader::PluginKey>
 PluginLoader::listPlugins() 
 {
     if (m_pluginLibraryMap.empty()) {
 
-        std::vector<std::string> path = PluginHostAdapter::getPluginPath();
+        vector<string> path = PluginHostAdapter::getPluginPath();
 
         size_t suffixLen = strlen(PLUGIN_SUFFIX);
 
         for (size_t i = 0; i < path.size(); ++i) {
+            
+            vector<string> files = getFilesInDir(path[i], PLUGIN_SUFFIX);
+            
 
-            DIR *d = opendir(path[i].c_str());
-            if (!d) {
-//                perror("Failed to open directory");
-                continue;
-            }
-            
-            struct dirent *e = 0;
-            while ((e = readdir(d))) {
+            for (vector<string>::iterator fi = files.begin();
+                 fi != files.end(); ++fi) {
 
-                if (!(e->d_type & DT_REG) || !e->d_name) {
-                    continue;
-                }
+                string basename = *fi;
+                basename = basename.substr(0, basename.length() - suffixLen - 1);
 
-                int len = strlen(e->d_name);
-                if (len < int(suffixLen + 2) ||
-                    e->d_name[len - suffixLen - 1] != '.' ||
-                    strcmp(e->d_name + len - suffixLen, PLUGIN_SUFFIX)) {
-                    continue;
-                }
-
-                std::string basename = e->d_name;
-                basename = basename.substr(0, basename.length() - suffixLen - 1);
-                std::string fullPath = path[i].c_str();
-                fullPath = fullPath + "/" + e->d_name;
+                string fullPath = path[i];
+                fullPath = fullPath + "/" + *fi; //!!! systemize
                 void *handle = DLOPEN(fullPath, RTLD_LAZY);
 
                 if (!handle) {
-                    std::cerr << "Vamp::PluginLoader: " << e->d_name
+                    cerr << "Vamp::PluginLoader: " << *fi
                               << ": unable to load library (" << DLERROR()
-                              << ")" << std::endl;
+                              << ")" << endl;
                     continue;
                 }
             
@@ -118,13 +109,11 @@
 
                 DLCLOSE(handle);
             }
-
-            closedir(d);
         }
     }
 
-    std::vector<PluginKey> plugins;
-    for (std::map<PluginKey, std::string>::iterator mi =
+    vector<PluginKey> plugins;
+    for (map<PluginKey, string>::iterator mi =
              m_pluginLibraryMap.begin();
          mi != m_pluginLibraryMap.end(); ++mi) {
         plugins.push_back(mi->first);
@@ -133,34 +122,42 @@
     return plugins;
 }
 
-std::string
-PluginLoader::getLibraryPath(PluginKey key)
+PluginLoader::PluginCategoryHierarchy
+PluginLoader::getPluginCategory(PluginKey plugin)
+{
+    if (m_taxonomy.empty()) generateTaxonomy();
+    if (m_taxonomy.find(plugin) == m_taxonomy.end()) return PluginCategoryHierarchy();
+    return m_taxonomy[plugin];
+}
+
+string
+PluginLoader::getLibraryPathForPlugin(PluginKey plugin)
 {
     if (m_pluginLibraryMap.empty()) (void)listPlugins();
-    if (m_pluginLibraryMap.find(key) == m_pluginLibraryMap.end()) return "";
-    return m_pluginLibraryMap[key];
+    if (m_pluginLibraryMap.find(plugin) == m_pluginLibraryMap.end()) return "";
+    return m_pluginLibraryMap[plugin];
 }    
 
 Plugin *
 PluginLoader::load(PluginKey key, float inputSampleRate)
 {
-    std::string fullPath = getLibraryPath(key);
+    string fullPath = getLibraryPathForPlugin(key);
     if (fullPath == "") return 0;
     
-    std::string::size_type ki = key.find(':');
-    if (ki == std::string::npos) {
+    string::size_type ki = key.find(':');
+    if (ki == string::npos) {
         //!!! flag error
         return 0;
     }
 
-    std::string identifier = key.substr(ki + 1);
+    string identifier = key.substr(ki + 1);
     
     void *handle = DLOPEN(fullPath, RTLD_LAZY);
 
     if (!handle) {
-        std::cerr << "Vamp::PluginLoader: " << fullPath
+        cerr << "Vamp::PluginLoader: " << fullPath
                   << ": unable to load library (" << DLERROR()
-                  << ")" << std::endl;
+                  << ")" << endl;
         return 0;
     }
     
@@ -179,7 +176,7 @@
     const VampPluginDescriptor *descriptor = 0;
 
     while ((descriptor = fn(VAMP_API_VERSION, index))) {
-        if (std::string(descriptor->identifier) == identifier) {
+        if (string(descriptor->identifier) == identifier) {
             return new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
         }
         ++index;
@@ -189,5 +186,118 @@
     return 0;
 }
 
+vector<string>
+PluginLoader::getFilesInDir(string dir, string extension)
+{
+    vector<string> files;
+
+    DIR *d = opendir(dir.c_str());
+    if (!d) return files;
+            
+    struct dirent *e = 0;
+    while ((e = readdir(d))) {
+        
+        if (!(e->d_type & DT_REG) || !e->d_name) {
+            continue;
+        }
+        
+        int len = strlen(e->d_name);
+        if (len < int(extension.length() + 2) ||
+            e->d_name[len - extension.length() - 1] != '.' ||
+            strcmp(e->d_name + len - extension.length(), extension.c_str())) {
+            continue;
+        }
+
+        files.push_back(e->d_name);
+    }
+
+    closedir(d);
+
+    return files;
 }
 
+void
+PluginLoader::generateTaxonomy()
+{
+//    cerr << "PluginLoader::generateTaxonomy" << endl;
+
+    vector<string> path = PluginHostAdapter::getPluginPath();
+    string libfragment = "/lib/";
+    vector<string> catpath;
+
+    string suffix = "cat";
+
+    for (vector<string>::iterator i = path.begin();
+         i != path.end(); ++i) {
+        
+        string dir = *i;
+        string::size_type li = dir.find(libfragment);
+
+        if (li != string::npos) {
+            catpath.push_back
+                (dir.substr(0, li)
+                 + "/share/"
+                 + dir.substr(li + libfragment.length()));
+        }
+
+        catpath.push_back(dir);
+    }
+
+    char buffer[1024];
+
+    for (vector<string>::iterator i = catpath.begin();
+         i != catpath.end(); ++i) {
+        
+        vector<string> files = getFilesInDir(*i, suffix);
+
+        for (vector<string>::iterator fi = files.begin();
+             fi != files.end(); ++fi) {
+
+            string filepath = *i + "/" + *fi; //!!! systemize
+            ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
+
+            if (is.fail()) {
+//                cerr << "failed to open: " << filepath << endl;
+                continue;
+            }
+
+//            cerr << "opened: " << filepath << endl;
+
+            while (!!is.getline(buffer, 1024)) {
+
+                string line(buffer);
+
+//                cerr << "line = " << line << endl;
+
+                string::size_type di = line.find("::");
+                if (di == string::npos) continue;
+
+                string id = line.substr(0, di);
+                string encodedCat = line.substr(di + 2);
+
+                if (id.substr(0, 5) != "vamp:") continue;
+                id = id.substr(5);
+
+                while (encodedCat.length() >= 1 &&
+                       encodedCat[encodedCat.length()-1] == '\r') {
+                    encodedCat = encodedCat.substr(0, encodedCat.length()-1);
+                }
+
+//                cerr << "id = " << id << ", cat = " << encodedCat << endl;
+
+                PluginCategoryHierarchy category;
+                string::size_type ai;
+                while ((ai = encodedCat.find(" > ")) != string::npos) {
+                    category.push_back(encodedCat.substr(0, ai));
+                    encodedCat = encodedCat.substr(ai + 3);
+                }
+                if (encodedCat != "") category.push_back(encodedCat);
+
+                m_taxonomy[id] = category;
+            }
+        }
+    }
+}    
+
+
+}
--- a/vamp-hostsdk/PluginLoader.h	Fri May 04 15:21:12 2007 +0000
+++ b/vamp-hostsdk/PluginLoader.h	Wed May 09 15:21:37 2007 +0000
@@ -52,6 +52,7 @@
     virtual ~PluginLoader();
 
     typedef std::string PluginKey;
+    typedef std::vector<std::string> PluginCategoryHierarchy;
 
     std::vector<PluginKey> listPlugins(); //!!! pass in version number?
 
@@ -59,12 +60,17 @@
     //have to consider library loading issues -- do we have a wrapper
     //class that tells us when it's been deleted, and keep a reference
     //count for the dynamic library?
-    Plugin *load(PluginKey key, float inputSampleRate);
+    Plugin *load(PluginKey plugin, float inputSampleRate);
 
-    std::string getLibraryPath(PluginKey key);
+    PluginCategoryHierarchy getPluginCategory(PluginKey plugin);
+
+    std::string getLibraryPathForPlugin(PluginKey plugin);
 
 protected:
     std::map<PluginKey, std::string> m_pluginLibraryMap;
+    std::map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
+    void generateTaxonomy();
+    std::vector<std::string> getFilesInDir(std::string dir, std::string ext);
 };
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-hostsdk/PluginWrapper.cpp	Wed May 09 15:21:37 2007 +0000
@@ -0,0 +1,189 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Vamp
+
+    An API for audio analysis and feature extraction plugins.
+
+    Centre for Digital Music, Queen Mary, University of London.
+    Copyright 2006 Chris Cannam.
+  
+    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.
+*/
+
+#include "PluginWrapper.h"
+
+namespace Vamp {
+
+PluginWrapper::PluginWrapper(Plugin *plugin) :
+    Plugin(0)
+{
+}
+
+PluginWrapper::~PluginWrapper()
+{
+    delete m_plugin;
+}
+    
+bool
+PluginWrapper::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    return m_plugin->initialise(channels, stepSize, blockSize);
+}
+
+void
+PluginWrapper::reset()
+{
+    m_plugin->reset();
+}
+
+Plugin::InputDomain
+PluginWrapper::getInputDomain() const
+{
+    return m_plugin->getInputDomain();
+}
+
+unsigned int
+PluginWrapper::getVampApiVersion() const
+{
+    return m_plugin->getVampApiVersion();
+}
+
+std::string
+PluginWrapper::getIdentifier() const
+{
+    return m_plugin->getIdentifier();
+}
+
+std::string
+PluginWrapper::getName() const
+{
+    return m_plugin->getName();
+}
+
+std::string
+PluginWrapper::getDescription() const
+{
+    return m_plugin->getDescription();
+}
+
+std::string
+PluginWrapper::getMaker() const
+{
+    return m_plugin->getMaker();
+}
+
+int
+PluginWrapper::getPluginVersion() const
+{
+    return m_plugin->getPluginVersion();
+}
+
+std::string
+PluginWrapper::getCopyright() const
+{
+    return m_plugin->getCopyright();
+}
+
+PluginBase::ParameterList
+PluginWrapper::getParameterDescriptors() const
+{
+    return m_plugin->getParameterDescriptors();
+}
+
+float
+PluginWrapper::getParameter(std::string parameter) const
+{
+    return m_plugin->getParameter(parameter);
+}
+
+void
+PluginWrapper::setParameter(std::string parameter, float value)
+{
+    m_plugin->setParameter(parameter, value);
+}
+
+PluginBase::ProgramList
+PluginWrapper::getPrograms() const
+{
+    return m_plugin->getPrograms();
+}
+
+std::string
+PluginWrapper::getCurrentProgram() const
+{
+    return m_plugin->getCurrentProgram();
+}
+
+void
+PluginWrapper::selectProgram(std::string program)
+{
+    m_plugin->selectProgram(program);
+}
+
+size_t
+PluginWrapper::getPreferredStepSize() const
+{
+    return m_plugin->getPreferredStepSize();
+}
+
+size_t
+PluginWrapper::getPreferredBlockSize() const
+{
+    return m_plugin->getPreferredBlockSize();
+}
+
+size_t
+PluginWrapper::getMinChannelCount() const
+{
+    return m_plugin->getMinChannelCount();
+}
+
+size_t PluginWrapper::getMaxChannelCount() const
+{
+    return m_plugin->getMaxChannelCount();
+}
+
+Plugin::OutputList
+PluginWrapper::getOutputDescriptors() const
+{
+    return m_plugin->getOutputDescriptors();
+}
+
+Plugin::FeatureSet
+PluginWrapper::process(const float *const *inputBuffers, RealTime timestamp)
+{
+    return m_plugin->process(inputBuffers, timestamp);
+}
+
+Plugin::FeatureSet
+PluginWrapper::getRemainingFeatures()
+{
+    return m_plugin->getRemainingFeatures();
+}
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-hostsdk/PluginWrapper.h	Wed May 09 15:21:37 2007 +0000
@@ -0,0 +1,88 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Vamp
+
+    An API for audio analysis and feature extraction plugins.
+
+    Centre for Digital Music, Queen Mary, University of London.
+    Copyright 2006 Chris Cannam.
+  
+    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 _PLUGIN_WRAPPER_H_
+
+#include <vamp-sdk/Plugin.h>
+
+namespace Vamp {
+
+class PluginWrapper : public Plugin
+{
+public:
+    virtual ~PluginWrapper();
+    
+    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+    void reset();
+
+    InputDomain getInputDomain() const;
+
+    unsigned int getVampApiVersion() const;
+    std::string getIdentifier() const;
+    std::string getName() const;
+    std::string getDescription() const;
+    std::string getMaker() const;
+    int getPluginVersion() const;
+    std::string getCopyright() const;
+
+    ParameterList getParameterDescriptors() const;
+    float getParameter(std::string) const;
+    void setParameter(std::string, float);
+
+    ProgramList getPrograms() const;
+    std::string getCurrentProgram() const;
+    void selectProgram(std::string);
+
+    size_t getPreferredStepSize() const;
+    size_t getPreferredBlockSize() const;
+
+    size_t getMinChannelCount() const;
+    size_t getMaxChannelCount() const;
+
+    OutputList getOutputDescriptors() const;
+
+    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
+
+    FeatureSet getRemainingFeatures();
+
+protected:
+    PluginWrapper(Plugin *plugin); // I take ownership of plugin
+    Plugin *m_plugin;
+};
+
+}
+
+#endif