changeset 227:6b30e064cab7 distinct-libraries

* more moving
author cannam
date Thu, 06 Nov 2008 14:13:12 +0000
parents 14029eb08472
children e58242c9ff85
files examples/AmplitudeFollower.cpp examples/FixedTempoEstimator.cpp examples/PercussionOnsetDetector.cpp examples/SpectralCentroid.cpp examples/ZeroCrossing.cpp examples/plugins.cpp host/vamp-simple-host.cpp src/AmplitudeFollower.cpp src/FixedTempoEstimator.cpp src/PercussionOnsetDetector.cpp src/PluginAdapter.cpp src/PluginHostAdapter.cpp src/RealTime.cpp src/SpectralCentroid.cpp src/ZeroCrossing.cpp src/plugins.cpp src/vamp-hostsdk/PluginHostAdapter.cpp src/vamp-hostsdk/hostext/PluginBufferingAdapter.cpp src/vamp-hostsdk/hostext/PluginChannelAdapter.cpp src/vamp-hostsdk/hostext/PluginInputDomainAdapter.cpp src/vamp-hostsdk/hostext/PluginLoader.cpp src/vamp-hostsdk/hostext/PluginSummarisingAdapter.cpp src/vamp-hostsdk/hostext/PluginWrapper.cpp src/vamp-sdk/PluginAdapter.cpp src/vamp-sdk/RealTime.cpp src/vamp-simple-host.cpp vamp-hostsdk/hostext/PluginBufferingAdapter.h vamp-hostsdk/hostext/PluginChannelAdapter.h vamp-hostsdk/hostext/PluginInputDomainAdapter.h vamp-hostsdk/hostext/PluginLoader.h vamp-hostsdk/hostext/PluginSummarisingAdapter.h vamp-hostsdk/hostext/PluginWrapper.h vamp-sdk/hostext/PluginBufferingAdapter.cpp vamp-sdk/hostext/PluginBufferingAdapter.h vamp-sdk/hostext/PluginChannelAdapter.cpp vamp-sdk/hostext/PluginChannelAdapter.h vamp-sdk/hostext/PluginInputDomainAdapter.cpp vamp-sdk/hostext/PluginInputDomainAdapter.h vamp-sdk/hostext/PluginLoader.cpp vamp-sdk/hostext/PluginLoader.h vamp-sdk/hostext/PluginSummarisingAdapter.cpp vamp-sdk/hostext/PluginSummarisingAdapter.h vamp-sdk/hostext/PluginWrapper.cpp vamp-sdk/hostext/PluginWrapper.h
diffstat 44 files changed, 7933 insertions(+), 7933 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/AmplitudeFollower.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,247 @@
+/* -*- 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.
+    This file copyright 2006 Dan Stowell.
+  
+    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 "AmplitudeFollower.h"
+
+#include <cmath>
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+
+/**
+ * An implementation of SuperCollider's amplitude-follower algorithm
+ * as a simple Vamp plugin.
+ */
+
+AmplitudeFollower::AmplitudeFollower(float inputSampleRate) :
+    Plugin(inputSampleRate),
+    m_stepSize(0),
+    m_previn(0.0f),
+    m_clampcoef(0.01f),
+    m_relaxcoef(0.01f)
+{
+}
+
+AmplitudeFollower::~AmplitudeFollower()
+{
+}
+
+string
+AmplitudeFollower::getIdentifier() const
+{
+    return "amplitudefollower";
+}
+
+string
+AmplitudeFollower::getName() const
+{
+    return "Amplitude Follower";
+}
+
+string
+AmplitudeFollower::getDescription() const
+{
+    return "Track the amplitude of the audio signal";
+}
+
+string
+AmplitudeFollower::getMaker() const
+{
+    return "Vamp SDK Example Plugins";
+}
+
+int
+AmplitudeFollower::getPluginVersion() const
+{
+    return 1;
+}
+
+string
+AmplitudeFollower::getCopyright() const
+{
+    return "Code copyright 2006 Dan Stowell; method from SuperCollider.  Freely redistributable (BSD license)";
+}
+
+bool
+AmplitudeFollower::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    if (channels < getMinChannelCount() ||
+	channels > getMaxChannelCount()) return false;
+
+    m_stepSize = std::min(stepSize, blockSize);
+	
+    // Translate the coefficients 
+    // from their "convenient" 60dB convergence-time values
+    // to real coefficients
+    m_clampcoef = m_clampcoef==0.0 ? 0.0 : exp(log(0.1)/(m_clampcoef * m_inputSampleRate));
+    m_relaxcoef = m_relaxcoef==0.0 ? 0.0 : exp(log(0.1)/(m_relaxcoef * m_inputSampleRate));
+
+    return true;
+}
+
+void
+AmplitudeFollower::reset()
+{
+    m_previn = 0.0f;
+}
+
+AmplitudeFollower::OutputList
+AmplitudeFollower::getOutputDescriptors() const
+{
+    OutputList list;
+
+    OutputDescriptor sca;
+    sca.identifier = "amplitude";
+    sca.name = "Amplitude";
+    sca.description = "";
+    sca.unit = "V";
+    sca.hasFixedBinCount = true;
+    sca.binCount = 1;
+    sca.hasKnownExtents = false;
+    sca.isQuantized = false;
+    sca.sampleType = OutputDescriptor::OneSamplePerStep;
+    list.push_back(sca);
+
+    return list;
+}
+
+AmplitudeFollower::ParameterList
+AmplitudeFollower::getParameterDescriptors() const
+{
+    ParameterList list;
+	
+    ParameterDescriptor att;
+    att.identifier = "attack";
+    att.name = "Attack time";
+    att.description = "";
+    att.unit = "s";
+    att.minValue = 0.0f;
+    att.maxValue = 1.f;
+    att.defaultValue = 0.01f;
+    att.isQuantized = false;
+    
+    list.push_back(att);
+    
+    ParameterDescriptor dec;
+    dec.identifier = "release";
+    dec.name = "Release time";
+    dec.description = "";
+    dec.unit = "s";
+    dec.minValue = 0.0f;
+    dec.maxValue = 1.f;
+    dec.defaultValue = 0.01f;
+    dec.isQuantized = false;
+    
+    list.push_back(dec);
+    
+    return list;
+}
+
+void AmplitudeFollower::setParameter(std::string paramid, float newval)
+{
+    if (paramid == "attack") {
+        m_clampcoef = newval;
+    } else if (paramid == "release") {
+        m_relaxcoef = newval;
+    }
+}
+
+float AmplitudeFollower::getParameter(std::string paramid) const
+{
+    if (paramid == "attack") {
+        return m_clampcoef;
+    } else if (paramid == "release") {
+        return m_relaxcoef;
+    }
+
+    return 0.0f;
+}
+
+AmplitudeFollower::FeatureSet
+AmplitudeFollower::process(const float *const *inputBuffers,
+                           Vamp::RealTime timestamp)
+{
+    if (m_stepSize == 0) {
+	cerr << "ERROR: AmplitudeFollower::process: "
+	     << "AmplitudeFollower has not been initialised"
+	     << endl;
+	return FeatureSet();
+    }
+
+    float previn = m_previn;
+
+    FeatureSet returnFeatures;
+	
+    float val;
+    float peak = 0.0f;
+
+    for (size_t i = 0; i < m_stepSize; ++i) {
+
+        val = fabs(inputBuffers[0][i]);
+		
+        if (val < previn) {
+            val = val + (previn - val) * m_relaxcoef;
+        } else {
+            val = val + (previn - val) * m_clampcoef;
+        }
+
+        if (val > peak) peak = val;
+        previn = val;
+    }
+
+    m_previn = previn;
+
+    // Now store the "feature" (peak amp) for this sample
+    Feature feature;
+    feature.hasTimestamp = false;
+    feature.values.push_back(peak);
+    returnFeatures[0].push_back(feature);
+
+    return returnFeatures;
+}
+
+AmplitudeFollower::FeatureSet
+AmplitudeFollower::getRemainingFeatures()
+{
+    return FeatureSet();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/FixedTempoEstimator.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,534 @@
+/* -*- 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-2008 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.
+*/
+
+#include "FixedTempoEstimator.h"
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+
+using Vamp::RealTime;
+
+#include <cmath>
+
+
+FixedTempoEstimator::FixedTempoEstimator(float inputSampleRate) :
+    Plugin(inputSampleRate),
+    m_stepSize(0),
+    m_blockSize(0),
+    m_priorMagnitudes(0),
+    m_df(0),
+    m_r(0),
+    m_fr(0),
+    m_t(0),
+    m_n(0)
+{
+}
+
+FixedTempoEstimator::~FixedTempoEstimator()
+{
+    delete[] m_priorMagnitudes;
+    delete[] m_df;
+    delete[] m_r;
+    delete[] m_fr;
+    delete[] m_t;
+}
+
+string
+FixedTempoEstimator::getIdentifier() const
+{
+    return "fixedtempo";
+}
+
+string
+FixedTempoEstimator::getName() const
+{
+    return "Simple Fixed Tempo Estimator";
+}
+
+string
+FixedTempoEstimator::getDescription() const
+{
+    return "Study a short section of audio and estimate its tempo, assuming the tempo is constant";
+}
+
+string
+FixedTempoEstimator::getMaker() const
+{
+    return "Vamp SDK Example Plugins";
+}
+
+int
+FixedTempoEstimator::getPluginVersion() const
+{
+    return 1;
+}
+
+string
+FixedTempoEstimator::getCopyright() const
+{
+    return "Code copyright 2008 Queen Mary, University of London.  Freely redistributable (BSD license)";
+}
+
+size_t
+FixedTempoEstimator::getPreferredStepSize() const
+{
+    return 64;
+}
+
+size_t
+FixedTempoEstimator::getPreferredBlockSize() const
+{
+    return 256;
+}
+
+bool
+FixedTempoEstimator::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    if (channels < getMinChannelCount() ||
+	channels > getMaxChannelCount()) return false;
+
+    m_stepSize = stepSize;
+    m_blockSize = blockSize;
+
+    float dfLengthSecs = 10.f;
+    m_dfsize = (dfLengthSecs * m_inputSampleRate) / m_stepSize;
+
+    m_priorMagnitudes = new float[m_blockSize/2];
+    m_df = new float[m_dfsize];
+
+    for (size_t i = 0; i < m_blockSize/2; ++i) {
+        m_priorMagnitudes[i] = 0.f;
+    }
+    for (size_t i = 0; i < m_dfsize; ++i) {
+        m_df[i] = 0.f;
+    }
+
+    m_n = 0;
+
+    return true;
+}
+
+void
+FixedTempoEstimator::reset()
+{
+    cerr << "FixedTempoEstimator: reset called" << endl;
+
+    if (!m_priorMagnitudes) return;
+
+    cerr << "FixedTempoEstimator: resetting" << endl;
+
+    for (size_t i = 0; i < m_blockSize/2; ++i) {
+        m_priorMagnitudes[i] = 0.f;
+    }
+    for (size_t i = 0; i < m_dfsize; ++i) {
+        m_df[i] = 0.f;
+    }
+
+    delete[] m_r;
+    m_r = 0;
+
+    delete[] m_fr; 
+    m_fr = 0;
+
+    delete[] m_t; 
+    m_t = 0;
+
+    m_n = 0;
+
+    m_start = RealTime::zeroTime;
+    m_lasttime = RealTime::zeroTime;
+}
+
+FixedTempoEstimator::ParameterList
+FixedTempoEstimator::getParameterDescriptors() const
+{
+    ParameterList list;
+    return list;
+}
+
+float
+FixedTempoEstimator::getParameter(std::string id) const
+{
+    return 0.f;
+}
+
+void
+FixedTempoEstimator::setParameter(std::string id, float value)
+{
+}
+
+static int TempoOutput = 0;
+static int CandidatesOutput = 1;
+static int DFOutput = 2;
+static int ACFOutput = 3;
+static int FilteredACFOutput = 4;
+
+FixedTempoEstimator::OutputList
+FixedTempoEstimator::getOutputDescriptors() const
+{
+    OutputList list;
+
+    OutputDescriptor d;
+    d.identifier = "tempo";
+    d.name = "Tempo";
+    d.description = "Estimated tempo";
+    d.unit = "bpm";
+    d.hasFixedBinCount = true;
+    d.binCount = 1;
+    d.hasKnownExtents = false;
+    d.isQuantized = false;
+    d.sampleType = OutputDescriptor::VariableSampleRate;
+    d.sampleRate = m_inputSampleRate;
+    d.hasDuration = true; // our returned tempo spans a certain range
+    list.push_back(d);
+
+    d.identifier = "candidates";
+    d.name = "Tempo candidates";
+    d.description = "Possible tempo estimates, one per bin with the most likely in the first bin";
+    d.unit = "bpm";
+    d.hasFixedBinCount = false;
+    list.push_back(d);
+
+    d.identifier = "detectionfunction";
+    d.name = "Detection Function";
+    d.description = "Onset detection function";
+    d.unit = "";
+    d.hasFixedBinCount = 1;
+    d.binCount = 1;
+    d.hasKnownExtents = true;
+    d.minValue = 0.0;
+    d.maxValue = 1.0;
+    d.isQuantized = false;
+    d.quantizeStep = 0.0;
+    d.sampleType = OutputDescriptor::FixedSampleRate;
+    if (m_stepSize) {
+        d.sampleRate = m_inputSampleRate / m_stepSize;
+    } else {
+        d.sampleRate = m_inputSampleRate / (getPreferredBlockSize()/2);
+    }
+    d.hasDuration = false;
+    list.push_back(d);
+
+    d.identifier = "acf";
+    d.name = "Autocorrelation Function";
+    d.description = "Autocorrelation of onset detection function";
+    d.hasKnownExtents = false;
+    d.unit = "r";
+    list.push_back(d);
+
+    d.identifier = "filtered_acf";
+    d.name = "Filtered Autocorrelation";
+    d.description = "Filtered autocorrelation of onset detection function";
+    d.unit = "r";
+    list.push_back(d);
+
+    return list;
+}
+
+FixedTempoEstimator::FeatureSet
+FixedTempoEstimator::process(const float *const *inputBuffers, RealTime ts)
+{
+    FeatureSet fs;
+
+    if (m_stepSize == 0) {
+	cerr << "ERROR: FixedTempoEstimator::process: "
+	     << "FixedTempoEstimator has not been initialised"
+	     << endl;
+	return fs;
+    }
+
+//    if (m_n < m_dfsize) cerr << "m_n = " << m_n << endl;
+
+    if (m_n == 0) m_start = ts;
+    m_lasttime = ts;
+
+    if (m_n == m_dfsize) {
+        calculate();
+        fs = assembleFeatures();
+        ++m_n;
+        return fs;
+    }
+
+    if (m_n > m_dfsize) return FeatureSet();
+
+    float value = 0.f;
+
+    for (size_t i = 1; i < m_blockSize/2; ++i) {
+
+        float real = inputBuffers[0][i*2];
+        float imag = inputBuffers[0][i*2 + 1];
+
+        float sqrmag = real * real + imag * imag;
+        value += fabsf(sqrmag - m_priorMagnitudes[i]);
+
+        m_priorMagnitudes[i] = sqrmag;
+    }
+
+    m_df[m_n] = value;
+
+    ++m_n;
+    return fs;
+}
+
+FixedTempoEstimator::FeatureSet
+FixedTempoEstimator::getRemainingFeatures()
+{
+    FeatureSet fs;
+    if (m_n > m_dfsize) return fs;
+    calculate();
+    fs = assembleFeatures();
+    ++m_n;
+    return fs;
+}
+
+float
+FixedTempoEstimator::lag2tempo(int lag)
+{
+    return 60.f / ((lag * m_stepSize) / m_inputSampleRate);
+}
+
+int
+FixedTempoEstimator::tempo2lag(float tempo)
+{
+    return ((60.f / tempo) * m_inputSampleRate) / m_stepSize;
+}
+
+void
+FixedTempoEstimator::calculate()
+{    
+    cerr << "FixedTempoEstimator::calculate: m_n = " << m_n << endl;
+    
+    if (m_r) {
+        cerr << "FixedTempoEstimator::calculate: calculation already happened?" << endl;
+        return;
+    }
+
+    if (m_n < m_dfsize / 9) {
+        cerr << "FixedTempoEstimator::calculate: Not enough data to go on (have " << m_n << ", want at least " << m_dfsize/4 << ")" << endl;
+        return; // not enough data (perhaps we should return the duration of the input as the "estimated" beat length?)
+    }
+
+    int n = m_n;
+
+    m_r = new float[n/2];
+    m_fr = new float[n/2];
+    m_t = new float[n/2];
+
+    for (int i = 0; i < n/2; ++i) {
+        m_r[i] = 0.f;
+        m_fr[i] = 0.f;
+        m_t[i] = lag2tempo(i);
+    }
+
+    for (int i = 0; i < n/2; ++i) {
+
+        for (int j = i; j < n-1; ++j) {
+            m_r[i] += m_df[j] * m_df[j - i];
+        }
+
+        m_r[i] /= n - i - 1;
+    }
+
+    float related[] = { 0.5, 2, 3, 4 };
+
+    for (int i = 1; i < n/2-1; ++i) {
+
+        float weight = 1.f - fabsf(128.f - lag2tempo(i)) * 0.005;
+        if (weight < 0.f) weight = 0.f;
+        weight = weight * weight * weight;
+
+        m_fr[i] = m_r[i];
+
+        int div = 1;
+
+        for (int j = 0; j < int(sizeof(related)/sizeof(related[0])); ++j) {
+
+            int k0 = int(i * related[j] + 0.5);
+
+            if (k0 >= 0 && k0 < int(n/2)) {
+
+                int kmax = 0, kmin = 0;
+                float kvmax = 0, kvmin = 0;
+                bool have = false;
+
+                for (int k = k0 - 1; k <= k0 + 1; ++k) {
+
+                    if (k < 0 || k >= n/2) continue;
+
+                    if (!have || (m_r[k] > kvmax)) { kmax = k; kvmax = m_r[k]; }
+                    if (!have || (m_r[k] < kvmin)) { kmin = k; kvmin = m_r[k]; }
+                    
+                    have = true;
+                }
+                
+                m_fr[i] += m_r[kmax] / 5;
+
+                if ((kmax == 0 || m_r[kmax] > m_r[kmax-1]) &&
+                    (kmax == n/2-1 || m_r[kmax] > m_r[kmax+1]) &&
+                    kvmax > kvmin * 1.05) {
+                    
+                    m_t[i] = m_t[i] + lag2tempo(kmax) * related[j];
+                    ++div;
+                }
+            }
+        }
+        
+        m_t[i] /= div;
+        
+//        if (div > 1) {
+//            cerr << "adjusting tempo from " << lag2tempo(i) << " to "
+//                 << m_t[i] << " for fr = " << m_fr[i] << " (div = " << div << ")" << endl;
+//        }
+        
+        m_fr[i] += m_fr[i] * (weight / 3);
+    }
+}
+    
+
+FixedTempoEstimator::FeatureSet
+FixedTempoEstimator::assembleFeatures()
+{
+    FeatureSet fs;
+    if (!m_r) return fs; // No results
+
+    Feature feature;
+    feature.hasTimestamp = true;
+    feature.hasDuration = false;
+    feature.label = "";
+    feature.values.clear();
+    feature.values.push_back(0.f);
+
+    char buffer[40];
+
+    int n = m_n;
+
+    for (int i = 0; i < n; ++i) {
+        feature.timestamp = m_start +
+            RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
+        feature.values[0] = m_df[i];
+        feature.label = "";
+        fs[DFOutput].push_back(feature);
+    }
+
+    for (int i = 1; i < n/2; ++i) {
+        feature.timestamp = m_start +
+            RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
+        feature.values[0] = m_r[i];
+        sprintf(buffer, "%.1f bpm", lag2tempo(i));
+        if (i == n/2-1) feature.label = "";
+        else feature.label = buffer;
+        fs[ACFOutput].push_back(feature);
+    }
+
+    float t0 = 50.f; // our minimum detected tempo (could be a parameter)
+    float t1 = 190.f; // our maximum detected tempo
+
+    //!!! need some way for the host (or at least, the user) to know
+    //!!! that it should only pass a certain amount of
+    //!!! input... e.g. by making the amount configurable
+
+    int p0 = tempo2lag(t1);
+    int p1 = tempo2lag(t0);
+
+    std::map<float, int> candidates;
+
+    for (int i = p0; i <= p1 && i < n/2-1; ++i) {
+
+        if (m_fr[i] > m_fr[i-1] &&
+            m_fr[i] > m_fr[i+1]) {
+            candidates[m_fr[i]] = i;
+        }
+
+        feature.timestamp = m_start +
+            RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
+        feature.values[0] = m_fr[i];
+        sprintf(buffer, "%.1f bpm", lag2tempo(i));
+        if (i == p1 || i == n/2-2) feature.label = "";
+        else feature.label = buffer;
+        fs[FilteredACFOutput].push_back(feature);
+    }
+
+//    cerr << "maxpi = " << maxpi << " for tempo " << lag2tempo(maxpi) << " (value = " << maxp << ")" << endl;
+
+    if (candidates.empty()) {
+        cerr << "No tempo candidates!" << endl;
+        return fs;
+    }
+
+    feature.hasTimestamp = true;
+    feature.timestamp = m_start;
+    
+    feature.hasDuration = true;
+    feature.duration = m_lasttime - m_start;
+
+    std::map<float, int>::const_iterator ci = candidates.end();
+    --ci;
+    int maxpi = ci->second;
+
+    if (m_t[maxpi] > 0) {
+        cerr << "*** Using adjusted tempo " << m_t[maxpi] << " instead of lag tempo " << lag2tempo(maxpi) << endl;
+        feature.values[0] = m_t[maxpi];
+    } else {
+        // shouldn't happen -- it would imply that this high value was not a peak!
+        feature.values[0] = lag2tempo(maxpi);
+        cerr << "WARNING: No stored tempo for index " << maxpi << endl;
+    }
+
+    sprintf(buffer, "%.1f bpm", feature.values[0]);
+    feature.label = buffer;
+
+    fs[TempoOutput].push_back(feature);
+
+    feature.values.clear();
+    feature.label = "";
+
+    while (feature.values.size() < 8) {
+//        cerr << "adding tempo value from lag " << ci->second << endl;
+        if (m_t[ci->second] > 0) {
+            feature.values.push_back(m_t[ci->second]);
+        } else {
+            feature.values.push_back(lag2tempo(ci->second));
+        }
+        if (ci == candidates.begin()) break;
+        --ci;
+    }
+
+    fs[CandidatesOutput].push_back(feature);
+    
+    return fs;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/PercussionOnsetDetector.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,285 @@
+/* -*- 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 "PercussionOnsetDetector.h"
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+
+#include <cmath>
+
+
+PercussionOnsetDetector::PercussionOnsetDetector(float inputSampleRate) :
+    Plugin(inputSampleRate),
+    m_stepSize(0),
+    m_blockSize(0),
+    m_threshold(3),
+    m_sensitivity(40),
+    m_priorMagnitudes(0),
+    m_dfMinus1(0),
+    m_dfMinus2(0)
+{
+}
+
+PercussionOnsetDetector::~PercussionOnsetDetector()
+{
+    delete[] m_priorMagnitudes;
+}
+
+string
+PercussionOnsetDetector::getIdentifier() const
+{
+    return "percussiononsets";
+}
+
+string
+PercussionOnsetDetector::getName() const
+{
+    return "Simple Percussion Onset Detector";
+}
+
+string
+PercussionOnsetDetector::getDescription() const
+{
+    return "Detect percussive note onsets by identifying broadband energy rises";
+}
+
+string
+PercussionOnsetDetector::getMaker() const
+{
+    return "Vamp SDK Example Plugins";
+}
+
+int
+PercussionOnsetDetector::getPluginVersion() const
+{
+    return 2;
+}
+
+string
+PercussionOnsetDetector::getCopyright() const
+{
+    return "Code copyright 2006 Queen Mary, University of London, after Dan Barry et al 2005.  Freely redistributable (BSD license)";
+}
+
+size_t
+PercussionOnsetDetector::getPreferredStepSize() const
+{
+    return 0;
+}
+
+size_t
+PercussionOnsetDetector::getPreferredBlockSize() const
+{
+    return 1024;
+}
+
+bool
+PercussionOnsetDetector::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    if (channels < getMinChannelCount() ||
+	channels > getMaxChannelCount()) return false;
+
+    m_stepSize = stepSize;
+    m_blockSize = blockSize;
+
+    m_priorMagnitudes = new float[m_blockSize/2];
+
+    for (size_t i = 0; i < m_blockSize/2; ++i) {
+        m_priorMagnitudes[i] = 0.f;
+    }
+
+    m_dfMinus1 = 0.f;
+    m_dfMinus2 = 0.f;
+
+    return true;
+}
+
+void
+PercussionOnsetDetector::reset()
+{
+    for (size_t i = 0; i < m_blockSize/2; ++i) {
+        m_priorMagnitudes[i] = 0.f;
+    }
+
+    m_dfMinus1 = 0.f;
+    m_dfMinus2 = 0.f;
+}
+
+PercussionOnsetDetector::ParameterList
+PercussionOnsetDetector::getParameterDescriptors() const
+{
+    ParameterList list;
+
+    ParameterDescriptor d;
+    d.identifier = "threshold";
+    d.name = "Energy rise threshold";
+    d.description = "Energy rise within a frequency bin necessary to count toward broadband total";
+    d.unit = "dB";
+    d.minValue = 0;
+    d.maxValue = 20;
+    d.defaultValue = 3;
+    d.isQuantized = false;
+    list.push_back(d);
+
+    d.identifier = "sensitivity";
+    d.name = "Sensitivity";
+    d.description = "Sensitivity of peak detector applied to broadband detection function";
+    d.unit = "%";
+    d.minValue = 0;
+    d.maxValue = 100;
+    d.defaultValue = 40;
+    d.isQuantized = false;
+    list.push_back(d);
+
+    return list;
+}
+
+float
+PercussionOnsetDetector::getParameter(std::string id) const
+{
+    if (id == "threshold") return m_threshold;
+    if (id == "sensitivity") return m_sensitivity;
+    return 0.f;
+}
+
+void
+PercussionOnsetDetector::setParameter(std::string id, float value)
+{
+    if (id == "threshold") {
+        if (value < 0) value = 0;
+        if (value > 20) value = 20;
+        m_threshold = value;
+    } else if (id == "sensitivity") {
+        if (value < 0) value = 0;
+        if (value > 100) value = 100;
+        m_sensitivity = value;
+    }
+}
+
+PercussionOnsetDetector::OutputList
+PercussionOnsetDetector::getOutputDescriptors() const
+{
+    OutputList list;
+
+    OutputDescriptor d;
+    d.identifier = "onsets";
+    d.name = "Onsets";
+    d.description = "Percussive note onset locations";
+    d.unit = "";
+    d.hasFixedBinCount = true;
+    d.binCount = 0;
+    d.hasKnownExtents = false;
+    d.isQuantized = false;
+    d.sampleType = OutputDescriptor::VariableSampleRate;
+    d.sampleRate = m_inputSampleRate;
+    list.push_back(d);
+
+    d.identifier = "detectionfunction";
+    d.name = "Detection Function";
+    d.description = "Broadband energy rise detection function";
+    d.binCount = 1;
+    d.isQuantized = true;
+    d.quantizeStep = 1.0;
+    d.sampleType = OutputDescriptor::OneSamplePerStep;
+    list.push_back(d);
+
+    return list;
+}
+
+PercussionOnsetDetector::FeatureSet
+PercussionOnsetDetector::process(const float *const *inputBuffers,
+                                 Vamp::RealTime ts)
+{
+    if (m_stepSize == 0) {
+	cerr << "ERROR: PercussionOnsetDetector::process: "
+	     << "PercussionOnsetDetector has not been initialised"
+	     << endl;
+	return FeatureSet();
+    }
+
+    int count = 0;
+
+    for (size_t i = 1; i < m_blockSize/2; ++i) {
+
+        float real = inputBuffers[0][i*2];
+        float imag = inputBuffers[0][i*2 + 1];
+
+        float sqrmag = real * real + imag * imag;
+
+        if (m_priorMagnitudes[i] > 0.f) {
+            float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]);
+
+//        std::cout << "i=" << i << ", mag=" << mag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << std::endl;
+
+            if (diff >= m_threshold) ++count;
+        }
+
+        m_priorMagnitudes[i] = sqrmag;
+    }
+
+    FeatureSet returnFeatures;
+
+    Feature detectionFunction;
+    detectionFunction.hasTimestamp = false;
+    detectionFunction.values.push_back(count);
+    returnFeatures[1].push_back(detectionFunction);
+
+    if (m_dfMinus2 < m_dfMinus1 &&
+        m_dfMinus1 >= count &&
+        m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) {
+
+        Feature onset;
+        onset.hasTimestamp = true;
+        onset.timestamp = ts - Vamp::RealTime::frame2RealTime
+            (m_stepSize, int(m_inputSampleRate + 0.5));
+        returnFeatures[0].push_back(onset);
+    }
+
+    m_dfMinus2 = m_dfMinus1;
+    m_dfMinus1 = count;
+
+    return returnFeatures;
+}
+
+PercussionOnsetDetector::FeatureSet
+PercussionOnsetDetector::getRemainingFeatures()
+{
+    return FeatureSet();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/SpectralCentroid.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,196 @@
+/* -*- 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 "SpectralCentroid.h"
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+
+#include <math.h>
+
+#ifdef WIN32
+#define isnan(x) false
+#define isinf(x) false
+#endif
+
+SpectralCentroid::SpectralCentroid(float inputSampleRate) :
+    Plugin(inputSampleRate),
+    m_stepSize(0),
+    m_blockSize(0)
+{
+}
+
+SpectralCentroid::~SpectralCentroid()
+{
+}
+
+string
+SpectralCentroid::getIdentifier() const
+{
+    return "spectralcentroid";
+}
+
+string
+SpectralCentroid::getName() const
+{
+    return "Spectral Centroid";
+}
+
+string
+SpectralCentroid::getDescription() const
+{
+    return "Calculate the centroid frequency of the spectrum of the input signal";
+}
+
+string
+SpectralCentroid::getMaker() const
+{
+    return "Vamp SDK Example Plugins";
+}
+
+int
+SpectralCentroid::getPluginVersion() const
+{
+    return 2;
+}
+
+string
+SpectralCentroid::getCopyright() const
+{
+    return "Freely redistributable (BSD license)";
+}
+
+bool
+SpectralCentroid::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    if (channels < getMinChannelCount() ||
+	channels > getMaxChannelCount()) return false;
+
+    m_stepSize = stepSize;
+    m_blockSize = blockSize;
+
+    return true;
+}
+
+void
+SpectralCentroid::reset()
+{
+}
+
+SpectralCentroid::OutputList
+SpectralCentroid::getOutputDescriptors() const
+{
+    OutputList list;
+
+    OutputDescriptor d;
+    d.identifier = "logcentroid";
+    d.name = "Log Frequency Centroid";
+    d.description = "Centroid of the log weighted frequency spectrum";
+    d.unit = "Hz";
+    d.hasFixedBinCount = true;
+    d.binCount = 1;
+    d.hasKnownExtents = false;
+    d.isQuantized = false;
+    d.sampleType = OutputDescriptor::OneSamplePerStep;
+    list.push_back(d);
+
+    d.identifier = "linearcentroid";
+    d.name = "Linear Frequency Centroid";
+    d.description = "Centroid of the linear frequency spectrum";
+    list.push_back(d);
+
+    return list;
+}
+
+//static int scount = 0;
+
+SpectralCentroid::FeatureSet
+SpectralCentroid::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
+{
+    if (m_stepSize == 0) {
+	cerr << "ERROR: SpectralCentroid::process: "
+	     << "SpectralCentroid has not been initialised"
+	     << endl;
+	return FeatureSet();
+    }
+
+//    std::cerr << "SpectralCentroid::process: count = " << scount++ << ", timestamp = " << timestamp << ", total power = ";
+
+    double numLin = 0.0, numLog = 0.0, denom = 0.0;
+
+    for (size_t i = 1; i <= m_blockSize/2; ++i) {
+	double freq = (double(i) * m_inputSampleRate) / m_blockSize;
+	double real = inputBuffers[0][i*2];
+	double imag = inputBuffers[0][i*2 + 1];
+	double power = sqrt(real * real + imag * imag) / (m_blockSize/2);
+	numLin += freq * power;
+        numLog += log10f(freq) * power;
+	denom += power;
+    }
+
+//    std::cerr << denom << std::endl;
+
+    FeatureSet returnFeatures;
+
+    if (denom != 0.0) {
+	float centroidLin = float(numLin / denom);
+	float centroidLog = powf(10, float(numLog / denom));
+
+	Feature feature;
+	feature.hasTimestamp = false;
+    if (!isnan(centroidLog) && !isinf(centroidLog)) {
+        feature.values.push_back(centroidLog);
+    }
+	returnFeatures[0].push_back(feature);
+
+    feature.values.clear();
+    if (!isnan(centroidLin) && !isinf(centroidLin)) {
+        feature.values.push_back(centroidLin);
+    }
+	returnFeatures[1].push_back(feature);
+    }
+
+    return returnFeatures;
+}
+
+SpectralCentroid::FeatureSet
+SpectralCentroid::getRemainingFeatures()
+{
+    return FeatureSet();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/ZeroCrossing.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,206 @@
+/* -*- 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 "ZeroCrossing.h"
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+
+#include <cmath>
+
+ZeroCrossing::ZeroCrossing(float inputSampleRate) :
+    Plugin(inputSampleRate),
+    m_stepSize(0),
+    m_previousSample(0.0f)
+{
+}
+
+ZeroCrossing::~ZeroCrossing()
+{
+}
+
+string
+ZeroCrossing::getIdentifier() const
+{
+    return "zerocrossing";
+}
+
+string
+ZeroCrossing::getName() const
+{
+    return "Zero Crossings";
+}
+
+string
+ZeroCrossing::getDescription() const
+{
+    return "Detect and count zero crossing points";
+}
+
+string
+ZeroCrossing::getMaker() const
+{
+    return "Vamp SDK Example Plugins";
+}
+
+int
+ZeroCrossing::getPluginVersion() const
+{
+    return 2;
+}
+
+string
+ZeroCrossing::getCopyright() const
+{
+    return "Freely redistributable (BSD license)";
+}
+
+bool
+ZeroCrossing::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    if (channels < getMinChannelCount() ||
+	channels > getMaxChannelCount()) return false;
+
+    m_stepSize = std::min(stepSize, blockSize);
+
+    return true;
+}
+
+void
+ZeroCrossing::reset()
+{
+    m_previousSample = 0.0f;
+}
+
+ZeroCrossing::OutputList
+ZeroCrossing::getOutputDescriptors() const
+{
+    OutputList list;
+
+    OutputDescriptor zc;
+    zc.identifier = "counts";
+    zc.name = "Zero Crossing Counts";
+    zc.description = "The number of zero crossing points per processing block";
+    zc.unit = "crossings";
+    zc.hasFixedBinCount = true;
+    zc.binCount = 1;
+    zc.hasKnownExtents = false;
+    zc.isQuantized = true;
+    zc.quantizeStep = 1.0;
+    zc.sampleType = OutputDescriptor::OneSamplePerStep;
+    list.push_back(zc);
+
+    zc.identifier = "zerocrossings";
+    zc.name = "Zero Crossings";
+    zc.description = "The locations of zero crossing points";
+    zc.unit = "";
+    zc.hasFixedBinCount = true;
+    zc.binCount = 0;
+    zc.sampleType = OutputDescriptor::VariableSampleRate;
+    zc.sampleRate = m_inputSampleRate;
+    list.push_back(zc);
+
+    return list;
+}
+
+//static int scount = 0;
+
+ZeroCrossing::FeatureSet
+ZeroCrossing::process(const float *const *inputBuffers,
+                      Vamp::RealTime timestamp)
+{
+    if (m_stepSize == 0) {
+	cerr << "ERROR: ZeroCrossing::process: "
+	     << "ZeroCrossing has not been initialised"
+	     << endl;
+	return FeatureSet();
+    }
+
+//    std::cerr << "ZeroCrossing::process: count = " << scount++ << ", timestamp = " << timestamp << ", rms = ";
+
+    float prev = m_previousSample;
+    size_t count = 0;
+
+    FeatureSet returnFeatures;
+
+//    double acc = 0.0;
+
+    for (size_t i = 0; i < m_stepSize; ++i) {
+
+	float sample = inputBuffers[0][i];
+	bool crossing = false;
+
+	if (sample <= 0.0) {
+	    if (prev > 0.0) crossing = true;
+	} else if (sample > 0.0) {
+	    if (prev <= 0.0) crossing = true;
+	}
+
+	if (crossing) {
+	    ++count; 
+	    Feature feature;
+	    feature.hasTimestamp = true;
+	    feature.timestamp = timestamp +
+		Vamp::RealTime::frame2RealTime(i, (size_t)m_inputSampleRate);
+	    returnFeatures[1].push_back(feature);
+	}
+
+//        acc += sample * sample;
+
+	prev = sample;
+    }
+
+//    acc /= m_stepSize;
+//    std::cerr << sqrt(acc) << std::endl;
+
+    m_previousSample = prev;
+
+    Feature feature;
+    feature.hasTimestamp = false;
+    feature.values.push_back(count);
+
+    returnFeatures[0].push_back(feature);
+    return returnFeatures;
+}
+
+ZeroCrossing::FeatureSet
+ZeroCrossing::getRemainingFeatures()
+{
+    return FeatureSet();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/plugins.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,66 @@
+/* -*- 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 "vamp/vamp.h"
+#include "vamp-sdk/PluginAdapter.h"
+
+#include "ZeroCrossing.h"
+#include "SpectralCentroid.h"
+#include "PercussionOnsetDetector.h"
+#include "FixedTempoEstimator.h"
+#include "AmplitudeFollower.h"
+
+static Vamp::PluginAdapter<ZeroCrossing> zeroCrossingAdapter;
+static Vamp::PluginAdapter<SpectralCentroid> spectralCentroidAdapter;
+static Vamp::PluginAdapter<PercussionOnsetDetector> percussionOnsetAdapter;
+static Vamp::PluginAdapter<FixedTempoEstimator> fixedTempoAdapter;
+static Vamp::PluginAdapter<AmplitudeFollower> amplitudeAdapter;
+
+const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
+                                                    unsigned int index)
+{
+    if (version < 1) return 0;
+
+    switch (index) {
+    case  0: return zeroCrossingAdapter.getDescriptor();
+    case  1: return spectralCentroidAdapter.getDescriptor();
+    case  2: return percussionOnsetAdapter.getDescriptor();
+    case  3: return amplitudeAdapter.getDescriptor();
+    case  4: return fixedTempoAdapter.getDescriptor();
+    default: return 0;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host/vamp-simple-host.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,644 @@
+/* -*- 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.
+    FFT code from Don Cross's public domain FFT implementation.
+  
+    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 "vamp-sdk/PluginHostAdapter.h"
+#include "vamp-sdk/hostext/PluginInputDomainAdapter.h"
+#include "vamp-sdk/hostext/PluginLoader.h"
+#include "vamp/vamp.h"
+
+#include <iostream>
+#include <fstream>
+#include <set>
+#include <sndfile.h>
+
+#include <cstring>
+#include <cstdlib>
+
+#include "system.h"
+
+#include <cmath>
+
+using namespace std;
+
+using Vamp::Plugin;
+using Vamp::PluginHostAdapter;
+using Vamp::RealTime;
+using Vamp::HostExt::PluginLoader;
+using Vamp::HostExt::PluginWrapper;
+using Vamp::HostExt::PluginInputDomainAdapter;
+
+#define HOST_VERSION "1.3"
+
+enum Verbosity {
+    PluginIds,
+    PluginOutputIds,
+    PluginInformation
+};
+
+void printFeatures(int, int, int, Plugin::FeatureSet, ofstream *, bool frames);
+void transformInput(float *, size_t);
+void fft(unsigned int, bool, double *, double *, double *, double *);
+void printPluginPath(bool verbose);
+void printPluginCategoryList();
+void enumeratePlugins(Verbosity);
+void listPluginsInLibrary(string soname);
+int runPlugin(string myname, string soname, string id, string output,
+              int outputNo, string inputFile, string outfilename, bool frames);
+
+void usage(const char *name)
+{
+    cerr << "\n"
+         << name << ": A simple Vamp plugin host.\n\n"
+        "Centre for Digital Music, Queen Mary, University of London.\n"
+        "Copyright 2006-2007 Chris Cannam and QMUL.\n"
+        "Freely redistributable; published under a BSD-style license.\n\n"
+        "Usage:\n\n"
+        "  " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o out.txt]\n"
+        "  " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno] [-o out.txt]\n\n"
+        "    -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n"
+        "       audio data in \"file.wav\", retrieving the named \"output\", or output\n"
+        "       number \"outputno\" (the first output by default) and dumping it to\n"
+        "       standard output, or to \"out.txt\" if the -o option is given.\n\n"
+        "       \"pluginlibrary\" should be a library name, not a file path; the\n"
+        "       standard Vamp library search path will be used to locate it.  If\n"
+        "       a file path is supplied, the directory part(s) will be ignored.\n\n"
+        "       If the -s option is given, results will be labelled with the audio\n"
+        "       sample frame at which they occur. Otherwise, they will be labelled\n"
+        "       with time in seconds.\n\n"
+        "  " << name << " -l\n\n"
+        "    -- List the plugin libraries and Vamp plugins in the library search path\n"
+        "       in a verbose human-readable format.\n\n"
+        "  " << name << " --list-ids\n\n"
+        "    -- List the plugins in the search path in a terse machine-readable format,\n"
+        "       in the form vamp:soname:identifier.\n\n"
+        "  " << name << " --list-outputs\n\n"
+        "    -- List the outputs for plugins in the search path in a machine-readable\n"
+        "       format, in the form vamp:soname:identifier:output.\n\n"
+        "  " << name << " --list-by-category\n\n"
+        "    -- List the plugins as a plugin index by category, in a machine-readable\n"
+        "       format.  The format may change in future releases.\n\n"
+        "  " << name << " -p\n\n"
+        "    -- Print out the Vamp library search path.\n\n"
+        "  " << name << " -v\n\n"
+        "    -- Display version information only.\n"
+         << endl;
+    exit(2);
+}
+
+int main(int argc, char **argv)
+{
+    char *scooter = argv[0];
+    char *name = 0;
+    while (scooter && *scooter) {
+        if (*scooter == '/' || *scooter == '\\') name = ++scooter;
+        else ++scooter;
+    }
+    if (!name || !*name) name = argv[0];
+    
+    if (argc < 2) usage(name);
+
+    if (argc == 2) {
+
+        if (!strcmp(argv[1], "-v")) {
+
+            cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl
+                 << "Vamp API version: " << VAMP_API_VERSION << endl
+                 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl;
+            return 0;
+
+        } else if (!strcmp(argv[1], "-l")) {
+
+            printPluginPath(true);
+            enumeratePlugins(PluginInformation);
+            return 0;
+
+        } else if (!strcmp(argv[1], "-p")) {
+
+            printPluginPath(false);
+            return 0;
+
+        } else if (!strcmp(argv[1], "--list-ids")) {
+
+            enumeratePlugins(PluginIds);
+            return 0;
+
+        } else if (!strcmp(argv[1], "--list-outputs")) {
+
+            enumeratePlugins(PluginOutputIds);
+            return 0;
+
+        } else if (!strcmp(argv[1], "--list-by-category")) {
+
+            printPluginCategoryList();
+            return 0;
+
+        } else usage(name);
+    }
+
+    if (argc < 3) usage(name);
+
+    bool useFrames = false;
+    
+    int base = 1;
+    if (!strcmp(argv[1], "-s")) {
+        useFrames = true;
+        base = 2;
+    }
+
+    string soname = argv[base];
+    string wavname = argv[base+1];
+    string plugid = "";
+    string output = "";
+    int outputNo = -1;
+    string outfilename;
+
+    if (argc >= base+3) {
+
+        int idx = base+2;
+
+        if (isdigit(*argv[idx])) {
+            outputNo = atoi(argv[idx++]);
+        }
+
+        if (argc == idx + 2) {
+            if (!strcmp(argv[idx], "-o")) {
+                outfilename = argv[idx+1];
+            } else usage(name);
+        } else if (argc != idx) {
+            (usage(name));
+        }
+    }
+
+    cerr << endl << name << ": Running..." << endl;
+
+    cerr << "Reading file: \"" << wavname << "\", writing to ";
+    if (outfilename == "") {
+        cerr << "standard output" << endl;
+    } else {
+        cerr << "\"" << outfilename << "\"" << endl;
+    }
+
+    string::size_type sep = soname.find(':');
+
+    if (sep != string::npos) {
+        plugid = soname.substr(sep + 1);
+        soname = soname.substr(0, sep);
+
+        sep = plugid.find(':');
+        if (sep != string::npos) {
+            output = plugid.substr(sep + 1);
+            plugid = plugid.substr(0, sep);
+        }
+    }
+
+    if (plugid == "") {
+        usage(name);
+    }
+
+    if (output != "" && outputNo != -1) {
+        usage(name);
+    }
+
+    if (output == "" && outputNo == -1) {
+        outputNo = 0;
+    }
+
+    return runPlugin(name, soname, plugid, output, outputNo,
+                     wavname, outfilename, useFrames);
+}
+
+
+int runPlugin(string myname, string soname, string id,
+              string output, int outputNo, string wavname,
+              string outfilename, bool useFrames)
+{
+    PluginLoader *loader = PluginLoader::getInstance();
+
+    PluginLoader::PluginKey key = loader->composePluginKey(soname, id);
+    
+    SNDFILE *sndfile;
+    SF_INFO sfinfo;
+    memset(&sfinfo, 0, sizeof(SF_INFO));
+
+    sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
+    if (!sndfile) {
+	cerr << myname << ": ERROR: Failed to open input file \""
+             << wavname << "\": " << sf_strerror(sndfile) << endl;
+	return 1;
+    }
+
+    ofstream *out = 0;
+    if (outfilename != "") {
+        out = new ofstream(outfilename.c_str(), ios::out);
+        if (!*out) {
+            cerr << myname << ": ERROR: Failed to open output file \""
+                 << outfilename << "\" for writing" << endl;
+            delete out;
+            return 1;
+        }
+    }
+
+    Plugin *plugin = loader->loadPlugin
+        (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE);
+    if (!plugin) {
+        cerr << myname << ": ERROR: Failed to load plugin \"" << id
+             << "\" from library \"" << soname << "\"" << endl;
+        sf_close(sndfile);
+        if (out) {
+            out->close();
+            delete out;
+        }
+        return 1;
+    }
+
+    cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
+
+    int blockSize = plugin->getPreferredBlockSize();
+    int stepSize = plugin->getPreferredStepSize();
+
+    if (blockSize == 0) {
+        blockSize = 1024;
+    }
+    if (stepSize == 0) {
+        if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
+            stepSize = blockSize/2;
+        } else {
+            stepSize = blockSize;
+        }
+    } else if (stepSize > blockSize) {
+        cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to ";
+        if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
+            blockSize = stepSize * 2;
+        } else {
+            blockSize = stepSize;
+        }
+        cerr << blockSize << endl;
+    }
+
+    int channels = sfinfo.channels;
+
+    float *filebuf = new float[blockSize * channels];
+    float **plugbuf = new float*[channels];
+    for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2];
+
+    cerr << "Using block size = " << blockSize << ", step size = "
+              << stepSize << endl;
+
+    int minch = plugin->getMinChannelCount();
+    int maxch = plugin->getMaxChannelCount();
+    cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
+    cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
+
+    Plugin::OutputList outputs = plugin->getOutputDescriptors();
+    Plugin::OutputDescriptor od;
+
+    int returnValue = 1;
+    int progress = 0;
+
+    RealTime rt;
+    PluginWrapper *wrapper = 0;
+    RealTime adjustment = RealTime::zeroTime;
+
+    if (outputs.empty()) {
+	cerr << "ERROR: Plugin has no outputs!" << endl;
+        goto done;
+    }
+
+    if (outputNo < 0) {
+
+        for (size_t oi = 0; oi < outputs.size(); ++oi) {
+            if (outputs[oi].identifier == output) {
+                outputNo = oi;
+                break;
+            }
+        }
+
+        if (outputNo < 0) {
+            cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
+            goto done;
+        }
+
+    } else {
+
+        if (int(outputs.size()) <= outputNo) {
+            cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
+            goto done;
+        }        
+    }
+
+    od = outputs[outputNo];
+    cerr << "Output is: \"" << od.identifier << "\"" << endl;
+
+    if (!plugin->initialise(channels, stepSize, blockSize)) {
+        cerr << "ERROR: Plugin initialise (channels = " << channels
+             << ", stepSize = " << stepSize << ", blockSize = "
+             << blockSize << ") failed." << endl;
+        goto done;
+    }
+
+    wrapper = dynamic_cast<PluginWrapper *>(plugin);
+    if (wrapper) {
+        PluginInputDomainAdapter *ida =
+            wrapper->getWrapper<PluginInputDomainAdapter>();
+        if (ida) adjustment = ida->getTimestampAdjustment();
+    }
+
+    for (size_t i = 0; i < sfinfo.frames; i += stepSize) {
+
+        int count;
+
+        if (sf_seek(sndfile, i, SEEK_SET) < 0) {
+            cerr << "ERROR: sf_seek failed: " << sf_strerror(sndfile) << endl;
+            break;
+        }
+        
+        if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
+            cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
+            break;
+        }
+
+        for (int c = 0; c < channels; ++c) {
+            int j = 0;
+            while (j < count) {
+                plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
+                ++j;
+            }
+            while (j < blockSize) {
+                plugbuf[c][j] = 0.0f;
+                ++j;
+            }
+        }
+
+        rt = RealTime::frame2RealTime(i, sfinfo.samplerate);
+
+        printFeatures
+            (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
+             sfinfo.samplerate, outputNo, plugin->process(plugbuf, rt),
+             out, useFrames);
+
+        int pp = progress;
+        progress = lrintf((float(i) / sfinfo.frames) * 100.f);
+        if (progress != pp && out) {
+            cerr << "\r" << progress << "%";
+        }
+    }
+    if (out) cerr << "\rDone" << endl;
+
+    rt = RealTime::frame2RealTime(sfinfo.frames, sfinfo.samplerate);
+
+    printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
+                  sfinfo.samplerate, outputNo,
+                  plugin->getRemainingFeatures(), out, useFrames);
+
+    returnValue = 0;
+
+done:
+    delete plugin;
+    if (out) {
+        out->close();
+        delete out;
+    }
+    sf_close(sndfile);
+    return returnValue;
+}
+
+void
+printFeatures(int frame, int sr, int output,
+              Plugin::FeatureSet features, ofstream *out, bool useFrames)
+{
+    for (unsigned int i = 0; i < features[output].size(); ++i) {
+
+        if (useFrames) {
+
+            int displayFrame = frame;
+
+            if (features[output][i].hasTimestamp) {
+                displayFrame = RealTime::realTime2Frame
+                    (features[output][i].timestamp, sr);
+            }
+
+            (out ? *out : cout) << displayFrame;
+
+            if (features[output][i].hasDuration) {
+                displayFrame = RealTime::realTime2Frame
+                    (features[output][i].duration, sr);
+                (out ? *out : cout) << "," << displayFrame;
+            }
+
+            (out ? *out : cout)  << ":";
+
+        } else {
+
+            RealTime rt = RealTime::frame2RealTime(frame, sr);
+
+            if (features[output][i].hasTimestamp) {
+                rt = features[output][i].timestamp;
+            }
+
+            (out ? *out : cout) << rt.toString();
+
+            if (features[output][i].hasDuration) {
+                rt = features[output][i].duration;
+                (out ? *out : cout) << "," << rt.toString();
+            }
+
+            (out ? *out : cout) << ":";
+        }
+
+        for (unsigned int j = 0; j < features[output][i].values.size(); ++j) {
+            (out ? *out : cout) << " " << features[output][i].values[j];
+        }
+
+        (out ? *out : cout) << endl;
+    }
+}
+
+void
+printPluginPath(bool verbose)
+{
+    if (verbose) {
+        cout << "\nVamp plugin search path: ";
+    }
+
+    vector<string> path = PluginHostAdapter::getPluginPath();
+    for (size_t i = 0; i < path.size(); ++i) {
+        if (verbose) {
+            cout << "[" << path[i] << "]";
+        } else {
+            cout << path[i] << endl;
+        }
+    }
+
+    if (verbose) cout << endl;
+}
+
+void
+enumeratePlugins(Verbosity verbosity)
+{
+    PluginLoader *loader = PluginLoader::getInstance();
+
+    if (verbosity == PluginInformation) {
+        cout << "\nVamp plugin libraries found in search path:" << endl;
+    }
+
+    vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
+    typedef multimap<string, PluginLoader::PluginKey>
+        LibraryMap;
+    LibraryMap libraryMap;
+
+    for (size_t i = 0; i < plugins.size(); ++i) {
+        string path = loader->getLibraryPathForPlugin(plugins[i]);
+        libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
+    }
+
+    string prevPath = "";
+    int index = 0;
+
+    for (LibraryMap::iterator i = libraryMap.begin();
+         i != libraryMap.end(); ++i) {
+        
+        string path = i->first;
+        PluginLoader::PluginKey key = i->second;
+
+        if (path != prevPath) {
+            prevPath = path;
+            index = 0;
+            if (verbosity == PluginInformation) {
+                cout << "\n  " << path << ":" << endl;
+            }
+        }
+
+        Plugin *plugin = loader->loadPlugin(key, 48000);
+        if (plugin) {
+
+            char c = char('A' + index);
+            if (c > 'Z') c = char('a' + (index - 26));
+
+            if (verbosity == PluginInformation) {
+
+                cout << "    [" << c << "] [v"
+                     << plugin->getVampApiVersion() << "] "
+                     << plugin->getName() << ", \""
+                     << plugin->getIdentifier() << "\"" << " ["
+                     << plugin->getMaker() << "]" << endl;
+
+                PluginLoader::PluginCategoryHierarchy category =
+                    loader->getPluginCategory(key);
+
+                if (!category.empty()) {
+                    cout << "       ";
+                    for (size_t ci = 0; ci < category.size(); ++ci) {
+                        cout << " > " << category[ci];
+                    }
+                    cout << endl;
+                }
+
+                if (plugin->getDescription() != "") {
+                    cout << "        - " << plugin->getDescription() << endl;
+                }
+
+            } else if (verbosity == PluginIds) {
+                cout << "vamp:" << key << endl;
+            }
+            
+            Plugin::OutputList outputs =
+                plugin->getOutputDescriptors();
+
+            if (outputs.size() > 1 || verbosity == PluginOutputIds) {
+                for (size_t j = 0; j < outputs.size(); ++j) {
+                    if (verbosity == PluginInformation) {
+                        cout << "         (" << j << ") "
+                             << outputs[j].name << ", \""
+                             << outputs[j].identifier << "\"" << endl;
+                        if (outputs[j].description != "") {
+                            cout << "             - " 
+                                 << outputs[j].description << endl;
+                        }
+                    } else if (verbosity == PluginOutputIds) {
+                        cout << "vamp:" << key << ":" << outputs[j].identifier << endl;
+                    }
+                }
+            }
+
+            ++index;
+
+            delete plugin;
+        }
+    }
+
+    if (verbosity == PluginInformation) {
+        cout << endl;
+    }
+}
+
+void
+printPluginCategoryList()
+{
+    PluginLoader *loader = PluginLoader::getInstance();
+
+    vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
+
+    set<string> printedcats;
+
+    for (size_t i = 0; i < plugins.size(); ++i) {
+
+        PluginLoader::PluginKey key = plugins[i];
+        
+        PluginLoader::PluginCategoryHierarchy category =
+            loader->getPluginCategory(key);
+
+        Plugin *plugin = loader->loadPlugin(key, 48000);
+        if (!plugin) continue;
+
+        string catstr = "";
+
+        if (category.empty()) catstr = '|';
+        else {
+            for (size_t j = 0; j < category.size(); ++j) {
+                catstr += category[j];
+                catstr += '|';
+                if (printedcats.find(catstr) == printedcats.end()) {
+                    std::cout << catstr << std::endl;
+                    printedcats.insert(catstr);
+                }
+            }
+        }
+
+        std::cout << catstr << key << ":::" << plugin->getName() << ":::" << plugin->getMaker() << ":::" << plugin->getDescription() << std::endl;
+    }
+}
+
--- a/src/AmplitudeFollower.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,247 +0,0 @@
-/* -*- 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.
-    This file copyright 2006 Dan Stowell.
-  
-    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 "AmplitudeFollower.h"
-
-#include <cmath>
-
-#include <string>
-#include <vector>
-#include <iostream>
-
-using std::string;
-using std::vector;
-using std::cerr;
-using std::endl;
-
-/**
- * An implementation of SuperCollider's amplitude-follower algorithm
- * as a simple Vamp plugin.
- */
-
-AmplitudeFollower::AmplitudeFollower(float inputSampleRate) :
-    Plugin(inputSampleRate),
-    m_stepSize(0),
-    m_previn(0.0f),
-    m_clampcoef(0.01f),
-    m_relaxcoef(0.01f)
-{
-}
-
-AmplitudeFollower::~AmplitudeFollower()
-{
-}
-
-string
-AmplitudeFollower::getIdentifier() const
-{
-    return "amplitudefollower";
-}
-
-string
-AmplitudeFollower::getName() const
-{
-    return "Amplitude Follower";
-}
-
-string
-AmplitudeFollower::getDescription() const
-{
-    return "Track the amplitude of the audio signal";
-}
-
-string
-AmplitudeFollower::getMaker() const
-{
-    return "Vamp SDK Example Plugins";
-}
-
-int
-AmplitudeFollower::getPluginVersion() const
-{
-    return 1;
-}
-
-string
-AmplitudeFollower::getCopyright() const
-{
-    return "Code copyright 2006 Dan Stowell; method from SuperCollider.  Freely redistributable (BSD license)";
-}
-
-bool
-AmplitudeFollower::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    if (channels < getMinChannelCount() ||
-	channels > getMaxChannelCount()) return false;
-
-    m_stepSize = std::min(stepSize, blockSize);
-	
-    // Translate the coefficients 
-    // from their "convenient" 60dB convergence-time values
-    // to real coefficients
-    m_clampcoef = m_clampcoef==0.0 ? 0.0 : exp(log(0.1)/(m_clampcoef * m_inputSampleRate));
-    m_relaxcoef = m_relaxcoef==0.0 ? 0.0 : exp(log(0.1)/(m_relaxcoef * m_inputSampleRate));
-
-    return true;
-}
-
-void
-AmplitudeFollower::reset()
-{
-    m_previn = 0.0f;
-}
-
-AmplitudeFollower::OutputList
-AmplitudeFollower::getOutputDescriptors() const
-{
-    OutputList list;
-
-    OutputDescriptor sca;
-    sca.identifier = "amplitude";
-    sca.name = "Amplitude";
-    sca.description = "";
-    sca.unit = "V";
-    sca.hasFixedBinCount = true;
-    sca.binCount = 1;
-    sca.hasKnownExtents = false;
-    sca.isQuantized = false;
-    sca.sampleType = OutputDescriptor::OneSamplePerStep;
-    list.push_back(sca);
-
-    return list;
-}
-
-AmplitudeFollower::ParameterList
-AmplitudeFollower::getParameterDescriptors() const
-{
-    ParameterList list;
-	
-    ParameterDescriptor att;
-    att.identifier = "attack";
-    att.name = "Attack time";
-    att.description = "";
-    att.unit = "s";
-    att.minValue = 0.0f;
-    att.maxValue = 1.f;
-    att.defaultValue = 0.01f;
-    att.isQuantized = false;
-    
-    list.push_back(att);
-    
-    ParameterDescriptor dec;
-    dec.identifier = "release";
-    dec.name = "Release time";
-    dec.description = "";
-    dec.unit = "s";
-    dec.minValue = 0.0f;
-    dec.maxValue = 1.f;
-    dec.defaultValue = 0.01f;
-    dec.isQuantized = false;
-    
-    list.push_back(dec);
-    
-    return list;
-}
-
-void AmplitudeFollower::setParameter(std::string paramid, float newval)
-{
-    if (paramid == "attack") {
-        m_clampcoef = newval;
-    } else if (paramid == "release") {
-        m_relaxcoef = newval;
-    }
-}
-
-float AmplitudeFollower::getParameter(std::string paramid) const
-{
-    if (paramid == "attack") {
-        return m_clampcoef;
-    } else if (paramid == "release") {
-        return m_relaxcoef;
-    }
-
-    return 0.0f;
-}
-
-AmplitudeFollower::FeatureSet
-AmplitudeFollower::process(const float *const *inputBuffers,
-                           Vamp::RealTime timestamp)
-{
-    if (m_stepSize == 0) {
-	cerr << "ERROR: AmplitudeFollower::process: "
-	     << "AmplitudeFollower has not been initialised"
-	     << endl;
-	return FeatureSet();
-    }
-
-    float previn = m_previn;
-
-    FeatureSet returnFeatures;
-	
-    float val;
-    float peak = 0.0f;
-
-    for (size_t i = 0; i < m_stepSize; ++i) {
-
-        val = fabs(inputBuffers[0][i]);
-		
-        if (val < previn) {
-            val = val + (previn - val) * m_relaxcoef;
-        } else {
-            val = val + (previn - val) * m_clampcoef;
-        }
-
-        if (val > peak) peak = val;
-        previn = val;
-    }
-
-    m_previn = previn;
-
-    // Now store the "feature" (peak amp) for this sample
-    Feature feature;
-    feature.hasTimestamp = false;
-    feature.values.push_back(peak);
-    returnFeatures[0].push_back(feature);
-
-    return returnFeatures;
-}
-
-AmplitudeFollower::FeatureSet
-AmplitudeFollower::getRemainingFeatures()
-{
-    return FeatureSet();
-}
-
--- a/src/FixedTempoEstimator.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,534 +0,0 @@
-/* -*- 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-2008 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.
-*/
-
-#include "FixedTempoEstimator.h"
-
-using std::string;
-using std::vector;
-using std::cerr;
-using std::endl;
-
-using Vamp::RealTime;
-
-#include <cmath>
-
-
-FixedTempoEstimator::FixedTempoEstimator(float inputSampleRate) :
-    Plugin(inputSampleRate),
-    m_stepSize(0),
-    m_blockSize(0),
-    m_priorMagnitudes(0),
-    m_df(0),
-    m_r(0),
-    m_fr(0),
-    m_t(0),
-    m_n(0)
-{
-}
-
-FixedTempoEstimator::~FixedTempoEstimator()
-{
-    delete[] m_priorMagnitudes;
-    delete[] m_df;
-    delete[] m_r;
-    delete[] m_fr;
-    delete[] m_t;
-}
-
-string
-FixedTempoEstimator::getIdentifier() const
-{
-    return "fixedtempo";
-}
-
-string
-FixedTempoEstimator::getName() const
-{
-    return "Simple Fixed Tempo Estimator";
-}
-
-string
-FixedTempoEstimator::getDescription() const
-{
-    return "Study a short section of audio and estimate its tempo, assuming the tempo is constant";
-}
-
-string
-FixedTempoEstimator::getMaker() const
-{
-    return "Vamp SDK Example Plugins";
-}
-
-int
-FixedTempoEstimator::getPluginVersion() const
-{
-    return 1;
-}
-
-string
-FixedTempoEstimator::getCopyright() const
-{
-    return "Code copyright 2008 Queen Mary, University of London.  Freely redistributable (BSD license)";
-}
-
-size_t
-FixedTempoEstimator::getPreferredStepSize() const
-{
-    return 64;
-}
-
-size_t
-FixedTempoEstimator::getPreferredBlockSize() const
-{
-    return 256;
-}
-
-bool
-FixedTempoEstimator::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    if (channels < getMinChannelCount() ||
-	channels > getMaxChannelCount()) return false;
-
-    m_stepSize = stepSize;
-    m_blockSize = blockSize;
-
-    float dfLengthSecs = 10.f;
-    m_dfsize = (dfLengthSecs * m_inputSampleRate) / m_stepSize;
-
-    m_priorMagnitudes = new float[m_blockSize/2];
-    m_df = new float[m_dfsize];
-
-    for (size_t i = 0; i < m_blockSize/2; ++i) {
-        m_priorMagnitudes[i] = 0.f;
-    }
-    for (size_t i = 0; i < m_dfsize; ++i) {
-        m_df[i] = 0.f;
-    }
-
-    m_n = 0;
-
-    return true;
-}
-
-void
-FixedTempoEstimator::reset()
-{
-    cerr << "FixedTempoEstimator: reset called" << endl;
-
-    if (!m_priorMagnitudes) return;
-
-    cerr << "FixedTempoEstimator: resetting" << endl;
-
-    for (size_t i = 0; i < m_blockSize/2; ++i) {
-        m_priorMagnitudes[i] = 0.f;
-    }
-    for (size_t i = 0; i < m_dfsize; ++i) {
-        m_df[i] = 0.f;
-    }
-
-    delete[] m_r;
-    m_r = 0;
-
-    delete[] m_fr; 
-    m_fr = 0;
-
-    delete[] m_t; 
-    m_t = 0;
-
-    m_n = 0;
-
-    m_start = RealTime::zeroTime;
-    m_lasttime = RealTime::zeroTime;
-}
-
-FixedTempoEstimator::ParameterList
-FixedTempoEstimator::getParameterDescriptors() const
-{
-    ParameterList list;
-    return list;
-}
-
-float
-FixedTempoEstimator::getParameter(std::string id) const
-{
-    return 0.f;
-}
-
-void
-FixedTempoEstimator::setParameter(std::string id, float value)
-{
-}
-
-static int TempoOutput = 0;
-static int CandidatesOutput = 1;
-static int DFOutput = 2;
-static int ACFOutput = 3;
-static int FilteredACFOutput = 4;
-
-FixedTempoEstimator::OutputList
-FixedTempoEstimator::getOutputDescriptors() const
-{
-    OutputList list;
-
-    OutputDescriptor d;
-    d.identifier = "tempo";
-    d.name = "Tempo";
-    d.description = "Estimated tempo";
-    d.unit = "bpm";
-    d.hasFixedBinCount = true;
-    d.binCount = 1;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::VariableSampleRate;
-    d.sampleRate = m_inputSampleRate;
-    d.hasDuration = true; // our returned tempo spans a certain range
-    list.push_back(d);
-
-    d.identifier = "candidates";
-    d.name = "Tempo candidates";
-    d.description = "Possible tempo estimates, one per bin with the most likely in the first bin";
-    d.unit = "bpm";
-    d.hasFixedBinCount = false;
-    list.push_back(d);
-
-    d.identifier = "detectionfunction";
-    d.name = "Detection Function";
-    d.description = "Onset detection function";
-    d.unit = "";
-    d.hasFixedBinCount = 1;
-    d.binCount = 1;
-    d.hasKnownExtents = true;
-    d.minValue = 0.0;
-    d.maxValue = 1.0;
-    d.isQuantized = false;
-    d.quantizeStep = 0.0;
-    d.sampleType = OutputDescriptor::FixedSampleRate;
-    if (m_stepSize) {
-        d.sampleRate = m_inputSampleRate / m_stepSize;
-    } else {
-        d.sampleRate = m_inputSampleRate / (getPreferredBlockSize()/2);
-    }
-    d.hasDuration = false;
-    list.push_back(d);
-
-    d.identifier = "acf";
-    d.name = "Autocorrelation Function";
-    d.description = "Autocorrelation of onset detection function";
-    d.hasKnownExtents = false;
-    d.unit = "r";
-    list.push_back(d);
-
-    d.identifier = "filtered_acf";
-    d.name = "Filtered Autocorrelation";
-    d.description = "Filtered autocorrelation of onset detection function";
-    d.unit = "r";
-    list.push_back(d);
-
-    return list;
-}
-
-FixedTempoEstimator::FeatureSet
-FixedTempoEstimator::process(const float *const *inputBuffers, RealTime ts)
-{
-    FeatureSet fs;
-
-    if (m_stepSize == 0) {
-	cerr << "ERROR: FixedTempoEstimator::process: "
-	     << "FixedTempoEstimator has not been initialised"
-	     << endl;
-	return fs;
-    }
-
-//    if (m_n < m_dfsize) cerr << "m_n = " << m_n << endl;
-
-    if (m_n == 0) m_start = ts;
-    m_lasttime = ts;
-
-    if (m_n == m_dfsize) {
-        calculate();
-        fs = assembleFeatures();
-        ++m_n;
-        return fs;
-    }
-
-    if (m_n > m_dfsize) return FeatureSet();
-
-    float value = 0.f;
-
-    for (size_t i = 1; i < m_blockSize/2; ++i) {
-
-        float real = inputBuffers[0][i*2];
-        float imag = inputBuffers[0][i*2 + 1];
-
-        float sqrmag = real * real + imag * imag;
-        value += fabsf(sqrmag - m_priorMagnitudes[i]);
-
-        m_priorMagnitudes[i] = sqrmag;
-    }
-
-    m_df[m_n] = value;
-
-    ++m_n;
-    return fs;
-}
-
-FixedTempoEstimator::FeatureSet
-FixedTempoEstimator::getRemainingFeatures()
-{
-    FeatureSet fs;
-    if (m_n > m_dfsize) return fs;
-    calculate();
-    fs = assembleFeatures();
-    ++m_n;
-    return fs;
-}
-
-float
-FixedTempoEstimator::lag2tempo(int lag)
-{
-    return 60.f / ((lag * m_stepSize) / m_inputSampleRate);
-}
-
-int
-FixedTempoEstimator::tempo2lag(float tempo)
-{
-    return ((60.f / tempo) * m_inputSampleRate) / m_stepSize;
-}
-
-void
-FixedTempoEstimator::calculate()
-{    
-    cerr << "FixedTempoEstimator::calculate: m_n = " << m_n << endl;
-    
-    if (m_r) {
-        cerr << "FixedTempoEstimator::calculate: calculation already happened?" << endl;
-        return;
-    }
-
-    if (m_n < m_dfsize / 9) {
-        cerr << "FixedTempoEstimator::calculate: Not enough data to go on (have " << m_n << ", want at least " << m_dfsize/4 << ")" << endl;
-        return; // not enough data (perhaps we should return the duration of the input as the "estimated" beat length?)
-    }
-
-    int n = m_n;
-
-    m_r = new float[n/2];
-    m_fr = new float[n/2];
-    m_t = new float[n/2];
-
-    for (int i = 0; i < n/2; ++i) {
-        m_r[i] = 0.f;
-        m_fr[i] = 0.f;
-        m_t[i] = lag2tempo(i);
-    }
-
-    for (int i = 0; i < n/2; ++i) {
-
-        for (int j = i; j < n-1; ++j) {
-            m_r[i] += m_df[j] * m_df[j - i];
-        }
-
-        m_r[i] /= n - i - 1;
-    }
-
-    float related[] = { 0.5, 2, 3, 4 };
-
-    for (int i = 1; i < n/2-1; ++i) {
-
-        float weight = 1.f - fabsf(128.f - lag2tempo(i)) * 0.005;
-        if (weight < 0.f) weight = 0.f;
-        weight = weight * weight * weight;
-
-        m_fr[i] = m_r[i];
-
-        int div = 1;
-
-        for (int j = 0; j < int(sizeof(related)/sizeof(related[0])); ++j) {
-
-            int k0 = int(i * related[j] + 0.5);
-
-            if (k0 >= 0 && k0 < int(n/2)) {
-
-                int kmax = 0, kmin = 0;
-                float kvmax = 0, kvmin = 0;
-                bool have = false;
-
-                for (int k = k0 - 1; k <= k0 + 1; ++k) {
-
-                    if (k < 0 || k >= n/2) continue;
-
-                    if (!have || (m_r[k] > kvmax)) { kmax = k; kvmax = m_r[k]; }
-                    if (!have || (m_r[k] < kvmin)) { kmin = k; kvmin = m_r[k]; }
-                    
-                    have = true;
-                }
-                
-                m_fr[i] += m_r[kmax] / 5;
-
-                if ((kmax == 0 || m_r[kmax] > m_r[kmax-1]) &&
-                    (kmax == n/2-1 || m_r[kmax] > m_r[kmax+1]) &&
-                    kvmax > kvmin * 1.05) {
-                    
-                    m_t[i] = m_t[i] + lag2tempo(kmax) * related[j];
-                    ++div;
-                }
-            }
-        }
-        
-        m_t[i] /= div;
-        
-//        if (div > 1) {
-//            cerr << "adjusting tempo from " << lag2tempo(i) << " to "
-//                 << m_t[i] << " for fr = " << m_fr[i] << " (div = " << div << ")" << endl;
-//        }
-        
-        m_fr[i] += m_fr[i] * (weight / 3);
-    }
-}
-    
-
-FixedTempoEstimator::FeatureSet
-FixedTempoEstimator::assembleFeatures()
-{
-    FeatureSet fs;
-    if (!m_r) return fs; // No results
-
-    Feature feature;
-    feature.hasTimestamp = true;
-    feature.hasDuration = false;
-    feature.label = "";
-    feature.values.clear();
-    feature.values.push_back(0.f);
-
-    char buffer[40];
-
-    int n = m_n;
-
-    for (int i = 0; i < n; ++i) {
-        feature.timestamp = m_start +
-            RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
-        feature.values[0] = m_df[i];
-        feature.label = "";
-        fs[DFOutput].push_back(feature);
-    }
-
-    for (int i = 1; i < n/2; ++i) {
-        feature.timestamp = m_start +
-            RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
-        feature.values[0] = m_r[i];
-        sprintf(buffer, "%.1f bpm", lag2tempo(i));
-        if (i == n/2-1) feature.label = "";
-        else feature.label = buffer;
-        fs[ACFOutput].push_back(feature);
-    }
-
-    float t0 = 50.f; // our minimum detected tempo (could be a parameter)
-    float t1 = 190.f; // our maximum detected tempo
-
-    //!!! need some way for the host (or at least, the user) to know
-    //!!! that it should only pass a certain amount of
-    //!!! input... e.g. by making the amount configurable
-
-    int p0 = tempo2lag(t1);
-    int p1 = tempo2lag(t0);
-
-    std::map<float, int> candidates;
-
-    for (int i = p0; i <= p1 && i < n/2-1; ++i) {
-
-        if (m_fr[i] > m_fr[i-1] &&
-            m_fr[i] > m_fr[i+1]) {
-            candidates[m_fr[i]] = i;
-        }
-
-        feature.timestamp = m_start +
-            RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate);
-        feature.values[0] = m_fr[i];
-        sprintf(buffer, "%.1f bpm", lag2tempo(i));
-        if (i == p1 || i == n/2-2) feature.label = "";
-        else feature.label = buffer;
-        fs[FilteredACFOutput].push_back(feature);
-    }
-
-//    cerr << "maxpi = " << maxpi << " for tempo " << lag2tempo(maxpi) << " (value = " << maxp << ")" << endl;
-
-    if (candidates.empty()) {
-        cerr << "No tempo candidates!" << endl;
-        return fs;
-    }
-
-    feature.hasTimestamp = true;
-    feature.timestamp = m_start;
-    
-    feature.hasDuration = true;
-    feature.duration = m_lasttime - m_start;
-
-    std::map<float, int>::const_iterator ci = candidates.end();
-    --ci;
-    int maxpi = ci->second;
-
-    if (m_t[maxpi] > 0) {
-        cerr << "*** Using adjusted tempo " << m_t[maxpi] << " instead of lag tempo " << lag2tempo(maxpi) << endl;
-        feature.values[0] = m_t[maxpi];
-    } else {
-        // shouldn't happen -- it would imply that this high value was not a peak!
-        feature.values[0] = lag2tempo(maxpi);
-        cerr << "WARNING: No stored tempo for index " << maxpi << endl;
-    }
-
-    sprintf(buffer, "%.1f bpm", feature.values[0]);
-    feature.label = buffer;
-
-    fs[TempoOutput].push_back(feature);
-
-    feature.values.clear();
-    feature.label = "";
-
-    while (feature.values.size() < 8) {
-//        cerr << "adding tempo value from lag " << ci->second << endl;
-        if (m_t[ci->second] > 0) {
-            feature.values.push_back(m_t[ci->second]);
-        } else {
-            feature.values.push_back(lag2tempo(ci->second));
-        }
-        if (ci == candidates.begin()) break;
-        --ci;
-    }
-
-    fs[CandidatesOutput].push_back(feature);
-    
-    return fs;
-}
--- a/src/PercussionOnsetDetector.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,285 +0,0 @@
-/* -*- 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 "PercussionOnsetDetector.h"
-
-using std::string;
-using std::vector;
-using std::cerr;
-using std::endl;
-
-#include <cmath>
-
-
-PercussionOnsetDetector::PercussionOnsetDetector(float inputSampleRate) :
-    Plugin(inputSampleRate),
-    m_stepSize(0),
-    m_blockSize(0),
-    m_threshold(3),
-    m_sensitivity(40),
-    m_priorMagnitudes(0),
-    m_dfMinus1(0),
-    m_dfMinus2(0)
-{
-}
-
-PercussionOnsetDetector::~PercussionOnsetDetector()
-{
-    delete[] m_priorMagnitudes;
-}
-
-string
-PercussionOnsetDetector::getIdentifier() const
-{
-    return "percussiononsets";
-}
-
-string
-PercussionOnsetDetector::getName() const
-{
-    return "Simple Percussion Onset Detector";
-}
-
-string
-PercussionOnsetDetector::getDescription() const
-{
-    return "Detect percussive note onsets by identifying broadband energy rises";
-}
-
-string
-PercussionOnsetDetector::getMaker() const
-{
-    return "Vamp SDK Example Plugins";
-}
-
-int
-PercussionOnsetDetector::getPluginVersion() const
-{
-    return 2;
-}
-
-string
-PercussionOnsetDetector::getCopyright() const
-{
-    return "Code copyright 2006 Queen Mary, University of London, after Dan Barry et al 2005.  Freely redistributable (BSD license)";
-}
-
-size_t
-PercussionOnsetDetector::getPreferredStepSize() const
-{
-    return 0;
-}
-
-size_t
-PercussionOnsetDetector::getPreferredBlockSize() const
-{
-    return 1024;
-}
-
-bool
-PercussionOnsetDetector::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    if (channels < getMinChannelCount() ||
-	channels > getMaxChannelCount()) return false;
-
-    m_stepSize = stepSize;
-    m_blockSize = blockSize;
-
-    m_priorMagnitudes = new float[m_blockSize/2];
-
-    for (size_t i = 0; i < m_blockSize/2; ++i) {
-        m_priorMagnitudes[i] = 0.f;
-    }
-
-    m_dfMinus1 = 0.f;
-    m_dfMinus2 = 0.f;
-
-    return true;
-}
-
-void
-PercussionOnsetDetector::reset()
-{
-    for (size_t i = 0; i < m_blockSize/2; ++i) {
-        m_priorMagnitudes[i] = 0.f;
-    }
-
-    m_dfMinus1 = 0.f;
-    m_dfMinus2 = 0.f;
-}
-
-PercussionOnsetDetector::ParameterList
-PercussionOnsetDetector::getParameterDescriptors() const
-{
-    ParameterList list;
-
-    ParameterDescriptor d;
-    d.identifier = "threshold";
-    d.name = "Energy rise threshold";
-    d.description = "Energy rise within a frequency bin necessary to count toward broadband total";
-    d.unit = "dB";
-    d.minValue = 0;
-    d.maxValue = 20;
-    d.defaultValue = 3;
-    d.isQuantized = false;
-    list.push_back(d);
-
-    d.identifier = "sensitivity";
-    d.name = "Sensitivity";
-    d.description = "Sensitivity of peak detector applied to broadband detection function";
-    d.unit = "%";
-    d.minValue = 0;
-    d.maxValue = 100;
-    d.defaultValue = 40;
-    d.isQuantized = false;
-    list.push_back(d);
-
-    return list;
-}
-
-float
-PercussionOnsetDetector::getParameter(std::string id) const
-{
-    if (id == "threshold") return m_threshold;
-    if (id == "sensitivity") return m_sensitivity;
-    return 0.f;
-}
-
-void
-PercussionOnsetDetector::setParameter(std::string id, float value)
-{
-    if (id == "threshold") {
-        if (value < 0) value = 0;
-        if (value > 20) value = 20;
-        m_threshold = value;
-    } else if (id == "sensitivity") {
-        if (value < 0) value = 0;
-        if (value > 100) value = 100;
-        m_sensitivity = value;
-    }
-}
-
-PercussionOnsetDetector::OutputList
-PercussionOnsetDetector::getOutputDescriptors() const
-{
-    OutputList list;
-
-    OutputDescriptor d;
-    d.identifier = "onsets";
-    d.name = "Onsets";
-    d.description = "Percussive note onset locations";
-    d.unit = "";
-    d.hasFixedBinCount = true;
-    d.binCount = 0;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::VariableSampleRate;
-    d.sampleRate = m_inputSampleRate;
-    list.push_back(d);
-
-    d.identifier = "detectionfunction";
-    d.name = "Detection Function";
-    d.description = "Broadband energy rise detection function";
-    d.binCount = 1;
-    d.isQuantized = true;
-    d.quantizeStep = 1.0;
-    d.sampleType = OutputDescriptor::OneSamplePerStep;
-    list.push_back(d);
-
-    return list;
-}
-
-PercussionOnsetDetector::FeatureSet
-PercussionOnsetDetector::process(const float *const *inputBuffers,
-                                 Vamp::RealTime ts)
-{
-    if (m_stepSize == 0) {
-	cerr << "ERROR: PercussionOnsetDetector::process: "
-	     << "PercussionOnsetDetector has not been initialised"
-	     << endl;
-	return FeatureSet();
-    }
-
-    int count = 0;
-
-    for (size_t i = 1; i < m_blockSize/2; ++i) {
-
-        float real = inputBuffers[0][i*2];
-        float imag = inputBuffers[0][i*2 + 1];
-
-        float sqrmag = real * real + imag * imag;
-
-        if (m_priorMagnitudes[i] > 0.f) {
-            float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]);
-
-//        std::cout << "i=" << i << ", mag=" << mag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << std::endl;
-
-            if (diff >= m_threshold) ++count;
-        }
-
-        m_priorMagnitudes[i] = sqrmag;
-    }
-
-    FeatureSet returnFeatures;
-
-    Feature detectionFunction;
-    detectionFunction.hasTimestamp = false;
-    detectionFunction.values.push_back(count);
-    returnFeatures[1].push_back(detectionFunction);
-
-    if (m_dfMinus2 < m_dfMinus1 &&
-        m_dfMinus1 >= count &&
-        m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) {
-
-        Feature onset;
-        onset.hasTimestamp = true;
-        onset.timestamp = ts - Vamp::RealTime::frame2RealTime
-            (m_stepSize, int(m_inputSampleRate + 0.5));
-        returnFeatures[0].push_back(onset);
-    }
-
-    m_dfMinus2 = m_dfMinus1;
-    m_dfMinus1 = count;
-
-    return returnFeatures;
-}
-
-PercussionOnsetDetector::FeatureSet
-PercussionOnsetDetector::getRemainingFeatures()
-{
-    return FeatureSet();
-}
-
--- a/src/PluginAdapter.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,873 +0,0 @@
-/* -*- 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 "PluginAdapter.h"
-
-#include <cstring>
-#include <cstdlib>
-
-//#define DEBUG_PLUGIN_ADAPTER 1
-
-namespace Vamp {
-
-class PluginAdapterBase::Impl
-{
-public:
-    Impl(PluginAdapterBase *);
-    ~Impl();
-
-    const VampPluginDescriptor *getDescriptor();
-
-protected:
-    PluginAdapterBase *m_base;
-
-    static VampPluginHandle vampInstantiate(const VampPluginDescriptor *desc,
-                                            float inputSampleRate);
-
-    static void vampCleanup(VampPluginHandle handle);
-
-    static int vampInitialise(VampPluginHandle handle, unsigned int channels,
-                             unsigned int stepSize, unsigned int blockSize);
-
-    static void vampReset(VampPluginHandle handle);
-
-    static float vampGetParameter(VampPluginHandle handle, int param);
-    static void vampSetParameter(VampPluginHandle handle, int param, float value);
-
-    static unsigned int vampGetCurrentProgram(VampPluginHandle handle);
-    static void vampSelectProgram(VampPluginHandle handle, unsigned int program);
-
-    static unsigned int vampGetPreferredStepSize(VampPluginHandle handle);
-    static unsigned int vampGetPreferredBlockSize(VampPluginHandle handle);
-    static unsigned int vampGetMinChannelCount(VampPluginHandle handle);
-    static unsigned int vampGetMaxChannelCount(VampPluginHandle handle);
-
-    static unsigned int vampGetOutputCount(VampPluginHandle handle);
-
-    static VampOutputDescriptor *vampGetOutputDescriptor(VampPluginHandle handle,
-                                                       unsigned int i);
-
-    static void vampReleaseOutputDescriptor(VampOutputDescriptor *desc);
-
-    static VampFeatureList *vampProcess(VampPluginHandle handle,
-                                        const float *const *inputBuffers,
-                                        int sec,
-                                        int nsec);
-
-    static VampFeatureList *vampGetRemainingFeatures(VampPluginHandle handle);
-
-    static void vampReleaseFeatureSet(VampFeatureList *fs);
-
-    void cleanup(Plugin *plugin);
-    void checkOutputMap(Plugin *plugin);
-    unsigned int getOutputCount(Plugin *plugin);
-    VampOutputDescriptor *getOutputDescriptor(Plugin *plugin,
-                                             unsigned int i);
-    VampFeatureList *process(Plugin *plugin,
-                             const float *const *inputBuffers,
-                             int sec, int nsec);
-    VampFeatureList *getRemainingFeatures(Plugin *plugin);
-    VampFeatureList *convertFeatures(Plugin *plugin,
-                                     const Plugin::FeatureSet &features);
-    
-    // maps both plugins and descriptors to adapters
-    typedef std::map<const void *, Impl *> AdapterMap;
-    static AdapterMap *m_adapterMap;
-    static Impl *lookupAdapter(VampPluginHandle);
-
-    bool m_populated;
-    VampPluginDescriptor m_descriptor;
-    Plugin::ParameterList m_parameters;
-    Plugin::ProgramList m_programs;
-    
-    typedef std::map<Plugin *, Plugin::OutputList *> OutputMap;
-    OutputMap m_pluginOutputs;
-
-    std::map<Plugin *, VampFeatureList *> m_fs;
-    std::map<Plugin *, std::vector<size_t> > m_fsizes;
-    std::map<Plugin *, std::vector<std::vector<size_t> > > m_fvsizes;
-    void resizeFS(Plugin *plugin, int n);
-    void resizeFL(Plugin *plugin, int n, size_t sz);
-    void resizeFV(Plugin *plugin, int n, int j, size_t sz);
-};
-
-PluginAdapterBase::PluginAdapterBase()
-{
-    m_impl = new Impl(this);
-}
-
-PluginAdapterBase::~PluginAdapterBase()
-{
-    delete m_impl;
-}
-
-const VampPluginDescriptor *
-PluginAdapterBase::getDescriptor()
-{
-    return m_impl->getDescriptor();
-}
-
-PluginAdapterBase::Impl::Impl(PluginAdapterBase *base) :
-    m_base(base),
-    m_populated(false)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl[" << this << "]::Impl" << std::endl;
-#endif
-}
-
-const VampPluginDescriptor *
-PluginAdapterBase::Impl::getDescriptor()
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl[" << this << "]::getDescriptor" << std::endl;
-#endif
-
-    if (m_populated) return &m_descriptor;
-
-    Plugin *plugin = m_base->createPlugin(48000);
-
-    if (plugin->getVampApiVersion() != VAMP_API_VERSION) {
-        std::cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: "
-                  << "API version " << plugin->getVampApiVersion()
-                  << " for\nplugin \"" << plugin->getIdentifier() << "\" "
-                  << "differs from version "
-                  << VAMP_API_VERSION << " for adapter.\n"
-                  << "This plugin is probably linked against a different version of the Vamp SDK\n"
-                  << "from the version it was compiled with.  It will need to be re-linked correctly\n"
-                  << "before it can be used." << std::endl;
-        delete plugin;
-        return 0;
-    }
-
-    m_parameters = plugin->getParameterDescriptors();
-    m_programs = plugin->getPrograms();
-
-    m_descriptor.vampApiVersion = plugin->getVampApiVersion();
-    m_descriptor.identifier = strdup(plugin->getIdentifier().c_str());
-    m_descriptor.name = strdup(plugin->getName().c_str());
-    m_descriptor.description = strdup(plugin->getDescription().c_str());
-    m_descriptor.maker = strdup(plugin->getMaker().c_str());
-    m_descriptor.pluginVersion = plugin->getPluginVersion();
-    m_descriptor.copyright = strdup(plugin->getCopyright().c_str());
-    
-    m_descriptor.parameterCount = m_parameters.size();
-    m_descriptor.parameters = (const VampParameterDescriptor **)
-        malloc(m_parameters.size() * sizeof(VampParameterDescriptor));
-
-    unsigned int i;
-    
-    for (i = 0; i < m_parameters.size(); ++i) {
-        VampParameterDescriptor *desc = (VampParameterDescriptor *)
-            malloc(sizeof(VampParameterDescriptor));
-        desc->identifier = strdup(m_parameters[i].identifier.c_str());
-        desc->name = strdup(m_parameters[i].name.c_str());
-        desc->description = strdup(m_parameters[i].description.c_str());
-        desc->unit = strdup(m_parameters[i].unit.c_str());
-        desc->minValue = m_parameters[i].minValue;
-        desc->maxValue = m_parameters[i].maxValue;
-        desc->defaultValue = m_parameters[i].defaultValue;
-        desc->isQuantized = m_parameters[i].isQuantized;
-        desc->quantizeStep = m_parameters[i].quantizeStep;
-        desc->valueNames = 0;
-        if (desc->isQuantized && !m_parameters[i].valueNames.empty()) {
-            desc->valueNames = (const char **)
-                malloc((m_parameters[i].valueNames.size()+1) * sizeof(char *));
-            for (unsigned int j = 0; j < m_parameters[i].valueNames.size(); ++j) {
-                desc->valueNames[j] = strdup(m_parameters[i].valueNames[j].c_str());
-            }
-            desc->valueNames[m_parameters[i].valueNames.size()] = 0;
-        }
-        m_descriptor.parameters[i] = desc;
-    }
-    
-    m_descriptor.programCount = m_programs.size();
-    m_descriptor.programs = (const char **)
-        malloc(m_programs.size() * sizeof(const char *));
-    
-    for (i = 0; i < m_programs.size(); ++i) {
-        m_descriptor.programs[i] = strdup(m_programs[i].c_str());
-    }
-    
-    if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
-        m_descriptor.inputDomain = vampFrequencyDomain;
-    } else {
-        m_descriptor.inputDomain = vampTimeDomain;
-    }
-
-    m_descriptor.instantiate = vampInstantiate;
-    m_descriptor.cleanup = vampCleanup;
-    m_descriptor.initialise = vampInitialise;
-    m_descriptor.reset = vampReset;
-    m_descriptor.getParameter = vampGetParameter;
-    m_descriptor.setParameter = vampSetParameter;
-    m_descriptor.getCurrentProgram = vampGetCurrentProgram;
-    m_descriptor.selectProgram = vampSelectProgram;
-    m_descriptor.getPreferredStepSize = vampGetPreferredStepSize;
-    m_descriptor.getPreferredBlockSize = vampGetPreferredBlockSize;
-    m_descriptor.getMinChannelCount = vampGetMinChannelCount;
-    m_descriptor.getMaxChannelCount = vampGetMaxChannelCount;
-    m_descriptor.getOutputCount = vampGetOutputCount;
-    m_descriptor.getOutputDescriptor = vampGetOutputDescriptor;
-    m_descriptor.releaseOutputDescriptor = vampReleaseOutputDescriptor;
-    m_descriptor.process = vampProcess;
-    m_descriptor.getRemainingFeatures = vampGetRemainingFeatures;
-    m_descriptor.releaseFeatureSet = vampReleaseFeatureSet;
-    
-    if (!m_adapterMap) {
-        m_adapterMap = new AdapterMap;
-    }
-    (*m_adapterMap)[&m_descriptor] = this;
-
-    delete plugin;
-
-    m_populated = true;
-    return &m_descriptor;
-}
-
-PluginAdapterBase::Impl::~Impl()
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl[" << this << "]::~Impl" << std::endl;
-#endif
-
-    if (!m_populated) return;
-
-    free((void *)m_descriptor.identifier);
-    free((void *)m_descriptor.name);
-    free((void *)m_descriptor.description);
-    free((void *)m_descriptor.maker);
-    free((void *)m_descriptor.copyright);
-        
-    for (unsigned int i = 0; i < m_descriptor.parameterCount; ++i) {
-        const VampParameterDescriptor *desc = m_descriptor.parameters[i];
-        free((void *)desc->identifier);
-        free((void *)desc->name);
-        free((void *)desc->description);
-        free((void *)desc->unit);
-        if (desc->valueNames) {
-            for (unsigned int j = 0; desc->valueNames[j]; ++j) {
-                free((void *)desc->valueNames[j]);
-            }
-            free((void *)desc->valueNames);
-        }
-    }
-    free((void *)m_descriptor.parameters);
-
-    for (unsigned int i = 0; i < m_descriptor.programCount; ++i) {
-        free((void *)m_descriptor.programs[i]);
-    }
-    free((void *)m_descriptor.programs);
-
-    if (m_adapterMap) {
-        
-        m_adapterMap->erase(&m_descriptor);
-
-        if (m_adapterMap->empty()) {
-            delete m_adapterMap;
-            m_adapterMap = 0;
-        }
-    }
-}
-
-PluginAdapterBase::Impl *
-PluginAdapterBase::Impl::lookupAdapter(VampPluginHandle handle)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::lookupAdapter(" << handle << ")" << std::endl;
-#endif
-
-    if (!m_adapterMap) return 0;
-    AdapterMap::const_iterator i = m_adapterMap->find(handle);
-    if (i == m_adapterMap->end()) return 0;
-    return i->second;
-}
-
-VampPluginHandle
-PluginAdapterBase::Impl::vampInstantiate(const VampPluginDescriptor *desc,
-                                   float inputSampleRate)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << ")" << std::endl;
-#endif
-
-    if (!m_adapterMap) {
-        m_adapterMap = new AdapterMap();
-    }
-
-    if (m_adapterMap->find(desc) == m_adapterMap->end()) {
-        std::cerr << "WARNING: PluginAdapterBase::Impl::vampInstantiate: Descriptor " << desc << " not in adapter map" << std::endl;
-        return 0;
-    }
-
-    Impl *adapter = (*m_adapterMap)[desc];
-    if (desc != &adapter->m_descriptor) return 0;
-
-    Plugin *plugin = adapter->m_base->createPlugin(inputSampleRate);
-    if (plugin) {
-        (*m_adapterMap)[plugin] = adapter;
-    }
-
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << "): returning handle " << plugin << std::endl;
-#endif
-
-    return plugin;
-}
-
-void
-PluginAdapterBase::Impl::vampCleanup(VampPluginHandle handle)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampCleanup(" << handle << ")" << std::endl;
-#endif
-
-    Impl *adapter = lookupAdapter(handle);
-    if (!adapter) {
-        delete ((Plugin *)handle);
-        return;
-    }
-    adapter->cleanup(((Plugin *)handle));
-}
-
-int
-PluginAdapterBase::Impl::vampInitialise(VampPluginHandle handle,
-                                  unsigned int channels,
-                                  unsigned int stepSize,
-                                  unsigned int blockSize)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << std::endl;
-#endif
-
-    bool result = ((Plugin *)handle)->initialise
-        (channels, stepSize, blockSize);
-    return result ? 1 : 0;
-}
-
-void
-PluginAdapterBase::Impl::vampReset(VampPluginHandle handle) 
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampReset(" << handle << ")" << std::endl;
-#endif
-
-    ((Plugin *)handle)->reset();
-}
-
-float
-PluginAdapterBase::Impl::vampGetParameter(VampPluginHandle handle,
-                                    int param) 
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetParameter(" << handle << ", " << param << ")" << std::endl;
-#endif
-
-    Impl *adapter = lookupAdapter(handle);
-    if (!adapter) return 0.0;
-    Plugin::ParameterList &list = adapter->m_parameters;
-    return ((Plugin *)handle)->getParameter(list[param].identifier);
-}
-
-void
-PluginAdapterBase::Impl::vampSetParameter(VampPluginHandle handle,
-                                    int param, float value)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << std::endl;
-#endif
-
-    Impl *adapter = lookupAdapter(handle);
-    if (!adapter) return;
-    Plugin::ParameterList &list = adapter->m_parameters;
-    ((Plugin *)handle)->setParameter(list[param].identifier, value);
-}
-
-unsigned int
-PluginAdapterBase::Impl::vampGetCurrentProgram(VampPluginHandle handle)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetCurrentProgram(" << handle << ")" << std::endl;
-#endif
-
-    Impl *adapter = lookupAdapter(handle);
-    if (!adapter) return 0;
-    Plugin::ProgramList &list = adapter->m_programs;
-    std::string program = ((Plugin *)handle)->getCurrentProgram();
-    for (unsigned int i = 0; i < list.size(); ++i) {
-        if (list[i] == program) return i;
-    }
-    return 0;
-}
-
-void
-PluginAdapterBase::Impl::vampSelectProgram(VampPluginHandle handle,
-                                     unsigned int program)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << std::endl;
-#endif
-
-    Impl *adapter = lookupAdapter(handle);
-    if (!adapter) return;
-    Plugin::ProgramList &list = adapter->m_programs;
-    ((Plugin *)handle)->selectProgram(list[program]);
-}
-
-unsigned int
-PluginAdapterBase::Impl::vampGetPreferredStepSize(VampPluginHandle handle)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetPreferredStepSize(" << handle << ")" << std::endl;
-#endif
-
-    return ((Plugin *)handle)->getPreferredStepSize();
-}
-
-unsigned int
-PluginAdapterBase::Impl::vampGetPreferredBlockSize(VampPluginHandle handle) 
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetPreferredBlockSize(" << handle << ")" << std::endl;
-#endif
-
-    return ((Plugin *)handle)->getPreferredBlockSize();
-}
-
-unsigned int
-PluginAdapterBase::Impl::vampGetMinChannelCount(VampPluginHandle handle)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetMinChannelCount(" << handle << ")" << std::endl;
-#endif
-
-    return ((Plugin *)handle)->getMinChannelCount();
-}
-
-unsigned int
-PluginAdapterBase::Impl::vampGetMaxChannelCount(VampPluginHandle handle)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetMaxChannelCount(" << handle << ")" << std::endl;
-#endif
-
-    return ((Plugin *)handle)->getMaxChannelCount();
-}
-
-unsigned int
-PluginAdapterBase::Impl::vampGetOutputCount(VampPluginHandle handle)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetOutputCount(" << handle << ")" << std::endl;
-#endif
-
-    Impl *adapter = lookupAdapter(handle);
-
-//    std::cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << std::endl;
-
-    if (!adapter) return 0;
-    return adapter->getOutputCount((Plugin *)handle);
-}
-
-VampOutputDescriptor *
-PluginAdapterBase::Impl::vampGetOutputDescriptor(VampPluginHandle handle,
-                                           unsigned int i)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetOutputDescriptor(" << handle << ", " << i << ")" << std::endl;
-#endif
-
-    Impl *adapter = lookupAdapter(handle);
-
-//    std::cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << std::endl;
-
-    if (!adapter) return 0;
-    return adapter->getOutputDescriptor((Plugin *)handle, i);
-}
-
-void
-PluginAdapterBase::Impl::vampReleaseOutputDescriptor(VampOutputDescriptor *desc)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampReleaseOutputDescriptor(" << desc << ")" << std::endl;
-#endif
-
-    if (desc->identifier) free((void *)desc->identifier);
-    if (desc->name) free((void *)desc->name);
-    if (desc->description) free((void *)desc->description);
-    if (desc->unit) free((void *)desc->unit);
-    if (desc->hasFixedBinCount && desc->binNames) {
-        for (unsigned int i = 0; i < desc->binCount; ++i) {
-            if (desc->binNames[i]) {
-                free((void *)desc->binNames[i]);
-            }
-        }
-    }
-    if (desc->binNames) free((void *)desc->binNames);
-    free((void *)desc);
-}
-
-VampFeatureList *
-PluginAdapterBase::Impl::vampProcess(VampPluginHandle handle,
-                                     const float *const *inputBuffers,
-                                     int sec,
-                                     int nsec)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << std::endl;
-#endif
-
-    Impl *adapter = lookupAdapter(handle);
-    if (!adapter) return 0;
-    return adapter->process((Plugin *)handle,
-                            inputBuffers, sec, nsec);
-}
-
-VampFeatureList *
-PluginAdapterBase::Impl::vampGetRemainingFeatures(VampPluginHandle handle)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetRemainingFeatures(" << handle << ")" << std::endl;
-#endif
-
-    Impl *adapter = lookupAdapter(handle);
-    if (!adapter) return 0;
-    return adapter->getRemainingFeatures((Plugin *)handle);
-}
-
-void
-PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *fs)
-{
-#ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << std::endl;
-#endif
-}
-
-void 
-PluginAdapterBase::Impl::cleanup(Plugin *plugin)
-{
-    if (m_fs.find(plugin) != m_fs.end()) {
-        size_t outputCount = 0;
-        if (m_pluginOutputs[plugin]) {
-            outputCount = m_pluginOutputs[plugin]->size();
-        }
-        VampFeatureList *list = m_fs[plugin];
-        for (unsigned int i = 0; i < outputCount; ++i) {
-            for (unsigned int j = 0; j < m_fsizes[plugin][i]; ++j) {
-                if (list[i].features[j].v1.label) {
-                    free(list[i].features[j].v1.label);
-                }
-                if (list[i].features[j].v1.values) {
-                    free(list[i].features[j].v1.values);
-                }
-            }
-            if (list[i].features) free(list[i].features);
-        }
-        m_fs.erase(plugin);
-        m_fsizes.erase(plugin);
-        m_fvsizes.erase(plugin);
-    }
-
-    if (m_pluginOutputs.find(plugin) != m_pluginOutputs.end()) {
-        delete m_pluginOutputs[plugin];
-        m_pluginOutputs.erase(plugin);
-    }
-
-    if (m_adapterMap) {
-        m_adapterMap->erase(plugin);
-
-        if (m_adapterMap->empty()) {
-            delete m_adapterMap;
-            m_adapterMap = 0;
-        }
-    }
-
-    delete ((Plugin *)plugin);
-}
-
-void 
-PluginAdapterBase::Impl::checkOutputMap(Plugin *plugin)
-{
-    if (m_pluginOutputs.find(plugin) == m_pluginOutputs.end() ||
-        !m_pluginOutputs[plugin]) {
-        m_pluginOutputs[plugin] = new Plugin::OutputList
-            (plugin->getOutputDescriptors());
-//        std::cerr << "PluginAdapterBase::Impl::checkOutputMap: Have " << m_pluginOutputs[plugin]->size() << " outputs for plugin " << plugin->getIdentifier() << std::endl;
-    }
-}
-
-unsigned int 
-PluginAdapterBase::Impl::getOutputCount(Plugin *plugin)
-{
-    checkOutputMap(plugin);
-    return m_pluginOutputs[plugin]->size();
-}
-
-VampOutputDescriptor *
-PluginAdapterBase::Impl::getOutputDescriptor(Plugin *plugin,
-                                       unsigned int i)
-{
-    checkOutputMap(plugin);
-    Plugin::OutputDescriptor &od =
-        (*m_pluginOutputs[plugin])[i];
-
-    VampOutputDescriptor *desc = (VampOutputDescriptor *)
-        malloc(sizeof(VampOutputDescriptor));
-
-    desc->identifier = strdup(od.identifier.c_str());
-    desc->name = strdup(od.name.c_str());
-    desc->description = strdup(od.description.c_str());
-    desc->unit = strdup(od.unit.c_str());
-    desc->hasFixedBinCount = od.hasFixedBinCount;
-    desc->binCount = od.binCount;
-
-    if (od.hasFixedBinCount && od.binCount > 0) {
-        desc->binNames = (const char **)
-            malloc(od.binCount * sizeof(const char *));
-        
-        for (unsigned int i = 0; i < od.binCount; ++i) {
-            if (i < od.binNames.size()) {
-                desc->binNames[i] = strdup(od.binNames[i].c_str());
-            } else {
-                desc->binNames[i] = 0;
-            }
-        }
-    } else {
-        desc->binNames = 0;
-    }
-
-    desc->hasKnownExtents = od.hasKnownExtents;
-    desc->minValue = od.minValue;
-    desc->maxValue = od.maxValue;
-    desc->isQuantized = od.isQuantized;
-    desc->quantizeStep = od.quantizeStep;
-
-    switch (od.sampleType) {
-    case Plugin::OutputDescriptor::OneSamplePerStep:
-        desc->sampleType = vampOneSamplePerStep; break;
-    case Plugin::OutputDescriptor::FixedSampleRate:
-        desc->sampleType = vampFixedSampleRate; break;
-    case Plugin::OutputDescriptor::VariableSampleRate:
-        desc->sampleType = vampVariableSampleRate; break;
-    }
-
-    desc->sampleRate = od.sampleRate;
-    desc->hasDuration = od.hasDuration;
-
-    return desc;
-}
-    
-VampFeatureList *
-PluginAdapterBase::Impl::process(Plugin *plugin,
-                                 const float *const *inputBuffers,
-                                 int sec, int nsec)
-{
-//    std::cerr << "PluginAdapterBase::Impl::process" << std::endl;
-    RealTime rt(sec, nsec);
-    checkOutputMap(plugin);
-    return convertFeatures(plugin, plugin->process(inputBuffers, rt));
-}
-    
-VampFeatureList *
-PluginAdapterBase::Impl::getRemainingFeatures(Plugin *plugin)
-{
-//    std::cerr << "PluginAdapterBase::Impl::getRemainingFeatures" << std::endl;
-    checkOutputMap(plugin);
-    return convertFeatures(plugin, plugin->getRemainingFeatures());
-}
-
-VampFeatureList *
-PluginAdapterBase::Impl::convertFeatures(Plugin *plugin,
-                                         const Plugin::FeatureSet &features)
-{
-    int lastN = -1;
-
-    int outputCount = 0;
-    if (m_pluginOutputs[plugin]) outputCount = m_pluginOutputs[plugin]->size();
-    
-    resizeFS(plugin, outputCount);
-    VampFeatureList *fs = m_fs[plugin];
-
-//    std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: sizeof(Feature) == " << sizeof(Plugin::Feature) << ", sizeof(VampFeature) == " << sizeof(VampFeature) << ", sizeof(VampFeatureList) == " << sizeof(VampFeatureList) << std::endl;
-
-    for (Plugin::FeatureSet::const_iterator fi = features.begin();
-         fi != features.end(); ++fi) {
-
-        int n = fi->first;
-        
-//        std::cerr << "PluginAdapterBase::Impl::convertFeatures: n = " << n << std::endl;
-
-        if (n >= int(outputCount)) {
-            std::cerr << "WARNING: PluginAdapterBase::Impl::convertFeatures: Too many outputs from plugin (" << n+1 << ", only should be " << outputCount << ")" << std::endl;
-            continue;
-        }
-
-        if (n > lastN + 1) {
-            for (int i = lastN + 1; i < n; ++i) {
-                fs[i].featureCount = 0;
-            }
-        }
-
-        const Plugin::FeatureList &fl = fi->second;
-
-        size_t sz = fl.size();
-        if (sz > m_fsizes[plugin][n]) resizeFL(plugin, n, sz);
-        fs[n].featureCount = sz;
-        
-        for (size_t j = 0; j < sz; ++j) {
-
-//            std::cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << std::endl;
-
-            VampFeature *feature = &fs[n].features[j].v1;
-
-            feature->hasTimestamp = fl[j].hasTimestamp;
-            feature->sec = fl[j].timestamp.sec;
-            feature->nsec = fl[j].timestamp.nsec;
-            feature->valueCount = fl[j].values.size();
-
-            VampFeatureV2 *v2 = &fs[n].features[j + sz].v2;
-            
-            v2->hasDuration = fl[j].hasDuration;
-            v2->durationSec = fl[j].duration.sec;
-            v2->durationNsec = fl[j].duration.nsec;
-
-            if (feature->label) free(feature->label);
-
-            if (fl[j].label.empty()) {
-                feature->label = 0;
-            } else {
-                feature->label = strdup(fl[j].label.c_str());
-            }
-
-            if (feature->valueCount > m_fvsizes[plugin][n][j]) {
-                resizeFV(plugin, n, j, feature->valueCount);
-            }
-
-            for (unsigned int k = 0; k < feature->valueCount; ++k) {
-//                std::cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << std::endl;
-                feature->values[k] = fl[j].values[k];
-            }
-        }
-
-        lastN = n;
-    }
-
-    if (lastN == -1) return 0;
-
-    if (int(outputCount) > lastN + 1) {
-        for (int i = lastN + 1; i < int(outputCount); ++i) {
-            fs[i].featureCount = 0;
-        }
-    }
-
-//    std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: have " << outputCount << " outputs" << std::endl;
-//    for (int i = 0; i < outputCount; ++i) {
-//        std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: output " << i << " has " << fs[i].featureCount << " features" << std::endl;
-//    }
-
-
-    return fs;
-}
-
-void
-PluginAdapterBase::Impl::resizeFS(Plugin *plugin, int n)
-{
-//    std::cerr << "PluginAdapterBase::Impl::resizeFS(" << plugin << ", " << n << ")" << std::endl;
-
-    int i = m_fsizes[plugin].size();
-    if (i >= n) return;
-
-//    std::cerr << "resizing from " << i << std::endl;
-
-    m_fs[plugin] = (VampFeatureList *)realloc
-        (m_fs[plugin], n * sizeof(VampFeatureList));
-
-    while (i < n) {
-        m_fs[plugin][i].featureCount = 0;
-        m_fs[plugin][i].features = 0;
-        m_fsizes[plugin].push_back(0);
-        m_fvsizes[plugin].push_back(std::vector<size_t>());
-        i++;
-    }
-}
-
-void
-PluginAdapterBase::Impl::resizeFL(Plugin *plugin, int n, size_t sz)
-{
-//    std::cerr << "PluginAdapterBase::Impl::resizeFL(" << plugin << ", " << n << ", "
-//              << sz << ")" << std::endl;
-
-    size_t i = m_fsizes[plugin][n];
-    if (i >= sz) return;
-
-//    std::cerr << "resizing from " << i << std::endl;
-
-    m_fs[plugin][n].features = (VampFeatureUnion *)realloc
-        (m_fs[plugin][n].features, 2 * sz * sizeof(VampFeatureUnion));
-
-    while (m_fsizes[plugin][n] < sz) {
-        m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.hasTimestamp = 0;
-        m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.valueCount = 0;
-        m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.values = 0;
-        m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.label = 0;
-        m_fs[plugin][n].features[m_fsizes[plugin][n] + sz].v2.hasDuration = 0;
-        m_fvsizes[plugin][n].push_back(0);
-        m_fsizes[plugin][n]++;
-    }
-}
-
-void
-PluginAdapterBase::Impl::resizeFV(Plugin *plugin, int n, int j, size_t sz)
-{
-//    std::cerr << "PluginAdapterBase::Impl::resizeFV(" << plugin << ", " << n << ", "
-//              << j << ", " << sz << ")" << std::endl;
-
-    size_t i = m_fvsizes[plugin][n][j];
-    if (i >= sz) return;
-
-//    std::cerr << "resizing from " << i << std::endl;
-
-    m_fs[plugin][n].features[j].v1.values = (float *)realloc
-        (m_fs[plugin][n].features[j].v1.values, sz * sizeof(float));
-
-    m_fvsizes[plugin][n][j] = sz;
-}
-  
-PluginAdapterBase::Impl::AdapterMap *
-PluginAdapterBase::Impl::m_adapterMap = 0;
-
-}
-
--- a/src/PluginHostAdapter.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,447 +0,0 @@
-/* -*- 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 "PluginHostAdapter.h"
-#include <cstdlib>
-
-namespace Vamp
-{
-
-PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor,
-                                     float inputSampleRate) :
-    Plugin(inputSampleRate),
-    m_descriptor(descriptor)
-{
-//    std::cerr << "PluginHostAdapter::PluginHostAdapter (plugin = " << descriptor->name << ")" << std::endl;
-    m_handle = m_descriptor->instantiate(m_descriptor, inputSampleRate);
-    if (!m_handle) {
-//        std::cerr << "WARNING: PluginHostAdapter: Plugin instantiation failed for plugin " << m_descriptor->name << std::endl;
-    }
-}
-
-PluginHostAdapter::~PluginHostAdapter()
-{
-//    std::cerr << "PluginHostAdapter::~PluginHostAdapter (plugin = " << m_descriptor->name << ")" << std::endl;
-    if (m_handle) m_descriptor->cleanup(m_handle);
-}
-
-std::vector<std::string>
-PluginHostAdapter::getPluginPath()
-{
-    std::vector<std::string> path;
-    std::string envPath;
-
-    char *cpath = getenv("VAMP_PATH");
-    if (cpath) envPath = cpath;
-
-#ifdef _WIN32
-#define PATH_SEPARATOR ';'
-#define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins"
-#else
-#define PATH_SEPARATOR ':'
-#ifdef __APPLE__
-#define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"
-#else
-#define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"
-#endif
-#endif
-
-    if (envPath == "") {
-        envPath = DEFAULT_VAMP_PATH;
-        char *chome = getenv("HOME");
-        if (chome) {
-            std::string home(chome);
-            std::string::size_type f;
-            while ((f = envPath.find("$HOME")) != std::string::npos &&
-                    f < envPath.length()) {
-                envPath.replace(f, 5, home);
-            }
-        }
-#ifdef _WIN32
-        char *cpfiles = getenv("ProgramFiles");
-        if (!cpfiles) cpfiles = "C:\\Program Files";
-        std::string pfiles(cpfiles);
-        std::string::size_type f;
-        while ((f = envPath.find("%ProgramFiles%")) != std::string::npos &&
-               f < envPath.length()) {
-            envPath.replace(f, 14, pfiles);
-        }
-#endif
-    }
-
-    std::string::size_type index = 0, newindex = 0;
-
-    while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) {
-	path.push_back(envPath.substr(index, newindex - index));
-	index = newindex + 1;
-    }
-    
-    path.push_back(envPath.substr(index));
-
-    return path;
-}
-
-bool
-PluginHostAdapter::initialise(size_t channels,
-                              size_t stepSize,
-                              size_t blockSize)
-{
-    if (!m_handle) return false;
-    return m_descriptor->initialise(m_handle, channels, stepSize, blockSize) ?
-        true : false;
-}
-
-void
-PluginHostAdapter::reset()
-{
-    if (!m_handle) {
-//        std::cerr << "PluginHostAdapter::reset: no handle" << std::endl;
-        return;
-    }
-//    std::cerr << "PluginHostAdapter::reset(" << m_handle << ")" << std::endl;
-    m_descriptor->reset(m_handle);
-}
-
-PluginHostAdapter::InputDomain
-PluginHostAdapter::getInputDomain() const
-{
-    if (m_descriptor->inputDomain == vampFrequencyDomain) {
-        return FrequencyDomain;
-    } else {
-        return TimeDomain;
-    }
-}
-
-unsigned int
-PluginHostAdapter::getVampApiVersion() const
-{
-    return m_descriptor->vampApiVersion;
-}
-
-std::string
-PluginHostAdapter::getIdentifier() const
-{
-    return m_descriptor->identifier;
-}
-
-std::string
-PluginHostAdapter::getName() const
-{
-    return m_descriptor->name;
-}
-
-std::string
-PluginHostAdapter::getDescription() const
-{
-    return m_descriptor->description;
-}
-
-std::string
-PluginHostAdapter::getMaker() const
-{
-    return m_descriptor->maker;
-}
-
-int
-PluginHostAdapter::getPluginVersion() const
-{
-    return m_descriptor->pluginVersion;
-}
-
-std::string
-PluginHostAdapter::getCopyright() const
-{
-    return m_descriptor->copyright;
-}
-
-PluginHostAdapter::ParameterList
-PluginHostAdapter::getParameterDescriptors() const
-{
-    ParameterList list;
-    for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
-        const VampParameterDescriptor *spd = m_descriptor->parameters[i];
-        ParameterDescriptor pd;
-        pd.identifier = spd->identifier;
-        pd.name = spd->name;
-        pd.description = spd->description;
-        pd.unit = spd->unit;
-        pd.minValue = spd->minValue;
-        pd.maxValue = spd->maxValue;
-        pd.defaultValue = spd->defaultValue;
-        pd.isQuantized = spd->isQuantized;
-        pd.quantizeStep = spd->quantizeStep;
-        if (pd.isQuantized && spd->valueNames) {
-            for (unsigned int j = 0; spd->valueNames[j]; ++j) {
-                pd.valueNames.push_back(spd->valueNames[j]);
-            }
-        }
-        list.push_back(pd);
-    }
-    return list;
-}
-
-float
-PluginHostAdapter::getParameter(std::string param) const
-{
-    if (!m_handle) return 0.0;
-
-    for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
-        if (param == m_descriptor->parameters[i]->identifier) {
-            return m_descriptor->getParameter(m_handle, i);
-        }
-    }
-
-    return 0.0;
-}
-
-void
-PluginHostAdapter::setParameter(std::string param, 
-                                float value)
-{
-    if (!m_handle) return;
-
-    for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
-        if (param == m_descriptor->parameters[i]->identifier) {
-            m_descriptor->setParameter(m_handle, i, value);
-            return;
-        }
-    }
-}
-
-PluginHostAdapter::ProgramList
-PluginHostAdapter::getPrograms() const
-{
-    ProgramList list;
-    
-    for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
-        list.push_back(m_descriptor->programs[i]);
-    }
-    
-    return list;
-}
-
-std::string
-PluginHostAdapter::getCurrentProgram() const
-{
-    if (!m_handle) return "";
-
-    int pn = m_descriptor->getCurrentProgram(m_handle);
-    return m_descriptor->programs[pn];
-}
-
-void
-PluginHostAdapter::selectProgram(std::string program)
-{
-    if (!m_handle) return;
-
-    for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
-        if (program == m_descriptor->programs[i]) {
-            m_descriptor->selectProgram(m_handle, i);
-            return;
-        }
-    }
-}
-
-size_t
-PluginHostAdapter::getPreferredStepSize() const
-{
-    if (!m_handle) return 0;
-    return m_descriptor->getPreferredStepSize(m_handle);
-}
-
-size_t
-PluginHostAdapter::getPreferredBlockSize() const
-{
-    if (!m_handle) return 0;
-    return m_descriptor->getPreferredBlockSize(m_handle);
-}
-
-size_t
-PluginHostAdapter::getMinChannelCount() const
-{
-    if (!m_handle) return 0;
-    return m_descriptor->getMinChannelCount(m_handle);
-}
-
-size_t
-PluginHostAdapter::getMaxChannelCount() const
-{
-    if (!m_handle) return 0;
-    return m_descriptor->getMaxChannelCount(m_handle);
-}
-
-PluginHostAdapter::OutputList
-PluginHostAdapter::getOutputDescriptors() const
-{
-    OutputList list;
-    if (!m_handle) {
-//        std::cerr << "PluginHostAdapter::getOutputDescriptors: no handle " << std::endl;
-        return list;
-    }
-
-    unsigned int count = m_descriptor->getOutputCount(m_handle);
-
-    for (unsigned int i = 0; i < count; ++i) {
-        VampOutputDescriptor *sd = m_descriptor->getOutputDescriptor(m_handle, i);
-        OutputDescriptor d;
-        d.identifier = sd->identifier;
-        d.name = sd->name;
-        d.description = sd->description;
-        d.unit = sd->unit;
-        d.hasFixedBinCount = sd->hasFixedBinCount;
-        d.binCount = sd->binCount;
-        if (d.hasFixedBinCount) {
-            for (unsigned int j = 0; j < sd->binCount; ++j) {
-                d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : "");
-            }
-        }
-        d.hasKnownExtents = sd->hasKnownExtents;
-        d.minValue = sd->minValue;
-        d.maxValue = sd->maxValue;
-        d.isQuantized = sd->isQuantized;
-        d.quantizeStep = sd->quantizeStep;
-
-        switch (sd->sampleType) {
-        case vampOneSamplePerStep:
-            d.sampleType = OutputDescriptor::OneSamplePerStep; break;
-        case vampFixedSampleRate:
-            d.sampleType = OutputDescriptor::FixedSampleRate; break;
-        case vampVariableSampleRate:
-            d.sampleType = OutputDescriptor::VariableSampleRate; break;
-        }
-
-        d.sampleRate = sd->sampleRate;
-
-        if (m_descriptor->vampApiVersion >= 2) {
-            d.hasDuration = sd->hasDuration;
-        } else {
-            d.hasDuration = false;
-        }
-
-        list.push_back(d);
-
-        m_descriptor->releaseOutputDescriptor(sd);
-    }
-
-    return list;
-}
-
-PluginHostAdapter::FeatureSet
-PluginHostAdapter::process(const float *const *inputBuffers,
-                           RealTime timestamp)
-{
-    FeatureSet fs;
-    if (!m_handle) return fs;
-
-    int sec = timestamp.sec;
-    int nsec = timestamp.nsec;
-    
-    VampFeatureList *features = m_descriptor->process(m_handle,
-                                                      inputBuffers,
-                                                      sec, nsec);
-    
-    convertFeatures(features, fs);
-    m_descriptor->releaseFeatureSet(features);
-    return fs;
-}
-
-PluginHostAdapter::FeatureSet
-PluginHostAdapter::getRemainingFeatures()
-{
-    FeatureSet fs;
-    if (!m_handle) return fs;
-    
-    VampFeatureList *features = m_descriptor->getRemainingFeatures(m_handle); 
-
-    convertFeatures(features, fs);
-    m_descriptor->releaseFeatureSet(features);
-    return fs;
-}
-
-void
-PluginHostAdapter::convertFeatures(VampFeatureList *features,
-                                   FeatureSet &fs)
-{
-    if (!features) return;
-
-    unsigned int outputs = m_descriptor->getOutputCount(m_handle);
-
-    for (unsigned int i = 0; i < outputs; ++i) {
-        
-        VampFeatureList &list = features[i];
-
-        if (list.featureCount > 0) {
-
-            Feature feature;
-            feature.values.reserve(list.features[0].v1.valueCount);
-
-            for (unsigned int j = 0; j < list.featureCount; ++j) {
-
-                feature.hasTimestamp = list.features[j].v1.hasTimestamp;
-                feature.timestamp = RealTime(list.features[j].v1.sec,
-                                             list.features[j].v1.nsec);
-                feature.hasDuration = false;
-
-                if (m_descriptor->vampApiVersion >= 2) {
-                    unsigned int j2 = j + list.featureCount;
-                    feature.hasDuration = list.features[j2].v2.hasDuration;
-                    feature.duration = RealTime(list.features[j2].v2.durationSec,
-                                                list.features[j2].v2.durationNsec);
-                }
-
-                for (unsigned int k = 0; k < list.features[j].v1.valueCount; ++k) {
-                    feature.values.push_back(list.features[j].v1.values[k]);
-                }
-
-                if (list.features[j].v1.label) {
-                    feature.label = list.features[j].v1.label;
-                }
-
-                fs[i].push_back(feature);
-
-                if (list.features[j].v1.valueCount > 0) {
-                    feature.values.clear();
-                }
-
-                if (list.features[j].v1.label) {
-                    feature.label = "";
-                }
-            }
-        }
-    }
-}
-
-}
--- a/src/RealTime.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,245 +0,0 @@
-/* -*- 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.
-*/
-
-/*
-   This is a modified version of a source file from the 
-   Rosegarden MIDI and audio sequencer and notation editor.
-   This file copyright 2000-2006 Chris Cannam.
-   Relicensed by the author as detailed above.
-*/
-
-#include <iostream>
-
-#if (__GNUC__ < 3)
-#include <strstream>
-#define stringstream strstream
-#else
-#include <sstream>
-#endif
-
-using std::cerr;
-using std::endl;
-
-#include "RealTime.h"
-
-#ifndef _WIN32
-#include <sys/time.h>
-#endif
-
-namespace Vamp {
-
-// A RealTime consists of two ints that must be at least 32 bits each.
-// A signed 32-bit int can store values exceeding +/- 2 billion.  This
-// means we can safely use our lower int for nanoseconds, as there are
-// 1 billion nanoseconds in a second and we need to handle double that
-// because of the implementations of addition etc that we use.
-//
-// The maximum valid RealTime on a 32-bit system is somewhere around
-// 68 years: 999999999 nanoseconds longer than the classic Unix epoch.
-
-#define ONE_BILLION 1000000000
-
-RealTime::RealTime(int s, int n) :
-    sec(s), nsec(n)
-{
-    if (sec == 0) {
-	while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
-	while (nsec >=  ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
-    } else if (sec < 0) {
-	while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
-	while (nsec > 0)             { nsec -= ONE_BILLION; ++sec; }
-    } else { 
-	while (nsec >=  ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
-	while (nsec < 0)             { nsec += ONE_BILLION; --sec; }
-    }
-}
-
-RealTime
-RealTime::fromSeconds(double sec)
-{
-    return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5));
-}
-
-RealTime
-RealTime::fromMilliseconds(int msec)
-{
-    return RealTime(msec / 1000, (msec % 1000) * 1000000);
-}
-
-#ifndef _WIN32
-RealTime
-RealTime::fromTimeval(const struct timeval &tv)
-{
-    return RealTime(tv.tv_sec, tv.tv_usec * 1000);
-}
-#endif
-
-std::ostream &operator<<(std::ostream &out, const RealTime &rt)
-{
-    if (rt < RealTime::zeroTime) {
-	out << "-";
-    } else {
-	out << " ";
-    }
-
-    int s = (rt.sec < 0 ? -rt.sec : rt.sec);
-    int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec);
-
-    out << s << ".";
-
-    int nn(n);
-    if (nn == 0) out << "00000000";
-    else while (nn < (ONE_BILLION / 10)) {
-	out << "0";
-	nn *= 10;
-    }
-    
-    out << n << "R";
-    return out;
-}
-
-std::string
-RealTime::toString() const
-{
-    std::stringstream out;
-    out << *this;
-    
-#if (__GNUC__ < 3)
-    out << std::ends;
-#endif
-
-    std::string s = out.str();
-
-    // remove trailing R
-    return s.substr(0, s.length() - 1);
-}
-
-std::string
-RealTime::toText(bool fixedDp) const
-{
-    if (*this < RealTime::zeroTime) return "-" + (-*this).toText();
-
-    std::stringstream out;
-
-    if (sec >= 3600) {
-	out << (sec / 3600) << ":";
-    }
-
-    if (sec >= 60) {
-	out << (sec % 3600) / 60 << ":";
-    }
-
-    if (sec >= 10) {
-	out << ((sec % 60) / 10);
-    }
-
-    out << (sec % 10);
-    
-    int ms = msec();
-
-    if (ms != 0) {
-	out << ".";
-	out << (ms / 100);
-	ms = ms % 100;
-	if (ms != 0) {
-	    out << (ms / 10);
-	    ms = ms % 10;
-	} else if (fixedDp) {
-	    out << "0";
-	}
-	if (ms != 0) {
-	    out << ms;
-	} else if (fixedDp) {
-	    out << "0";
-	}
-    } else if (fixedDp) {
-	out << ".000";
-    }
-	
-#if (__GNUC__ < 3)
-    out << std::ends;
-#endif
-
-    std::string s = out.str();
-
-    return s;
-}
-
-
-RealTime
-RealTime::operator/(int d) const
-{
-    int secdiv = sec / d;
-    int secrem = sec % d;
-
-    double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d;
-    
-    return RealTime(secdiv, int(nsecdiv + 0.5));
-}
-
-double 
-RealTime::operator/(const RealTime &r) const
-{
-    double lTotal = double(sec) * ONE_BILLION + double(nsec);
-    double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec);
-    
-    if (rTotal == 0) return 0.0;
-    else return lTotal/rTotal;
-}
-
-long
-RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate)
-{
-    if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
-    double s = time.sec + double(time.nsec + 1) / 1000000000.0;
-    return long(s * sampleRate);
-}
-
-RealTime
-RealTime::frame2RealTime(long frame, unsigned int sampleRate)
-{
-    if (frame < 0) return -frame2RealTime(-frame, sampleRate);
-
-    RealTime rt;
-    rt.sec = frame / long(sampleRate);
-    frame -= rt.sec * long(sampleRate);
-    rt.nsec = (int)(((double(frame) * 1000000.0) / sampleRate) * 1000.0);
-    return rt;
-}
-
-const RealTime RealTime::zeroTime(0,0);
-
-}
--- a/src/SpectralCentroid.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +0,0 @@
-/* -*- 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 "SpectralCentroid.h"
-
-using std::string;
-using std::vector;
-using std::cerr;
-using std::endl;
-
-#include <math.h>
-
-#ifdef WIN32
-#define isnan(x) false
-#define isinf(x) false
-#endif
-
-SpectralCentroid::SpectralCentroid(float inputSampleRate) :
-    Plugin(inputSampleRate),
-    m_stepSize(0),
-    m_blockSize(0)
-{
-}
-
-SpectralCentroid::~SpectralCentroid()
-{
-}
-
-string
-SpectralCentroid::getIdentifier() const
-{
-    return "spectralcentroid";
-}
-
-string
-SpectralCentroid::getName() const
-{
-    return "Spectral Centroid";
-}
-
-string
-SpectralCentroid::getDescription() const
-{
-    return "Calculate the centroid frequency of the spectrum of the input signal";
-}
-
-string
-SpectralCentroid::getMaker() const
-{
-    return "Vamp SDK Example Plugins";
-}
-
-int
-SpectralCentroid::getPluginVersion() const
-{
-    return 2;
-}
-
-string
-SpectralCentroid::getCopyright() const
-{
-    return "Freely redistributable (BSD license)";
-}
-
-bool
-SpectralCentroid::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    if (channels < getMinChannelCount() ||
-	channels > getMaxChannelCount()) return false;
-
-    m_stepSize = stepSize;
-    m_blockSize = blockSize;
-
-    return true;
-}
-
-void
-SpectralCentroid::reset()
-{
-}
-
-SpectralCentroid::OutputList
-SpectralCentroid::getOutputDescriptors() const
-{
-    OutputList list;
-
-    OutputDescriptor d;
-    d.identifier = "logcentroid";
-    d.name = "Log Frequency Centroid";
-    d.description = "Centroid of the log weighted frequency spectrum";
-    d.unit = "Hz";
-    d.hasFixedBinCount = true;
-    d.binCount = 1;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::OneSamplePerStep;
-    list.push_back(d);
-
-    d.identifier = "linearcentroid";
-    d.name = "Linear Frequency Centroid";
-    d.description = "Centroid of the linear frequency spectrum";
-    list.push_back(d);
-
-    return list;
-}
-
-//static int scount = 0;
-
-SpectralCentroid::FeatureSet
-SpectralCentroid::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
-{
-    if (m_stepSize == 0) {
-	cerr << "ERROR: SpectralCentroid::process: "
-	     << "SpectralCentroid has not been initialised"
-	     << endl;
-	return FeatureSet();
-    }
-
-//    std::cerr << "SpectralCentroid::process: count = " << scount++ << ", timestamp = " << timestamp << ", total power = ";
-
-    double numLin = 0.0, numLog = 0.0, denom = 0.0;
-
-    for (size_t i = 1; i <= m_blockSize/2; ++i) {
-	double freq = (double(i) * m_inputSampleRate) / m_blockSize;
-	double real = inputBuffers[0][i*2];
-	double imag = inputBuffers[0][i*2 + 1];
-	double power = sqrt(real * real + imag * imag) / (m_blockSize/2);
-	numLin += freq * power;
-        numLog += log10f(freq) * power;
-	denom += power;
-    }
-
-//    std::cerr << denom << std::endl;
-
-    FeatureSet returnFeatures;
-
-    if (denom != 0.0) {
-	float centroidLin = float(numLin / denom);
-	float centroidLog = powf(10, float(numLog / denom));
-
-	Feature feature;
-	feature.hasTimestamp = false;
-    if (!isnan(centroidLog) && !isinf(centroidLog)) {
-        feature.values.push_back(centroidLog);
-    }
-	returnFeatures[0].push_back(feature);
-
-    feature.values.clear();
-    if (!isnan(centroidLin) && !isinf(centroidLin)) {
-        feature.values.push_back(centroidLin);
-    }
-	returnFeatures[1].push_back(feature);
-    }
-
-    return returnFeatures;
-}
-
-SpectralCentroid::FeatureSet
-SpectralCentroid::getRemainingFeatures()
-{
-    return FeatureSet();
-}
-
--- a/src/ZeroCrossing.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-/* -*- 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 "ZeroCrossing.h"
-
-using std::string;
-using std::vector;
-using std::cerr;
-using std::endl;
-
-#include <cmath>
-
-ZeroCrossing::ZeroCrossing(float inputSampleRate) :
-    Plugin(inputSampleRate),
-    m_stepSize(0),
-    m_previousSample(0.0f)
-{
-}
-
-ZeroCrossing::~ZeroCrossing()
-{
-}
-
-string
-ZeroCrossing::getIdentifier() const
-{
-    return "zerocrossing";
-}
-
-string
-ZeroCrossing::getName() const
-{
-    return "Zero Crossings";
-}
-
-string
-ZeroCrossing::getDescription() const
-{
-    return "Detect and count zero crossing points";
-}
-
-string
-ZeroCrossing::getMaker() const
-{
-    return "Vamp SDK Example Plugins";
-}
-
-int
-ZeroCrossing::getPluginVersion() const
-{
-    return 2;
-}
-
-string
-ZeroCrossing::getCopyright() const
-{
-    return "Freely redistributable (BSD license)";
-}
-
-bool
-ZeroCrossing::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    if (channels < getMinChannelCount() ||
-	channels > getMaxChannelCount()) return false;
-
-    m_stepSize = std::min(stepSize, blockSize);
-
-    return true;
-}
-
-void
-ZeroCrossing::reset()
-{
-    m_previousSample = 0.0f;
-}
-
-ZeroCrossing::OutputList
-ZeroCrossing::getOutputDescriptors() const
-{
-    OutputList list;
-
-    OutputDescriptor zc;
-    zc.identifier = "counts";
-    zc.name = "Zero Crossing Counts";
-    zc.description = "The number of zero crossing points per processing block";
-    zc.unit = "crossings";
-    zc.hasFixedBinCount = true;
-    zc.binCount = 1;
-    zc.hasKnownExtents = false;
-    zc.isQuantized = true;
-    zc.quantizeStep = 1.0;
-    zc.sampleType = OutputDescriptor::OneSamplePerStep;
-    list.push_back(zc);
-
-    zc.identifier = "zerocrossings";
-    zc.name = "Zero Crossings";
-    zc.description = "The locations of zero crossing points";
-    zc.unit = "";
-    zc.hasFixedBinCount = true;
-    zc.binCount = 0;
-    zc.sampleType = OutputDescriptor::VariableSampleRate;
-    zc.sampleRate = m_inputSampleRate;
-    list.push_back(zc);
-
-    return list;
-}
-
-//static int scount = 0;
-
-ZeroCrossing::FeatureSet
-ZeroCrossing::process(const float *const *inputBuffers,
-                      Vamp::RealTime timestamp)
-{
-    if (m_stepSize == 0) {
-	cerr << "ERROR: ZeroCrossing::process: "
-	     << "ZeroCrossing has not been initialised"
-	     << endl;
-	return FeatureSet();
-    }
-
-//    std::cerr << "ZeroCrossing::process: count = " << scount++ << ", timestamp = " << timestamp << ", rms = ";
-
-    float prev = m_previousSample;
-    size_t count = 0;
-
-    FeatureSet returnFeatures;
-
-//    double acc = 0.0;
-
-    for (size_t i = 0; i < m_stepSize; ++i) {
-
-	float sample = inputBuffers[0][i];
-	bool crossing = false;
-
-	if (sample <= 0.0) {
-	    if (prev > 0.0) crossing = true;
-	} else if (sample > 0.0) {
-	    if (prev <= 0.0) crossing = true;
-	}
-
-	if (crossing) {
-	    ++count; 
-	    Feature feature;
-	    feature.hasTimestamp = true;
-	    feature.timestamp = timestamp +
-		Vamp::RealTime::frame2RealTime(i, (size_t)m_inputSampleRate);
-	    returnFeatures[1].push_back(feature);
-	}
-
-//        acc += sample * sample;
-
-	prev = sample;
-    }
-
-//    acc /= m_stepSize;
-//    std::cerr << sqrt(acc) << std::endl;
-
-    m_previousSample = prev;
-
-    Feature feature;
-    feature.hasTimestamp = false;
-    feature.values.push_back(count);
-
-    returnFeatures[0].push_back(feature);
-    return returnFeatures;
-}
-
-ZeroCrossing::FeatureSet
-ZeroCrossing::getRemainingFeatures()
-{
-    return FeatureSet();
-}
-
--- a/src/plugins.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/* -*- 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 "vamp/vamp.h"
-#include "vamp-sdk/PluginAdapter.h"
-
-#include "ZeroCrossing.h"
-#include "SpectralCentroid.h"
-#include "PercussionOnsetDetector.h"
-#include "FixedTempoEstimator.h"
-#include "AmplitudeFollower.h"
-
-static Vamp::PluginAdapter<ZeroCrossing> zeroCrossingAdapter;
-static Vamp::PluginAdapter<SpectralCentroid> spectralCentroidAdapter;
-static Vamp::PluginAdapter<PercussionOnsetDetector> percussionOnsetAdapter;
-static Vamp::PluginAdapter<FixedTempoEstimator> fixedTempoAdapter;
-static Vamp::PluginAdapter<AmplitudeFollower> amplitudeAdapter;
-
-const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
-                                                    unsigned int index)
-{
-    if (version < 1) return 0;
-
-    switch (index) {
-    case  0: return zeroCrossingAdapter.getDescriptor();
-    case  1: return spectralCentroidAdapter.getDescriptor();
-    case  2: return percussionOnsetAdapter.getDescriptor();
-    case  3: return amplitudeAdapter.getDescriptor();
-    case  4: return fixedTempoAdapter.getDescriptor();
-    default: return 0;
-    }
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vamp-hostsdk/PluginHostAdapter.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,447 @@
+/* -*- 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 "PluginHostAdapter.h"
+#include <cstdlib>
+
+namespace Vamp
+{
+
+PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor,
+                                     float inputSampleRate) :
+    Plugin(inputSampleRate),
+    m_descriptor(descriptor)
+{
+//    std::cerr << "PluginHostAdapter::PluginHostAdapter (plugin = " << descriptor->name << ")" << std::endl;
+    m_handle = m_descriptor->instantiate(m_descriptor, inputSampleRate);
+    if (!m_handle) {
+//        std::cerr << "WARNING: PluginHostAdapter: Plugin instantiation failed for plugin " << m_descriptor->name << std::endl;
+    }
+}
+
+PluginHostAdapter::~PluginHostAdapter()
+{
+//    std::cerr << "PluginHostAdapter::~PluginHostAdapter (plugin = " << m_descriptor->name << ")" << std::endl;
+    if (m_handle) m_descriptor->cleanup(m_handle);
+}
+
+std::vector<std::string>
+PluginHostAdapter::getPluginPath()
+{
+    std::vector<std::string> path;
+    std::string envPath;
+
+    char *cpath = getenv("VAMP_PATH");
+    if (cpath) envPath = cpath;
+
+#ifdef _WIN32
+#define PATH_SEPARATOR ';'
+#define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins"
+#else
+#define PATH_SEPARATOR ':'
+#ifdef __APPLE__
+#define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"
+#else
+#define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"
+#endif
+#endif
+
+    if (envPath == "") {
+        envPath = DEFAULT_VAMP_PATH;
+        char *chome = getenv("HOME");
+        if (chome) {
+            std::string home(chome);
+            std::string::size_type f;
+            while ((f = envPath.find("$HOME")) != std::string::npos &&
+                    f < envPath.length()) {
+                envPath.replace(f, 5, home);
+            }
+        }
+#ifdef _WIN32
+        char *cpfiles = getenv("ProgramFiles");
+        if (!cpfiles) cpfiles = "C:\\Program Files";
+        std::string pfiles(cpfiles);
+        std::string::size_type f;
+        while ((f = envPath.find("%ProgramFiles%")) != std::string::npos &&
+               f < envPath.length()) {
+            envPath.replace(f, 14, pfiles);
+        }
+#endif
+    }
+
+    std::string::size_type index = 0, newindex = 0;
+
+    while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) {
+	path.push_back(envPath.substr(index, newindex - index));
+	index = newindex + 1;
+    }
+    
+    path.push_back(envPath.substr(index));
+
+    return path;
+}
+
+bool
+PluginHostAdapter::initialise(size_t channels,
+                              size_t stepSize,
+                              size_t blockSize)
+{
+    if (!m_handle) return false;
+    return m_descriptor->initialise(m_handle, channels, stepSize, blockSize) ?
+        true : false;
+}
+
+void
+PluginHostAdapter::reset()
+{
+    if (!m_handle) {
+//        std::cerr << "PluginHostAdapter::reset: no handle" << std::endl;
+        return;
+    }
+//    std::cerr << "PluginHostAdapter::reset(" << m_handle << ")" << std::endl;
+    m_descriptor->reset(m_handle);
+}
+
+PluginHostAdapter::InputDomain
+PluginHostAdapter::getInputDomain() const
+{
+    if (m_descriptor->inputDomain == vampFrequencyDomain) {
+        return FrequencyDomain;
+    } else {
+        return TimeDomain;
+    }
+}
+
+unsigned int
+PluginHostAdapter::getVampApiVersion() const
+{
+    return m_descriptor->vampApiVersion;
+}
+
+std::string
+PluginHostAdapter::getIdentifier() const
+{
+    return m_descriptor->identifier;
+}
+
+std::string
+PluginHostAdapter::getName() const
+{
+    return m_descriptor->name;
+}
+
+std::string
+PluginHostAdapter::getDescription() const
+{
+    return m_descriptor->description;
+}
+
+std::string
+PluginHostAdapter::getMaker() const
+{
+    return m_descriptor->maker;
+}
+
+int
+PluginHostAdapter::getPluginVersion() const
+{
+    return m_descriptor->pluginVersion;
+}
+
+std::string
+PluginHostAdapter::getCopyright() const
+{
+    return m_descriptor->copyright;
+}
+
+PluginHostAdapter::ParameterList
+PluginHostAdapter::getParameterDescriptors() const
+{
+    ParameterList list;
+    for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
+        const VampParameterDescriptor *spd = m_descriptor->parameters[i];
+        ParameterDescriptor pd;
+        pd.identifier = spd->identifier;
+        pd.name = spd->name;
+        pd.description = spd->description;
+        pd.unit = spd->unit;
+        pd.minValue = spd->minValue;
+        pd.maxValue = spd->maxValue;
+        pd.defaultValue = spd->defaultValue;
+        pd.isQuantized = spd->isQuantized;
+        pd.quantizeStep = spd->quantizeStep;
+        if (pd.isQuantized && spd->valueNames) {
+            for (unsigned int j = 0; spd->valueNames[j]; ++j) {
+                pd.valueNames.push_back(spd->valueNames[j]);
+            }
+        }
+        list.push_back(pd);
+    }
+    return list;
+}
+
+float
+PluginHostAdapter::getParameter(std::string param) const
+{
+    if (!m_handle) return 0.0;
+
+    for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
+        if (param == m_descriptor->parameters[i]->identifier) {
+            return m_descriptor->getParameter(m_handle, i);
+        }
+    }
+
+    return 0.0;
+}
+
+void
+PluginHostAdapter::setParameter(std::string param, 
+                                float value)
+{
+    if (!m_handle) return;
+
+    for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
+        if (param == m_descriptor->parameters[i]->identifier) {
+            m_descriptor->setParameter(m_handle, i, value);
+            return;
+        }
+    }
+}
+
+PluginHostAdapter::ProgramList
+PluginHostAdapter::getPrograms() const
+{
+    ProgramList list;
+    
+    for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
+        list.push_back(m_descriptor->programs[i]);
+    }
+    
+    return list;
+}
+
+std::string
+PluginHostAdapter::getCurrentProgram() const
+{
+    if (!m_handle) return "";
+
+    int pn = m_descriptor->getCurrentProgram(m_handle);
+    return m_descriptor->programs[pn];
+}
+
+void
+PluginHostAdapter::selectProgram(std::string program)
+{
+    if (!m_handle) return;
+
+    for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
+        if (program == m_descriptor->programs[i]) {
+            m_descriptor->selectProgram(m_handle, i);
+            return;
+        }
+    }
+}
+
+size_t
+PluginHostAdapter::getPreferredStepSize() const
+{
+    if (!m_handle) return 0;
+    return m_descriptor->getPreferredStepSize(m_handle);
+}
+
+size_t
+PluginHostAdapter::getPreferredBlockSize() const
+{
+    if (!m_handle) return 0;
+    return m_descriptor->getPreferredBlockSize(m_handle);
+}
+
+size_t
+PluginHostAdapter::getMinChannelCount() const
+{
+    if (!m_handle) return 0;
+    return m_descriptor->getMinChannelCount(m_handle);
+}
+
+size_t
+PluginHostAdapter::getMaxChannelCount() const
+{
+    if (!m_handle) return 0;
+    return m_descriptor->getMaxChannelCount(m_handle);
+}
+
+PluginHostAdapter::OutputList
+PluginHostAdapter::getOutputDescriptors() const
+{
+    OutputList list;
+    if (!m_handle) {
+//        std::cerr << "PluginHostAdapter::getOutputDescriptors: no handle " << std::endl;
+        return list;
+    }
+
+    unsigned int count = m_descriptor->getOutputCount(m_handle);
+
+    for (unsigned int i = 0; i < count; ++i) {
+        VampOutputDescriptor *sd = m_descriptor->getOutputDescriptor(m_handle, i);
+        OutputDescriptor d;
+        d.identifier = sd->identifier;
+        d.name = sd->name;
+        d.description = sd->description;
+        d.unit = sd->unit;
+        d.hasFixedBinCount = sd->hasFixedBinCount;
+        d.binCount = sd->binCount;
+        if (d.hasFixedBinCount) {
+            for (unsigned int j = 0; j < sd->binCount; ++j) {
+                d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : "");
+            }
+        }
+        d.hasKnownExtents = sd->hasKnownExtents;
+        d.minValue = sd->minValue;
+        d.maxValue = sd->maxValue;
+        d.isQuantized = sd->isQuantized;
+        d.quantizeStep = sd->quantizeStep;
+
+        switch (sd->sampleType) {
+        case vampOneSamplePerStep:
+            d.sampleType = OutputDescriptor::OneSamplePerStep; break;
+        case vampFixedSampleRate:
+            d.sampleType = OutputDescriptor::FixedSampleRate; break;
+        case vampVariableSampleRate:
+            d.sampleType = OutputDescriptor::VariableSampleRate; break;
+        }
+
+        d.sampleRate = sd->sampleRate;
+
+        if (m_descriptor->vampApiVersion >= 2) {
+            d.hasDuration = sd->hasDuration;
+        } else {
+            d.hasDuration = false;
+        }
+
+        list.push_back(d);
+
+        m_descriptor->releaseOutputDescriptor(sd);
+    }
+
+    return list;
+}
+
+PluginHostAdapter::FeatureSet
+PluginHostAdapter::process(const float *const *inputBuffers,
+                           RealTime timestamp)
+{
+    FeatureSet fs;
+    if (!m_handle) return fs;
+
+    int sec = timestamp.sec;
+    int nsec = timestamp.nsec;
+    
+    VampFeatureList *features = m_descriptor->process(m_handle,
+                                                      inputBuffers,
+                                                      sec, nsec);
+    
+    convertFeatures(features, fs);
+    m_descriptor->releaseFeatureSet(features);
+    return fs;
+}
+
+PluginHostAdapter::FeatureSet
+PluginHostAdapter::getRemainingFeatures()
+{
+    FeatureSet fs;
+    if (!m_handle) return fs;
+    
+    VampFeatureList *features = m_descriptor->getRemainingFeatures(m_handle); 
+
+    convertFeatures(features, fs);
+    m_descriptor->releaseFeatureSet(features);
+    return fs;
+}
+
+void
+PluginHostAdapter::convertFeatures(VampFeatureList *features,
+                                   FeatureSet &fs)
+{
+    if (!features) return;
+
+    unsigned int outputs = m_descriptor->getOutputCount(m_handle);
+
+    for (unsigned int i = 0; i < outputs; ++i) {
+        
+        VampFeatureList &list = features[i];
+
+        if (list.featureCount > 0) {
+
+            Feature feature;
+            feature.values.reserve(list.features[0].v1.valueCount);
+
+            for (unsigned int j = 0; j < list.featureCount; ++j) {
+
+                feature.hasTimestamp = list.features[j].v1.hasTimestamp;
+                feature.timestamp = RealTime(list.features[j].v1.sec,
+                                             list.features[j].v1.nsec);
+                feature.hasDuration = false;
+
+                if (m_descriptor->vampApiVersion >= 2) {
+                    unsigned int j2 = j + list.featureCount;
+                    feature.hasDuration = list.features[j2].v2.hasDuration;
+                    feature.duration = RealTime(list.features[j2].v2.durationSec,
+                                                list.features[j2].v2.durationNsec);
+                }
+
+                for (unsigned int k = 0; k < list.features[j].v1.valueCount; ++k) {
+                    feature.values.push_back(list.features[j].v1.values[k]);
+                }
+
+                if (list.features[j].v1.label) {
+                    feature.label = list.features[j].v1.label;
+                }
+
+                fs[i].push_back(feature);
+
+                if (list.features[j].v1.valueCount > 0) {
+                    feature.values.clear();
+                }
+
+                if (list.features[j].v1.label) {
+                    feature.label = "";
+                }
+            }
+        }
+    }
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vamp-hostsdk/hostext/PluginBufferingAdapter.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,657 @@
+/* -*- 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-2007 Chris Cannam and QMUL.
+    This file by Mark Levy and Chris Cannam, Copyright 2007-2008 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.
+*/
+
+#include <vector>
+#include <map>
+
+#include "PluginBufferingAdapter.h"
+
+using std::vector;
+using std::map;
+
+namespace Vamp {
+	
+namespace HostExt {
+		
+class PluginBufferingAdapter::Impl
+{
+public:
+    Impl(Plugin *plugin, float inputSampleRate);
+    ~Impl();
+	
+    void setPluginStepSize(size_t stepSize);	
+    void setPluginBlockSize(size_t blockSize);
+
+    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+
+    void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
+
+    OutputList getOutputDescriptors() const;
+
+    void reset();
+
+    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
+		
+    FeatureSet getRemainingFeatures();
+		
+protected:
+    class RingBuffer
+    {
+    public:
+        RingBuffer(int n) :
+            m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { }
+        virtual ~RingBuffer() { delete[] m_buffer; }
+
+        int getSize() const { return m_size-1; }
+        void reset() { m_writer = 0; m_reader = 0; }
+
+        int getReadSpace() const {
+            int writer = m_writer, reader = m_reader, space;
+            if (writer > reader) space = writer - reader;
+            else if (writer < reader) space = (writer + m_size) - reader;
+            else space = 0;
+            return space;
+        }
+
+        int getWriteSpace() const {
+            int writer = m_writer;
+            int reader = m_reader;
+            int space = (reader + m_size - writer - 1);
+            if (space >= m_size) space -= m_size;
+            return space;
+        }
+        
+        int peek(float *destination, int n) const {
+
+            int available = getReadSpace();
+
+            if (n > available) {
+                for (int i = available; i < n; ++i) {
+                    destination[i] = 0.f;
+                }
+                n = available;
+            }
+            if (n == 0) return n;
+
+            int reader = m_reader;
+            int here = m_size - reader;
+            const float *const bufbase = m_buffer + reader;
+
+            if (here >= n) {
+                for (int i = 0; i < n; ++i) {
+                    destination[i] = bufbase[i];
+                }
+            } else {
+                for (int i = 0; i < here; ++i) {
+                    destination[i] = bufbase[i];
+                }
+                float *const destbase = destination + here;
+                const int nh = n - here;
+                for (int i = 0; i < nh; ++i) {
+                    destbase[i] = m_buffer[i];
+                }
+            }
+
+            return n;
+        }
+
+        int skip(int n) {
+            
+            int available = getReadSpace();
+            if (n > available) {
+                n = available;
+            }
+            if (n == 0) return n;
+
+            int reader = m_reader;
+            reader += n;
+            while (reader >= m_size) reader -= m_size;
+            m_reader = reader;
+            return n;
+        }
+        
+        int write(const float *source, int n) {
+
+            int available = getWriteSpace();
+            if (n > available) {
+                n = available;
+            }
+            if (n == 0) return n;
+
+            int writer = m_writer;
+            int here = m_size - writer;
+            float *const bufbase = m_buffer + writer;
+            
+            if (here >= n) {
+                for (int i = 0; i < n; ++i) {
+                    bufbase[i] = source[i];
+                }
+            } else {
+                for (int i = 0; i < here; ++i) {
+                    bufbase[i] = source[i];
+                }
+                const int nh = n - here;
+                const float *const srcbase = source + here;
+                float *const buf = m_buffer;
+                for (int i = 0; i < nh; ++i) {
+                    buf[i] = srcbase[i];
+                }
+            }
+
+            writer += n;
+            while (writer >= m_size) writer -= m_size;
+            m_writer = writer;
+
+            return n;
+        }
+
+        int zero(int n) {
+            
+            int available = getWriteSpace();
+            if (n > available) {
+                n = available;
+            }
+            if (n == 0) return n;
+
+            int writer = m_writer;
+            int here = m_size - writer;
+            float *const bufbase = m_buffer + writer;
+
+            if (here >= n) {
+                for (int i = 0; i < n; ++i) {
+                    bufbase[i] = 0.f;
+                }
+            } else {
+                for (int i = 0; i < here; ++i) {
+                    bufbase[i] = 0.f;
+                }
+                const int nh = n - here;
+                for (int i = 0; i < nh; ++i) {
+                    m_buffer[i] = 0.f;
+                }
+            }
+            
+            writer += n;
+            while (writer >= m_size) writer -= m_size;
+            m_writer = writer;
+
+            return n;
+        }
+
+    protected:
+        float *m_buffer;
+        int    m_writer;
+        int    m_reader;
+        int    m_size;
+
+    private:
+        RingBuffer(const RingBuffer &); // not provided
+        RingBuffer &operator=(const RingBuffer &); // not provided
+    };
+
+    Plugin *m_plugin;
+    size_t m_inputStepSize;  // value passed to wrapper initialise()
+    size_t m_inputBlockSize; // value passed to wrapper initialise()
+    size_t m_setStepSize;    // value passed to setPluginStepSize()
+    size_t m_setBlockSize;   // value passed to setPluginBlockSize()
+    size_t m_stepSize;       // value actually used to initialise plugin
+    size_t m_blockSize;      // value actually used to initialise plugin
+    size_t m_channels;
+    vector<RingBuffer *> m_queue;
+    float **m_buffers;
+    float m_inputSampleRate;
+    long m_frame;
+    bool m_unrun;
+    mutable OutputList m_outputs;
+    mutable std::map<int, bool> m_rewriteOutputTimes;
+		
+    void processBlock(FeatureSet& allFeatureSets);
+};
+		
+PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
+    PluginWrapper(plugin)
+{
+    m_impl = new Impl(plugin, m_inputSampleRate);
+}
+		
+PluginBufferingAdapter::~PluginBufferingAdapter()
+{
+    delete m_impl;
+}
+
+size_t
+PluginBufferingAdapter::getPreferredStepSize() const
+{
+    return getPreferredBlockSize();
+}
+
+size_t
+PluginBufferingAdapter::getPreferredBlockSize() const
+{
+    return PluginWrapper::getPreferredBlockSize();
+}
+
+size_t
+PluginBufferingAdapter::getPluginPreferredStepSize() const
+{
+    return PluginWrapper::getPreferredStepSize();
+}
+
+size_t
+PluginBufferingAdapter::getPluginPreferredBlockSize() const
+{
+    return PluginWrapper::getPreferredBlockSize();
+}
+
+void
+PluginBufferingAdapter::setPluginStepSize(size_t stepSize)
+{
+    m_impl->setPluginStepSize(stepSize);
+}
+
+void
+PluginBufferingAdapter::setPluginBlockSize(size_t blockSize)
+{
+    m_impl->setPluginBlockSize(blockSize);
+}
+
+void
+PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize,
+                                                   size_t &blockSize)
+{
+    m_impl->getActualStepAndBlockSizes(stepSize, blockSize);
+}
+		
+bool
+PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    return m_impl->initialise(channels, stepSize, blockSize);
+}
+
+PluginBufferingAdapter::OutputList
+PluginBufferingAdapter::getOutputDescriptors() const
+{
+    return m_impl->getOutputDescriptors();
+}
+
+void
+PluginBufferingAdapter::reset()
+{
+    m_impl->reset();
+}
+		
+PluginBufferingAdapter::FeatureSet
+PluginBufferingAdapter::process(const float *const *inputBuffers,
+                                RealTime timestamp)
+{
+    return m_impl->process(inputBuffers, timestamp);
+}
+		
+PluginBufferingAdapter::FeatureSet
+PluginBufferingAdapter::getRemainingFeatures()
+{
+    return m_impl->getRemainingFeatures();
+}
+		
+PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
+    m_plugin(plugin),
+    m_inputStepSize(0),
+    m_inputBlockSize(0),
+    m_setStepSize(0),
+    m_setBlockSize(0),
+    m_stepSize(0),
+    m_blockSize(0),
+    m_channels(0), 
+    m_queue(0),
+    m_buffers(0),
+    m_inputSampleRate(inputSampleRate),
+    m_frame(0),
+    m_unrun(true)
+{
+    (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
+}
+		
+PluginBufferingAdapter::Impl::~Impl()
+{
+    // the adapter will delete the plugin
+
+    for (size_t i = 0; i < m_channels; ++i) {
+        delete m_queue[i];
+        delete[] m_buffers[i];
+    }
+    delete[] m_buffers;
+}
+		
+void
+PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize)
+{
+    if (m_inputStepSize != 0) {
+        std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl;
+        return;
+    }
+    m_setStepSize = stepSize;
+}
+		
+void
+PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize)
+{
+    if (m_inputBlockSize != 0) {
+        std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl;
+        return;
+    }
+    m_setBlockSize = blockSize;
+}
+
+void
+PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize,
+                                                         size_t &blockSize)
+{
+    stepSize = m_stepSize;
+    blockSize = m_blockSize;
+}
+
+bool
+PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    if (stepSize != blockSize) {
+        std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
+        return false;
+    }
+
+    m_channels = channels;	
+    m_inputStepSize = stepSize;
+    m_inputBlockSize = blockSize;
+
+    // if the user has requested particular step or block sizes, use
+    // those; otherwise use the step and block sizes which the plugin
+    // prefers
+
+    m_stepSize = 0;
+    m_blockSize = 0;
+
+    if (m_setStepSize > 0) {
+        m_stepSize = m_setStepSize;
+    }
+    if (m_setBlockSize > 0) {
+        m_blockSize = m_setBlockSize;
+    }
+
+    if (m_stepSize == 0 && m_blockSize == 0) {
+        m_stepSize = m_plugin->getPreferredStepSize();
+        m_blockSize = m_plugin->getPreferredBlockSize();
+    }
+    
+    bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain);
+    
+    // or sensible defaults if it has no preference
+    if (m_blockSize == 0) {
+        if (m_stepSize == 0) {
+            m_blockSize = 1024;
+        } else if (freq) {
+            m_blockSize = m_stepSize * 2;
+        } else {
+            m_blockSize = m_stepSize;
+        }
+    } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above)
+        if (freq) {
+            m_stepSize = m_blockSize/2;
+        } else {
+            m_stepSize = m_blockSize;
+        }
+    }
+    
+    // current implementation breaks if step is greater than block
+    if (m_stepSize > m_blockSize) {
+        size_t newBlockSize;
+        if (freq) {
+            newBlockSize = m_stepSize * 2;
+        } else {
+            newBlockSize = m_stepSize;
+        }
+        std::cerr << "PluginBufferingAdapter::initialise: WARNING: step size " << m_stepSize << " is greater than block size " << m_blockSize << ": cannot handle this in adapter; adjusting block size to " << newBlockSize << std::endl;
+        m_blockSize = newBlockSize;
+    }
+    
+    std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize 
+              << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;			
+
+    m_buffers = new float *[m_channels];
+
+    for (size_t i = 0; i < m_channels; ++i) {
+        m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
+        m_buffers[i] = new float[m_blockSize];
+    }
+    
+    return m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
+}
+		
+PluginBufferingAdapter::OutputList
+PluginBufferingAdapter::Impl::getOutputDescriptors() const
+{
+    if (m_outputs.empty()) {
+        m_outputs = m_plugin->getOutputDescriptors();
+    }
+
+    PluginBufferingAdapter::OutputList outs = m_outputs;
+
+    for (size_t i = 0; i < outs.size(); ++i) {
+
+        switch (outs[i].sampleType) {
+
+        case OutputDescriptor::OneSamplePerStep:
+            outs[i].sampleType = OutputDescriptor::FixedSampleRate;
+            outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
+            m_rewriteOutputTimes[i] = true;
+            break;
+            
+        case OutputDescriptor::FixedSampleRate:
+            if (outs[i].sampleRate == 0.f) {
+                outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
+            }
+            // We actually only need to rewrite output times for
+            // features that don't have timestamps already, but we
+            // can't tell from here whether our features will have
+            // timestamps or not
+            m_rewriteOutputTimes[i] = true;
+            break;
+
+        case OutputDescriptor::VariableSampleRate:
+            m_rewriteOutputTimes[i] = false;
+            break;
+        }
+    }
+
+    return outs;
+}
+
+void
+PluginBufferingAdapter::Impl::reset()
+{
+    m_frame = 0;
+    m_unrun = true;
+
+    for (size_t i = 0; i < m_queue.size(); ++i) {
+        m_queue[i]->reset();
+    }
+
+    m_plugin->reset();
+}
+
+PluginBufferingAdapter::FeatureSet
+PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
+                                      RealTime timestamp)
+{
+    if (m_inputStepSize == 0) {
+        std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl;
+        return FeatureSet();
+    }
+
+    FeatureSet allFeatureSets;
+
+    if (m_unrun) {
+        m_frame = RealTime::realTime2Frame(timestamp,
+                                           int(m_inputSampleRate + 0.5));
+        m_unrun = false;
+    }
+			
+    // queue the new input
+    
+    for (size_t i = 0; i < m_channels; ++i) {
+        int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
+        if (written < int(m_inputBlockSize) && i == 0) {
+            std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
+                      << "Buffer overflow: wrote " << written 
+                      << " of " << m_inputBlockSize 
+                      << " input samples (for plugin step size "
+                      << m_stepSize << ", block size " << m_blockSize << ")"
+                      << std::endl;
+        }
+    }    
+    
+    // process as much as we can
+
+    while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
+        processBlock(allFeatureSets);
+    }	
+    
+    return allFeatureSets;
+}
+    
+PluginBufferingAdapter::FeatureSet
+PluginBufferingAdapter::Impl::getRemainingFeatures() 
+{
+    FeatureSet allFeatureSets;
+    
+    // process remaining samples in queue
+    while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
+        processBlock(allFeatureSets);
+    }
+    
+    // pad any last samples remaining and process
+    if (m_queue[0]->getReadSpace() > 0) {
+        for (size_t i = 0; i < m_channels; ++i) {
+            m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
+        }
+        processBlock(allFeatureSets);
+    }			
+    
+    // get remaining features			
+
+    FeatureSet featureSet = m_plugin->getRemainingFeatures();
+
+    for (map<int, FeatureList>::iterator iter = featureSet.begin();
+         iter != featureSet.end(); ++iter) {
+        FeatureList featureList = iter->second;
+        for (size_t i = 0; i < featureList.size(); ++i) {
+            allFeatureSets[iter->first].push_back(featureList[i]);
+        }
+    }
+    
+    return allFeatureSets;
+}
+    
+void
+PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
+{
+    for (size_t i = 0; i < m_channels; ++i) {
+        m_queue[i]->peek(m_buffers[i], m_blockSize);
+    }
+
+    long frame = m_frame;
+    RealTime timestamp = RealTime::frame2RealTime
+        (frame, int(m_inputSampleRate + 0.5));
+
+    FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
+    
+    for (FeatureSet::iterator iter = featureSet.begin();
+         iter != featureSet.end(); ++iter) {
+
+        int outputNo = iter->first;
+
+        if (m_rewriteOutputTimes[outputNo]) {
+            
+            FeatureList featureList = iter->second;
+	
+            for (size_t i = 0; i < featureList.size(); ++i) {
+
+                switch (m_outputs[outputNo].sampleType) {
+
+                case OutputDescriptor::OneSamplePerStep:
+                    // use our internal timestamp, always
+                    featureList[i].timestamp = timestamp;
+                    featureList[i].hasTimestamp = true;
+                    break;
+
+                case OutputDescriptor::FixedSampleRate:
+                    // use our internal timestamp if feature lacks one
+                    if (!featureList[i].hasTimestamp) {
+                        featureList[i].timestamp = timestamp;
+                        featureList[i].hasTimestamp = true;
+                    }
+                    break;
+
+                case OutputDescriptor::VariableSampleRate:
+                    break;		// plugin must set timestamp
+
+                default:
+                    break;
+                }
+            
+                allFeatureSets[outputNo].push_back(featureList[i]);
+            }
+        } else {
+            for (size_t i = 0; i < iter->second.size(); ++i) {
+                allFeatureSets[outputNo].push_back(iter->second[i]);
+            }
+        }
+    }
+    
+    // step forward
+
+    for (size_t i = 0; i < m_channels; ++i) {
+        m_queue[i]->skip(m_stepSize);
+    }
+    
+    // increment internal frame counter each time we step forward
+    m_frame += m_stepSize;
+}
+
+}
+	
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vamp-hostsdk/hostext/PluginChannelAdapter.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,266 @@
+/* -*- 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-2007 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.
+*/
+
+#include "PluginChannelAdapter.h"
+
+namespace Vamp {
+
+namespace HostExt {
+
+class PluginChannelAdapter::Impl
+{
+public:
+    Impl(Plugin *plugin);
+    ~Impl();
+
+    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+
+    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
+    FeatureSet processInterleaved(const float *inputBuffers, RealTime timestamp);
+
+protected:
+    Plugin *m_plugin;
+    size_t m_blockSize;
+    size_t m_inputChannels;
+    size_t m_pluginChannels;
+    float **m_buffer;
+    float **m_deinterleave;
+    const float **m_forwardPtrs;
+};
+
+PluginChannelAdapter::PluginChannelAdapter(Plugin *plugin) :
+    PluginWrapper(plugin)
+{
+    m_impl = new Impl(plugin);
+}
+
+PluginChannelAdapter::~PluginChannelAdapter()
+{
+    delete m_impl;
+}
+
+bool
+PluginChannelAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    return m_impl->initialise(channels, stepSize, blockSize);
+}
+
+PluginChannelAdapter::FeatureSet
+PluginChannelAdapter::process(const float *const *inputBuffers,
+                              RealTime timestamp)
+{
+    return m_impl->process(inputBuffers, timestamp);
+}
+
+PluginChannelAdapter::FeatureSet
+PluginChannelAdapter::processInterleaved(const float *inputBuffers,
+                                         RealTime timestamp)
+{
+    return m_impl->processInterleaved(inputBuffers, timestamp);
+}
+
+PluginChannelAdapter::Impl::Impl(Plugin *plugin) :
+    m_plugin(plugin),
+    m_blockSize(0),
+    m_inputChannels(0),
+    m_pluginChannels(0),
+    m_buffer(0),
+    m_deinterleave(0),
+    m_forwardPtrs(0)
+{
+}
+
+PluginChannelAdapter::Impl::~Impl()
+{
+    // the adapter will delete the plugin
+
+    if (m_buffer) {
+        if (m_inputChannels > m_pluginChannels) {
+            delete[] m_buffer[0];
+        } else {
+            for (size_t i = 0; i < m_pluginChannels - m_inputChannels; ++i) {
+                delete[] m_buffer[i];
+            }
+        }
+        delete[] m_buffer;
+        m_buffer = 0;
+    }
+
+    if (m_deinterleave) {
+        for (size_t i = 0; i < m_inputChannels; ++i) {
+            delete[] m_deinterleave[i];
+        }
+        delete[] m_deinterleave;
+        m_deinterleave = 0;
+    }
+
+    if (m_forwardPtrs) {
+        delete[] m_forwardPtrs;
+        m_forwardPtrs = 0;
+    }
+}
+
+bool
+PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    m_blockSize = blockSize;
+
+    size_t minch = m_plugin->getMinChannelCount();
+    size_t maxch = m_plugin->getMaxChannelCount();
+
+    m_inputChannels = channels;
+
+    if (m_inputChannels < minch) {
+
+        m_forwardPtrs = new const float *[minch];
+
+        if (m_inputChannels > 1) {
+            // We need a set of zero-valued buffers to add to the
+            // forwarded pointers
+            m_buffer = new float*[minch - channels];
+            for (size_t i = 0; i < minch; ++i) {
+                m_buffer[i] = new float[blockSize];
+                for (size_t j = 0; j < blockSize; ++j) {
+                    m_buffer[i][j] = 0.f;
+                }
+            }
+        }
+
+        m_pluginChannels = minch;
+
+        std::cerr << "PluginChannelAdapter::initialise: expanding " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
+
+    } else if (m_inputChannels > maxch) {
+
+        // We only need m_buffer if we are mixing down to a single
+        // channel -- otherwise we can just forward the same float* as
+        // passed in to process(), expecting the excess to be ignored
+
+        if (maxch == 1) {
+            m_buffer = new float *[1];
+            m_buffer[0] = new float[blockSize];
+
+            std::cerr << "PluginChannelAdapter::initialise: mixing " << m_inputChannels << " to mono for plugin" << std::endl;
+
+        } else {
+            
+            std::cerr << "PluginChannelAdapter::initialise: reducing " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
+        }
+
+        m_pluginChannels = maxch;
+
+    } else {
+ 
+        std::cerr << "PluginChannelAdapter::initialise: accepting given number of channels (" << m_inputChannels << ")" << std::endl;
+        m_pluginChannels = m_inputChannels;
+    }
+
+    return m_plugin->initialise(m_pluginChannels, stepSize, blockSize);
+}
+
+PluginChannelAdapter::FeatureSet
+PluginChannelAdapter::Impl::processInterleaved(const float *inputBuffers,
+                                               RealTime timestamp)
+{
+    if (!m_deinterleave) {
+        m_deinterleave = new float *[m_inputChannels];
+        for (size_t i = 0; i < m_inputChannels; ++i) {
+            m_deinterleave[i] = new float[m_blockSize];
+        }
+    }
+
+    for (size_t i = 0; i < m_inputChannels; ++i) {
+        for (size_t j = 0; j < m_blockSize; ++j) {
+            m_deinterleave[i][j] = inputBuffers[j * m_inputChannels + i];
+        }
+    }
+
+    return process(m_deinterleave, timestamp);
+}
+
+PluginChannelAdapter::FeatureSet
+PluginChannelAdapter::Impl::process(const float *const *inputBuffers,
+                                    RealTime timestamp)
+{
+//    std::cerr << "PluginChannelAdapter::process: " << m_inputChannels << " -> " << m_pluginChannels << " channels" << std::endl;
+
+    if (m_inputChannels < m_pluginChannels) {
+
+        if (m_inputChannels == 1) {
+            for (size_t i = 0; i < m_pluginChannels; ++i) {
+                m_forwardPtrs[i] = inputBuffers[0];
+            }
+        } else {
+            for (size_t i = 0; i < m_inputChannels; ++i) {
+                m_forwardPtrs[i] = inputBuffers[i];
+            }
+            for (size_t i = m_inputChannels; i < m_pluginChannels; ++i) {
+                m_forwardPtrs[i] = m_buffer[i - m_inputChannels];
+            }
+        }
+
+        return m_plugin->process(m_forwardPtrs, timestamp);
+
+    } else if (m_inputChannels > m_pluginChannels) {
+
+        if (m_pluginChannels == 1) {
+            for (size_t j = 0; j < m_blockSize; ++j) {
+                m_buffer[0][j] = inputBuffers[0][j];
+            }
+            for (size_t i = 1; i < m_inputChannels; ++i) {
+                for (size_t j = 0; j < m_blockSize; ++j) {
+                    m_buffer[0][j] += inputBuffers[i][j];
+                }
+            }
+            for (size_t j = 0; j < m_blockSize; ++j) {
+                m_buffer[0][j] /= m_inputChannels;
+            }
+            return m_plugin->process(m_buffer, timestamp);
+        } else {
+            return m_plugin->process(inputBuffers, timestamp);
+        }
+
+    } else {
+
+        return m_plugin->process(inputBuffers, timestamp);
+    }
+}
+
+}
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vamp-hostsdk/hostext/PluginInputDomainAdapter.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,578 @@
+/* -*- 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-2007 Chris Cannam and QMUL.
+  
+    This file is based in part on Don Cross's public domain FFT
+    implementation.
+
+    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 "PluginInputDomainAdapter.h"
+
+#include <cmath>
+
+
+/**
+ * If you want to compile using FFTW instead of the built-in FFT
+ * implementation for the PluginInputDomainAdapter, define HAVE_FFTW3
+ * in the Makefile.
+ *
+ * Be aware that FFTW is licensed under the GPL -- unlike this SDK,
+ * which is provided under a more liberal BSD license in order to
+ * permit use in closed source applications.  The use of FFTW would
+ * mean that your code would need to be licensed under the GPL as
+ * well.  Do not define this symbol unless you understand and accept
+ * the implications of this.
+ *
+ * Parties such as Linux distribution packagers who redistribute this
+ * SDK for use in other programs should _not_ define this symbol, as
+ * it would change the effective licensing terms under which the SDK
+ * was available to third party developers.
+ *
+ * The default is not to use FFTW, and to use the built-in FFT instead.
+ * 
+ * Note: The FFTW code uses FFTW_MEASURE, and so will perform badly on
+ * its first invocation unless the host has saved and restored FFTW
+ * wisdom (see the FFTW documentation).
+ */
+#ifdef HAVE_FFTW3
+#include <fftw3.h>
+#endif
+
+
+namespace Vamp {
+
+namespace HostExt {
+
+class PluginInputDomainAdapter::Impl
+{
+public:
+    Impl(Plugin *plugin, float inputSampleRate);
+    ~Impl();
+    
+    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+
+    size_t getPreferredStepSize() const;
+    size_t getPreferredBlockSize() const;
+
+    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
+    
+    RealTime getTimestampAdjustment() const;
+
+protected:
+    Plugin *m_plugin;
+    float m_inputSampleRate;
+    int m_channels;
+    int m_blockSize;
+    float **m_freqbuf;
+
+    double *m_ri;
+    double *m_window;
+
+#ifdef HAVE_FFTW3
+    fftw_plan m_plan;
+    fftw_complex *m_cbuf;
+#else
+    double *m_ro;
+    double *m_io;
+    void fft(unsigned int n, bool inverse,
+             double *ri, double *ii, double *ro, double *io);
+#endif
+
+    size_t makeBlockSizeAcceptable(size_t) const;
+};
+
+PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
+    PluginWrapper(plugin)
+{
+    m_impl = new Impl(plugin, m_inputSampleRate);
+}
+
+PluginInputDomainAdapter::~PluginInputDomainAdapter()
+{
+    delete m_impl;
+}
+  
+bool
+PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    return m_impl->initialise(channels, stepSize, blockSize);
+}
+
+Plugin::InputDomain
+PluginInputDomainAdapter::getInputDomain() const
+{
+    return TimeDomain;
+}
+
+size_t
+PluginInputDomainAdapter::getPreferredStepSize() const
+{
+    return m_impl->getPreferredStepSize();
+}
+
+size_t
+PluginInputDomainAdapter::getPreferredBlockSize() const
+{
+    return m_impl->getPreferredBlockSize();
+}
+
+Plugin::FeatureSet
+PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
+{
+    return m_impl->process(inputBuffers, timestamp);
+}
+
+RealTime
+PluginInputDomainAdapter::getTimestampAdjustment() const
+{
+    return m_impl->getTimestampAdjustment();
+}
+
+
+PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
+    m_plugin(plugin),
+    m_inputSampleRate(inputSampleRate),
+    m_channels(0),
+    m_blockSize(0),
+    m_freqbuf(0),
+    m_ri(0),
+    m_window(0),
+#ifdef HAVE_FFTW3
+    m_plan(0),
+    m_cbuf(0)
+#else
+    m_ro(0),
+    m_io(0)
+#endif
+{
+}
+
+PluginInputDomainAdapter::Impl::~Impl()
+{
+    // the adapter will delete the plugin
+
+    if (m_channels > 0) {
+        for (int c = 0; c < m_channels; ++c) {
+            delete[] m_freqbuf[c];
+        }
+        delete[] m_freqbuf;
+#ifdef HAVE_FFTW3
+        if (m_plan) {
+            fftw_destroy_plan(m_plan);
+            fftw_free(m_ri);
+            fftw_free(m_cbuf);
+            m_plan = 0;
+        }
+#else
+        delete[] m_ri;
+        delete[] m_ro;
+        delete[] m_io;
+#endif
+        delete[] m_window;
+    }
+}
+
+// for some visual studii apparently
+#ifndef M_PI
+#define M_PI 3.14159265358979232846
+#endif
+    
+bool
+PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    if (m_plugin->getInputDomain() == TimeDomain) {
+
+        m_blockSize = int(blockSize);
+        m_channels = int(channels);
+
+        return m_plugin->initialise(channels, stepSize, blockSize);
+    }
+
+    if (blockSize < 2) {
+        std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not supported" << std::endl;
+        return false;
+    }                
+        
+    if (blockSize & (blockSize-1)) {
+        std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
+        return false;
+    }
+
+    if (m_channels > 0) {
+        for (int c = 0; c < m_channels; ++c) {
+            delete[] m_freqbuf[c];
+        }
+        delete[] m_freqbuf;
+#ifdef HAVE_FFTW3
+        if (m_plan) {
+            fftw_destroy_plan(m_plan);
+            fftw_free(m_ri);
+            fftw_free(m_cbuf);
+            m_plan = 0;
+        }
+#else
+        delete[] m_ri;
+        delete[] m_ro;
+        delete[] m_io;
+#endif
+        delete[] m_window;
+    }
+
+    m_blockSize = int(blockSize);
+    m_channels = int(channels);
+
+    m_freqbuf = new float *[m_channels];
+    for (int c = 0; c < m_channels; ++c) {
+        m_freqbuf[c] = new float[m_blockSize + 2];
+    }
+    m_window = new double[m_blockSize];
+
+    for (int i = 0; i < m_blockSize; ++i) {
+        // Hanning window
+        m_window[i] = (0.50 - 0.50 * cos((2.0 * M_PI * i) / m_blockSize));
+    }
+
+#ifdef HAVE_FFTW3
+    m_ri = (double *)fftw_malloc(blockSize * sizeof(double));
+    m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex));
+    m_plan = fftw_plan_dft_r2c_1d(blockSize, m_ri, m_cbuf, FFTW_MEASURE);
+#else
+    m_ri = new double[m_blockSize];
+    m_ro = new double[m_blockSize];
+    m_io = new double[m_blockSize];
+#endif
+
+    return m_plugin->initialise(channels, stepSize, blockSize);
+}
+
+size_t
+PluginInputDomainAdapter::Impl::getPreferredStepSize() const
+{
+    size_t step = m_plugin->getPreferredStepSize();
+
+    if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) {
+        step = getPreferredBlockSize() / 2;
+    }
+
+    return step;
+}
+
+size_t
+PluginInputDomainAdapter::Impl::getPreferredBlockSize() const
+{
+    size_t block = m_plugin->getPreferredBlockSize();
+
+    if (m_plugin->getInputDomain() == FrequencyDomain) {
+        if (block == 0) {
+            block = 1024;
+        } else {
+            block = makeBlockSizeAcceptable(block);
+        }
+    }
+
+    return block;
+}
+
+size_t
+PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
+{
+    if (blockSize < 2) {
+
+        std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not" << std::endl
+                  << "supported, increasing from " << blockSize << " to 2" << std::endl;
+        blockSize = 2;
+        
+    } else if (blockSize & (blockSize-1)) {
+            
+#ifdef HAVE_FFTW3
+        // not an issue with FFTW
+#else
+
+        // not a power of two, can't handle that with our built-in FFT
+        // implementation
+
+        size_t nearest = blockSize;
+        size_t power = 0;
+        while (nearest > 1) {
+            nearest >>= 1;
+            ++power;
+        }
+        nearest = 1;
+        while (power) {
+            nearest <<= 1;
+            --power;
+        }
+        
+        if (blockSize - nearest > (nearest*2) - blockSize) {
+            nearest = nearest*2;
+        }
+        
+        std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
+        blockSize = nearest;
+
+#endif
+    }
+
+    return blockSize;
+}
+
+RealTime
+PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
+{
+    if (m_plugin->getInputDomain() == TimeDomain) {
+        return RealTime::zeroTime;
+    } else {
+        return RealTime::frame2RealTime
+            (m_blockSize/2, int(m_inputSampleRate + 0.5));
+    }
+}
+
+Plugin::FeatureSet
+PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
+                                        RealTime timestamp)
+{
+    if (m_plugin->getInputDomain() == TimeDomain) {
+        return m_plugin->process(inputBuffers, timestamp);
+    }
+
+    // The timestamp supplied should be (according to the Vamp::Plugin
+    // spec) the time of the start of the time-domain input block.
+    // However, we want to pass to the plugin an FFT output calculated
+    // from the block of samples _centred_ on that timestamp.
+    // 
+    // We have two options:
+    // 
+    // 1. Buffer the input, calculating the fft of the values at the
+    // passed-in block minus blockSize/2 rather than starting at the
+    // passed-in block.  So each time we call process on the plugin,
+    // we are passing in the same timestamp as was passed to our own
+    // process plugin, but not (the frequency domain representation
+    // of) the same set of samples.  Advantages: avoids confusion in
+    // the host by ensuring the returned values have timestamps
+    // comparable with that passed in to this function (in fact this
+    // is pretty much essential for one-value-per-block outputs);
+    // consistent with hosts such as SV that deal with the
+    // frequency-domain transform themselves.  Disadvantages: means
+    // making the not necessarily correct assumption that the samples
+    // preceding the first official block are all zero (or some other
+    // known value).
+    //
+    // 2. Increase the passed-in timestamps by half the blocksize.  So
+    // when we call process, we are passing in the frequency domain
+    // representation of the same set of samples as passed to us, but
+    // with a different timestamp.  Advantages: simplicity; avoids
+    // iffy assumption mentioned above.  Disadvantages: inconsistency
+    // with SV in cases where stepSize != blockSize/2; potential
+    // confusion arising from returned timestamps being calculated
+    // from the adjusted input timestamps rather than the original
+    // ones (and inaccuracy where the returned timestamp is implied,
+    // as in one-value-per-block).
+    //
+    // Neither way is ideal, but I don't think either is strictly
+    // incorrect either.  I think this is just a case where the same
+    // plugin can legitimately produce differing results from the same
+    // input data, depending on how that data is packaged.
+    // 
+    // We'll go for option 2, adjusting the timestamps.  Note in
+    // particular that this means some results can differ from those
+    // produced by SV.
+
+//    std::cerr << "PluginInputDomainAdapter: sampleRate " << m_inputSampleRate << ", blocksize " << m_blockSize << ", adjusting time from " << timestamp;
+
+    timestamp = timestamp + getTimestampAdjustment();
+
+//    std::cerr << " to " << timestamp << std::endl;
+
+    for (int c = 0; c < m_channels; ++c) {
+
+        for (int i = 0; i < m_blockSize; ++i) {
+            m_ri[i] = double(inputBuffers[c][i]) * m_window[i];
+        }
+
+        for (int i = 0; i < m_blockSize/2; ++i) {
+            // FFT shift
+            double value = m_ri[i];
+            m_ri[i] = m_ri[i + m_blockSize/2];
+            m_ri[i + m_blockSize/2] = value;
+        }
+
+#ifdef HAVE_FFTW3
+
+        fftw_execute(m_plan);
+
+        for (int i = 0; i <= m_blockSize/2; ++i) {
+            m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
+            m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
+        }
+
+#else
+
+        fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
+
+        for (int i = 0; i <= m_blockSize/2; ++i) {
+            m_freqbuf[c][i * 2] = float(m_ro[i]);
+            m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
+        }
+
+#endif
+    }
+
+    return m_plugin->process(m_freqbuf, timestamp);
+}
+
+#ifndef HAVE_FFTW3
+
+void
+PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse,
+                                    double *ri, double *ii, double *ro, double *io)
+{
+    if (!ri || !ro || !io) return;
+
+    unsigned int bits;
+    unsigned int i, j, k, m;
+    unsigned int blockSize, blockEnd;
+
+    double tr, ti;
+
+    if (n < 2) return;
+    if (n & (n-1)) return;
+
+    double angle = 2.0 * M_PI;
+    if (inverse) angle = -angle;
+
+    for (i = 0; ; ++i) {
+	if (n & (1 << i)) {
+	    bits = i;
+	    break;
+	}
+    }
+
+    static unsigned int tableSize = 0;
+    static int *table = 0;
+
+    if (tableSize != n) {
+
+	delete[] table;
+
+	table = new int[n];
+
+	for (i = 0; i < n; ++i) {
+	
+	    m = i;
+
+	    for (j = k = 0; j < bits; ++j) {
+		k = (k << 1) | (m & 1);
+		m >>= 1;
+	    }
+
+	    table[i] = k;
+	}
+
+	tableSize = n;
+    }
+
+    if (ii) {
+	for (i = 0; i < n; ++i) {
+	    ro[table[i]] = ri[i];
+	    io[table[i]] = ii[i];
+	}
+    } else {
+	for (i = 0; i < n; ++i) {
+	    ro[table[i]] = ri[i];
+	    io[table[i]] = 0.0;
+	}
+    }
+
+    blockEnd = 1;
+
+    for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
+
+	double delta = angle / (double)blockSize;
+	double sm2 = -sin(-2 * delta);
+	double sm1 = -sin(-delta);
+	double cm2 = cos(-2 * delta);
+	double cm1 = cos(-delta);
+	double w = 2 * cm1;
+	double ar[3], ai[3];
+
+	for (i = 0; i < n; i += blockSize) {
+
+	    ar[2] = cm2;
+	    ar[1] = cm1;
+
+	    ai[2] = sm2;
+	    ai[1] = sm1;
+
+	    for (j = i, m = 0; m < blockEnd; j++, m++) {
+
+		ar[0] = w * ar[1] - ar[2];
+		ar[2] = ar[1];
+		ar[1] = ar[0];
+
+		ai[0] = w * ai[1] - ai[2];
+		ai[2] = ai[1];
+		ai[1] = ai[0];
+
+		k = j + blockEnd;
+		tr = ar[0] * ro[k] - ai[0] * io[k];
+		ti = ar[0] * io[k] + ai[0] * ro[k];
+
+		ro[k] = ro[j] - tr;
+		io[k] = io[j] - ti;
+
+		ro[j] += tr;
+		io[j] += ti;
+	    }
+	}
+
+	blockEnd = blockSize;
+    }
+
+    if (inverse) {
+
+	double denom = (double)n;
+
+	for (i = 0; i < n; i++) {
+	    ro[i] /= denom;
+	    io[i] /= denom;
+	}
+    }
+}
+
+#endif
+
+}
+        
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vamp-hostsdk/hostext/PluginLoader.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,636 @@
+/* -*- 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-2007 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.
+*/
+
+#include "vamp-sdk/PluginHostAdapter.h"
+#include "PluginLoader.h"
+#include "PluginInputDomainAdapter.h"
+#include "PluginChannelAdapter.h"
+#include "PluginBufferingAdapter.h"
+
+#include <fstream>
+#include <cctype> // tolower
+
+#include <cstring>
+
+#ifdef _WIN32
+
+#include <windows.h>
+#include <tchar.h>
+#define PLUGIN_SUFFIX "dll"
+
+#else /* ! _WIN32 */
+
+#include <dirent.h>
+#include <dlfcn.h>
+
+#ifdef __APPLE__
+#define PLUGIN_SUFFIX "dylib"
+#else /* ! __APPLE__ */
+#define PLUGIN_SUFFIX "so"
+#endif /* ! __APPLE__ */
+
+#endif /* ! _WIN32 */
+
+using namespace std;
+
+namespace Vamp {
+	
+namespace HostExt {
+
+class PluginLoader::Impl
+{
+public:
+    Impl();
+    virtual ~Impl();
+
+    PluginKeyList listPlugins();
+
+    Plugin *loadPlugin(PluginKey key,
+                       float inputSampleRate,
+                       int adapterFlags);
+
+    PluginKey composePluginKey(string libraryName, string identifier);
+
+    PluginCategoryHierarchy getPluginCategory(PluginKey key);
+
+    string getLibraryPathForPlugin(PluginKey key);
+
+    static void setInstanceToClean(PluginLoader *instance);
+
+protected:
+    class PluginDeletionNotifyAdapter : public PluginWrapper {
+    public:
+        PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
+        virtual ~PluginDeletionNotifyAdapter();
+    protected:
+        Impl *m_loader;
+    };
+
+    class InstanceCleaner {
+    public:
+        InstanceCleaner() : m_instance(0) { }
+        ~InstanceCleaner() { delete m_instance; }
+        void setInstance(PluginLoader *instance) { m_instance = instance; }
+    protected:
+        PluginLoader *m_instance;
+    };
+
+    virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
+
+    map<PluginKey, string> m_pluginLibraryNameMap;
+    bool m_allPluginsEnumerated;
+    void enumeratePlugins(PluginKey forPlugin = "");
+
+    map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
+    void generateTaxonomy();
+
+    map<Plugin *, void *> m_pluginLibraryHandleMap;
+
+    bool decomposePluginKey(PluginKey key,
+                            string &libraryName, string &identifier);
+
+    void *loadLibrary(string path);
+    void unloadLibrary(void *handle);
+    void *lookupInLibrary(void *handle, const char *symbol);
+
+    string splicePath(string a, string b);
+    vector<string> listFiles(string dir, string ext);
+    
+    static InstanceCleaner m_cleaner;
+};
+
+PluginLoader *
+PluginLoader::m_instance = 0;
+
+PluginLoader::Impl::InstanceCleaner
+PluginLoader::Impl::m_cleaner;
+
+PluginLoader::PluginLoader()
+{
+    m_impl = new Impl();
+}
+
+PluginLoader::~PluginLoader()
+{
+    delete m_impl;
+}
+
+PluginLoader *
+PluginLoader::getInstance()
+{
+    if (!m_instance) {
+        // The cleaner doesn't own the instance, because we leave the
+        // instance pointer in the base class for binary backwards
+        // compatibility reasons and to avoid waste
+        m_instance = new PluginLoader();
+        Impl::setInstanceToClean(m_instance);
+    }
+    return m_instance;
+}
+
+vector<PluginLoader::PluginKey>
+PluginLoader::listPlugins() 
+{
+    return m_impl->listPlugins();
+}
+
+Plugin *
+PluginLoader::loadPlugin(PluginKey key,
+                         float inputSampleRate,
+                         int adapterFlags)
+{
+    return m_impl->loadPlugin(key, inputSampleRate, adapterFlags);
+}
+
+PluginLoader::PluginKey
+PluginLoader::composePluginKey(string libraryName, string identifier) 
+{
+    return m_impl->composePluginKey(libraryName, identifier);
+}
+
+PluginLoader::PluginCategoryHierarchy
+PluginLoader::getPluginCategory(PluginKey key)
+{
+    return m_impl->getPluginCategory(key);
+}
+
+string
+PluginLoader::getLibraryPathForPlugin(PluginKey key)
+{
+    return m_impl->getLibraryPathForPlugin(key);
+}
+ 
+PluginLoader::Impl::Impl() :
+    m_allPluginsEnumerated(false)
+{
+}
+
+PluginLoader::Impl::~Impl()
+{
+}
+
+void
+PluginLoader::Impl::setInstanceToClean(PluginLoader *instance)
+{
+    m_cleaner.setInstance(instance);
+}
+
+vector<PluginLoader::PluginKey>
+PluginLoader::Impl::listPlugins() 
+{
+    if (!m_allPluginsEnumerated) enumeratePlugins();
+
+    vector<PluginKey> plugins;
+    for (map<PluginKey, string>::iterator mi = m_pluginLibraryNameMap.begin();
+         mi != m_pluginLibraryNameMap.end(); ++mi) {
+        plugins.push_back(mi->first);
+    }
+
+    return plugins;
+}
+
+void
+PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin)
+{
+    vector<string> path = PluginHostAdapter::getPluginPath();
+
+    string libraryName, identifier;
+    if (forPlugin != "") {
+        if (!decomposePluginKey(forPlugin, libraryName, identifier)) {
+            std::cerr << "WARNING: Vamp::HostExt::PluginLoader: Invalid plugin key \""
+                      << forPlugin << "\" in enumerate" << std::endl;
+            return;
+        }
+    }
+
+    for (size_t i = 0; i < path.size(); ++i) {
+        
+        vector<string> files = listFiles(path[i], PLUGIN_SUFFIX);
+
+        for (vector<string>::iterator fi = files.begin();
+             fi != files.end(); ++fi) {
+            
+            if (libraryName != "") {
+                // libraryName is lowercased and lacking an extension,
+                // as it came from the plugin key
+                string temp = *fi;
+                for (size_t i = 0; i < temp.length(); ++i) {
+                    temp[i] = tolower(temp[i]);
+                }
+                string::size_type pi = temp.find('.');
+                if (pi == string::npos) {
+                    if (libraryName != temp) continue;
+                } else {
+                    if (libraryName != temp.substr(0, pi)) continue;
+                }
+            }
+
+            string fullPath = path[i];
+            fullPath = splicePath(fullPath, *fi);
+            void *handle = loadLibrary(fullPath);
+            if (!handle) continue;
+            
+            VampGetPluginDescriptorFunction fn =
+                (VampGetPluginDescriptorFunction)lookupInLibrary
+                (handle, "vampGetPluginDescriptor");
+            
+            if (!fn) {
+                unloadLibrary(handle);
+                continue;
+            }
+            
+            int index = 0;
+            const VampPluginDescriptor *descriptor = 0;
+            
+            while ((descriptor = fn(VAMP_API_VERSION, index))) {
+                ++index;
+                if (identifier != "") {
+                    if (descriptor->identifier != identifier) continue;
+                }
+                PluginKey key = composePluginKey(*fi, descriptor->identifier);
+//                std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl;
+                if (m_pluginLibraryNameMap.find(key) ==
+                    m_pluginLibraryNameMap.end()) {
+                    m_pluginLibraryNameMap[key] = fullPath;
+                }
+            }
+            
+            unloadLibrary(handle);
+        }
+    }
+
+    if (forPlugin == "") m_allPluginsEnumerated = true;
+}
+
+PluginLoader::PluginKey
+PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
+{
+    string basename = libraryName;
+
+    string::size_type li = basename.rfind('/');
+    if (li != string::npos) basename = basename.substr(li + 1);
+
+    li = basename.find('.');
+    if (li != string::npos) basename = basename.substr(0, li);
+
+    for (size_t i = 0; i < basename.length(); ++i) {
+        basename[i] = tolower(basename[i]);
+    }
+
+    return basename + ":" + identifier;
+}
+
+bool
+PluginLoader::Impl::decomposePluginKey(PluginKey key,
+                                       string &libraryName,
+                                       string &identifier)
+{
+    string::size_type ki = key.find(':');
+    if (ki == string::npos) {
+        return false;
+    }
+
+    libraryName = key.substr(0, ki);
+    identifier = key.substr(ki + 1);
+    return true;
+}
+
+PluginLoader::PluginCategoryHierarchy
+PluginLoader::Impl::getPluginCategory(PluginKey plugin)
+{
+    if (m_taxonomy.empty()) generateTaxonomy();
+    if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
+        return PluginCategoryHierarchy();
+    }
+    return m_taxonomy[plugin];
+}
+
+string
+PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
+{
+    if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
+        if (m_allPluginsEnumerated) return "";
+        enumeratePlugins(plugin);
+    }
+    if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
+        return "";
+    }
+    return m_pluginLibraryNameMap[plugin];
+}    
+
+Plugin *
+PluginLoader::Impl::loadPlugin(PluginKey key,
+                               float inputSampleRate, int adapterFlags)
+{
+    string libname, identifier;
+    if (!decomposePluginKey(key, libname, identifier)) {
+        std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \""
+                  << key << "\" in loadPlugin" << std::endl;
+        return 0;
+    }
+        
+    string fullPath = getLibraryPathForPlugin(key);
+    if (fullPath == "") return 0;
+    
+    void *handle = loadLibrary(fullPath);
+    if (!handle) return 0;
+    
+    VampGetPluginDescriptorFunction fn =
+        (VampGetPluginDescriptorFunction)lookupInLibrary
+        (handle, "vampGetPluginDescriptor");
+
+    if (!fn) {
+        unloadLibrary(handle);
+        return 0;
+    }
+
+    int index = 0;
+    const VampPluginDescriptor *descriptor = 0;
+
+    while ((descriptor = fn(VAMP_API_VERSION, index))) {
+
+        if (string(descriptor->identifier) == identifier) {
+
+            Vamp::PluginHostAdapter *plugin =
+                new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
+
+            Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
+
+            m_pluginLibraryHandleMap[adapter] = handle;
+
+            if (adapterFlags & ADAPT_INPUT_DOMAIN) {
+                if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
+                    adapter = new PluginInputDomainAdapter(adapter);
+                }
+            }
+
+            if (adapterFlags & ADAPT_BUFFER_SIZE) {
+                adapter = new PluginBufferingAdapter(adapter);
+            }
+
+            if (adapterFlags & ADAPT_CHANNEL_COUNT) {
+                adapter = new PluginChannelAdapter(adapter);
+            }
+
+            return adapter;
+        }
+
+        ++index;
+    }
+
+    cerr << "Vamp::HostExt::PluginLoader: Plugin \""
+         << identifier << "\" not found in library \""
+         << fullPath << "\"" << endl;
+
+    return 0;
+}
+
+void
+PluginLoader::Impl::generateTaxonomy()
+{
+//    cerr << "PluginLoader::Impl::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) {
+
+        // It doesn't matter that we're using literal forward-slash in
+        // this bit, as it's only relevant if the path contains
+        // "/lib/", which is only meaningful and only plausible on
+        // systems with forward-slash delimiters
+        
+        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 = listFiles(*i, suffix);
+
+        for (vector<string>::iterator fi = files.begin();
+             fi != files.end(); ++fi) {
+
+            string filepath = splicePath(*i, *fi);
+            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;
+            }
+        }
+    }
+}    
+
+void *
+PluginLoader::Impl::loadLibrary(string path)
+{
+    void *handle = 0;
+#ifdef _WIN32
+    handle = LoadLibrary(path.c_str());
+    if (!handle) {
+        cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
+             << path << "\"" << endl;
+    }
+#else
+    handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
+    if (!handle) {
+        cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
+             << path << "\": " << dlerror() << endl;
+    }
+#endif
+    return handle;
+}
+
+void
+PluginLoader::Impl::unloadLibrary(void *handle)
+{
+#ifdef _WIN32
+    FreeLibrary((HINSTANCE)handle);
+#else
+    dlclose(handle);
+#endif
+}
+
+void *
+PluginLoader::Impl::lookupInLibrary(void *handle, const char *symbol)
+{
+#ifdef _WIN32
+    return (void *)GetProcAddress((HINSTANCE)handle, symbol);
+#else
+    return (void *)dlsym(handle, symbol);
+#endif
+}
+
+string
+PluginLoader::Impl::splicePath(string a, string b)
+{
+#ifdef _WIN32
+    return a + "\\" + b;
+#else
+    return a + "/" + b;
+#endif
+}
+
+vector<string>
+PluginLoader::Impl::listFiles(string dir, string extension)
+{
+    vector<string> files;
+
+#ifdef _WIN32
+
+    string expression = dir + "\\*." + extension;
+    WIN32_FIND_DATA data;
+    HANDLE fh = FindFirstFile(expression.c_str(), &data);
+    if (fh == INVALID_HANDLE_VALUE) return files;
+
+    bool ok = true;
+    while (ok) {
+        files.push_back(data.cFileName);
+        ok = FindNextFile(fh, &data);
+    }
+
+    FindClose(fh);
+
+#else
+
+    size_t extlen = extension.length();
+    DIR *d = opendir(dir.c_str());
+    if (!d) return files;
+            
+    struct dirent *e = 0;
+    while ((e = readdir(d))) {
+ 
+        if (!e->d_name) continue;
+       
+        size_t len = strlen(e->d_name);
+        if (len < extlen + 2 ||
+            e->d_name + len - extlen - 1 != "." + extension) {
+            continue;
+        }
+
+        files.push_back(e->d_name);
+    }
+
+    closedir(d);
+#endif
+
+    return files;
+}
+
+void
+PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
+{
+    void *handle = m_pluginLibraryHandleMap[adapter];
+    if (handle) unloadLibrary(handle);
+    m_pluginLibraryHandleMap.erase(adapter);
+}
+
+PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
+                                                                             Impl *loader) :
+    PluginWrapper(plugin),
+    m_loader(loader)
+{
+}
+
+PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
+{
+    // We need to delete the plugin before calling pluginDeleted, as
+    // the delete call may require calling through to the descriptor
+    // (for e.g. cleanup) but pluginDeleted may unload the required
+    // library for the call.  To prevent a double deletion when our
+    // parent's destructor runs (after this one), be sure to set
+    // m_plugin to 0 after deletion.
+    delete m_plugin;
+    m_plugin = 0;
+
+    if (m_loader) m_loader->pluginDeleted(this);
+}
+
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vamp-hostsdk/hostext/PluginSummarisingAdapter.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,913 @@
+/* -*- 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-2008 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.
+*/
+
+#include "PluginSummarisingAdapter.h"
+
+#include <map>
+#include <algorithm>
+#include <cmath>
+#include <climits>
+
+#define DEBUG_PLUGIN_SUMMARISING_ADAPTER 1
+//#define DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT 1
+
+namespace Vamp {
+
+namespace HostExt {
+
+class PluginSummarisingAdapter::Impl
+{
+public:
+    Impl(Plugin *plugin, float inputSampleRate);
+    ~Impl();
+
+    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+
+    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
+    FeatureSet getRemainingFeatures();
+
+    void setSummarySegmentBoundaries(const SegmentBoundaries &);
+
+    FeatureList getSummaryForOutput(int output,
+                                    SummaryType type,
+                                    AveragingMethod avg);
+
+    FeatureSet getSummaryForAllOutputs(SummaryType type,
+                                       AveragingMethod avg);
+
+protected:
+    Plugin *m_plugin;
+    float m_inputSampleRate;
+    size_t m_stepSize;
+    size_t m_blockSize;
+
+    SegmentBoundaries m_boundaries;
+
+    typedef std::vector<float> ValueList;
+
+    struct Result { // smaller than Feature
+        RealTime time;
+        RealTime duration;
+        ValueList values; // bin number -> value
+    };
+
+    typedef std::vector<Result> ResultList;
+
+    struct OutputAccumulator {
+        int bins;
+        ResultList results;
+        OutputAccumulator() : bins(0) { }
+    };
+
+    typedef std::map<int, OutputAccumulator> OutputAccumulatorMap;
+    OutputAccumulatorMap m_accumulators; // output number -> accumulator
+
+    typedef std::map<RealTime, OutputAccumulator> SegmentAccumulatorMap;
+    typedef std::map<int, SegmentAccumulatorMap> OutputSegmentAccumulatorMap;
+    OutputSegmentAccumulatorMap m_segmentedAccumulators; // output -> segmented
+
+    typedef std::map<int, RealTime> OutputTimestampMap;
+    OutputTimestampMap m_prevTimestamps; // output number -> timestamp
+    OutputTimestampMap m_prevDurations; // output number -> durations
+
+    struct OutputBinSummary {
+
+        int count;
+
+        // extents
+        double minimum;
+        double maximum;
+        double sum;
+
+        // sample-average results
+        double median;
+        double mode;
+        double variance;
+
+        // continuous-time average results
+        double median_c;
+        double mode_c;
+        double mean_c;
+        double variance_c;
+    };
+
+    typedef std::map<int, OutputBinSummary> OutputSummary;
+    typedef std::map<RealTime, OutputSummary> SummarySegmentMap;
+    typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap;
+
+    OutputSummarySegmentMap m_summaries;
+
+    bool m_reduced;
+    RealTime m_endTime;
+
+    void accumulate(const FeatureSet &fs, RealTime, bool final);
+    void accumulate(int output, const Feature &f, RealTime, bool final);
+    void accumulateFinalDurations();
+    void findSegmentBounds(RealTime t, RealTime &start, RealTime &end);
+    void segment();
+    void reduce();
+
+    std::string getSummaryLabel(SummaryType type, AveragingMethod avg);
+};
+
+static RealTime INVALID_DURATION(INT_MIN, INT_MIN);
+    
+PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) :
+    PluginWrapper(plugin)
+{
+    m_impl = new Impl(plugin, m_inputSampleRate);
+}
+
+PluginSummarisingAdapter::~PluginSummarisingAdapter()
+{
+    delete m_impl;
+}
+
+bool
+PluginSummarisingAdapter::initialise(size_t channels,
+                                     size_t stepSize, size_t blockSize)
+{
+    return
+        PluginWrapper::initialise(channels, stepSize, blockSize) &&
+        m_impl->initialise(channels, stepSize, blockSize);
+}
+
+Plugin::FeatureSet
+PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp)
+{
+    return m_impl->process(inputBuffers, timestamp);
+}
+
+Plugin::FeatureSet
+PluginSummarisingAdapter::getRemainingFeatures()
+{
+    return m_impl->getRemainingFeatures();
+}
+
+void
+PluginSummarisingAdapter::setSummarySegmentBoundaries(const SegmentBoundaries &b)
+{
+    m_impl->setSummarySegmentBoundaries(b);
+}
+
+Plugin::FeatureList
+PluginSummarisingAdapter::getSummaryForOutput(int output,
+                                              SummaryType type,
+                                              AveragingMethod avg)
+{
+    return m_impl->getSummaryForOutput(output, type, avg);
+}
+
+Plugin::FeatureSet
+PluginSummarisingAdapter::getSummaryForAllOutputs(SummaryType type,
+                                                  AveragingMethod avg)
+{
+    return m_impl->getSummaryForAllOutputs(type, avg);
+}
+
+PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
+    m_plugin(plugin),
+    m_inputSampleRate(inputSampleRate),
+    m_reduced(false)
+{
+}
+
+PluginSummarisingAdapter::Impl::~Impl()
+{
+}
+
+bool
+PluginSummarisingAdapter::Impl::initialise(size_t channels,
+                                           size_t stepSize, size_t blockSize)
+{
+    m_stepSize = stepSize;
+    m_blockSize = blockSize;
+    return true;
+}
+
+Plugin::FeatureSet
+PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers,
+                                        RealTime timestamp)
+{
+    if (m_reduced) {
+        std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
+    }
+    FeatureSet fs = m_plugin->process(inputBuffers, timestamp);
+    accumulate(fs, timestamp, false);
+    m_endTime = timestamp + 
+        RealTime::frame2RealTime(m_stepSize, m_inputSampleRate);
+    return fs;
+}
+
+Plugin::FeatureSet
+PluginSummarisingAdapter::Impl::getRemainingFeatures()
+{
+    if (m_reduced) {
+        std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
+    }
+    FeatureSet fs = m_plugin->getRemainingFeatures();
+    accumulate(fs, m_endTime, true);
+    return fs;
+}
+
+void
+PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b)
+{
+    m_boundaries = b;
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+    std::cerr << "PluginSummarisingAdapter::setSummarySegmentBoundaries: boundaries are:" << std::endl;
+    for (SegmentBoundaries::const_iterator i = m_boundaries.begin();
+         i != m_boundaries.end(); ++i) {
+        std::cerr << *i << "  ";
+    }
+    std::cerr << std::endl;
+#endif
+}
+
+Plugin::FeatureList
+PluginSummarisingAdapter::Impl::getSummaryForOutput(int output,
+                                                    SummaryType type,
+                                                    AveragingMethod avg)
+{
+    if (!m_reduced) {
+        accumulateFinalDurations();
+        segment();
+        reduce();
+        m_reduced = true;
+    }
+
+    bool continuous = (avg == ContinuousTimeAverage);
+
+    FeatureList fl;
+    for (SummarySegmentMap::const_iterator i = m_summaries[output].begin();
+         i != m_summaries[output].end(); ++i) {
+
+        Feature f;
+
+        f.hasTimestamp = true;
+        f.timestamp = i->first;
+
+        f.hasDuration = true;
+        SummarySegmentMap::const_iterator ii = i;
+        if (++ii == m_summaries[output].end()) {
+            f.duration = m_endTime - f.timestamp;
+        } else {
+            f.duration = ii->first - f.timestamp;
+        }
+
+        f.label = getSummaryLabel(type, avg);
+
+        for (OutputSummary::const_iterator j = i->second.begin();
+             j != i->second.end(); ++j) {
+
+            // these will be ordered by bin number, and no bin numbers
+            // will be missing except at the end (because of the way
+            // the accumulators were initially filled in accumulate())
+
+            const OutputBinSummary &summary = j->second;
+            double result = 0.f;
+
+            switch (type) {
+
+            case Minimum:
+                result = summary.minimum;
+                break;
+
+            case Maximum:
+                result = summary.maximum;
+                break;
+
+            case Mean:
+                if (continuous) {
+                    result = summary.mean_c;
+                } else if (summary.count) {
+                    result = summary.sum / summary.count;
+                }
+                break;
+
+            case Median:
+                if (continuous) result = summary.median_c;
+                else result = summary.median;
+                break;
+
+            case Mode:
+                if (continuous) result = summary.mode_c;
+                else result = summary.mode;
+                break;
+
+            case Sum:
+                result = summary.sum;
+                break;
+
+            case Variance:
+                if (continuous) result = summary.variance_c;
+                else result = summary.variance;
+                break;
+
+            case StandardDeviation:
+                if (continuous) result = sqrtf(summary.variance_c);
+                else result = sqrtf(summary.variance);
+                break;
+
+            case Count:
+                result = summary.count;
+                break;
+
+            case UnknownSummaryType:
+                break;
+
+            default:
+                break;
+            }
+            
+            f.values.push_back(result);
+        }
+
+        fl.push_back(f);
+    }
+    return fl;
+}
+
+Plugin::FeatureSet
+PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type,
+                                                        AveragingMethod avg)
+{
+    if (!m_reduced) {
+        accumulateFinalDurations();
+        segment();
+        reduce();
+        m_reduced = true;
+    }
+
+    FeatureSet fs;
+    for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin();
+         i != m_summaries.end(); ++i) {
+        fs[i->first] = getSummaryForOutput(i->first, type, avg);
+    }
+    return fs;
+}
+
+void
+PluginSummarisingAdapter::Impl::accumulate(const FeatureSet &fs,
+                                           RealTime timestamp, 
+                                           bool final)
+{
+    for (FeatureSet::const_iterator i = fs.begin(); i != fs.end(); ++i) {
+        for (FeatureList::const_iterator j = i->second.begin();
+             j != i->second.end(); ++j) {
+            if (j->hasTimestamp) {
+                accumulate(i->first, *j, j->timestamp, final);
+            } else {
+                //!!! is this correct?
+                accumulate(i->first, *j, timestamp, final);
+            }
+        }
+    }
+}
+
+std::string
+PluginSummarisingAdapter::Impl::getSummaryLabel(SummaryType type,
+                                                AveragingMethod avg)
+{
+    std::string label;
+    std::string avglabel;
+
+    if (avg == SampleAverage) avglabel = ", sample average";
+    else avglabel = ", continuous-time average";
+
+    switch (type) {
+    case Minimum:  label = "(minimum value)"; break;
+    case Maximum:  label = "(maximum value)"; break;
+    case Mean:     label = "(mean value" + avglabel + ")"; break;
+    case Median:   label = "(median value" + avglabel + ")"; break;
+    case Mode:     label = "(modal value" + avglabel + ")"; break;
+    case Sum:      label = "(sum)"; break;
+    case Variance: label = "(variance" + avglabel + ")"; break;
+    case StandardDeviation: label = "(standard deviation" + avglabel + ")"; break;
+    case Count:    label = "(count)"; break;
+    case UnknownSummaryType: label = "(unknown summary)"; break;
+    }
+    
+    return label;
+}
+
+void
+PluginSummarisingAdapter::Impl::accumulate(int output,
+                                           const Feature &f,
+                                           RealTime timestamp,
+                                           bool final)
+{
+//!!! to do: use timestamp to determine which segment we're on
+    
+//!!! What should happen if a feature's duration spans a segment
+// boundary?  I think we probably want to chop it, and pretend that it
+// appears in both -- don't we? do we?  A very long feature (e.g. key,
+// if the whole audio is in a single key) might span many or all
+// segments, and we want that to be reflected in the results (e.g. it
+// is the modal key in all of those segments, not just the first).
+// That is actually quite complicated to do!
+
+//!!! This affects how we record things.  If features spanning a
+// boundary should be chopped, then we need to have per-segment
+// accumulators (and the feature value goes into both -- perhaps we
+// need a separate phase to split the accumulator up into segments).
+// If features spanning a boundary should be counted only in the first
+// segment, with their full duration, then we should store them in a
+// single accumulator and distribute into segments only on reduce.
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+    std::cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << ", final " << final << std::endl;
+#endif
+
+    // At each process step, accumulate() is called once for each
+    // feature on each output within that process's returned feature
+    // list, and with the timestamp passed in being that of the start
+    // of the process block.
+
+    // At the end (in getRemainingFeatures), accumulate() is called
+    // once for each feature on each output within the feature list
+    // returned by getRemainingFeatures, and with the timestamp being
+    // the same as the last process block and final set to true.
+
+    // (What if getRemainingFeatures doesn't return any features?  We
+    // still need to ensure that the final duration is written.  Need
+    // a separate function to close the durations.)
+
+    // At each call, we pull out the value for the feature and stuff
+    // it into the accumulator's appropriate values array; and we
+    // calculate the duration for the _previous_ feature, or pull it
+    // from the prevDurations array if the previous feature had a
+    // duration in its structure, and stuff that into the
+    // accumulator's appropriate durations array.
+
+    if (m_prevDurations.find(output) != m_prevDurations.end()) {
+
+        // Not the first time accumulate has been called for this
+        // output -- there has been a previous feature
+
+        RealTime prevDuration;
+
+        // Note that m_prevDurations[output] only contains the
+        // duration field that was contained in the previous feature.
+        // If it didn't have an explicit duration,
+        // m_prevDurations[output] should be INVALID_DURATION and we
+        // will have to calculate the duration from the previous and
+        // current timestamps.
+
+        if (m_prevDurations[output] != INVALID_DURATION) {
+            prevDuration = m_prevDurations[output];
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+            std::cerr << "Previous duration from previous feature: " << prevDuration << std::endl;
+#endif
+        } else {
+            prevDuration = timestamp - m_prevTimestamps[output];
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+            std::cerr << "Previous duration from diff: " << timestamp << " - "
+                      << m_prevTimestamps[output] << std::endl;
+#endif
+        }
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+        std::cerr << "output " << output << ": ";
+        std::cerr << "Pushing previous duration as " << prevDuration << std::endl;
+#endif
+        
+        m_accumulators[output].results
+            [m_accumulators[output].results.size() - 1]
+            .duration = prevDuration;
+    }
+
+    if (f.hasDuration) m_prevDurations[output] = f.duration;
+    else m_prevDurations[output] = INVALID_DURATION;
+
+    m_prevTimestamps[output] = timestamp;
+
+    if (f.hasDuration) {
+        RealTime et = timestamp;
+        et = et + f.duration;
+        if (et > m_endTime) m_endTime = et;
+    }
+
+    Result result;
+    result.time = timestamp;
+    result.duration = INVALID_DURATION;
+
+    if (f.values.size() > m_accumulators[output].bins) {
+        m_accumulators[output].bins = f.values.size();
+    }
+
+    for (int i = 0; i < int(f.values.size()); ++i) {
+        result.values.push_back(f.values[i]);
+    }
+
+    m_accumulators[output].results.push_back(result);
+}
+
+void
+PluginSummarisingAdapter::Impl::accumulateFinalDurations()
+{
+    for (OutputTimestampMap::iterator i = m_prevTimestamps.begin();
+         i != m_prevTimestamps.end(); ++i) {
+
+        int output = i->first;
+
+        int acount = m_accumulators[output].results.size();
+
+        if (acount == 0) continue;
+
+        RealTime prevTimestamp = i->second;
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+        std::cerr << "output " << output << ": ";
+#endif
+
+        if (m_prevDurations.find(output) != m_prevDurations.end() &&
+            m_prevDurations[output] != INVALID_DURATION) {
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+            std::cerr << "Pushing final duration from feature as " << m_prevDurations[output] << std::endl;
+#endif
+
+            m_accumulators[output].results[acount - 1].duration =
+                m_prevDurations[output];
+
+        } else {
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+            std::cerr << "Pushing final duration from diff as " << m_endTime << " - " << m_prevTimestamps[output] << std::endl;
+#endif
+
+            m_accumulators[output].results[acount - 1].duration =
+                m_endTime - m_prevTimestamps[output];
+        }
+        
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+        std::cerr << "so duration for result no " << acount-1 << " is "
+                  << m_accumulators[output].results[acount-1].duration
+                  << std::endl;
+#endif
+    }
+}
+
+void
+PluginSummarisingAdapter::Impl::findSegmentBounds(RealTime t,
+                                                  RealTime &start,
+                                                  RealTime &end)
+{
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
+    std::cerr << "findSegmentBounds: t = " << t <<  std::endl;
+#endif
+
+    SegmentBoundaries::const_iterator i = std::upper_bound
+        (m_boundaries.begin(), m_boundaries.end(), t);
+
+    start = RealTime::zeroTime;
+    end = m_endTime;
+
+    if (i != m_boundaries.end()) {
+        end = *i;
+    }
+
+    if (i != m_boundaries.begin()) {
+        start = *--i;
+    }
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
+    std::cerr << "findSegmentBounds: " << t << " is in segment " << start << " -> " << end << std::endl;
+#endif
+}
+
+void
+PluginSummarisingAdapter::Impl::segment()
+{
+    SegmentBoundaries::iterator boundaryitr = m_boundaries.begin();
+    RealTime segmentStart = RealTime::zeroTime;
+    
+    for (OutputAccumulatorMap::iterator i = m_accumulators.begin();
+         i != m_accumulators.end(); ++i) {
+
+        int output = i->first;
+        OutputAccumulator &source = i->second;
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
+        std::cerr << "segment: total results for output " << output << " = "
+                  << source.results.size() << std::endl;
+#endif
+
+        //!!! This is basically nonsense if the results have no values
+        //!!! (i.e. their times and counts are the only things of
+        //!!! interest) but perhaps it's the user's problem if they
+        //!!! ask for segmentation in that case
+
+        for (int n = 0; n < source.results.size(); ++n) {
+            
+            // This result spans source.results[n].time to
+            // source.results[n].time + source.results[n].duration.
+            // We need to dispose it into segments appropriately
+
+            RealTime resultStart = source.results[n].time;
+            RealTime resultEnd = resultStart + source.results[n].duration;
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
+            std::cerr << "output: " << output << ", result start = " << resultStart << ", end = " << resultEnd << std::endl;
+#endif
+
+            RealTime segmentStart = RealTime::zeroTime;
+            RealTime segmentEnd = resultEnd - RealTime(1, 0);
+            
+            while (segmentEnd < resultEnd) {
+
+                findSegmentBounds(resultStart, segmentStart, segmentEnd);
+                
+                RealTime chunkStart = resultStart;
+                if (chunkStart < segmentStart) chunkStart = segmentStart;
+
+                RealTime chunkEnd = resultEnd;
+                if (chunkEnd > segmentEnd) chunkEnd = segmentEnd;
+                
+                m_segmentedAccumulators[output][segmentStart].bins = source.bins;
+
+                Result chunk;
+                chunk.time = chunkStart;
+                chunk.duration = chunkEnd - chunkStart;
+                chunk.values = source.results[n].values;
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
+                std::cerr << "chunk for segment " << segmentStart << ": from " << chunk.time << ", duration " << chunk.duration << std::endl;
+#endif
+
+                m_segmentedAccumulators[output][segmentStart].results
+                    .push_back(chunk);
+
+                resultStart = chunkEnd;
+            }
+        }
+    }
+}
+
+struct ValueDurationFloatPair
+{
+    float value;
+    float duration;
+
+    ValueDurationFloatPair() : value(0), duration(0) { }
+    ValueDurationFloatPair(float v, float d) : value(v), duration(d) { }
+    ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) {
+        value = p.value;
+        duration = p.duration;
+        return *this;
+    }
+    bool operator<(const ValueDurationFloatPair &p) const {
+        return value < p.value;
+    }
+};
+
+static double toSec(const RealTime &r)
+{
+    return r.sec + double(r.nsec) / 1000000000.0;
+}
+
+void
+PluginSummarisingAdapter::Impl::reduce()
+{
+    for (OutputSegmentAccumulatorMap::iterator i =
+             m_segmentedAccumulators.begin();
+         i != m_segmentedAccumulators.end(); ++i) {
+
+        int output = i->first;
+        SegmentAccumulatorMap &segments = i->second;
+
+        for (SegmentAccumulatorMap::iterator j = segments.begin();
+             j != segments.end(); ++j) {
+
+            RealTime segmentStart = j->first;
+            OutputAccumulator &accumulator = j->second;
+
+            int sz = accumulator.results.size();
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+            std::cerr << "reduce: segment starting at " << segmentStart
+                      << " on output " << output << " has " << sz << " result(s)" << std::endl;
+#endif
+
+            double totalDuration = 0.0;
+            //!!! is this right?
+            if (sz > 0) {
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+                std::cerr << "last time = " << accumulator.results[sz-1].time 
+                          << ", duration = " << accumulator.results[sz-1].duration
+                          << " (step = " << m_stepSize << ", block = " << m_blockSize << ")"
+                          << std::endl;
+#endif
+                totalDuration = toSec((accumulator.results[sz-1].time +
+                                       accumulator.results[sz-1].duration) -
+                                      segmentStart);
+            }
+
+            for (int bin = 0; bin < accumulator.bins; ++bin) {
+
+                // work on all values over time for a single bin
+
+                OutputBinSummary summary;
+
+                summary.count = sz;
+
+                summary.minimum = 0.f;
+                summary.maximum = 0.f;
+
+                summary.median = 0.f;
+                summary.mode = 0.f;
+                summary.sum = 0.f;
+                summary.variance = 0.f;
+
+                summary.median_c = 0.f;
+                summary.mode_c = 0.f;
+                summary.mean_c = 0.f;
+                summary.variance_c = 0.f;
+
+                if (sz == 0) continue;
+
+                std::vector<ValueDurationFloatPair> valvec;
+
+                for (int k = 0; k < sz; ++k) {
+                    while (accumulator.results[k].values.size() <
+                           accumulator.bins) {
+                        accumulator.results[k].values.push_back(0.f);
+                    }
+                }
+
+                for (int k = 0; k < sz; ++k) {
+                    float value = accumulator.results[k].values[bin];
+                    valvec.push_back(ValueDurationFloatPair
+                                     (value,
+                                      toSec(accumulator.results[k].duration)));
+                }
+
+                std::sort(valvec.begin(), valvec.end());
+
+                summary.minimum = valvec[0].value;
+                summary.maximum = valvec[sz-1].value;
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+                std::cerr << "total duration = " << totalDuration << std::endl;
+#endif
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+/*
+                std::cerr << "value vector for medians:" << std::endl;
+                for (int k = 0; k < sz; ++k) {
+                    std::cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") ";
+                }
+                std::cerr << std::endl;
+*/
+#endif
+
+                if (sz % 2 == 1) {
+                    summary.median = valvec[sz/2].value;
+                } else {
+                    summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2;
+                }
+            
+                double duracc = 0.0;
+                summary.median_c = valvec[sz-1].value;
+
+                for (int k = 0; k < sz; ++k) {
+                    duracc += valvec[k].duration;
+                    if (duracc > totalDuration/2) {
+                        summary.median_c = valvec[k].value;
+                        break;
+                    }
+                }
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+                std::cerr << "median_c = " << summary.median_c << std::endl;
+                std::cerr << "median = " << summary.median << std::endl;
+#endif
+                
+                std::map<float, int> distribution;
+
+                for (int k = 0; k < sz; ++k) {
+                    summary.sum += accumulator.results[k].values[bin];
+                    distribution[accumulator.results[k].values[bin]] += 1;
+                }
+
+                int md = 0;
+
+                for (std::map<float, int>::iterator di = distribution.begin();
+                     di != distribution.end(); ++di) {
+                    if (di->second > md) {
+                        md = di->second;
+                        summary.mode = di->first;
+                    }
+                }
+
+                distribution.clear();
+
+                std::map<float, double> distribution_c;
+
+                for (int k = 0; k < sz; ++k) {
+                    distribution_c[accumulator.results[k].values[bin]]
+                        += toSec(accumulator.results[k].duration);
+                }
+
+                double mrd = 0.0;
+
+                for (std::map<float, double>::iterator di = distribution_c.begin();
+                     di != distribution_c.end(); ++di) {
+                    if (di->second > mrd) {
+                        mrd = di->second;
+                        summary.mode_c = di->first;
+                    }
+                }
+
+                distribution_c.clear();
+
+                if (totalDuration > 0.0) {
+
+                    double sum_c = 0.0;
+
+                    for (int k = 0; k < sz; ++k) {
+                        double value = accumulator.results[k].values[bin]
+                            * toSec(accumulator.results[k].duration);
+                        sum_c += value;
+                    }
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+                    std::cerr << "mean_c = " << sum_c << " / " << totalDuration << " = "
+                              << sum_c / totalDuration << " (sz = " << sz << ")" << std::endl;
+#endif
+                
+                    summary.mean_c = sum_c / totalDuration;
+
+                    for (int k = 0; k < sz; ++k) {
+                        double value = accumulator.results[k].values[bin];
+//                            * toSec(accumulator.results[k].duration);
+                        summary.variance_c +=
+                            (value - summary.mean_c) * (value - summary.mean_c)
+                            * toSec(accumulator.results[k].duration);
+                    }
+
+//                    summary.variance_c /= summary.count;
+                    summary.variance_c /= totalDuration;
+                }
+
+                double mean = summary.sum / summary.count;
+
+#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
+                std::cerr << "mean = " << summary.sum << " / " << summary.count << " = "
+                          << summary.sum / summary.count << std::endl;
+#endif
+
+                for (int k = 0; k < sz; ++k) {
+                    float value = accumulator.results[k].values[bin];
+                    summary.variance += (value - mean) * (value - mean);
+                }
+                summary.variance /= summary.count;
+
+                m_summaries[output][segmentStart][bin] = summary;
+            }
+        }
+    }
+
+    m_segmentedAccumulators.clear();
+    m_accumulators.clear();
+}
+
+
+}
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vamp-hostsdk/hostext/PluginWrapper.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,201 @@
+/* -*- 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-2007 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.
+*/
+
+#include "PluginWrapper.h"
+
+namespace Vamp {
+
+namespace HostExt {
+
+class PluginRateExtractor : public Plugin
+{
+public:
+    PluginRateExtractor() : Plugin(0) { }
+    float getRate() const { return m_inputSampleRate; }
+};
+
+PluginWrapper::PluginWrapper(Plugin *plugin) :
+    Plugin(((PluginRateExtractor *)plugin)->getRate()),
+    m_plugin(plugin)
+{
+}
+
+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/src/vamp-sdk/PluginAdapter.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,873 @@
+/* -*- 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 "PluginAdapter.h"
+
+#include <cstring>
+#include <cstdlib>
+
+//#define DEBUG_PLUGIN_ADAPTER 1
+
+namespace Vamp {
+
+class PluginAdapterBase::Impl
+{
+public:
+    Impl(PluginAdapterBase *);
+    ~Impl();
+
+    const VampPluginDescriptor *getDescriptor();
+
+protected:
+    PluginAdapterBase *m_base;
+
+    static VampPluginHandle vampInstantiate(const VampPluginDescriptor *desc,
+                                            float inputSampleRate);
+
+    static void vampCleanup(VampPluginHandle handle);
+
+    static int vampInitialise(VampPluginHandle handle, unsigned int channels,
+                             unsigned int stepSize, unsigned int blockSize);
+
+    static void vampReset(VampPluginHandle handle);
+
+    static float vampGetParameter(VampPluginHandle handle, int param);
+    static void vampSetParameter(VampPluginHandle handle, int param, float value);
+
+    static unsigned int vampGetCurrentProgram(VampPluginHandle handle);
+    static void vampSelectProgram(VampPluginHandle handle, unsigned int program);
+
+    static unsigned int vampGetPreferredStepSize(VampPluginHandle handle);
+    static unsigned int vampGetPreferredBlockSize(VampPluginHandle handle);
+    static unsigned int vampGetMinChannelCount(VampPluginHandle handle);
+    static unsigned int vampGetMaxChannelCount(VampPluginHandle handle);
+
+    static unsigned int vampGetOutputCount(VampPluginHandle handle);
+
+    static VampOutputDescriptor *vampGetOutputDescriptor(VampPluginHandle handle,
+                                                       unsigned int i);
+
+    static void vampReleaseOutputDescriptor(VampOutputDescriptor *desc);
+
+    static VampFeatureList *vampProcess(VampPluginHandle handle,
+                                        const float *const *inputBuffers,
+                                        int sec,
+                                        int nsec);
+
+    static VampFeatureList *vampGetRemainingFeatures(VampPluginHandle handle);
+
+    static void vampReleaseFeatureSet(VampFeatureList *fs);
+
+    void cleanup(Plugin *plugin);
+    void checkOutputMap(Plugin *plugin);
+    unsigned int getOutputCount(Plugin *plugin);
+    VampOutputDescriptor *getOutputDescriptor(Plugin *plugin,
+                                             unsigned int i);
+    VampFeatureList *process(Plugin *plugin,
+                             const float *const *inputBuffers,
+                             int sec, int nsec);
+    VampFeatureList *getRemainingFeatures(Plugin *plugin);
+    VampFeatureList *convertFeatures(Plugin *plugin,
+                                     const Plugin::FeatureSet &features);
+    
+    // maps both plugins and descriptors to adapters
+    typedef std::map<const void *, Impl *> AdapterMap;
+    static AdapterMap *m_adapterMap;
+    static Impl *lookupAdapter(VampPluginHandle);
+
+    bool m_populated;
+    VampPluginDescriptor m_descriptor;
+    Plugin::ParameterList m_parameters;
+    Plugin::ProgramList m_programs;
+    
+    typedef std::map<Plugin *, Plugin::OutputList *> OutputMap;
+    OutputMap m_pluginOutputs;
+
+    std::map<Plugin *, VampFeatureList *> m_fs;
+    std::map<Plugin *, std::vector<size_t> > m_fsizes;
+    std::map<Plugin *, std::vector<std::vector<size_t> > > m_fvsizes;
+    void resizeFS(Plugin *plugin, int n);
+    void resizeFL(Plugin *plugin, int n, size_t sz);
+    void resizeFV(Plugin *plugin, int n, int j, size_t sz);
+};
+
+PluginAdapterBase::PluginAdapterBase()
+{
+    m_impl = new Impl(this);
+}
+
+PluginAdapterBase::~PluginAdapterBase()
+{
+    delete m_impl;
+}
+
+const VampPluginDescriptor *
+PluginAdapterBase::getDescriptor()
+{
+    return m_impl->getDescriptor();
+}
+
+PluginAdapterBase::Impl::Impl(PluginAdapterBase *base) :
+    m_base(base),
+    m_populated(false)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl[" << this << "]::Impl" << std::endl;
+#endif
+}
+
+const VampPluginDescriptor *
+PluginAdapterBase::Impl::getDescriptor()
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl[" << this << "]::getDescriptor" << std::endl;
+#endif
+
+    if (m_populated) return &m_descriptor;
+
+    Plugin *plugin = m_base->createPlugin(48000);
+
+    if (plugin->getVampApiVersion() != VAMP_API_VERSION) {
+        std::cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: "
+                  << "API version " << plugin->getVampApiVersion()
+                  << " for\nplugin \"" << plugin->getIdentifier() << "\" "
+                  << "differs from version "
+                  << VAMP_API_VERSION << " for adapter.\n"
+                  << "This plugin is probably linked against a different version of the Vamp SDK\n"
+                  << "from the version it was compiled with.  It will need to be re-linked correctly\n"
+                  << "before it can be used." << std::endl;
+        delete plugin;
+        return 0;
+    }
+
+    m_parameters = plugin->getParameterDescriptors();
+    m_programs = plugin->getPrograms();
+
+    m_descriptor.vampApiVersion = plugin->getVampApiVersion();
+    m_descriptor.identifier = strdup(plugin->getIdentifier().c_str());
+    m_descriptor.name = strdup(plugin->getName().c_str());
+    m_descriptor.description = strdup(plugin->getDescription().c_str());
+    m_descriptor.maker = strdup(plugin->getMaker().c_str());
+    m_descriptor.pluginVersion = plugin->getPluginVersion();
+    m_descriptor.copyright = strdup(plugin->getCopyright().c_str());
+    
+    m_descriptor.parameterCount = m_parameters.size();
+    m_descriptor.parameters = (const VampParameterDescriptor **)
+        malloc(m_parameters.size() * sizeof(VampParameterDescriptor));
+
+    unsigned int i;
+    
+    for (i = 0; i < m_parameters.size(); ++i) {
+        VampParameterDescriptor *desc = (VampParameterDescriptor *)
+            malloc(sizeof(VampParameterDescriptor));
+        desc->identifier = strdup(m_parameters[i].identifier.c_str());
+        desc->name = strdup(m_parameters[i].name.c_str());
+        desc->description = strdup(m_parameters[i].description.c_str());
+        desc->unit = strdup(m_parameters[i].unit.c_str());
+        desc->minValue = m_parameters[i].minValue;
+        desc->maxValue = m_parameters[i].maxValue;
+        desc->defaultValue = m_parameters[i].defaultValue;
+        desc->isQuantized = m_parameters[i].isQuantized;
+        desc->quantizeStep = m_parameters[i].quantizeStep;
+        desc->valueNames = 0;
+        if (desc->isQuantized && !m_parameters[i].valueNames.empty()) {
+            desc->valueNames = (const char **)
+                malloc((m_parameters[i].valueNames.size()+1) * sizeof(char *));
+            for (unsigned int j = 0; j < m_parameters[i].valueNames.size(); ++j) {
+                desc->valueNames[j] = strdup(m_parameters[i].valueNames[j].c_str());
+            }
+            desc->valueNames[m_parameters[i].valueNames.size()] = 0;
+        }
+        m_descriptor.parameters[i] = desc;
+    }
+    
+    m_descriptor.programCount = m_programs.size();
+    m_descriptor.programs = (const char **)
+        malloc(m_programs.size() * sizeof(const char *));
+    
+    for (i = 0; i < m_programs.size(); ++i) {
+        m_descriptor.programs[i] = strdup(m_programs[i].c_str());
+    }
+    
+    if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
+        m_descriptor.inputDomain = vampFrequencyDomain;
+    } else {
+        m_descriptor.inputDomain = vampTimeDomain;
+    }
+
+    m_descriptor.instantiate = vampInstantiate;
+    m_descriptor.cleanup = vampCleanup;
+    m_descriptor.initialise = vampInitialise;
+    m_descriptor.reset = vampReset;
+    m_descriptor.getParameter = vampGetParameter;
+    m_descriptor.setParameter = vampSetParameter;
+    m_descriptor.getCurrentProgram = vampGetCurrentProgram;
+    m_descriptor.selectProgram = vampSelectProgram;
+    m_descriptor.getPreferredStepSize = vampGetPreferredStepSize;
+    m_descriptor.getPreferredBlockSize = vampGetPreferredBlockSize;
+    m_descriptor.getMinChannelCount = vampGetMinChannelCount;
+    m_descriptor.getMaxChannelCount = vampGetMaxChannelCount;
+    m_descriptor.getOutputCount = vampGetOutputCount;
+    m_descriptor.getOutputDescriptor = vampGetOutputDescriptor;
+    m_descriptor.releaseOutputDescriptor = vampReleaseOutputDescriptor;
+    m_descriptor.process = vampProcess;
+    m_descriptor.getRemainingFeatures = vampGetRemainingFeatures;
+    m_descriptor.releaseFeatureSet = vampReleaseFeatureSet;
+    
+    if (!m_adapterMap) {
+        m_adapterMap = new AdapterMap;
+    }
+    (*m_adapterMap)[&m_descriptor] = this;
+
+    delete plugin;
+
+    m_populated = true;
+    return &m_descriptor;
+}
+
+PluginAdapterBase::Impl::~Impl()
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl[" << this << "]::~Impl" << std::endl;
+#endif
+
+    if (!m_populated) return;
+
+    free((void *)m_descriptor.identifier);
+    free((void *)m_descriptor.name);
+    free((void *)m_descriptor.description);
+    free((void *)m_descriptor.maker);
+    free((void *)m_descriptor.copyright);
+        
+    for (unsigned int i = 0; i < m_descriptor.parameterCount; ++i) {
+        const VampParameterDescriptor *desc = m_descriptor.parameters[i];
+        free((void *)desc->identifier);
+        free((void *)desc->name);
+        free((void *)desc->description);
+        free((void *)desc->unit);
+        if (desc->valueNames) {
+            for (unsigned int j = 0; desc->valueNames[j]; ++j) {
+                free((void *)desc->valueNames[j]);
+            }
+            free((void *)desc->valueNames);
+        }
+    }
+    free((void *)m_descriptor.parameters);
+
+    for (unsigned int i = 0; i < m_descriptor.programCount; ++i) {
+        free((void *)m_descriptor.programs[i]);
+    }
+    free((void *)m_descriptor.programs);
+
+    if (m_adapterMap) {
+        
+        m_adapterMap->erase(&m_descriptor);
+
+        if (m_adapterMap->empty()) {
+            delete m_adapterMap;
+            m_adapterMap = 0;
+        }
+    }
+}
+
+PluginAdapterBase::Impl *
+PluginAdapterBase::Impl::lookupAdapter(VampPluginHandle handle)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::lookupAdapter(" << handle << ")" << std::endl;
+#endif
+
+    if (!m_adapterMap) return 0;
+    AdapterMap::const_iterator i = m_adapterMap->find(handle);
+    if (i == m_adapterMap->end()) return 0;
+    return i->second;
+}
+
+VampPluginHandle
+PluginAdapterBase::Impl::vampInstantiate(const VampPluginDescriptor *desc,
+                                   float inputSampleRate)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << ")" << std::endl;
+#endif
+
+    if (!m_adapterMap) {
+        m_adapterMap = new AdapterMap();
+    }
+
+    if (m_adapterMap->find(desc) == m_adapterMap->end()) {
+        std::cerr << "WARNING: PluginAdapterBase::Impl::vampInstantiate: Descriptor " << desc << " not in adapter map" << std::endl;
+        return 0;
+    }
+
+    Impl *adapter = (*m_adapterMap)[desc];
+    if (desc != &adapter->m_descriptor) return 0;
+
+    Plugin *plugin = adapter->m_base->createPlugin(inputSampleRate);
+    if (plugin) {
+        (*m_adapterMap)[plugin] = adapter;
+    }
+
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << "): returning handle " << plugin << std::endl;
+#endif
+
+    return plugin;
+}
+
+void
+PluginAdapterBase::Impl::vampCleanup(VampPluginHandle handle)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampCleanup(" << handle << ")" << std::endl;
+#endif
+
+    Impl *adapter = lookupAdapter(handle);
+    if (!adapter) {
+        delete ((Plugin *)handle);
+        return;
+    }
+    adapter->cleanup(((Plugin *)handle));
+}
+
+int
+PluginAdapterBase::Impl::vampInitialise(VampPluginHandle handle,
+                                  unsigned int channels,
+                                  unsigned int stepSize,
+                                  unsigned int blockSize)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << std::endl;
+#endif
+
+    bool result = ((Plugin *)handle)->initialise
+        (channels, stepSize, blockSize);
+    return result ? 1 : 0;
+}
+
+void
+PluginAdapterBase::Impl::vampReset(VampPluginHandle handle) 
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampReset(" << handle << ")" << std::endl;
+#endif
+
+    ((Plugin *)handle)->reset();
+}
+
+float
+PluginAdapterBase::Impl::vampGetParameter(VampPluginHandle handle,
+                                    int param) 
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampGetParameter(" << handle << ", " << param << ")" << std::endl;
+#endif
+
+    Impl *adapter = lookupAdapter(handle);
+    if (!adapter) return 0.0;
+    Plugin::ParameterList &list = adapter->m_parameters;
+    return ((Plugin *)handle)->getParameter(list[param].identifier);
+}
+
+void
+PluginAdapterBase::Impl::vampSetParameter(VampPluginHandle handle,
+                                    int param, float value)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << std::endl;
+#endif
+
+    Impl *adapter = lookupAdapter(handle);
+    if (!adapter) return;
+    Plugin::ParameterList &list = adapter->m_parameters;
+    ((Plugin *)handle)->setParameter(list[param].identifier, value);
+}
+
+unsigned int
+PluginAdapterBase::Impl::vampGetCurrentProgram(VampPluginHandle handle)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampGetCurrentProgram(" << handle << ")" << std::endl;
+#endif
+
+    Impl *adapter = lookupAdapter(handle);
+    if (!adapter) return 0;
+    Plugin::ProgramList &list = adapter->m_programs;
+    std::string program = ((Plugin *)handle)->getCurrentProgram();
+    for (unsigned int i = 0; i < list.size(); ++i) {
+        if (list[i] == program) return i;
+    }
+    return 0;
+}
+
+void
+PluginAdapterBase::Impl::vampSelectProgram(VampPluginHandle handle,
+                                     unsigned int program)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << std::endl;
+#endif
+
+    Impl *adapter = lookupAdapter(handle);
+    if (!adapter) return;
+    Plugin::ProgramList &list = adapter->m_programs;
+    ((Plugin *)handle)->selectProgram(list[program]);
+}
+
+unsigned int
+PluginAdapterBase::Impl::vampGetPreferredStepSize(VampPluginHandle handle)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampGetPreferredStepSize(" << handle << ")" << std::endl;
+#endif
+
+    return ((Plugin *)handle)->getPreferredStepSize();
+}
+
+unsigned int
+PluginAdapterBase::Impl::vampGetPreferredBlockSize(VampPluginHandle handle) 
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampGetPreferredBlockSize(" << handle << ")" << std::endl;
+#endif
+
+    return ((Plugin *)handle)->getPreferredBlockSize();
+}
+
+unsigned int
+PluginAdapterBase::Impl::vampGetMinChannelCount(VampPluginHandle handle)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampGetMinChannelCount(" << handle << ")" << std::endl;
+#endif
+
+    return ((Plugin *)handle)->getMinChannelCount();
+}
+
+unsigned int
+PluginAdapterBase::Impl::vampGetMaxChannelCount(VampPluginHandle handle)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampGetMaxChannelCount(" << handle << ")" << std::endl;
+#endif
+
+    return ((Plugin *)handle)->getMaxChannelCount();
+}
+
+unsigned int
+PluginAdapterBase::Impl::vampGetOutputCount(VampPluginHandle handle)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampGetOutputCount(" << handle << ")" << std::endl;
+#endif
+
+    Impl *adapter = lookupAdapter(handle);
+
+//    std::cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << std::endl;
+
+    if (!adapter) return 0;
+    return adapter->getOutputCount((Plugin *)handle);
+}
+
+VampOutputDescriptor *
+PluginAdapterBase::Impl::vampGetOutputDescriptor(VampPluginHandle handle,
+                                           unsigned int i)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampGetOutputDescriptor(" << handle << ", " << i << ")" << std::endl;
+#endif
+
+    Impl *adapter = lookupAdapter(handle);
+
+//    std::cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << std::endl;
+
+    if (!adapter) return 0;
+    return adapter->getOutputDescriptor((Plugin *)handle, i);
+}
+
+void
+PluginAdapterBase::Impl::vampReleaseOutputDescriptor(VampOutputDescriptor *desc)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampReleaseOutputDescriptor(" << desc << ")" << std::endl;
+#endif
+
+    if (desc->identifier) free((void *)desc->identifier);
+    if (desc->name) free((void *)desc->name);
+    if (desc->description) free((void *)desc->description);
+    if (desc->unit) free((void *)desc->unit);
+    if (desc->hasFixedBinCount && desc->binNames) {
+        for (unsigned int i = 0; i < desc->binCount; ++i) {
+            if (desc->binNames[i]) {
+                free((void *)desc->binNames[i]);
+            }
+        }
+    }
+    if (desc->binNames) free((void *)desc->binNames);
+    free((void *)desc);
+}
+
+VampFeatureList *
+PluginAdapterBase::Impl::vampProcess(VampPluginHandle handle,
+                                     const float *const *inputBuffers,
+                                     int sec,
+                                     int nsec)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << std::endl;
+#endif
+
+    Impl *adapter = lookupAdapter(handle);
+    if (!adapter) return 0;
+    return adapter->process((Plugin *)handle,
+                            inputBuffers, sec, nsec);
+}
+
+VampFeatureList *
+PluginAdapterBase::Impl::vampGetRemainingFeatures(VampPluginHandle handle)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampGetRemainingFeatures(" << handle << ")" << std::endl;
+#endif
+
+    Impl *adapter = lookupAdapter(handle);
+    if (!adapter) return 0;
+    return adapter->getRemainingFeatures((Plugin *)handle);
+}
+
+void
+PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *fs)
+{
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << std::endl;
+#endif
+}
+
+void 
+PluginAdapterBase::Impl::cleanup(Plugin *plugin)
+{
+    if (m_fs.find(plugin) != m_fs.end()) {
+        size_t outputCount = 0;
+        if (m_pluginOutputs[plugin]) {
+            outputCount = m_pluginOutputs[plugin]->size();
+        }
+        VampFeatureList *list = m_fs[plugin];
+        for (unsigned int i = 0; i < outputCount; ++i) {
+            for (unsigned int j = 0; j < m_fsizes[plugin][i]; ++j) {
+                if (list[i].features[j].v1.label) {
+                    free(list[i].features[j].v1.label);
+                }
+                if (list[i].features[j].v1.values) {
+                    free(list[i].features[j].v1.values);
+                }
+            }
+            if (list[i].features) free(list[i].features);
+        }
+        m_fs.erase(plugin);
+        m_fsizes.erase(plugin);
+        m_fvsizes.erase(plugin);
+    }
+
+    if (m_pluginOutputs.find(plugin) != m_pluginOutputs.end()) {
+        delete m_pluginOutputs[plugin];
+        m_pluginOutputs.erase(plugin);
+    }
+
+    if (m_adapterMap) {
+        m_adapterMap->erase(plugin);
+
+        if (m_adapterMap->empty()) {
+            delete m_adapterMap;
+            m_adapterMap = 0;
+        }
+    }
+
+    delete ((Plugin *)plugin);
+}
+
+void 
+PluginAdapterBase::Impl::checkOutputMap(Plugin *plugin)
+{
+    if (m_pluginOutputs.find(plugin) == m_pluginOutputs.end() ||
+        !m_pluginOutputs[plugin]) {
+        m_pluginOutputs[plugin] = new Plugin::OutputList
+            (plugin->getOutputDescriptors());
+//        std::cerr << "PluginAdapterBase::Impl::checkOutputMap: Have " << m_pluginOutputs[plugin]->size() << " outputs for plugin " << plugin->getIdentifier() << std::endl;
+    }
+}
+
+unsigned int 
+PluginAdapterBase::Impl::getOutputCount(Plugin *plugin)
+{
+    checkOutputMap(plugin);
+    return m_pluginOutputs[plugin]->size();
+}
+
+VampOutputDescriptor *
+PluginAdapterBase::Impl::getOutputDescriptor(Plugin *plugin,
+                                       unsigned int i)
+{
+    checkOutputMap(plugin);
+    Plugin::OutputDescriptor &od =
+        (*m_pluginOutputs[plugin])[i];
+
+    VampOutputDescriptor *desc = (VampOutputDescriptor *)
+        malloc(sizeof(VampOutputDescriptor));
+
+    desc->identifier = strdup(od.identifier.c_str());
+    desc->name = strdup(od.name.c_str());
+    desc->description = strdup(od.description.c_str());
+    desc->unit = strdup(od.unit.c_str());
+    desc->hasFixedBinCount = od.hasFixedBinCount;
+    desc->binCount = od.binCount;
+
+    if (od.hasFixedBinCount && od.binCount > 0) {
+        desc->binNames = (const char **)
+            malloc(od.binCount * sizeof(const char *));
+        
+        for (unsigned int i = 0; i < od.binCount; ++i) {
+            if (i < od.binNames.size()) {
+                desc->binNames[i] = strdup(od.binNames[i].c_str());
+            } else {
+                desc->binNames[i] = 0;
+            }
+        }
+    } else {
+        desc->binNames = 0;
+    }
+
+    desc->hasKnownExtents = od.hasKnownExtents;
+    desc->minValue = od.minValue;
+    desc->maxValue = od.maxValue;
+    desc->isQuantized = od.isQuantized;
+    desc->quantizeStep = od.quantizeStep;
+
+    switch (od.sampleType) {
+    case Plugin::OutputDescriptor::OneSamplePerStep:
+        desc->sampleType = vampOneSamplePerStep; break;
+    case Plugin::OutputDescriptor::FixedSampleRate:
+        desc->sampleType = vampFixedSampleRate; break;
+    case Plugin::OutputDescriptor::VariableSampleRate:
+        desc->sampleType = vampVariableSampleRate; break;
+    }
+
+    desc->sampleRate = od.sampleRate;
+    desc->hasDuration = od.hasDuration;
+
+    return desc;
+}
+    
+VampFeatureList *
+PluginAdapterBase::Impl::process(Plugin *plugin,
+                                 const float *const *inputBuffers,
+                                 int sec, int nsec)
+{
+//    std::cerr << "PluginAdapterBase::Impl::process" << std::endl;
+    RealTime rt(sec, nsec);
+    checkOutputMap(plugin);
+    return convertFeatures(plugin, plugin->process(inputBuffers, rt));
+}
+    
+VampFeatureList *
+PluginAdapterBase::Impl::getRemainingFeatures(Plugin *plugin)
+{
+//    std::cerr << "PluginAdapterBase::Impl::getRemainingFeatures" << std::endl;
+    checkOutputMap(plugin);
+    return convertFeatures(plugin, plugin->getRemainingFeatures());
+}
+
+VampFeatureList *
+PluginAdapterBase::Impl::convertFeatures(Plugin *plugin,
+                                         const Plugin::FeatureSet &features)
+{
+    int lastN = -1;
+
+    int outputCount = 0;
+    if (m_pluginOutputs[plugin]) outputCount = m_pluginOutputs[plugin]->size();
+    
+    resizeFS(plugin, outputCount);
+    VampFeatureList *fs = m_fs[plugin];
+
+//    std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: sizeof(Feature) == " << sizeof(Plugin::Feature) << ", sizeof(VampFeature) == " << sizeof(VampFeature) << ", sizeof(VampFeatureList) == " << sizeof(VampFeatureList) << std::endl;
+
+    for (Plugin::FeatureSet::const_iterator fi = features.begin();
+         fi != features.end(); ++fi) {
+
+        int n = fi->first;
+        
+//        std::cerr << "PluginAdapterBase::Impl::convertFeatures: n = " << n << std::endl;
+
+        if (n >= int(outputCount)) {
+            std::cerr << "WARNING: PluginAdapterBase::Impl::convertFeatures: Too many outputs from plugin (" << n+1 << ", only should be " << outputCount << ")" << std::endl;
+            continue;
+        }
+
+        if (n > lastN + 1) {
+            for (int i = lastN + 1; i < n; ++i) {
+                fs[i].featureCount = 0;
+            }
+        }
+
+        const Plugin::FeatureList &fl = fi->second;
+
+        size_t sz = fl.size();
+        if (sz > m_fsizes[plugin][n]) resizeFL(plugin, n, sz);
+        fs[n].featureCount = sz;
+        
+        for (size_t j = 0; j < sz; ++j) {
+
+//            std::cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << std::endl;
+
+            VampFeature *feature = &fs[n].features[j].v1;
+
+            feature->hasTimestamp = fl[j].hasTimestamp;
+            feature->sec = fl[j].timestamp.sec;
+            feature->nsec = fl[j].timestamp.nsec;
+            feature->valueCount = fl[j].values.size();
+
+            VampFeatureV2 *v2 = &fs[n].features[j + sz].v2;
+            
+            v2->hasDuration = fl[j].hasDuration;
+            v2->durationSec = fl[j].duration.sec;
+            v2->durationNsec = fl[j].duration.nsec;
+
+            if (feature->label) free(feature->label);
+
+            if (fl[j].label.empty()) {
+                feature->label = 0;
+            } else {
+                feature->label = strdup(fl[j].label.c_str());
+            }
+
+            if (feature->valueCount > m_fvsizes[plugin][n][j]) {
+                resizeFV(plugin, n, j, feature->valueCount);
+            }
+
+            for (unsigned int k = 0; k < feature->valueCount; ++k) {
+//                std::cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << std::endl;
+                feature->values[k] = fl[j].values[k];
+            }
+        }
+
+        lastN = n;
+    }
+
+    if (lastN == -1) return 0;
+
+    if (int(outputCount) > lastN + 1) {
+        for (int i = lastN + 1; i < int(outputCount); ++i) {
+            fs[i].featureCount = 0;
+        }
+    }
+
+//    std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: have " << outputCount << " outputs" << std::endl;
+//    for (int i = 0; i < outputCount; ++i) {
+//        std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: output " << i << " has " << fs[i].featureCount << " features" << std::endl;
+//    }
+
+
+    return fs;
+}
+
+void
+PluginAdapterBase::Impl::resizeFS(Plugin *plugin, int n)
+{
+//    std::cerr << "PluginAdapterBase::Impl::resizeFS(" << plugin << ", " << n << ")" << std::endl;
+
+    int i = m_fsizes[plugin].size();
+    if (i >= n) return;
+
+//    std::cerr << "resizing from " << i << std::endl;
+
+    m_fs[plugin] = (VampFeatureList *)realloc
+        (m_fs[plugin], n * sizeof(VampFeatureList));
+
+    while (i < n) {
+        m_fs[plugin][i].featureCount = 0;
+        m_fs[plugin][i].features = 0;
+        m_fsizes[plugin].push_back(0);
+        m_fvsizes[plugin].push_back(std::vector<size_t>());
+        i++;
+    }
+}
+
+void
+PluginAdapterBase::Impl::resizeFL(Plugin *plugin, int n, size_t sz)
+{
+//    std::cerr << "PluginAdapterBase::Impl::resizeFL(" << plugin << ", " << n << ", "
+//              << sz << ")" << std::endl;
+
+    size_t i = m_fsizes[plugin][n];
+    if (i >= sz) return;
+
+//    std::cerr << "resizing from " << i << std::endl;
+
+    m_fs[plugin][n].features = (VampFeatureUnion *)realloc
+        (m_fs[plugin][n].features, 2 * sz * sizeof(VampFeatureUnion));
+
+    while (m_fsizes[plugin][n] < sz) {
+        m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.hasTimestamp = 0;
+        m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.valueCount = 0;
+        m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.values = 0;
+        m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.label = 0;
+        m_fs[plugin][n].features[m_fsizes[plugin][n] + sz].v2.hasDuration = 0;
+        m_fvsizes[plugin][n].push_back(0);
+        m_fsizes[plugin][n]++;
+    }
+}
+
+void
+PluginAdapterBase::Impl::resizeFV(Plugin *plugin, int n, int j, size_t sz)
+{
+//    std::cerr << "PluginAdapterBase::Impl::resizeFV(" << plugin << ", " << n << ", "
+//              << j << ", " << sz << ")" << std::endl;
+
+    size_t i = m_fvsizes[plugin][n][j];
+    if (i >= sz) return;
+
+//    std::cerr << "resizing from " << i << std::endl;
+
+    m_fs[plugin][n].features[j].v1.values = (float *)realloc
+        (m_fs[plugin][n].features[j].v1.values, sz * sizeof(float));
+
+    m_fvsizes[plugin][n][j] = sz;
+}
+  
+PluginAdapterBase::Impl::AdapterMap *
+PluginAdapterBase::Impl::m_adapterMap = 0;
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vamp-sdk/RealTime.cpp	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,245 @@
+/* -*- 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.
+*/
+
+/*
+   This is a modified version of a source file from the 
+   Rosegarden MIDI and audio sequencer and notation editor.
+   This file copyright 2000-2006 Chris Cannam.
+   Relicensed by the author as detailed above.
+*/
+
+#include <iostream>
+
+#if (__GNUC__ < 3)
+#include <strstream>
+#define stringstream strstream
+#else
+#include <sstream>
+#endif
+
+using std::cerr;
+using std::endl;
+
+#include "RealTime.h"
+
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+
+namespace Vamp {
+
+// A RealTime consists of two ints that must be at least 32 bits each.
+// A signed 32-bit int can store values exceeding +/- 2 billion.  This
+// means we can safely use our lower int for nanoseconds, as there are
+// 1 billion nanoseconds in a second and we need to handle double that
+// because of the implementations of addition etc that we use.
+//
+// The maximum valid RealTime on a 32-bit system is somewhere around
+// 68 years: 999999999 nanoseconds longer than the classic Unix epoch.
+
+#define ONE_BILLION 1000000000
+
+RealTime::RealTime(int s, int n) :
+    sec(s), nsec(n)
+{
+    if (sec == 0) {
+	while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
+	while (nsec >=  ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
+    } else if (sec < 0) {
+	while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
+	while (nsec > 0)             { nsec -= ONE_BILLION; ++sec; }
+    } else { 
+	while (nsec >=  ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
+	while (nsec < 0)             { nsec += ONE_BILLION; --sec; }
+    }
+}
+
+RealTime
+RealTime::fromSeconds(double sec)
+{
+    return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5));
+}
+
+RealTime
+RealTime::fromMilliseconds(int msec)
+{
+    return RealTime(msec / 1000, (msec % 1000) * 1000000);
+}
+
+#ifndef _WIN32
+RealTime
+RealTime::fromTimeval(const struct timeval &tv)
+{
+    return RealTime(tv.tv_sec, tv.tv_usec * 1000);
+}
+#endif
+
+std::ostream &operator<<(std::ostream &out, const RealTime &rt)
+{
+    if (rt < RealTime::zeroTime) {
+	out << "-";
+    } else {
+	out << " ";
+    }
+
+    int s = (rt.sec < 0 ? -rt.sec : rt.sec);
+    int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec);
+
+    out << s << ".";
+
+    int nn(n);
+    if (nn == 0) out << "00000000";
+    else while (nn < (ONE_BILLION / 10)) {
+	out << "0";
+	nn *= 10;
+    }
+    
+    out << n << "R";
+    return out;
+}
+
+std::string
+RealTime::toString() const
+{
+    std::stringstream out;
+    out << *this;
+    
+#if (__GNUC__ < 3)
+    out << std::ends;
+#endif
+
+    std::string s = out.str();
+
+    // remove trailing R
+    return s.substr(0, s.length() - 1);
+}
+
+std::string
+RealTime::toText(bool fixedDp) const
+{
+    if (*this < RealTime::zeroTime) return "-" + (-*this).toText();
+
+    std::stringstream out;
+
+    if (sec >= 3600) {
+	out << (sec / 3600) << ":";
+    }
+
+    if (sec >= 60) {
+	out << (sec % 3600) / 60 << ":";
+    }
+
+    if (sec >= 10) {
+	out << ((sec % 60) / 10);
+    }
+
+    out << (sec % 10);
+    
+    int ms = msec();
+
+    if (ms != 0) {
+	out << ".";
+	out << (ms / 100);
+	ms = ms % 100;
+	if (ms != 0) {
+	    out << (ms / 10);
+	    ms = ms % 10;
+	} else if (fixedDp) {
+	    out << "0";
+	}
+	if (ms != 0) {
+	    out << ms;
+	} else if (fixedDp) {
+	    out << "0";
+	}
+    } else if (fixedDp) {
+	out << ".000";
+    }
+	
+#if (__GNUC__ < 3)
+    out << std::ends;
+#endif
+
+    std::string s = out.str();
+
+    return s;
+}
+
+
+RealTime
+RealTime::operator/(int d) const
+{
+    int secdiv = sec / d;
+    int secrem = sec % d;
+
+    double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d;
+    
+    return RealTime(secdiv, int(nsecdiv + 0.5));
+}
+
+double 
+RealTime::operator/(const RealTime &r) const
+{
+    double lTotal = double(sec) * ONE_BILLION + double(nsec);
+    double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec);
+    
+    if (rTotal == 0) return 0.0;
+    else return lTotal/rTotal;
+}
+
+long
+RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate)
+{
+    if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
+    double s = time.sec + double(time.nsec + 1) / 1000000000.0;
+    return long(s * sampleRate);
+}
+
+RealTime
+RealTime::frame2RealTime(long frame, unsigned int sampleRate)
+{
+    if (frame < 0) return -frame2RealTime(-frame, sampleRate);
+
+    RealTime rt;
+    rt.sec = frame / long(sampleRate);
+    frame -= rt.sec * long(sampleRate);
+    rt.nsec = (int)(((double(frame) * 1000000.0) / sampleRate) * 1000.0);
+    return rt;
+}
+
+const RealTime RealTime::zeroTime(0,0);
+
+}
--- a/src/vamp-simple-host.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,644 +0,0 @@
-/* -*- 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.
-    FFT code from Don Cross's public domain FFT implementation.
-  
-    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 "vamp-sdk/PluginHostAdapter.h"
-#include "vamp-sdk/hostext/PluginInputDomainAdapter.h"
-#include "vamp-sdk/hostext/PluginLoader.h"
-#include "vamp/vamp.h"
-
-#include <iostream>
-#include <fstream>
-#include <set>
-#include <sndfile.h>
-
-#include <cstring>
-#include <cstdlib>
-
-#include "system.h"
-
-#include <cmath>
-
-using namespace std;
-
-using Vamp::Plugin;
-using Vamp::PluginHostAdapter;
-using Vamp::RealTime;
-using Vamp::HostExt::PluginLoader;
-using Vamp::HostExt::PluginWrapper;
-using Vamp::HostExt::PluginInputDomainAdapter;
-
-#define HOST_VERSION "1.3"
-
-enum Verbosity {
-    PluginIds,
-    PluginOutputIds,
-    PluginInformation
-};
-
-void printFeatures(int, int, int, Plugin::FeatureSet, ofstream *, bool frames);
-void transformInput(float *, size_t);
-void fft(unsigned int, bool, double *, double *, double *, double *);
-void printPluginPath(bool verbose);
-void printPluginCategoryList();
-void enumeratePlugins(Verbosity);
-void listPluginsInLibrary(string soname);
-int runPlugin(string myname, string soname, string id, string output,
-              int outputNo, string inputFile, string outfilename, bool frames);
-
-void usage(const char *name)
-{
-    cerr << "\n"
-         << name << ": A simple Vamp plugin host.\n\n"
-        "Centre for Digital Music, Queen Mary, University of London.\n"
-        "Copyright 2006-2007 Chris Cannam and QMUL.\n"
-        "Freely redistributable; published under a BSD-style license.\n\n"
-        "Usage:\n\n"
-        "  " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o out.txt]\n"
-        "  " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno] [-o out.txt]\n\n"
-        "    -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n"
-        "       audio data in \"file.wav\", retrieving the named \"output\", or output\n"
-        "       number \"outputno\" (the first output by default) and dumping it to\n"
-        "       standard output, or to \"out.txt\" if the -o option is given.\n\n"
-        "       \"pluginlibrary\" should be a library name, not a file path; the\n"
-        "       standard Vamp library search path will be used to locate it.  If\n"
-        "       a file path is supplied, the directory part(s) will be ignored.\n\n"
-        "       If the -s option is given, results will be labelled with the audio\n"
-        "       sample frame at which they occur. Otherwise, they will be labelled\n"
-        "       with time in seconds.\n\n"
-        "  " << name << " -l\n\n"
-        "    -- List the plugin libraries and Vamp plugins in the library search path\n"
-        "       in a verbose human-readable format.\n\n"
-        "  " << name << " --list-ids\n\n"
-        "    -- List the plugins in the search path in a terse machine-readable format,\n"
-        "       in the form vamp:soname:identifier.\n\n"
-        "  " << name << " --list-outputs\n\n"
-        "    -- List the outputs for plugins in the search path in a machine-readable\n"
-        "       format, in the form vamp:soname:identifier:output.\n\n"
-        "  " << name << " --list-by-category\n\n"
-        "    -- List the plugins as a plugin index by category, in a machine-readable\n"
-        "       format.  The format may change in future releases.\n\n"
-        "  " << name << " -p\n\n"
-        "    -- Print out the Vamp library search path.\n\n"
-        "  " << name << " -v\n\n"
-        "    -- Display version information only.\n"
-         << endl;
-    exit(2);
-}
-
-int main(int argc, char **argv)
-{
-    char *scooter = argv[0];
-    char *name = 0;
-    while (scooter && *scooter) {
-        if (*scooter == '/' || *scooter == '\\') name = ++scooter;
-        else ++scooter;
-    }
-    if (!name || !*name) name = argv[0];
-    
-    if (argc < 2) usage(name);
-
-    if (argc == 2) {
-
-        if (!strcmp(argv[1], "-v")) {
-
-            cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl
-                 << "Vamp API version: " << VAMP_API_VERSION << endl
-                 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl;
-            return 0;
-
-        } else if (!strcmp(argv[1], "-l")) {
-
-            printPluginPath(true);
-            enumeratePlugins(PluginInformation);
-            return 0;
-
-        } else if (!strcmp(argv[1], "-p")) {
-
-            printPluginPath(false);
-            return 0;
-
-        } else if (!strcmp(argv[1], "--list-ids")) {
-
-            enumeratePlugins(PluginIds);
-            return 0;
-
-        } else if (!strcmp(argv[1], "--list-outputs")) {
-
-            enumeratePlugins(PluginOutputIds);
-            return 0;
-
-        } else if (!strcmp(argv[1], "--list-by-category")) {
-
-            printPluginCategoryList();
-            return 0;
-
-        } else usage(name);
-    }
-
-    if (argc < 3) usage(name);
-
-    bool useFrames = false;
-    
-    int base = 1;
-    if (!strcmp(argv[1], "-s")) {
-        useFrames = true;
-        base = 2;
-    }
-
-    string soname = argv[base];
-    string wavname = argv[base+1];
-    string plugid = "";
-    string output = "";
-    int outputNo = -1;
-    string outfilename;
-
-    if (argc >= base+3) {
-
-        int idx = base+2;
-
-        if (isdigit(*argv[idx])) {
-            outputNo = atoi(argv[idx++]);
-        }
-
-        if (argc == idx + 2) {
-            if (!strcmp(argv[idx], "-o")) {
-                outfilename = argv[idx+1];
-            } else usage(name);
-        } else if (argc != idx) {
-            (usage(name));
-        }
-    }
-
-    cerr << endl << name << ": Running..." << endl;
-
-    cerr << "Reading file: \"" << wavname << "\", writing to ";
-    if (outfilename == "") {
-        cerr << "standard output" << endl;
-    } else {
-        cerr << "\"" << outfilename << "\"" << endl;
-    }
-
-    string::size_type sep = soname.find(':');
-
-    if (sep != string::npos) {
-        plugid = soname.substr(sep + 1);
-        soname = soname.substr(0, sep);
-
-        sep = plugid.find(':');
-        if (sep != string::npos) {
-            output = plugid.substr(sep + 1);
-            plugid = plugid.substr(0, sep);
-        }
-    }
-
-    if (plugid == "") {
-        usage(name);
-    }
-
-    if (output != "" && outputNo != -1) {
-        usage(name);
-    }
-
-    if (output == "" && outputNo == -1) {
-        outputNo = 0;
-    }
-
-    return runPlugin(name, soname, plugid, output, outputNo,
-                     wavname, outfilename, useFrames);
-}
-
-
-int runPlugin(string myname, string soname, string id,
-              string output, int outputNo, string wavname,
-              string outfilename, bool useFrames)
-{
-    PluginLoader *loader = PluginLoader::getInstance();
-
-    PluginLoader::PluginKey key = loader->composePluginKey(soname, id);
-    
-    SNDFILE *sndfile;
-    SF_INFO sfinfo;
-    memset(&sfinfo, 0, sizeof(SF_INFO));
-
-    sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
-    if (!sndfile) {
-	cerr << myname << ": ERROR: Failed to open input file \""
-             << wavname << "\": " << sf_strerror(sndfile) << endl;
-	return 1;
-    }
-
-    ofstream *out = 0;
-    if (outfilename != "") {
-        out = new ofstream(outfilename.c_str(), ios::out);
-        if (!*out) {
-            cerr << myname << ": ERROR: Failed to open output file \""
-                 << outfilename << "\" for writing" << endl;
-            delete out;
-            return 1;
-        }
-    }
-
-    Plugin *plugin = loader->loadPlugin
-        (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE);
-    if (!plugin) {
-        cerr << myname << ": ERROR: Failed to load plugin \"" << id
-             << "\" from library \"" << soname << "\"" << endl;
-        sf_close(sndfile);
-        if (out) {
-            out->close();
-            delete out;
-        }
-        return 1;
-    }
-
-    cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
-
-    int blockSize = plugin->getPreferredBlockSize();
-    int stepSize = plugin->getPreferredStepSize();
-
-    if (blockSize == 0) {
-        blockSize = 1024;
-    }
-    if (stepSize == 0) {
-        if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
-            stepSize = blockSize/2;
-        } else {
-            stepSize = blockSize;
-        }
-    } else if (stepSize > blockSize) {
-        cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to ";
-        if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
-            blockSize = stepSize * 2;
-        } else {
-            blockSize = stepSize;
-        }
-        cerr << blockSize << endl;
-    }
-
-    int channels = sfinfo.channels;
-
-    float *filebuf = new float[blockSize * channels];
-    float **plugbuf = new float*[channels];
-    for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2];
-
-    cerr << "Using block size = " << blockSize << ", step size = "
-              << stepSize << endl;
-
-    int minch = plugin->getMinChannelCount();
-    int maxch = plugin->getMaxChannelCount();
-    cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
-    cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
-
-    Plugin::OutputList outputs = plugin->getOutputDescriptors();
-    Plugin::OutputDescriptor od;
-
-    int returnValue = 1;
-    int progress = 0;
-
-    RealTime rt;
-    PluginWrapper *wrapper = 0;
-    RealTime adjustment = RealTime::zeroTime;
-
-    if (outputs.empty()) {
-	cerr << "ERROR: Plugin has no outputs!" << endl;
-        goto done;
-    }
-
-    if (outputNo < 0) {
-
-        for (size_t oi = 0; oi < outputs.size(); ++oi) {
-            if (outputs[oi].identifier == output) {
-                outputNo = oi;
-                break;
-            }
-        }
-
-        if (outputNo < 0) {
-            cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
-            goto done;
-        }
-
-    } else {
-
-        if (int(outputs.size()) <= outputNo) {
-            cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
-            goto done;
-        }        
-    }
-
-    od = outputs[outputNo];
-    cerr << "Output is: \"" << od.identifier << "\"" << endl;
-
-    if (!plugin->initialise(channels, stepSize, blockSize)) {
-        cerr << "ERROR: Plugin initialise (channels = " << channels
-             << ", stepSize = " << stepSize << ", blockSize = "
-             << blockSize << ") failed." << endl;
-        goto done;
-    }
-
-    wrapper = dynamic_cast<PluginWrapper *>(plugin);
-    if (wrapper) {
-        PluginInputDomainAdapter *ida =
-            wrapper->getWrapper<PluginInputDomainAdapter>();
-        if (ida) adjustment = ida->getTimestampAdjustment();
-    }
-
-    for (size_t i = 0; i < sfinfo.frames; i += stepSize) {
-
-        int count;
-
-        if (sf_seek(sndfile, i, SEEK_SET) < 0) {
-            cerr << "ERROR: sf_seek failed: " << sf_strerror(sndfile) << endl;
-            break;
-        }
-        
-        if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
-            cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
-            break;
-        }
-
-        for (int c = 0; c < channels; ++c) {
-            int j = 0;
-            while (j < count) {
-                plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
-                ++j;
-            }
-            while (j < blockSize) {
-                plugbuf[c][j] = 0.0f;
-                ++j;
-            }
-        }
-
-        rt = RealTime::frame2RealTime(i, sfinfo.samplerate);
-
-        printFeatures
-            (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
-             sfinfo.samplerate, outputNo, plugin->process(plugbuf, rt),
-             out, useFrames);
-
-        int pp = progress;
-        progress = lrintf((float(i) / sfinfo.frames) * 100.f);
-        if (progress != pp && out) {
-            cerr << "\r" << progress << "%";
-        }
-    }
-    if (out) cerr << "\rDone" << endl;
-
-    rt = RealTime::frame2RealTime(sfinfo.frames, sfinfo.samplerate);
-
-    printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
-                  sfinfo.samplerate, outputNo,
-                  plugin->getRemainingFeatures(), out, useFrames);
-
-    returnValue = 0;
-
-done:
-    delete plugin;
-    if (out) {
-        out->close();
-        delete out;
-    }
-    sf_close(sndfile);
-    return returnValue;
-}
-
-void
-printFeatures(int frame, int sr, int output,
-              Plugin::FeatureSet features, ofstream *out, bool useFrames)
-{
-    for (unsigned int i = 0; i < features[output].size(); ++i) {
-
-        if (useFrames) {
-
-            int displayFrame = frame;
-
-            if (features[output][i].hasTimestamp) {
-                displayFrame = RealTime::realTime2Frame
-                    (features[output][i].timestamp, sr);
-            }
-
-            (out ? *out : cout) << displayFrame;
-
-            if (features[output][i].hasDuration) {
-                displayFrame = RealTime::realTime2Frame
-                    (features[output][i].duration, sr);
-                (out ? *out : cout) << "," << displayFrame;
-            }
-
-            (out ? *out : cout)  << ":";
-
-        } else {
-
-            RealTime rt = RealTime::frame2RealTime(frame, sr);
-
-            if (features[output][i].hasTimestamp) {
-                rt = features[output][i].timestamp;
-            }
-
-            (out ? *out : cout) << rt.toString();
-
-            if (features[output][i].hasDuration) {
-                rt = features[output][i].duration;
-                (out ? *out : cout) << "," << rt.toString();
-            }
-
-            (out ? *out : cout) << ":";
-        }
-
-        for (unsigned int j = 0; j < features[output][i].values.size(); ++j) {
-            (out ? *out : cout) << " " << features[output][i].values[j];
-        }
-
-        (out ? *out : cout) << endl;
-    }
-}
-
-void
-printPluginPath(bool verbose)
-{
-    if (verbose) {
-        cout << "\nVamp plugin search path: ";
-    }
-
-    vector<string> path = PluginHostAdapter::getPluginPath();
-    for (size_t i = 0; i < path.size(); ++i) {
-        if (verbose) {
-            cout << "[" << path[i] << "]";
-        } else {
-            cout << path[i] << endl;
-        }
-    }
-
-    if (verbose) cout << endl;
-}
-
-void
-enumeratePlugins(Verbosity verbosity)
-{
-    PluginLoader *loader = PluginLoader::getInstance();
-
-    if (verbosity == PluginInformation) {
-        cout << "\nVamp plugin libraries found in search path:" << endl;
-    }
-
-    vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
-    typedef multimap<string, PluginLoader::PluginKey>
-        LibraryMap;
-    LibraryMap libraryMap;
-
-    for (size_t i = 0; i < plugins.size(); ++i) {
-        string path = loader->getLibraryPathForPlugin(plugins[i]);
-        libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
-    }
-
-    string prevPath = "";
-    int index = 0;
-
-    for (LibraryMap::iterator i = libraryMap.begin();
-         i != libraryMap.end(); ++i) {
-        
-        string path = i->first;
-        PluginLoader::PluginKey key = i->second;
-
-        if (path != prevPath) {
-            prevPath = path;
-            index = 0;
-            if (verbosity == PluginInformation) {
-                cout << "\n  " << path << ":" << endl;
-            }
-        }
-
-        Plugin *plugin = loader->loadPlugin(key, 48000);
-        if (plugin) {
-
-            char c = char('A' + index);
-            if (c > 'Z') c = char('a' + (index - 26));
-
-            if (verbosity == PluginInformation) {
-
-                cout << "    [" << c << "] [v"
-                     << plugin->getVampApiVersion() << "] "
-                     << plugin->getName() << ", \""
-                     << plugin->getIdentifier() << "\"" << " ["
-                     << plugin->getMaker() << "]" << endl;
-
-                PluginLoader::PluginCategoryHierarchy category =
-                    loader->getPluginCategory(key);
-
-                if (!category.empty()) {
-                    cout << "       ";
-                    for (size_t ci = 0; ci < category.size(); ++ci) {
-                        cout << " > " << category[ci];
-                    }
-                    cout << endl;
-                }
-
-                if (plugin->getDescription() != "") {
-                    cout << "        - " << plugin->getDescription() << endl;
-                }
-
-            } else if (verbosity == PluginIds) {
-                cout << "vamp:" << key << endl;
-            }
-            
-            Plugin::OutputList outputs =
-                plugin->getOutputDescriptors();
-
-            if (outputs.size() > 1 || verbosity == PluginOutputIds) {
-                for (size_t j = 0; j < outputs.size(); ++j) {
-                    if (verbosity == PluginInformation) {
-                        cout << "         (" << j << ") "
-                             << outputs[j].name << ", \""
-                             << outputs[j].identifier << "\"" << endl;
-                        if (outputs[j].description != "") {
-                            cout << "             - " 
-                                 << outputs[j].description << endl;
-                        }
-                    } else if (verbosity == PluginOutputIds) {
-                        cout << "vamp:" << key << ":" << outputs[j].identifier << endl;
-                    }
-                }
-            }
-
-            ++index;
-
-            delete plugin;
-        }
-    }
-
-    if (verbosity == PluginInformation) {
-        cout << endl;
-    }
-}
-
-void
-printPluginCategoryList()
-{
-    PluginLoader *loader = PluginLoader::getInstance();
-
-    vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
-
-    set<string> printedcats;
-
-    for (size_t i = 0; i < plugins.size(); ++i) {
-
-        PluginLoader::PluginKey key = plugins[i];
-        
-        PluginLoader::PluginCategoryHierarchy category =
-            loader->getPluginCategory(key);
-
-        Plugin *plugin = loader->loadPlugin(key, 48000);
-        if (!plugin) continue;
-
-        string catstr = "";
-
-        if (category.empty()) catstr = '|';
-        else {
-            for (size_t j = 0; j < category.size(); ++j) {
-                catstr += category[j];
-                catstr += '|';
-                if (printedcats.find(catstr) == printedcats.end()) {
-                    std::cout << catstr << std::endl;
-                    printedcats.insert(catstr);
-                }
-            }
-        }
-
-        std::cout << catstr << key << ":::" << plugin->getName() << ":::" << plugin->getMaker() << ":::" << plugin->getDescription() << std::endl;
-    }
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-hostsdk/hostext/PluginBufferingAdapter.h	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,181 @@
+/* -*- 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-2007 Chris Cannam and QMUL.
+    This file by Mark Levy and Chris Cannam, Copyright 2007-2008 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 _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
+#define _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
+
+#include "PluginWrapper.h"
+
+namespace Vamp {
+	
+namespace HostExt {
+		
+/**
+ * \class PluginBufferingAdapter PluginBufferingAdapter.h <vamp-sdk/hostext/PluginBufferingAdapter.h>
+ *
+ * PluginBufferingAdapter is a Vamp plugin adapter that allows plugins
+ * to be used by a host supplying an audio stream in non-overlapping
+ * buffers of arbitrary size.
+ *
+ * A host using PluginBufferingAdapter may ignore the preferred step
+ * and block size reported by the plugin, and still expect the plugin
+ * to run.  The value of blockSize and stepSize passed to initialise
+ * should be the size of the buffer which the host will supply; the
+ * stepSize should be equal to the blockSize.
+ *
+ * If the internal step size used for the plugin differs from that
+ * supplied by the host, the adapter will modify the sample type and
+ * rate specifications for the plugin outputs appropriately, and set
+ * timestamps on the output features for outputs that formerly used a
+ * different sample rate specification.  This is necessary in order to
+ * obtain correct time stamping.
+ * 
+ * In other respects, the PluginBufferingAdapter behaves identically
+ * to the plugin that it wraps. The wrapped plugin will be deleted
+ * when the wrapper is deleted.
+ */
+		
+class PluginBufferingAdapter : public PluginWrapper
+{
+public:
+    PluginBufferingAdapter(Plugin *plugin); // I take ownership of plugin
+    virtual ~PluginBufferingAdapter();
+
+    /**
+     * Return the preferred step size for this adapter.
+     * 
+     * Because of the way this adapter works, its preferred step size
+     * will always be the same as its preferred block size.  This may
+     * or may not be the same as the preferred step size of the
+     * underlying plugin, which may be obtained by calling
+     * getPluginPreferredStepSize().
+     */
+    size_t getPreferredStepSize() const;
+
+    /**
+     * Return the preferred block size for this adapter.
+     * 
+     * This may or may not be the same as the preferred block size of
+     * the underlying plugin, which may be obtained by calling
+     * getPluginPreferredBlockSize().
+     *
+     * Note that this adapter may be initialised with any block size,
+     * not just its supposedly preferred one.
+     */
+    size_t getPreferredBlockSize() const;
+
+    /**
+     * Initialise the adapter (and therefore the plugin) for the given
+     * number of channels.  Initialise the adapter for the given step
+     * and block size, which must be equal.
+     *
+     * The step and block size used for the underlying plugin will
+     * depend on its preferences, or any values previously passed to
+     * setPluginStepSize and setPluginBlockSize.
+     */
+    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+
+    /**
+     * Return the preferred step size of the plugin wrapped by this
+     * adapter.
+     *
+     * This is included mainly for informational purposes.  This value
+     * is not likely to be a valid step size for the adapter itself,
+     * and it is not usually of any use in interpreting the results
+     * (because the adapter re-writes OneSamplePerStep outputs to
+     * FixedSampleRate so that the hop size no longer needs to be
+     * known beforehand in order to interpret them).
+     */
+    size_t getPluginPreferredStepSize() const;
+
+    /** 
+     * Return the preferred block size of the plugin wrapped by this
+     * adapter.
+     *
+     * This is included mainly for informational purposes.
+     */
+    size_t getPluginPreferredBlockSize() const;
+
+    /**
+     * Set the step size that will be used for the underlying plugin
+     * when initialise() is called.  If this is not set, the plugin's
+     * own preferred step size will be used.  You will not usually
+     * need to call this function.  If you do call it, it must be
+     * before the first call to initialise().
+     */
+    void setPluginStepSize(size_t stepSize);
+
+    /**
+     * Set the block size that will be used for the underlying plugin
+     * when initialise() is called.  If this is not set, the plugin's
+     * own preferred block size will be used.  You will not usually
+     * need to call this function.  If you do call it, it must be
+     * before the first call to initialise().
+     */
+    void setPluginBlockSize(size_t blockSize);
+
+    /**
+     * Return the step and block sizes that were actually used when
+     * initialising the underlying plugin.
+     *
+     * This is included mainly for informational purposes.  You will
+     * not usually need to call this function.  If this is called
+     * before initialise(), it will return 0 for both values.  If it
+     * is called after a failed call to initialise(), it will return
+     * the values that were used in the failed call to the plugin's
+     * initialise() function.
+     */
+    void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
+
+    OutputList getOutputDescriptors() const;
+
+    void reset();
+
+    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
+    
+    FeatureSet getRemainingFeatures();
+    
+protected:
+    class Impl;
+    Impl *m_impl;
+};
+    
+}
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-hostsdk/hostext/PluginChannelAdapter.h	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,139 @@
+/* -*- 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-2007 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 _VAMP_PLUGIN_CHANNEL_ADAPTER_H_
+#define _VAMP_PLUGIN_CHANNEL_ADAPTER_H_
+
+#include "PluginWrapper.h"
+
+namespace Vamp {
+
+namespace HostExt {
+
+/**
+ * \class PluginChannelAdapter PluginChannelAdapter.h <vamp-sdk/hostext/PluginChannelAdapter.h>
+ *
+ * PluginChannelAdapter is a Vamp plugin adapter that implements a
+ * policy for management of plugins that expect a different number of
+ * input channels from the number actually available in the source
+ * audio data.
+ *
+ * A host using PluginChannelAdapter may ignore the getMinChannelCount
+ * and getMaxChannelCount reported by the plugin, and still expect the
+ * plugin to run.
+ *
+ * PluginChannelAdapter implements the following policy:
+ *
+ *  - If the plugin supports the provided number of channels directly,
+ *  PluginChannelAdapter will just run the plugin as normal.
+ *
+ *  - If the plugin only supports exactly one channel but more than
+ *  one channel is provided, PluginChannelAdapter will use the mean of
+ *  the channels.  This ensures that the resulting values remain
+ *  within the same magnitude range as expected for mono data.
+ *
+ *  - If the plugin requires more than one channel but exactly one is
+ *  provided, the provided channel will be duplicated across all the
+ *  plugin input channels.
+ *
+ * If none of the above apply:
+ * 
+ *  - If the plugin requires more channels than are provided, the
+ *  minimum acceptable number of channels will be produced by adding
+ *  empty (zero valued) channels to those provided.
+ *
+ *  - If the plugin requires fewer channels than are provided, the
+ *  maximum acceptable number of channels will be produced by
+ *  discarding the excess channels.
+ *
+ * Hosts requiring a different channel policy from the above will need
+ * to implement it themselves, instead of using PluginChannelAdapter.
+ *
+ * Note that PluginChannelAdapter does not override the minimum and
+ * maximum channel counts returned by the wrapped plugin.  The host
+ * will need to be aware that it is using a PluginChannelAdapter, and
+ * be prepared to ignore these counts as necessary.  (This contrasts
+ * with the approach used in PluginInputDomainAdapter, which aims to
+ * make the host completely unaware of which underlying input domain
+ * is in fact in use.)
+ * 
+ * (The rationale for this is that a host may wish to use the
+ * PluginChannelAdapter but still discriminate in some way on the
+ * basis of the number of channels actually supported.  For example, a
+ * simple stereo audio host may prefer to reject plugins that require
+ * more than two channels on the grounds that doesn't actually
+ * understand what they are for, rather than allow the channel adapter
+ * to make a potentially meaningless channel conversion for them.)
+ *
+ * In every respect other than its management of channels, the
+ * PluginChannelAdapter behaves identically to the plugin that it
+ * wraps.  The wrapped plugin will be deleted when the wrapper is
+ * deleted.
+ *
+ * \note This class was introduced in version 1.1 of the Vamp plugin SDK.
+ */
+
+class PluginChannelAdapter : public PluginWrapper
+{
+public:
+    PluginChannelAdapter(Plugin *plugin); // I take ownership of plugin
+    virtual ~PluginChannelAdapter();
+
+    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+
+    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
+
+    /**
+     * Call process(), providing interleaved audio data with the
+     * number of channels passed to initialise().  The adapter will
+     * de-interleave into temporary buffers as appropriate before
+     * calling process().
+     *
+     * \note This function was introduced in version 1.4 of the Vamp
+     * plugin SDK.
+     */
+    FeatureSet processInterleaved(const float *inputBuffer, RealTime timestamp);
+
+protected:
+    class Impl;
+    Impl *m_impl;
+};
+
+}
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-hostsdk/hostext/PluginInputDomainAdapter.h	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,126 @@
+/* -*- 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-2007 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 _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_
+#define _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_
+
+#include "PluginWrapper.h"
+
+namespace Vamp {
+
+namespace HostExt {
+
+/**
+ * \class PluginInputDomainAdapter PluginInputDomainAdapter.h <vamp-sdk/hostext/PluginInputDomainAdapter.h>
+ * 
+ * PluginInputDomainAdapter is a Vamp plugin adapter that converts
+ * time-domain input into frequency-domain input for plugins that need
+ * it.  This permits a host to use time- and frequency-domain plugins
+ * interchangeably without needing to handle the conversion itself.
+ *
+ * This adapter uses a basic Hanning windowed FFT that supports
+ * power-of-two block sizes only.  If a frequency domain plugin
+ * requests a non-power-of-two blocksize, the adapter will adjust it
+ * to a nearby power of two instead.  Thus, getPreferredBlockSize()
+ * will always return a power of two if the wrapped plugin is a
+ * frequency domain one.  If the plugin doesn't accept the adjusted
+ * power of two block size, initialise() will fail.
+ *
+ * The adapter provides no way for the host to discover whether the
+ * underlying plugin is actually a time or frequency domain plugin
+ * (except that if the preferred block size is not a power of two, it
+ * must be a time domain plugin).
+ *
+ * The FFT implementation is simple and self-contained, but unlikely
+ * to be the fastest available: a host can usually do better if it
+ * cares enough.
+ *
+ * In every respect other than its input domain handling, the
+ * PluginInputDomainAdapter behaves identically to the plugin that it
+ * wraps.  The wrapped plugin will be deleted when the wrapper is
+ * deleted.
+ *
+ * \note This class was introduced in version 1.1 of the Vamp plugin SDK.
+ */
+
+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);
+
+    InputDomain getInputDomain() const;
+
+    size_t getPreferredStepSize() const;
+    size_t getPreferredBlockSize() const;
+
+    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
+
+    /**
+     * Return the amount by which the timestamps supplied to process()
+     * are being incremented when they are passed to the plugin's own
+     * process() implementation.
+     *
+     * The Vamp API mandates that the timestamp passed to the plugin
+     * for time-domain input should be the time of the first sample in
+     * the block, but the timestamp passed for frequency-domain input
+     * should be the timestamp of the centre of the block.
+     *
+     * The PluginInputDomainAdapter adjusts its timestamps properly so
+     * that the plugin receives correct times, but in some
+     * circumstances (such as for establishing the correct timing of
+     * implicitly-timed features, i.e. features without their own
+     * timestamps) the host may need to be aware that this adjustment
+     * is taking place.
+     *
+     * If the plugin requires time-domain input, this function will
+     * return zero.  The result of calling this function before
+     * initialise() has been called is undefined.
+     */
+    RealTime getTimestampAdjustment() const;
+
+protected:
+    class Impl;
+    Impl *m_impl;
+};
+
+}
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-hostsdk/hostext/PluginLoader.h	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,238 @@
+/* -*- 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-2007 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 _VAMP_PLUGIN_LOADER_H_
+#define _VAMP_PLUGIN_LOADER_H_
+
+#include <vector>
+#include <string>
+#include <map>
+
+#include "PluginWrapper.h"
+
+namespace Vamp {
+
+class Plugin;
+
+namespace HostExt {
+
+/**
+ * \class PluginLoader PluginLoader.h <vamp-sdk/hostext/PluginLoader.h>
+ * 
+ * Vamp::HostExt::PluginLoader is a convenience class for discovering
+ * and loading Vamp plugins using the typical plugin-path, library
+ * naming, and categorisation conventions described in the Vamp SDK
+ * documentation.  This class is intended to greatly simplify the task
+ * of becoming a Vamp plugin host for any C++ application.
+ * 
+ * Hosts are not required by the Vamp specification to use the same
+ * plugin search path and naming conventions as implemented by this
+ * class, and are certainly not required to use this actual class.
+ * But we do strongly recommend it.
+ *
+ * \note This class was introduced in version 1.1 of the Vamp plugin SDK.
+ */
+
+class PluginLoader
+{
+public:
+    /**
+     * Obtain a pointer to the singleton instance of PluginLoader.
+     * Use this to obtain your loader object.
+     */
+    static PluginLoader *getInstance();
+
+    /**
+     * PluginKey is a string type that is used to identify a plugin
+     * uniquely within the scope of "the current system".  It consists
+     * of the lower-cased base name of the plugin library, a colon
+     * separator, and the identifier string for the plugin.  It is
+     * only meaningful in the context of a given plugin path (the one
+     * returned by PluginHostAdapter::getPluginPath()).
+     *
+     * Use composePluginKey() to construct a plugin key from a known
+     * plugin library name and identifier.
+     *
+     * Note: the fact that the library component of the key is
+     * lower-cased implies that library names are matched
+     * case-insensitively by the PluginLoader class, regardless of the
+     * case sensitivity of the underlying filesystem.  (Plugin
+     * identifiers _are_ case sensitive, however.)  Also, it is not
+     * possible to portably extract a working library name from a
+     * plugin key, as the result may fail on case-sensitive
+     * filesystems.  Use getLibraryPathForPlugin() instead.
+     */
+    typedef std::string PluginKey;
+
+    /**
+     * PluginKeyList is a sequence of plugin keys, such as returned by
+     * listPlugins().
+     */
+    typedef std::vector<PluginKey> PluginKeyList;
+
+    /**
+     * PluginCategoryHierarchy is a sequence of general->specific
+     * category names, as may be associated with a single plugin.
+     * This sequence describes the location of a plugin within a
+     * category forest, containing the human-readable names of the
+     * plugin's category tree root, followed by each of the nodes down
+     * to the leaf containing the plugin.
+     *
+     * \see getPluginCategory()
+     */
+    typedef std::vector<std::string> PluginCategoryHierarchy;
+
+    /**
+     * Search for all available Vamp plugins, and return a list of
+     * them in the order in which they were found.
+     */
+    PluginKeyList listPlugins();
+
+    /**
+     * AdapterFlags contains a set of values that may be OR'd together
+     * to indicate in which circumstances PluginLoader should use a
+     * plugin adapter to make a plugin easier to use for a host that
+     * does not want to cater for complex features.
+     *
+     * The available flags are:
+     * 
+     * ADAPT_INPUT_DOMAIN - If the plugin expects frequency domain
+     * input, wrap it in a PluginInputDomainAdapter that automatically
+     * converts the plugin to one that expects time-domain input.
+     * This enables a host to accommodate time- and frequency-domain
+     * plugins without needing to do any conversion itself.
+     *
+     * ADAPT_CHANNEL_COUNT - Wrap the plugin in a PluginChannelAdapter
+     * to handle any mismatch between the number of channels of audio
+     * the plugin can handle and the number available in the host.
+     * This enables a host to use plugins that may require the input
+     * to be mixed down to mono, etc., without having to worry about
+     * doing that itself.
+     *
+     * ADAPT_BUFFER_SIZE - Wrap the plugin in a PluginBufferingAdapter
+     * permitting the host to provide audio input using any block
+     * size, with no overlap, regardless of the plugin's preferred
+     * block size (suitable for hosts that read from non-seekable
+     * streaming media, for example).  This adapter introduces some
+     * run-time overhead and also changes the semantics of the plugin
+     * slightly (see the PluginBufferingAdapter header documentation
+     * for details).
+     *
+     * ADAPT_ALL_SAFE - Perform all available adaptations that are
+     * meaningful for the plugin and "safe".  Currently this means to
+     * ADAPT_INPUT_DOMAIN if the plugin wants FrequencyDomain input;
+     * ADAPT_CHANNEL_COUNT always; and ADAPT_BUFFER_SIZE never.
+     * 
+     * ADAPT_ALL - Perform all available adaptations that are
+     * meaningful for the plugin.
+     * 
+     * See PluginInputDomainAdapter, PluginChannelAdapter and
+     * PluginBufferingAdapter for more details of the classes that the
+     * loader may use if these flags are set.
+     */
+    enum AdapterFlags {
+
+        ADAPT_INPUT_DOMAIN  = 0x01,
+        ADAPT_CHANNEL_COUNT = 0x02,
+        ADAPT_BUFFER_SIZE   = 0x04,
+
+        ADAPT_ALL_SAFE      = 0x03,
+
+        ADAPT_ALL           = 0xff
+    };
+
+    /**
+     * Load a Vamp plugin, given its identifying key.  If the plugin
+     * could not be loaded, returns 0.
+     *
+     * The returned plugin should be deleted (using the standard C++
+     * delete keyword) after use.
+     *
+     * \param adapterFlags a bitwise OR of the values in the AdapterFlags
+     * enumeration, indicating under which circumstances an adapter should be
+     * used to wrap the original plugin.  If adapterFlags is 0, no
+     * optional adapters will be used.  Otherwise, the returned plugin
+     * may be of an adapter class type which will behave identically
+     * to the original plugin, apart from any particular features
+     * implemented by the adapter itself.
+     * 
+     * \see AdapterFlags, PluginInputDomainAdapter, PluginChannelAdapter
+     */
+    Plugin *loadPlugin(PluginKey key,
+                       float inputSampleRate,
+                       int adapterFlags = 0);
+
+    /**
+     * Given a Vamp plugin library name and plugin identifier, return
+     * the corresponding plugin key in a form suitable for passing in to
+     * loadPlugin().
+     */
+    PluginKey composePluginKey(std::string libraryName,
+                               std::string identifier);
+
+    /**
+     * Return the category hierarchy for a Vamp plugin, given its
+     * identifying key.
+     *
+     * If the plugin has no category information, return an empty
+     * hierarchy.
+     *
+     * \see PluginCategoryHierarchy
+     */
+    PluginCategoryHierarchy getPluginCategory(PluginKey plugin);
+
+    /**
+     * Return the file path of the dynamic library from which the
+     * given plugin will be loaded (if available).
+     */
+    std::string getLibraryPathForPlugin(PluginKey plugin);
+
+protected:
+    PluginLoader();
+    virtual ~PluginLoader();
+
+    class Impl;
+    Impl *m_impl;
+
+    static PluginLoader *m_instance;
+};
+
+}
+
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-hostsdk/hostext/PluginSummarisingAdapter.h	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,125 @@
+/* -*- 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-2008 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 _VAMP_PLUGIN_SUMMARISING_ADAPTER_H_
+#define _VAMP_PLUGIN_SUMMARISING_ADAPTER_H_
+
+#include "PluginWrapper.h"
+
+#include <set>
+
+namespace Vamp {
+
+namespace HostExt {
+
+/**
+ * \class PluginSummarisingAdapter PluginSummarisingAdapter.h <vamp-sdk/hostext/PluginSummarisingAdapter.h>
+ *
+ * \note This class was introduced in version 2.0 of the Vamp plugin SDK.
+ */
+
+class PluginSummarisingAdapter : public PluginWrapper
+{
+public:
+    PluginSummarisingAdapter(Plugin *plugin); // I take ownership of plugin
+    virtual ~PluginSummarisingAdapter();
+
+    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+
+    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
+    FeatureSet getRemainingFeatures();
+
+    typedef std::set<RealTime> SegmentBoundaries;
+    void setSummarySegmentBoundaries(const SegmentBoundaries &);
+
+    enum SummaryType {
+        Minimum            = 0,
+        Maximum            = 1,
+        Mean               = 2,
+        Median             = 3,
+        Mode               = 4,
+        Sum                = 5,
+        Variance           = 6,
+        StandardDeviation  = 7,
+        Count              = 8,
+
+        UnknownSummaryType = 999
+    };
+
+    /**
+     * AveragingMethod indicates how the adapter should handle
+     * average-based summaries of features whose results are not
+     * equally spaced in time.
+     *
+     * If SampleAverage is specified, summary types based on averages
+     * will be calculated by treating each result individually without
+     * regard to its time: for example, the mean will be the sum of
+     * all values divided by the number of values.
+     *
+     * If ContinuousTimeAverage is specified, each feature will be
+     * considered to have a duration, either as specified in the
+     * feature's duration field, or until the following feature: thus,
+     * for example, the mean will be the sum of the products of values
+     * and durations, divided by the total duration.
+     *
+     * Although SampleAverage is useful for many types of feature,
+     * ContinuousTimeAverage is essential for some situations, for
+     * example finding the result that spans the largest proportion of
+     * the input given a feature that emits a new result only when the
+     * value changes (the modal value integrated over time).
+     */
+    enum AveragingMethod {
+        SampleAverage         = 0,
+        ContinuousTimeAverage = 1,
+    };
+
+    FeatureList getSummaryForOutput(int output,
+                                    SummaryType type,
+                                    AveragingMethod method = SampleAverage);
+
+    FeatureSet getSummaryForAllOutputs(SummaryType type,
+                                       AveragingMethod method = SampleAverage);
+
+protected:
+    class Impl;
+    Impl *m_impl;
+};
+
+}
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-hostsdk/hostext/PluginWrapper.h	Thu Nov 06 14:13:12 2008 +0000
@@ -0,0 +1,130 @@
+/* -*- 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-2007 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 _VAMP_PLUGIN_WRAPPER_H_
+#define _VAMP_PLUGIN_WRAPPER_H_
+
+#include "vamp-sdk/Plugin.h"
+
+namespace Vamp {
+
+namespace HostExt {
+
+/**
+ * \class PluginWrapper PluginWrapper.h <vamp-sdk/hostext/PluginWrapper.h>
+ * 
+ * PluginWrapper is a simple base class for adapter plugins.  It takes
+ * a pointer to a "to be wrapped" Vamp plugin on construction, and
+ * provides implementations of all the Vamp plugin methods that simply
+ * delegate through to the wrapped plugin.  A subclass can therefore
+ * override only the methods that are meaningful for the particular
+ * adapter.
+ *
+ * \note This class was introduced in version 1.1 of the Vamp plugin SDK.
+ */
+
+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();
+
+    /**
+     * Return a pointer to the plugin wrapper of type WrapperType
+     * surrounding this wrapper's plugin, if present.
+     *
+     * This is useful in situations where a plugin is wrapped by
+     * multiple different wrappers (one inside another) and the host
+     * wants to call some wrapper-specific function on one of the
+     * layers without having to care about the order in which they are
+     * wrapped.  For example, the plugin returned by
+     * PluginLoader::loadPlugin may have more than one wrapper; if the
+     * host wanted to query or fine-tune some property of one of them,
+     * it would be hard to do so without knowing the order of the
+     * wrappers.  This function therefore gives direct access to the
+     * wrapper of a particular type.
+     */
+    template <typename WrapperType>
+    WrapperType *getWrapper() {
+        WrapperType *w = dynamic_cast<WrapperType *>(this);
+        if (w) return w;
+        PluginWrapper *pw = dynamic_cast<PluginWrapper *>(m_plugin);
+        if (pw) return pw->getWrapper<WrapperType>();
+        return 0;
+    }
+
+protected:
+    PluginWrapper(Plugin *plugin); // I take ownership of plugin
+    Plugin *m_plugin;
+};
+
+}
+
+}
+
+#endif
--- a/vamp-sdk/hostext/PluginBufferingAdapter.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,657 +0,0 @@
-/* -*- 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-2007 Chris Cannam and QMUL.
-    This file by Mark Levy and Chris Cannam, Copyright 2007-2008 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.
-*/
-
-#include <vector>
-#include <map>
-
-#include "PluginBufferingAdapter.h"
-
-using std::vector;
-using std::map;
-
-namespace Vamp {
-	
-namespace HostExt {
-		
-class PluginBufferingAdapter::Impl
-{
-public:
-    Impl(Plugin *plugin, float inputSampleRate);
-    ~Impl();
-	
-    void setPluginStepSize(size_t stepSize);	
-    void setPluginBlockSize(size_t blockSize);
-
-    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
-
-    void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
-
-    OutputList getOutputDescriptors() const;
-
-    void reset();
-
-    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
-		
-    FeatureSet getRemainingFeatures();
-		
-protected:
-    class RingBuffer
-    {
-    public:
-        RingBuffer(int n) :
-            m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { }
-        virtual ~RingBuffer() { delete[] m_buffer; }
-
-        int getSize() const { return m_size-1; }
-        void reset() { m_writer = 0; m_reader = 0; }
-
-        int getReadSpace() const {
-            int writer = m_writer, reader = m_reader, space;
-            if (writer > reader) space = writer - reader;
-            else if (writer < reader) space = (writer + m_size) - reader;
-            else space = 0;
-            return space;
-        }
-
-        int getWriteSpace() const {
-            int writer = m_writer;
-            int reader = m_reader;
-            int space = (reader + m_size - writer - 1);
-            if (space >= m_size) space -= m_size;
-            return space;
-        }
-        
-        int peek(float *destination, int n) const {
-
-            int available = getReadSpace();
-
-            if (n > available) {
-                for (int i = available; i < n; ++i) {
-                    destination[i] = 0.f;
-                }
-                n = available;
-            }
-            if (n == 0) return n;
-
-            int reader = m_reader;
-            int here = m_size - reader;
-            const float *const bufbase = m_buffer + reader;
-
-            if (here >= n) {
-                for (int i = 0; i < n; ++i) {
-                    destination[i] = bufbase[i];
-                }
-            } else {
-                for (int i = 0; i < here; ++i) {
-                    destination[i] = bufbase[i];
-                }
-                float *const destbase = destination + here;
-                const int nh = n - here;
-                for (int i = 0; i < nh; ++i) {
-                    destbase[i] = m_buffer[i];
-                }
-            }
-
-            return n;
-        }
-
-        int skip(int n) {
-            
-            int available = getReadSpace();
-            if (n > available) {
-                n = available;
-            }
-            if (n == 0) return n;
-
-            int reader = m_reader;
-            reader += n;
-            while (reader >= m_size) reader -= m_size;
-            m_reader = reader;
-            return n;
-        }
-        
-        int write(const float *source, int n) {
-
-            int available = getWriteSpace();
-            if (n > available) {
-                n = available;
-            }
-            if (n == 0) return n;
-
-            int writer = m_writer;
-            int here = m_size - writer;
-            float *const bufbase = m_buffer + writer;
-            
-            if (here >= n) {
-                for (int i = 0; i < n; ++i) {
-                    bufbase[i] = source[i];
-                }
-            } else {
-                for (int i = 0; i < here; ++i) {
-                    bufbase[i] = source[i];
-                }
-                const int nh = n - here;
-                const float *const srcbase = source + here;
-                float *const buf = m_buffer;
-                for (int i = 0; i < nh; ++i) {
-                    buf[i] = srcbase[i];
-                }
-            }
-
-            writer += n;
-            while (writer >= m_size) writer -= m_size;
-            m_writer = writer;
-
-            return n;
-        }
-
-        int zero(int n) {
-            
-            int available = getWriteSpace();
-            if (n > available) {
-                n = available;
-            }
-            if (n == 0) return n;
-
-            int writer = m_writer;
-            int here = m_size - writer;
-            float *const bufbase = m_buffer + writer;
-
-            if (here >= n) {
-                for (int i = 0; i < n; ++i) {
-                    bufbase[i] = 0.f;
-                }
-            } else {
-                for (int i = 0; i < here; ++i) {
-                    bufbase[i] = 0.f;
-                }
-                const int nh = n - here;
-                for (int i = 0; i < nh; ++i) {
-                    m_buffer[i] = 0.f;
-                }
-            }
-            
-            writer += n;
-            while (writer >= m_size) writer -= m_size;
-            m_writer = writer;
-
-            return n;
-        }
-
-    protected:
-        float *m_buffer;
-        int    m_writer;
-        int    m_reader;
-        int    m_size;
-
-    private:
-        RingBuffer(const RingBuffer &); // not provided
-        RingBuffer &operator=(const RingBuffer &); // not provided
-    };
-
-    Plugin *m_plugin;
-    size_t m_inputStepSize;  // value passed to wrapper initialise()
-    size_t m_inputBlockSize; // value passed to wrapper initialise()
-    size_t m_setStepSize;    // value passed to setPluginStepSize()
-    size_t m_setBlockSize;   // value passed to setPluginBlockSize()
-    size_t m_stepSize;       // value actually used to initialise plugin
-    size_t m_blockSize;      // value actually used to initialise plugin
-    size_t m_channels;
-    vector<RingBuffer *> m_queue;
-    float **m_buffers;
-    float m_inputSampleRate;
-    long m_frame;
-    bool m_unrun;
-    mutable OutputList m_outputs;
-    mutable std::map<int, bool> m_rewriteOutputTimes;
-		
-    void processBlock(FeatureSet& allFeatureSets);
-};
-		
-PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
-    PluginWrapper(plugin)
-{
-    m_impl = new Impl(plugin, m_inputSampleRate);
-}
-		
-PluginBufferingAdapter::~PluginBufferingAdapter()
-{
-    delete m_impl;
-}
-
-size_t
-PluginBufferingAdapter::getPreferredStepSize() const
-{
-    return getPreferredBlockSize();
-}
-
-size_t
-PluginBufferingAdapter::getPreferredBlockSize() const
-{
-    return PluginWrapper::getPreferredBlockSize();
-}
-
-size_t
-PluginBufferingAdapter::getPluginPreferredStepSize() const
-{
-    return PluginWrapper::getPreferredStepSize();
-}
-
-size_t
-PluginBufferingAdapter::getPluginPreferredBlockSize() const
-{
-    return PluginWrapper::getPreferredBlockSize();
-}
-
-void
-PluginBufferingAdapter::setPluginStepSize(size_t stepSize)
-{
-    m_impl->setPluginStepSize(stepSize);
-}
-
-void
-PluginBufferingAdapter::setPluginBlockSize(size_t blockSize)
-{
-    m_impl->setPluginBlockSize(blockSize);
-}
-
-void
-PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize,
-                                                   size_t &blockSize)
-{
-    m_impl->getActualStepAndBlockSizes(stepSize, blockSize);
-}
-		
-bool
-PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    return m_impl->initialise(channels, stepSize, blockSize);
-}
-
-PluginBufferingAdapter::OutputList
-PluginBufferingAdapter::getOutputDescriptors() const
-{
-    return m_impl->getOutputDescriptors();
-}
-
-void
-PluginBufferingAdapter::reset()
-{
-    m_impl->reset();
-}
-		
-PluginBufferingAdapter::FeatureSet
-PluginBufferingAdapter::process(const float *const *inputBuffers,
-                                RealTime timestamp)
-{
-    return m_impl->process(inputBuffers, timestamp);
-}
-		
-PluginBufferingAdapter::FeatureSet
-PluginBufferingAdapter::getRemainingFeatures()
-{
-    return m_impl->getRemainingFeatures();
-}
-		
-PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
-    m_plugin(plugin),
-    m_inputStepSize(0),
-    m_inputBlockSize(0),
-    m_setStepSize(0),
-    m_setBlockSize(0),
-    m_stepSize(0),
-    m_blockSize(0),
-    m_channels(0), 
-    m_queue(0),
-    m_buffers(0),
-    m_inputSampleRate(inputSampleRate),
-    m_frame(0),
-    m_unrun(true)
-{
-    (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
-}
-		
-PluginBufferingAdapter::Impl::~Impl()
-{
-    // the adapter will delete the plugin
-
-    for (size_t i = 0; i < m_channels; ++i) {
-        delete m_queue[i];
-        delete[] m_buffers[i];
-    }
-    delete[] m_buffers;
-}
-		
-void
-PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize)
-{
-    if (m_inputStepSize != 0) {
-        std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl;
-        return;
-    }
-    m_setStepSize = stepSize;
-}
-		
-void
-PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize)
-{
-    if (m_inputBlockSize != 0) {
-        std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl;
-        return;
-    }
-    m_setBlockSize = blockSize;
-}
-
-void
-PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize,
-                                                         size_t &blockSize)
-{
-    stepSize = m_stepSize;
-    blockSize = m_blockSize;
-}
-
-bool
-PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    if (stepSize != blockSize) {
-        std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
-        return false;
-    }
-
-    m_channels = channels;	
-    m_inputStepSize = stepSize;
-    m_inputBlockSize = blockSize;
-
-    // if the user has requested particular step or block sizes, use
-    // those; otherwise use the step and block sizes which the plugin
-    // prefers
-
-    m_stepSize = 0;
-    m_blockSize = 0;
-
-    if (m_setStepSize > 0) {
-        m_stepSize = m_setStepSize;
-    }
-    if (m_setBlockSize > 0) {
-        m_blockSize = m_setBlockSize;
-    }
-
-    if (m_stepSize == 0 && m_blockSize == 0) {
-        m_stepSize = m_plugin->getPreferredStepSize();
-        m_blockSize = m_plugin->getPreferredBlockSize();
-    }
-    
-    bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain);
-    
-    // or sensible defaults if it has no preference
-    if (m_blockSize == 0) {
-        if (m_stepSize == 0) {
-            m_blockSize = 1024;
-        } else if (freq) {
-            m_blockSize = m_stepSize * 2;
-        } else {
-            m_blockSize = m_stepSize;
-        }
-    } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above)
-        if (freq) {
-            m_stepSize = m_blockSize/2;
-        } else {
-            m_stepSize = m_blockSize;
-        }
-    }
-    
-    // current implementation breaks if step is greater than block
-    if (m_stepSize > m_blockSize) {
-        size_t newBlockSize;
-        if (freq) {
-            newBlockSize = m_stepSize * 2;
-        } else {
-            newBlockSize = m_stepSize;
-        }
-        std::cerr << "PluginBufferingAdapter::initialise: WARNING: step size " << m_stepSize << " is greater than block size " << m_blockSize << ": cannot handle this in adapter; adjusting block size to " << newBlockSize << std::endl;
-        m_blockSize = newBlockSize;
-    }
-    
-    std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize 
-              << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;			
-
-    m_buffers = new float *[m_channels];
-
-    for (size_t i = 0; i < m_channels; ++i) {
-        m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
-        m_buffers[i] = new float[m_blockSize];
-    }
-    
-    return m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
-}
-		
-PluginBufferingAdapter::OutputList
-PluginBufferingAdapter::Impl::getOutputDescriptors() const
-{
-    if (m_outputs.empty()) {
-        m_outputs = m_plugin->getOutputDescriptors();
-    }
-
-    PluginBufferingAdapter::OutputList outs = m_outputs;
-
-    for (size_t i = 0; i < outs.size(); ++i) {
-
-        switch (outs[i].sampleType) {
-
-        case OutputDescriptor::OneSamplePerStep:
-            outs[i].sampleType = OutputDescriptor::FixedSampleRate;
-            outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
-            m_rewriteOutputTimes[i] = true;
-            break;
-            
-        case OutputDescriptor::FixedSampleRate:
-            if (outs[i].sampleRate == 0.f) {
-                outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
-            }
-            // We actually only need to rewrite output times for
-            // features that don't have timestamps already, but we
-            // can't tell from here whether our features will have
-            // timestamps or not
-            m_rewriteOutputTimes[i] = true;
-            break;
-
-        case OutputDescriptor::VariableSampleRate:
-            m_rewriteOutputTimes[i] = false;
-            break;
-        }
-    }
-
-    return outs;
-}
-
-void
-PluginBufferingAdapter::Impl::reset()
-{
-    m_frame = 0;
-    m_unrun = true;
-
-    for (size_t i = 0; i < m_queue.size(); ++i) {
-        m_queue[i]->reset();
-    }
-
-    m_plugin->reset();
-}
-
-PluginBufferingAdapter::FeatureSet
-PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
-                                      RealTime timestamp)
-{
-    if (m_inputStepSize == 0) {
-        std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl;
-        return FeatureSet();
-    }
-
-    FeatureSet allFeatureSets;
-
-    if (m_unrun) {
-        m_frame = RealTime::realTime2Frame(timestamp,
-                                           int(m_inputSampleRate + 0.5));
-        m_unrun = false;
-    }
-			
-    // queue the new input
-    
-    for (size_t i = 0; i < m_channels; ++i) {
-        int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
-        if (written < int(m_inputBlockSize) && i == 0) {
-            std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
-                      << "Buffer overflow: wrote " << written 
-                      << " of " << m_inputBlockSize 
-                      << " input samples (for plugin step size "
-                      << m_stepSize << ", block size " << m_blockSize << ")"
-                      << std::endl;
-        }
-    }    
-    
-    // process as much as we can
-
-    while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
-        processBlock(allFeatureSets);
-    }	
-    
-    return allFeatureSets;
-}
-    
-PluginBufferingAdapter::FeatureSet
-PluginBufferingAdapter::Impl::getRemainingFeatures() 
-{
-    FeatureSet allFeatureSets;
-    
-    // process remaining samples in queue
-    while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
-        processBlock(allFeatureSets);
-    }
-    
-    // pad any last samples remaining and process
-    if (m_queue[0]->getReadSpace() > 0) {
-        for (size_t i = 0; i < m_channels; ++i) {
-            m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
-        }
-        processBlock(allFeatureSets);
-    }			
-    
-    // get remaining features			
-
-    FeatureSet featureSet = m_plugin->getRemainingFeatures();
-
-    for (map<int, FeatureList>::iterator iter = featureSet.begin();
-         iter != featureSet.end(); ++iter) {
-        FeatureList featureList = iter->second;
-        for (size_t i = 0; i < featureList.size(); ++i) {
-            allFeatureSets[iter->first].push_back(featureList[i]);
-        }
-    }
-    
-    return allFeatureSets;
-}
-    
-void
-PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
-{
-    for (size_t i = 0; i < m_channels; ++i) {
-        m_queue[i]->peek(m_buffers[i], m_blockSize);
-    }
-
-    long frame = m_frame;
-    RealTime timestamp = RealTime::frame2RealTime
-        (frame, int(m_inputSampleRate + 0.5));
-
-    FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
-    
-    for (FeatureSet::iterator iter = featureSet.begin();
-         iter != featureSet.end(); ++iter) {
-
-        int outputNo = iter->first;
-
-        if (m_rewriteOutputTimes[outputNo]) {
-            
-            FeatureList featureList = iter->second;
-	
-            for (size_t i = 0; i < featureList.size(); ++i) {
-
-                switch (m_outputs[outputNo].sampleType) {
-
-                case OutputDescriptor::OneSamplePerStep:
-                    // use our internal timestamp, always
-                    featureList[i].timestamp = timestamp;
-                    featureList[i].hasTimestamp = true;
-                    break;
-
-                case OutputDescriptor::FixedSampleRate:
-                    // use our internal timestamp if feature lacks one
-                    if (!featureList[i].hasTimestamp) {
-                        featureList[i].timestamp = timestamp;
-                        featureList[i].hasTimestamp = true;
-                    }
-                    break;
-
-                case OutputDescriptor::VariableSampleRate:
-                    break;		// plugin must set timestamp
-
-                default:
-                    break;
-                }
-            
-                allFeatureSets[outputNo].push_back(featureList[i]);
-            }
-        } else {
-            for (size_t i = 0; i < iter->second.size(); ++i) {
-                allFeatureSets[outputNo].push_back(iter->second[i]);
-            }
-        }
-    }
-    
-    // step forward
-
-    for (size_t i = 0; i < m_channels; ++i) {
-        m_queue[i]->skip(m_stepSize);
-    }
-    
-    // increment internal frame counter each time we step forward
-    m_frame += m_stepSize;
-}
-
-}
-	
-}
-
-
--- a/vamp-sdk/hostext/PluginBufferingAdapter.h	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +0,0 @@
-/* -*- 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-2007 Chris Cannam and QMUL.
-    This file by Mark Levy and Chris Cannam, Copyright 2007-2008 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 _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
-#define _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
-
-#include "PluginWrapper.h"
-
-namespace Vamp {
-	
-namespace HostExt {
-		
-/**
- * \class PluginBufferingAdapter PluginBufferingAdapter.h <vamp-sdk/hostext/PluginBufferingAdapter.h>
- *
- * PluginBufferingAdapter is a Vamp plugin adapter that allows plugins
- * to be used by a host supplying an audio stream in non-overlapping
- * buffers of arbitrary size.
- *
- * A host using PluginBufferingAdapter may ignore the preferred step
- * and block size reported by the plugin, and still expect the plugin
- * to run.  The value of blockSize and stepSize passed to initialise
- * should be the size of the buffer which the host will supply; the
- * stepSize should be equal to the blockSize.
- *
- * If the internal step size used for the plugin differs from that
- * supplied by the host, the adapter will modify the sample type and
- * rate specifications for the plugin outputs appropriately, and set
- * timestamps on the output features for outputs that formerly used a
- * different sample rate specification.  This is necessary in order to
- * obtain correct time stamping.
- * 
- * In other respects, the PluginBufferingAdapter behaves identically
- * to the plugin that it wraps. The wrapped plugin will be deleted
- * when the wrapper is deleted.
- */
-		
-class PluginBufferingAdapter : public PluginWrapper
-{
-public:
-    PluginBufferingAdapter(Plugin *plugin); // I take ownership of plugin
-    virtual ~PluginBufferingAdapter();
-
-    /**
-     * Return the preferred step size for this adapter.
-     * 
-     * Because of the way this adapter works, its preferred step size
-     * will always be the same as its preferred block size.  This may
-     * or may not be the same as the preferred step size of the
-     * underlying plugin, which may be obtained by calling
-     * getPluginPreferredStepSize().
-     */
-    size_t getPreferredStepSize() const;
-
-    /**
-     * Return the preferred block size for this adapter.
-     * 
-     * This may or may not be the same as the preferred block size of
-     * the underlying plugin, which may be obtained by calling
-     * getPluginPreferredBlockSize().
-     *
-     * Note that this adapter may be initialised with any block size,
-     * not just its supposedly preferred one.
-     */
-    size_t getPreferredBlockSize() const;
-
-    /**
-     * Initialise the adapter (and therefore the plugin) for the given
-     * number of channels.  Initialise the adapter for the given step
-     * and block size, which must be equal.
-     *
-     * The step and block size used for the underlying plugin will
-     * depend on its preferences, or any values previously passed to
-     * setPluginStepSize and setPluginBlockSize.
-     */
-    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
-
-    /**
-     * Return the preferred step size of the plugin wrapped by this
-     * adapter.
-     *
-     * This is included mainly for informational purposes.  This value
-     * is not likely to be a valid step size for the adapter itself,
-     * and it is not usually of any use in interpreting the results
-     * (because the adapter re-writes OneSamplePerStep outputs to
-     * FixedSampleRate so that the hop size no longer needs to be
-     * known beforehand in order to interpret them).
-     */
-    size_t getPluginPreferredStepSize() const;
-
-    /** 
-     * Return the preferred block size of the plugin wrapped by this
-     * adapter.
-     *
-     * This is included mainly for informational purposes.
-     */
-    size_t getPluginPreferredBlockSize() const;
-
-    /**
-     * Set the step size that will be used for the underlying plugin
-     * when initialise() is called.  If this is not set, the plugin's
-     * own preferred step size will be used.  You will not usually
-     * need to call this function.  If you do call it, it must be
-     * before the first call to initialise().
-     */
-    void setPluginStepSize(size_t stepSize);
-
-    /**
-     * Set the block size that will be used for the underlying plugin
-     * when initialise() is called.  If this is not set, the plugin's
-     * own preferred block size will be used.  You will not usually
-     * need to call this function.  If you do call it, it must be
-     * before the first call to initialise().
-     */
-    void setPluginBlockSize(size_t blockSize);
-
-    /**
-     * Return the step and block sizes that were actually used when
-     * initialising the underlying plugin.
-     *
-     * This is included mainly for informational purposes.  You will
-     * not usually need to call this function.  If this is called
-     * before initialise(), it will return 0 for both values.  If it
-     * is called after a failed call to initialise(), it will return
-     * the values that were used in the failed call to the plugin's
-     * initialise() function.
-     */
-    void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
-
-    OutputList getOutputDescriptors() const;
-
-    void reset();
-
-    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
-    
-    FeatureSet getRemainingFeatures();
-    
-protected:
-    class Impl;
-    Impl *m_impl;
-};
-    
-}
-
-}
-
-#endif
--- a/vamp-sdk/hostext/PluginChannelAdapter.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,266 +0,0 @@
-/* -*- 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-2007 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.
-*/
-
-#include "PluginChannelAdapter.h"
-
-namespace Vamp {
-
-namespace HostExt {
-
-class PluginChannelAdapter::Impl
-{
-public:
-    Impl(Plugin *plugin);
-    ~Impl();
-
-    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
-
-    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
-    FeatureSet processInterleaved(const float *inputBuffers, RealTime timestamp);
-
-protected:
-    Plugin *m_plugin;
-    size_t m_blockSize;
-    size_t m_inputChannels;
-    size_t m_pluginChannels;
-    float **m_buffer;
-    float **m_deinterleave;
-    const float **m_forwardPtrs;
-};
-
-PluginChannelAdapter::PluginChannelAdapter(Plugin *plugin) :
-    PluginWrapper(plugin)
-{
-    m_impl = new Impl(plugin);
-}
-
-PluginChannelAdapter::~PluginChannelAdapter()
-{
-    delete m_impl;
-}
-
-bool
-PluginChannelAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    return m_impl->initialise(channels, stepSize, blockSize);
-}
-
-PluginChannelAdapter::FeatureSet
-PluginChannelAdapter::process(const float *const *inputBuffers,
-                              RealTime timestamp)
-{
-    return m_impl->process(inputBuffers, timestamp);
-}
-
-PluginChannelAdapter::FeatureSet
-PluginChannelAdapter::processInterleaved(const float *inputBuffers,
-                                         RealTime timestamp)
-{
-    return m_impl->processInterleaved(inputBuffers, timestamp);
-}
-
-PluginChannelAdapter::Impl::Impl(Plugin *plugin) :
-    m_plugin(plugin),
-    m_blockSize(0),
-    m_inputChannels(0),
-    m_pluginChannels(0),
-    m_buffer(0),
-    m_deinterleave(0),
-    m_forwardPtrs(0)
-{
-}
-
-PluginChannelAdapter::Impl::~Impl()
-{
-    // the adapter will delete the plugin
-
-    if (m_buffer) {
-        if (m_inputChannels > m_pluginChannels) {
-            delete[] m_buffer[0];
-        } else {
-            for (size_t i = 0; i < m_pluginChannels - m_inputChannels; ++i) {
-                delete[] m_buffer[i];
-            }
-        }
-        delete[] m_buffer;
-        m_buffer = 0;
-    }
-
-    if (m_deinterleave) {
-        for (size_t i = 0; i < m_inputChannels; ++i) {
-            delete[] m_deinterleave[i];
-        }
-        delete[] m_deinterleave;
-        m_deinterleave = 0;
-    }
-
-    if (m_forwardPtrs) {
-        delete[] m_forwardPtrs;
-        m_forwardPtrs = 0;
-    }
-}
-
-bool
-PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    m_blockSize = blockSize;
-
-    size_t minch = m_plugin->getMinChannelCount();
-    size_t maxch = m_plugin->getMaxChannelCount();
-
-    m_inputChannels = channels;
-
-    if (m_inputChannels < minch) {
-
-        m_forwardPtrs = new const float *[minch];
-
-        if (m_inputChannels > 1) {
-            // We need a set of zero-valued buffers to add to the
-            // forwarded pointers
-            m_buffer = new float*[minch - channels];
-            for (size_t i = 0; i < minch; ++i) {
-                m_buffer[i] = new float[blockSize];
-                for (size_t j = 0; j < blockSize; ++j) {
-                    m_buffer[i][j] = 0.f;
-                }
-            }
-        }
-
-        m_pluginChannels = minch;
-
-        std::cerr << "PluginChannelAdapter::initialise: expanding " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
-
-    } else if (m_inputChannels > maxch) {
-
-        // We only need m_buffer if we are mixing down to a single
-        // channel -- otherwise we can just forward the same float* as
-        // passed in to process(), expecting the excess to be ignored
-
-        if (maxch == 1) {
-            m_buffer = new float *[1];
-            m_buffer[0] = new float[blockSize];
-
-            std::cerr << "PluginChannelAdapter::initialise: mixing " << m_inputChannels << " to mono for plugin" << std::endl;
-
-        } else {
-            
-            std::cerr << "PluginChannelAdapter::initialise: reducing " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
-        }
-
-        m_pluginChannels = maxch;
-
-    } else {
- 
-        std::cerr << "PluginChannelAdapter::initialise: accepting given number of channels (" << m_inputChannels << ")" << std::endl;
-        m_pluginChannels = m_inputChannels;
-    }
-
-    return m_plugin->initialise(m_pluginChannels, stepSize, blockSize);
-}
-
-PluginChannelAdapter::FeatureSet
-PluginChannelAdapter::Impl::processInterleaved(const float *inputBuffers,
-                                               RealTime timestamp)
-{
-    if (!m_deinterleave) {
-        m_deinterleave = new float *[m_inputChannels];
-        for (size_t i = 0; i < m_inputChannels; ++i) {
-            m_deinterleave[i] = new float[m_blockSize];
-        }
-    }
-
-    for (size_t i = 0; i < m_inputChannels; ++i) {
-        for (size_t j = 0; j < m_blockSize; ++j) {
-            m_deinterleave[i][j] = inputBuffers[j * m_inputChannels + i];
-        }
-    }
-
-    return process(m_deinterleave, timestamp);
-}
-
-PluginChannelAdapter::FeatureSet
-PluginChannelAdapter::Impl::process(const float *const *inputBuffers,
-                                    RealTime timestamp)
-{
-//    std::cerr << "PluginChannelAdapter::process: " << m_inputChannels << " -> " << m_pluginChannels << " channels" << std::endl;
-
-    if (m_inputChannels < m_pluginChannels) {
-
-        if (m_inputChannels == 1) {
-            for (size_t i = 0; i < m_pluginChannels; ++i) {
-                m_forwardPtrs[i] = inputBuffers[0];
-            }
-        } else {
-            for (size_t i = 0; i < m_inputChannels; ++i) {
-                m_forwardPtrs[i] = inputBuffers[i];
-            }
-            for (size_t i = m_inputChannels; i < m_pluginChannels; ++i) {
-                m_forwardPtrs[i] = m_buffer[i - m_inputChannels];
-            }
-        }
-
-        return m_plugin->process(m_forwardPtrs, timestamp);
-
-    } else if (m_inputChannels > m_pluginChannels) {
-
-        if (m_pluginChannels == 1) {
-            for (size_t j = 0; j < m_blockSize; ++j) {
-                m_buffer[0][j] = inputBuffers[0][j];
-            }
-            for (size_t i = 1; i < m_inputChannels; ++i) {
-                for (size_t j = 0; j < m_blockSize; ++j) {
-                    m_buffer[0][j] += inputBuffers[i][j];
-                }
-            }
-            for (size_t j = 0; j < m_blockSize; ++j) {
-                m_buffer[0][j] /= m_inputChannels;
-            }
-            return m_plugin->process(m_buffer, timestamp);
-        } else {
-            return m_plugin->process(inputBuffers, timestamp);
-        }
-
-    } else {
-
-        return m_plugin->process(inputBuffers, timestamp);
-    }
-}
-
-}
-
-}
-
-
--- a/vamp-sdk/hostext/PluginChannelAdapter.h	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-/* -*- 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-2007 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 _VAMP_PLUGIN_CHANNEL_ADAPTER_H_
-#define _VAMP_PLUGIN_CHANNEL_ADAPTER_H_
-
-#include "PluginWrapper.h"
-
-namespace Vamp {
-
-namespace HostExt {
-
-/**
- * \class PluginChannelAdapter PluginChannelAdapter.h <vamp-sdk/hostext/PluginChannelAdapter.h>
- *
- * PluginChannelAdapter is a Vamp plugin adapter that implements a
- * policy for management of plugins that expect a different number of
- * input channels from the number actually available in the source
- * audio data.
- *
- * A host using PluginChannelAdapter may ignore the getMinChannelCount
- * and getMaxChannelCount reported by the plugin, and still expect the
- * plugin to run.
- *
- * PluginChannelAdapter implements the following policy:
- *
- *  - If the plugin supports the provided number of channels directly,
- *  PluginChannelAdapter will just run the plugin as normal.
- *
- *  - If the plugin only supports exactly one channel but more than
- *  one channel is provided, PluginChannelAdapter will use the mean of
- *  the channels.  This ensures that the resulting values remain
- *  within the same magnitude range as expected for mono data.
- *
- *  - If the plugin requires more than one channel but exactly one is
- *  provided, the provided channel will be duplicated across all the
- *  plugin input channels.
- *
- * If none of the above apply:
- * 
- *  - If the plugin requires more channels than are provided, the
- *  minimum acceptable number of channels will be produced by adding
- *  empty (zero valued) channels to those provided.
- *
- *  - If the plugin requires fewer channels than are provided, the
- *  maximum acceptable number of channels will be produced by
- *  discarding the excess channels.
- *
- * Hosts requiring a different channel policy from the above will need
- * to implement it themselves, instead of using PluginChannelAdapter.
- *
- * Note that PluginChannelAdapter does not override the minimum and
- * maximum channel counts returned by the wrapped plugin.  The host
- * will need to be aware that it is using a PluginChannelAdapter, and
- * be prepared to ignore these counts as necessary.  (This contrasts
- * with the approach used in PluginInputDomainAdapter, which aims to
- * make the host completely unaware of which underlying input domain
- * is in fact in use.)
- * 
- * (The rationale for this is that a host may wish to use the
- * PluginChannelAdapter but still discriminate in some way on the
- * basis of the number of channels actually supported.  For example, a
- * simple stereo audio host may prefer to reject plugins that require
- * more than two channels on the grounds that doesn't actually
- * understand what they are for, rather than allow the channel adapter
- * to make a potentially meaningless channel conversion for them.)
- *
- * In every respect other than its management of channels, the
- * PluginChannelAdapter behaves identically to the plugin that it
- * wraps.  The wrapped plugin will be deleted when the wrapper is
- * deleted.
- *
- * \note This class was introduced in version 1.1 of the Vamp plugin SDK.
- */
-
-class PluginChannelAdapter : public PluginWrapper
-{
-public:
-    PluginChannelAdapter(Plugin *plugin); // I take ownership of plugin
-    virtual ~PluginChannelAdapter();
-
-    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
-
-    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
-
-    /**
-     * Call process(), providing interleaved audio data with the
-     * number of channels passed to initialise().  The adapter will
-     * de-interleave into temporary buffers as appropriate before
-     * calling process().
-     *
-     * \note This function was introduced in version 1.4 of the Vamp
-     * plugin SDK.
-     */
-    FeatureSet processInterleaved(const float *inputBuffer, RealTime timestamp);
-
-protected:
-    class Impl;
-    Impl *m_impl;
-};
-
-}
-
-}
-
-#endif
--- a/vamp-sdk/hostext/PluginInputDomainAdapter.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,578 +0,0 @@
-/* -*- 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-2007 Chris Cannam and QMUL.
-  
-    This file is based in part on Don Cross's public domain FFT
-    implementation.
-
-    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 "PluginInputDomainAdapter.h"
-
-#include <cmath>
-
-
-/**
- * If you want to compile using FFTW instead of the built-in FFT
- * implementation for the PluginInputDomainAdapter, define HAVE_FFTW3
- * in the Makefile.
- *
- * Be aware that FFTW is licensed under the GPL -- unlike this SDK,
- * which is provided under a more liberal BSD license in order to
- * permit use in closed source applications.  The use of FFTW would
- * mean that your code would need to be licensed under the GPL as
- * well.  Do not define this symbol unless you understand and accept
- * the implications of this.
- *
- * Parties such as Linux distribution packagers who redistribute this
- * SDK for use in other programs should _not_ define this symbol, as
- * it would change the effective licensing terms under which the SDK
- * was available to third party developers.
- *
- * The default is not to use FFTW, and to use the built-in FFT instead.
- * 
- * Note: The FFTW code uses FFTW_MEASURE, and so will perform badly on
- * its first invocation unless the host has saved and restored FFTW
- * wisdom (see the FFTW documentation).
- */
-#ifdef HAVE_FFTW3
-#include <fftw3.h>
-#endif
-
-
-namespace Vamp {
-
-namespace HostExt {
-
-class PluginInputDomainAdapter::Impl
-{
-public:
-    Impl(Plugin *plugin, float inputSampleRate);
-    ~Impl();
-    
-    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
-
-    size_t getPreferredStepSize() const;
-    size_t getPreferredBlockSize() const;
-
-    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
-    
-    RealTime getTimestampAdjustment() const;
-
-protected:
-    Plugin *m_plugin;
-    float m_inputSampleRate;
-    int m_channels;
-    int m_blockSize;
-    float **m_freqbuf;
-
-    double *m_ri;
-    double *m_window;
-
-#ifdef HAVE_FFTW3
-    fftw_plan m_plan;
-    fftw_complex *m_cbuf;
-#else
-    double *m_ro;
-    double *m_io;
-    void fft(unsigned int n, bool inverse,
-             double *ri, double *ii, double *ro, double *io);
-#endif
-
-    size_t makeBlockSizeAcceptable(size_t) const;
-};
-
-PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
-    PluginWrapper(plugin)
-{
-    m_impl = new Impl(plugin, m_inputSampleRate);
-}
-
-PluginInputDomainAdapter::~PluginInputDomainAdapter()
-{
-    delete m_impl;
-}
-  
-bool
-PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    return m_impl->initialise(channels, stepSize, blockSize);
-}
-
-Plugin::InputDomain
-PluginInputDomainAdapter::getInputDomain() const
-{
-    return TimeDomain;
-}
-
-size_t
-PluginInputDomainAdapter::getPreferredStepSize() const
-{
-    return m_impl->getPreferredStepSize();
-}
-
-size_t
-PluginInputDomainAdapter::getPreferredBlockSize() const
-{
-    return m_impl->getPreferredBlockSize();
-}
-
-Plugin::FeatureSet
-PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
-{
-    return m_impl->process(inputBuffers, timestamp);
-}
-
-RealTime
-PluginInputDomainAdapter::getTimestampAdjustment() const
-{
-    return m_impl->getTimestampAdjustment();
-}
-
-
-PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
-    m_plugin(plugin),
-    m_inputSampleRate(inputSampleRate),
-    m_channels(0),
-    m_blockSize(0),
-    m_freqbuf(0),
-    m_ri(0),
-    m_window(0),
-#ifdef HAVE_FFTW3
-    m_plan(0),
-    m_cbuf(0)
-#else
-    m_ro(0),
-    m_io(0)
-#endif
-{
-}
-
-PluginInputDomainAdapter::Impl::~Impl()
-{
-    // the adapter will delete the plugin
-
-    if (m_channels > 0) {
-        for (int c = 0; c < m_channels; ++c) {
-            delete[] m_freqbuf[c];
-        }
-        delete[] m_freqbuf;
-#ifdef HAVE_FFTW3
-        if (m_plan) {
-            fftw_destroy_plan(m_plan);
-            fftw_free(m_ri);
-            fftw_free(m_cbuf);
-            m_plan = 0;
-        }
-#else
-        delete[] m_ri;
-        delete[] m_ro;
-        delete[] m_io;
-#endif
-        delete[] m_window;
-    }
-}
-
-// for some visual studii apparently
-#ifndef M_PI
-#define M_PI 3.14159265358979232846
-#endif
-    
-bool
-PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    if (m_plugin->getInputDomain() == TimeDomain) {
-
-        m_blockSize = int(blockSize);
-        m_channels = int(channels);
-
-        return m_plugin->initialise(channels, stepSize, blockSize);
-    }
-
-    if (blockSize < 2) {
-        std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not supported" << std::endl;
-        return false;
-    }                
-        
-    if (blockSize & (blockSize-1)) {
-        std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
-        return false;
-    }
-
-    if (m_channels > 0) {
-        for (int c = 0; c < m_channels; ++c) {
-            delete[] m_freqbuf[c];
-        }
-        delete[] m_freqbuf;
-#ifdef HAVE_FFTW3
-        if (m_plan) {
-            fftw_destroy_plan(m_plan);
-            fftw_free(m_ri);
-            fftw_free(m_cbuf);
-            m_plan = 0;
-        }
-#else
-        delete[] m_ri;
-        delete[] m_ro;
-        delete[] m_io;
-#endif
-        delete[] m_window;
-    }
-
-    m_blockSize = int(blockSize);
-    m_channels = int(channels);
-
-    m_freqbuf = new float *[m_channels];
-    for (int c = 0; c < m_channels; ++c) {
-        m_freqbuf[c] = new float[m_blockSize + 2];
-    }
-    m_window = new double[m_blockSize];
-
-    for (int i = 0; i < m_blockSize; ++i) {
-        // Hanning window
-        m_window[i] = (0.50 - 0.50 * cos((2.0 * M_PI * i) / m_blockSize));
-    }
-
-#ifdef HAVE_FFTW3
-    m_ri = (double *)fftw_malloc(blockSize * sizeof(double));
-    m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex));
-    m_plan = fftw_plan_dft_r2c_1d(blockSize, m_ri, m_cbuf, FFTW_MEASURE);
-#else
-    m_ri = new double[m_blockSize];
-    m_ro = new double[m_blockSize];
-    m_io = new double[m_blockSize];
-#endif
-
-    return m_plugin->initialise(channels, stepSize, blockSize);
-}
-
-size_t
-PluginInputDomainAdapter::Impl::getPreferredStepSize() const
-{
-    size_t step = m_plugin->getPreferredStepSize();
-
-    if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) {
-        step = getPreferredBlockSize() / 2;
-    }
-
-    return step;
-}
-
-size_t
-PluginInputDomainAdapter::Impl::getPreferredBlockSize() const
-{
-    size_t block = m_plugin->getPreferredBlockSize();
-
-    if (m_plugin->getInputDomain() == FrequencyDomain) {
-        if (block == 0) {
-            block = 1024;
-        } else {
-            block = makeBlockSizeAcceptable(block);
-        }
-    }
-
-    return block;
-}
-
-size_t
-PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
-{
-    if (blockSize < 2) {
-
-        std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not" << std::endl
-                  << "supported, increasing from " << blockSize << " to 2" << std::endl;
-        blockSize = 2;
-        
-    } else if (blockSize & (blockSize-1)) {
-            
-#ifdef HAVE_FFTW3
-        // not an issue with FFTW
-#else
-
-        // not a power of two, can't handle that with our built-in FFT
-        // implementation
-
-        size_t nearest = blockSize;
-        size_t power = 0;
-        while (nearest > 1) {
-            nearest >>= 1;
-            ++power;
-        }
-        nearest = 1;
-        while (power) {
-            nearest <<= 1;
-            --power;
-        }
-        
-        if (blockSize - nearest > (nearest*2) - blockSize) {
-            nearest = nearest*2;
-        }
-        
-        std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
-        blockSize = nearest;
-
-#endif
-    }
-
-    return blockSize;
-}
-
-RealTime
-PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
-{
-    if (m_plugin->getInputDomain() == TimeDomain) {
-        return RealTime::zeroTime;
-    } else {
-        return RealTime::frame2RealTime
-            (m_blockSize/2, int(m_inputSampleRate + 0.5));
-    }
-}
-
-Plugin::FeatureSet
-PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
-                                        RealTime timestamp)
-{
-    if (m_plugin->getInputDomain() == TimeDomain) {
-        return m_plugin->process(inputBuffers, timestamp);
-    }
-
-    // The timestamp supplied should be (according to the Vamp::Plugin
-    // spec) the time of the start of the time-domain input block.
-    // However, we want to pass to the plugin an FFT output calculated
-    // from the block of samples _centred_ on that timestamp.
-    // 
-    // We have two options:
-    // 
-    // 1. Buffer the input, calculating the fft of the values at the
-    // passed-in block minus blockSize/2 rather than starting at the
-    // passed-in block.  So each time we call process on the plugin,
-    // we are passing in the same timestamp as was passed to our own
-    // process plugin, but not (the frequency domain representation
-    // of) the same set of samples.  Advantages: avoids confusion in
-    // the host by ensuring the returned values have timestamps
-    // comparable with that passed in to this function (in fact this
-    // is pretty much essential for one-value-per-block outputs);
-    // consistent with hosts such as SV that deal with the
-    // frequency-domain transform themselves.  Disadvantages: means
-    // making the not necessarily correct assumption that the samples
-    // preceding the first official block are all zero (or some other
-    // known value).
-    //
-    // 2. Increase the passed-in timestamps by half the blocksize.  So
-    // when we call process, we are passing in the frequency domain
-    // representation of the same set of samples as passed to us, but
-    // with a different timestamp.  Advantages: simplicity; avoids
-    // iffy assumption mentioned above.  Disadvantages: inconsistency
-    // with SV in cases where stepSize != blockSize/2; potential
-    // confusion arising from returned timestamps being calculated
-    // from the adjusted input timestamps rather than the original
-    // ones (and inaccuracy where the returned timestamp is implied,
-    // as in one-value-per-block).
-    //
-    // Neither way is ideal, but I don't think either is strictly
-    // incorrect either.  I think this is just a case where the same
-    // plugin can legitimately produce differing results from the same
-    // input data, depending on how that data is packaged.
-    // 
-    // We'll go for option 2, adjusting the timestamps.  Note in
-    // particular that this means some results can differ from those
-    // produced by SV.
-
-//    std::cerr << "PluginInputDomainAdapter: sampleRate " << m_inputSampleRate << ", blocksize " << m_blockSize << ", adjusting time from " << timestamp;
-
-    timestamp = timestamp + getTimestampAdjustment();
-
-//    std::cerr << " to " << timestamp << std::endl;
-
-    for (int c = 0; c < m_channels; ++c) {
-
-        for (int i = 0; i < m_blockSize; ++i) {
-            m_ri[i] = double(inputBuffers[c][i]) * m_window[i];
-        }
-
-        for (int i = 0; i < m_blockSize/2; ++i) {
-            // FFT shift
-            double value = m_ri[i];
-            m_ri[i] = m_ri[i + m_blockSize/2];
-            m_ri[i + m_blockSize/2] = value;
-        }
-
-#ifdef HAVE_FFTW3
-
-        fftw_execute(m_plan);
-
-        for (int i = 0; i <= m_blockSize/2; ++i) {
-            m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
-            m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
-        }
-
-#else
-
-        fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
-
-        for (int i = 0; i <= m_blockSize/2; ++i) {
-            m_freqbuf[c][i * 2] = float(m_ro[i]);
-            m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
-        }
-
-#endif
-    }
-
-    return m_plugin->process(m_freqbuf, timestamp);
-}
-
-#ifndef HAVE_FFTW3
-
-void
-PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse,
-                                    double *ri, double *ii, double *ro, double *io)
-{
-    if (!ri || !ro || !io) return;
-
-    unsigned int bits;
-    unsigned int i, j, k, m;
-    unsigned int blockSize, blockEnd;
-
-    double tr, ti;
-
-    if (n < 2) return;
-    if (n & (n-1)) return;
-
-    double angle = 2.0 * M_PI;
-    if (inverse) angle = -angle;
-
-    for (i = 0; ; ++i) {
-	if (n & (1 << i)) {
-	    bits = i;
-	    break;
-	}
-    }
-
-    static unsigned int tableSize = 0;
-    static int *table = 0;
-
-    if (tableSize != n) {
-
-	delete[] table;
-
-	table = new int[n];
-
-	for (i = 0; i < n; ++i) {
-	
-	    m = i;
-
-	    for (j = k = 0; j < bits; ++j) {
-		k = (k << 1) | (m & 1);
-		m >>= 1;
-	    }
-
-	    table[i] = k;
-	}
-
-	tableSize = n;
-    }
-
-    if (ii) {
-	for (i = 0; i < n; ++i) {
-	    ro[table[i]] = ri[i];
-	    io[table[i]] = ii[i];
-	}
-    } else {
-	for (i = 0; i < n; ++i) {
-	    ro[table[i]] = ri[i];
-	    io[table[i]] = 0.0;
-	}
-    }
-
-    blockEnd = 1;
-
-    for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
-
-	double delta = angle / (double)blockSize;
-	double sm2 = -sin(-2 * delta);
-	double sm1 = -sin(-delta);
-	double cm2 = cos(-2 * delta);
-	double cm1 = cos(-delta);
-	double w = 2 * cm1;
-	double ar[3], ai[3];
-
-	for (i = 0; i < n; i += blockSize) {
-
-	    ar[2] = cm2;
-	    ar[1] = cm1;
-
-	    ai[2] = sm2;
-	    ai[1] = sm1;
-
-	    for (j = i, m = 0; m < blockEnd; j++, m++) {
-
-		ar[0] = w * ar[1] - ar[2];
-		ar[2] = ar[1];
-		ar[1] = ar[0];
-
-		ai[0] = w * ai[1] - ai[2];
-		ai[2] = ai[1];
-		ai[1] = ai[0];
-
-		k = j + blockEnd;
-		tr = ar[0] * ro[k] - ai[0] * io[k];
-		ti = ar[0] * io[k] + ai[0] * ro[k];
-
-		ro[k] = ro[j] - tr;
-		io[k] = io[j] - ti;
-
-		ro[j] += tr;
-		io[j] += ti;
-	    }
-	}
-
-	blockEnd = blockSize;
-    }
-
-    if (inverse) {
-
-	double denom = (double)n;
-
-	for (i = 0; i < n; i++) {
-	    ro[i] /= denom;
-	    io[i] /= denom;
-	}
-    }
-}
-
-#endif
-
-}
-        
-}
-
--- a/vamp-sdk/hostext/PluginInputDomainAdapter.h	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-/* -*- 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-2007 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 _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_
-#define _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_
-
-#include "PluginWrapper.h"
-
-namespace Vamp {
-
-namespace HostExt {
-
-/**
- * \class PluginInputDomainAdapter PluginInputDomainAdapter.h <vamp-sdk/hostext/PluginInputDomainAdapter.h>
- * 
- * PluginInputDomainAdapter is a Vamp plugin adapter that converts
- * time-domain input into frequency-domain input for plugins that need
- * it.  This permits a host to use time- and frequency-domain plugins
- * interchangeably without needing to handle the conversion itself.
- *
- * This adapter uses a basic Hanning windowed FFT that supports
- * power-of-two block sizes only.  If a frequency domain plugin
- * requests a non-power-of-two blocksize, the adapter will adjust it
- * to a nearby power of two instead.  Thus, getPreferredBlockSize()
- * will always return a power of two if the wrapped plugin is a
- * frequency domain one.  If the plugin doesn't accept the adjusted
- * power of two block size, initialise() will fail.
- *
- * The adapter provides no way for the host to discover whether the
- * underlying plugin is actually a time or frequency domain plugin
- * (except that if the preferred block size is not a power of two, it
- * must be a time domain plugin).
- *
- * The FFT implementation is simple and self-contained, but unlikely
- * to be the fastest available: a host can usually do better if it
- * cares enough.
- *
- * In every respect other than its input domain handling, the
- * PluginInputDomainAdapter behaves identically to the plugin that it
- * wraps.  The wrapped plugin will be deleted when the wrapper is
- * deleted.
- *
- * \note This class was introduced in version 1.1 of the Vamp plugin SDK.
- */
-
-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);
-
-    InputDomain getInputDomain() const;
-
-    size_t getPreferredStepSize() const;
-    size_t getPreferredBlockSize() const;
-
-    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
-
-    /**
-     * Return the amount by which the timestamps supplied to process()
-     * are being incremented when they are passed to the plugin's own
-     * process() implementation.
-     *
-     * The Vamp API mandates that the timestamp passed to the plugin
-     * for time-domain input should be the time of the first sample in
-     * the block, but the timestamp passed for frequency-domain input
-     * should be the timestamp of the centre of the block.
-     *
-     * The PluginInputDomainAdapter adjusts its timestamps properly so
-     * that the plugin receives correct times, but in some
-     * circumstances (such as for establishing the correct timing of
-     * implicitly-timed features, i.e. features without their own
-     * timestamps) the host may need to be aware that this adjustment
-     * is taking place.
-     *
-     * If the plugin requires time-domain input, this function will
-     * return zero.  The result of calling this function before
-     * initialise() has been called is undefined.
-     */
-    RealTime getTimestampAdjustment() const;
-
-protected:
-    class Impl;
-    Impl *m_impl;
-};
-
-}
-
-}
-
-#endif
--- a/vamp-sdk/hostext/PluginLoader.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,636 +0,0 @@
-/* -*- 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-2007 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.
-*/
-
-#include "vamp-sdk/PluginHostAdapter.h"
-#include "PluginLoader.h"
-#include "PluginInputDomainAdapter.h"
-#include "PluginChannelAdapter.h"
-#include "PluginBufferingAdapter.h"
-
-#include <fstream>
-#include <cctype> // tolower
-
-#include <cstring>
-
-#ifdef _WIN32
-
-#include <windows.h>
-#include <tchar.h>
-#define PLUGIN_SUFFIX "dll"
-
-#else /* ! _WIN32 */
-
-#include <dirent.h>
-#include <dlfcn.h>
-
-#ifdef __APPLE__
-#define PLUGIN_SUFFIX "dylib"
-#else /* ! __APPLE__ */
-#define PLUGIN_SUFFIX "so"
-#endif /* ! __APPLE__ */
-
-#endif /* ! _WIN32 */
-
-using namespace std;
-
-namespace Vamp {
-	
-namespace HostExt {
-
-class PluginLoader::Impl
-{
-public:
-    Impl();
-    virtual ~Impl();
-
-    PluginKeyList listPlugins();
-
-    Plugin *loadPlugin(PluginKey key,
-                       float inputSampleRate,
-                       int adapterFlags);
-
-    PluginKey composePluginKey(string libraryName, string identifier);
-
-    PluginCategoryHierarchy getPluginCategory(PluginKey key);
-
-    string getLibraryPathForPlugin(PluginKey key);
-
-    static void setInstanceToClean(PluginLoader *instance);
-
-protected:
-    class PluginDeletionNotifyAdapter : public PluginWrapper {
-    public:
-        PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
-        virtual ~PluginDeletionNotifyAdapter();
-    protected:
-        Impl *m_loader;
-    };
-
-    class InstanceCleaner {
-    public:
-        InstanceCleaner() : m_instance(0) { }
-        ~InstanceCleaner() { delete m_instance; }
-        void setInstance(PluginLoader *instance) { m_instance = instance; }
-    protected:
-        PluginLoader *m_instance;
-    };
-
-    virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
-
-    map<PluginKey, string> m_pluginLibraryNameMap;
-    bool m_allPluginsEnumerated;
-    void enumeratePlugins(PluginKey forPlugin = "");
-
-    map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
-    void generateTaxonomy();
-
-    map<Plugin *, void *> m_pluginLibraryHandleMap;
-
-    bool decomposePluginKey(PluginKey key,
-                            string &libraryName, string &identifier);
-
-    void *loadLibrary(string path);
-    void unloadLibrary(void *handle);
-    void *lookupInLibrary(void *handle, const char *symbol);
-
-    string splicePath(string a, string b);
-    vector<string> listFiles(string dir, string ext);
-    
-    static InstanceCleaner m_cleaner;
-};
-
-PluginLoader *
-PluginLoader::m_instance = 0;
-
-PluginLoader::Impl::InstanceCleaner
-PluginLoader::Impl::m_cleaner;
-
-PluginLoader::PluginLoader()
-{
-    m_impl = new Impl();
-}
-
-PluginLoader::~PluginLoader()
-{
-    delete m_impl;
-}
-
-PluginLoader *
-PluginLoader::getInstance()
-{
-    if (!m_instance) {
-        // The cleaner doesn't own the instance, because we leave the
-        // instance pointer in the base class for binary backwards
-        // compatibility reasons and to avoid waste
-        m_instance = new PluginLoader();
-        Impl::setInstanceToClean(m_instance);
-    }
-    return m_instance;
-}
-
-vector<PluginLoader::PluginKey>
-PluginLoader::listPlugins() 
-{
-    return m_impl->listPlugins();
-}
-
-Plugin *
-PluginLoader::loadPlugin(PluginKey key,
-                         float inputSampleRate,
-                         int adapterFlags)
-{
-    return m_impl->loadPlugin(key, inputSampleRate, adapterFlags);
-}
-
-PluginLoader::PluginKey
-PluginLoader::composePluginKey(string libraryName, string identifier) 
-{
-    return m_impl->composePluginKey(libraryName, identifier);
-}
-
-PluginLoader::PluginCategoryHierarchy
-PluginLoader::getPluginCategory(PluginKey key)
-{
-    return m_impl->getPluginCategory(key);
-}
-
-string
-PluginLoader::getLibraryPathForPlugin(PluginKey key)
-{
-    return m_impl->getLibraryPathForPlugin(key);
-}
- 
-PluginLoader::Impl::Impl() :
-    m_allPluginsEnumerated(false)
-{
-}
-
-PluginLoader::Impl::~Impl()
-{
-}
-
-void
-PluginLoader::Impl::setInstanceToClean(PluginLoader *instance)
-{
-    m_cleaner.setInstance(instance);
-}
-
-vector<PluginLoader::PluginKey>
-PluginLoader::Impl::listPlugins() 
-{
-    if (!m_allPluginsEnumerated) enumeratePlugins();
-
-    vector<PluginKey> plugins;
-    for (map<PluginKey, string>::iterator mi = m_pluginLibraryNameMap.begin();
-         mi != m_pluginLibraryNameMap.end(); ++mi) {
-        plugins.push_back(mi->first);
-    }
-
-    return plugins;
-}
-
-void
-PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin)
-{
-    vector<string> path = PluginHostAdapter::getPluginPath();
-
-    string libraryName, identifier;
-    if (forPlugin != "") {
-        if (!decomposePluginKey(forPlugin, libraryName, identifier)) {
-            std::cerr << "WARNING: Vamp::HostExt::PluginLoader: Invalid plugin key \""
-                      << forPlugin << "\" in enumerate" << std::endl;
-            return;
-        }
-    }
-
-    for (size_t i = 0; i < path.size(); ++i) {
-        
-        vector<string> files = listFiles(path[i], PLUGIN_SUFFIX);
-
-        for (vector<string>::iterator fi = files.begin();
-             fi != files.end(); ++fi) {
-            
-            if (libraryName != "") {
-                // libraryName is lowercased and lacking an extension,
-                // as it came from the plugin key
-                string temp = *fi;
-                for (size_t i = 0; i < temp.length(); ++i) {
-                    temp[i] = tolower(temp[i]);
-                }
-                string::size_type pi = temp.find('.');
-                if (pi == string::npos) {
-                    if (libraryName != temp) continue;
-                } else {
-                    if (libraryName != temp.substr(0, pi)) continue;
-                }
-            }
-
-            string fullPath = path[i];
-            fullPath = splicePath(fullPath, *fi);
-            void *handle = loadLibrary(fullPath);
-            if (!handle) continue;
-            
-            VampGetPluginDescriptorFunction fn =
-                (VampGetPluginDescriptorFunction)lookupInLibrary
-                (handle, "vampGetPluginDescriptor");
-            
-            if (!fn) {
-                unloadLibrary(handle);
-                continue;
-            }
-            
-            int index = 0;
-            const VampPluginDescriptor *descriptor = 0;
-            
-            while ((descriptor = fn(VAMP_API_VERSION, index))) {
-                ++index;
-                if (identifier != "") {
-                    if (descriptor->identifier != identifier) continue;
-                }
-                PluginKey key = composePluginKey(*fi, descriptor->identifier);
-//                std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl;
-                if (m_pluginLibraryNameMap.find(key) ==
-                    m_pluginLibraryNameMap.end()) {
-                    m_pluginLibraryNameMap[key] = fullPath;
-                }
-            }
-            
-            unloadLibrary(handle);
-        }
-    }
-
-    if (forPlugin == "") m_allPluginsEnumerated = true;
-}
-
-PluginLoader::PluginKey
-PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
-{
-    string basename = libraryName;
-
-    string::size_type li = basename.rfind('/');
-    if (li != string::npos) basename = basename.substr(li + 1);
-
-    li = basename.find('.');
-    if (li != string::npos) basename = basename.substr(0, li);
-
-    for (size_t i = 0; i < basename.length(); ++i) {
-        basename[i] = tolower(basename[i]);
-    }
-
-    return basename + ":" + identifier;
-}
-
-bool
-PluginLoader::Impl::decomposePluginKey(PluginKey key,
-                                       string &libraryName,
-                                       string &identifier)
-{
-    string::size_type ki = key.find(':');
-    if (ki == string::npos) {
-        return false;
-    }
-
-    libraryName = key.substr(0, ki);
-    identifier = key.substr(ki + 1);
-    return true;
-}
-
-PluginLoader::PluginCategoryHierarchy
-PluginLoader::Impl::getPluginCategory(PluginKey plugin)
-{
-    if (m_taxonomy.empty()) generateTaxonomy();
-    if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
-        return PluginCategoryHierarchy();
-    }
-    return m_taxonomy[plugin];
-}
-
-string
-PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
-{
-    if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
-        if (m_allPluginsEnumerated) return "";
-        enumeratePlugins(plugin);
-    }
-    if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
-        return "";
-    }
-    return m_pluginLibraryNameMap[plugin];
-}    
-
-Plugin *
-PluginLoader::Impl::loadPlugin(PluginKey key,
-                               float inputSampleRate, int adapterFlags)
-{
-    string libname, identifier;
-    if (!decomposePluginKey(key, libname, identifier)) {
-        std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \""
-                  << key << "\" in loadPlugin" << std::endl;
-        return 0;
-    }
-        
-    string fullPath = getLibraryPathForPlugin(key);
-    if (fullPath == "") return 0;
-    
-    void *handle = loadLibrary(fullPath);
-    if (!handle) return 0;
-    
-    VampGetPluginDescriptorFunction fn =
-        (VampGetPluginDescriptorFunction)lookupInLibrary
-        (handle, "vampGetPluginDescriptor");
-
-    if (!fn) {
-        unloadLibrary(handle);
-        return 0;
-    }
-
-    int index = 0;
-    const VampPluginDescriptor *descriptor = 0;
-
-    while ((descriptor = fn(VAMP_API_VERSION, index))) {
-
-        if (string(descriptor->identifier) == identifier) {
-
-            Vamp::PluginHostAdapter *plugin =
-                new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
-
-            Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
-
-            m_pluginLibraryHandleMap[adapter] = handle;
-
-            if (adapterFlags & ADAPT_INPUT_DOMAIN) {
-                if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
-                    adapter = new PluginInputDomainAdapter(adapter);
-                }
-            }
-
-            if (adapterFlags & ADAPT_BUFFER_SIZE) {
-                adapter = new PluginBufferingAdapter(adapter);
-            }
-
-            if (adapterFlags & ADAPT_CHANNEL_COUNT) {
-                adapter = new PluginChannelAdapter(adapter);
-            }
-
-            return adapter;
-        }
-
-        ++index;
-    }
-
-    cerr << "Vamp::HostExt::PluginLoader: Plugin \""
-         << identifier << "\" not found in library \""
-         << fullPath << "\"" << endl;
-
-    return 0;
-}
-
-void
-PluginLoader::Impl::generateTaxonomy()
-{
-//    cerr << "PluginLoader::Impl::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) {
-
-        // It doesn't matter that we're using literal forward-slash in
-        // this bit, as it's only relevant if the path contains
-        // "/lib/", which is only meaningful and only plausible on
-        // systems with forward-slash delimiters
-        
-        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 = listFiles(*i, suffix);
-
-        for (vector<string>::iterator fi = files.begin();
-             fi != files.end(); ++fi) {
-
-            string filepath = splicePath(*i, *fi);
-            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;
-            }
-        }
-    }
-}    
-
-void *
-PluginLoader::Impl::loadLibrary(string path)
-{
-    void *handle = 0;
-#ifdef _WIN32
-    handle = LoadLibrary(path.c_str());
-    if (!handle) {
-        cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
-             << path << "\"" << endl;
-    }
-#else
-    handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
-    if (!handle) {
-        cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
-             << path << "\": " << dlerror() << endl;
-    }
-#endif
-    return handle;
-}
-
-void
-PluginLoader::Impl::unloadLibrary(void *handle)
-{
-#ifdef _WIN32
-    FreeLibrary((HINSTANCE)handle);
-#else
-    dlclose(handle);
-#endif
-}
-
-void *
-PluginLoader::Impl::lookupInLibrary(void *handle, const char *symbol)
-{
-#ifdef _WIN32
-    return (void *)GetProcAddress((HINSTANCE)handle, symbol);
-#else
-    return (void *)dlsym(handle, symbol);
-#endif
-}
-
-string
-PluginLoader::Impl::splicePath(string a, string b)
-{
-#ifdef _WIN32
-    return a + "\\" + b;
-#else
-    return a + "/" + b;
-#endif
-}
-
-vector<string>
-PluginLoader::Impl::listFiles(string dir, string extension)
-{
-    vector<string> files;
-
-#ifdef _WIN32
-
-    string expression = dir + "\\*." + extension;
-    WIN32_FIND_DATA data;
-    HANDLE fh = FindFirstFile(expression.c_str(), &data);
-    if (fh == INVALID_HANDLE_VALUE) return files;
-
-    bool ok = true;
-    while (ok) {
-        files.push_back(data.cFileName);
-        ok = FindNextFile(fh, &data);
-    }
-
-    FindClose(fh);
-
-#else
-
-    size_t extlen = extension.length();
-    DIR *d = opendir(dir.c_str());
-    if (!d) return files;
-            
-    struct dirent *e = 0;
-    while ((e = readdir(d))) {
- 
-        if (!e->d_name) continue;
-       
-        size_t len = strlen(e->d_name);
-        if (len < extlen + 2 ||
-            e->d_name + len - extlen - 1 != "." + extension) {
-            continue;
-        }
-
-        files.push_back(e->d_name);
-    }
-
-    closedir(d);
-#endif
-
-    return files;
-}
-
-void
-PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
-{
-    void *handle = m_pluginLibraryHandleMap[adapter];
-    if (handle) unloadLibrary(handle);
-    m_pluginLibraryHandleMap.erase(adapter);
-}
-
-PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
-                                                                             Impl *loader) :
-    PluginWrapper(plugin),
-    m_loader(loader)
-{
-}
-
-PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
-{
-    // We need to delete the plugin before calling pluginDeleted, as
-    // the delete call may require calling through to the descriptor
-    // (for e.g. cleanup) but pluginDeleted may unload the required
-    // library for the call.  To prevent a double deletion when our
-    // parent's destructor runs (after this one), be sure to set
-    // m_plugin to 0 after deletion.
-    delete m_plugin;
-    m_plugin = 0;
-
-    if (m_loader) m_loader->pluginDeleted(this);
-}
-
-}
-
-}
--- a/vamp-sdk/hostext/PluginLoader.h	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/* -*- 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-2007 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 _VAMP_PLUGIN_LOADER_H_
-#define _VAMP_PLUGIN_LOADER_H_
-
-#include <vector>
-#include <string>
-#include <map>
-
-#include "PluginWrapper.h"
-
-namespace Vamp {
-
-class Plugin;
-
-namespace HostExt {
-
-/**
- * \class PluginLoader PluginLoader.h <vamp-sdk/hostext/PluginLoader.h>
- * 
- * Vamp::HostExt::PluginLoader is a convenience class for discovering
- * and loading Vamp plugins using the typical plugin-path, library
- * naming, and categorisation conventions described in the Vamp SDK
- * documentation.  This class is intended to greatly simplify the task
- * of becoming a Vamp plugin host for any C++ application.
- * 
- * Hosts are not required by the Vamp specification to use the same
- * plugin search path and naming conventions as implemented by this
- * class, and are certainly not required to use this actual class.
- * But we do strongly recommend it.
- *
- * \note This class was introduced in version 1.1 of the Vamp plugin SDK.
- */
-
-class PluginLoader
-{
-public:
-    /**
-     * Obtain a pointer to the singleton instance of PluginLoader.
-     * Use this to obtain your loader object.
-     */
-    static PluginLoader *getInstance();
-
-    /**
-     * PluginKey is a string type that is used to identify a plugin
-     * uniquely within the scope of "the current system".  It consists
-     * of the lower-cased base name of the plugin library, a colon
-     * separator, and the identifier string for the plugin.  It is
-     * only meaningful in the context of a given plugin path (the one
-     * returned by PluginHostAdapter::getPluginPath()).
-     *
-     * Use composePluginKey() to construct a plugin key from a known
-     * plugin library name and identifier.
-     *
-     * Note: the fact that the library component of the key is
-     * lower-cased implies that library names are matched
-     * case-insensitively by the PluginLoader class, regardless of the
-     * case sensitivity of the underlying filesystem.  (Plugin
-     * identifiers _are_ case sensitive, however.)  Also, it is not
-     * possible to portably extract a working library name from a
-     * plugin key, as the result may fail on case-sensitive
-     * filesystems.  Use getLibraryPathForPlugin() instead.
-     */
-    typedef std::string PluginKey;
-
-    /**
-     * PluginKeyList is a sequence of plugin keys, such as returned by
-     * listPlugins().
-     */
-    typedef std::vector<PluginKey> PluginKeyList;
-
-    /**
-     * PluginCategoryHierarchy is a sequence of general->specific
-     * category names, as may be associated with a single plugin.
-     * This sequence describes the location of a plugin within a
-     * category forest, containing the human-readable names of the
-     * plugin's category tree root, followed by each of the nodes down
-     * to the leaf containing the plugin.
-     *
-     * \see getPluginCategory()
-     */
-    typedef std::vector<std::string> PluginCategoryHierarchy;
-
-    /**
-     * Search for all available Vamp plugins, and return a list of
-     * them in the order in which they were found.
-     */
-    PluginKeyList listPlugins();
-
-    /**
-     * AdapterFlags contains a set of values that may be OR'd together
-     * to indicate in which circumstances PluginLoader should use a
-     * plugin adapter to make a plugin easier to use for a host that
-     * does not want to cater for complex features.
-     *
-     * The available flags are:
-     * 
-     * ADAPT_INPUT_DOMAIN - If the plugin expects frequency domain
-     * input, wrap it in a PluginInputDomainAdapter that automatically
-     * converts the plugin to one that expects time-domain input.
-     * This enables a host to accommodate time- and frequency-domain
-     * plugins without needing to do any conversion itself.
-     *
-     * ADAPT_CHANNEL_COUNT - Wrap the plugin in a PluginChannelAdapter
-     * to handle any mismatch between the number of channels of audio
-     * the plugin can handle and the number available in the host.
-     * This enables a host to use plugins that may require the input
-     * to be mixed down to mono, etc., without having to worry about
-     * doing that itself.
-     *
-     * ADAPT_BUFFER_SIZE - Wrap the plugin in a PluginBufferingAdapter
-     * permitting the host to provide audio input using any block
-     * size, with no overlap, regardless of the plugin's preferred
-     * block size (suitable for hosts that read from non-seekable
-     * streaming media, for example).  This adapter introduces some
-     * run-time overhead and also changes the semantics of the plugin
-     * slightly (see the PluginBufferingAdapter header documentation
-     * for details).
-     *
-     * ADAPT_ALL_SAFE - Perform all available adaptations that are
-     * meaningful for the plugin and "safe".  Currently this means to
-     * ADAPT_INPUT_DOMAIN if the plugin wants FrequencyDomain input;
-     * ADAPT_CHANNEL_COUNT always; and ADAPT_BUFFER_SIZE never.
-     * 
-     * ADAPT_ALL - Perform all available adaptations that are
-     * meaningful for the plugin.
-     * 
-     * See PluginInputDomainAdapter, PluginChannelAdapter and
-     * PluginBufferingAdapter for more details of the classes that the
-     * loader may use if these flags are set.
-     */
-    enum AdapterFlags {
-
-        ADAPT_INPUT_DOMAIN  = 0x01,
-        ADAPT_CHANNEL_COUNT = 0x02,
-        ADAPT_BUFFER_SIZE   = 0x04,
-
-        ADAPT_ALL_SAFE      = 0x03,
-
-        ADAPT_ALL           = 0xff
-    };
-
-    /**
-     * Load a Vamp plugin, given its identifying key.  If the plugin
-     * could not be loaded, returns 0.
-     *
-     * The returned plugin should be deleted (using the standard C++
-     * delete keyword) after use.
-     *
-     * \param adapterFlags a bitwise OR of the values in the AdapterFlags
-     * enumeration, indicating under which circumstances an adapter should be
-     * used to wrap the original plugin.  If adapterFlags is 0, no
-     * optional adapters will be used.  Otherwise, the returned plugin
-     * may be of an adapter class type which will behave identically
-     * to the original plugin, apart from any particular features
-     * implemented by the adapter itself.
-     * 
-     * \see AdapterFlags, PluginInputDomainAdapter, PluginChannelAdapter
-     */
-    Plugin *loadPlugin(PluginKey key,
-                       float inputSampleRate,
-                       int adapterFlags = 0);
-
-    /**
-     * Given a Vamp plugin library name and plugin identifier, return
-     * the corresponding plugin key in a form suitable for passing in to
-     * loadPlugin().
-     */
-    PluginKey composePluginKey(std::string libraryName,
-                               std::string identifier);
-
-    /**
-     * Return the category hierarchy for a Vamp plugin, given its
-     * identifying key.
-     *
-     * If the plugin has no category information, return an empty
-     * hierarchy.
-     *
-     * \see PluginCategoryHierarchy
-     */
-    PluginCategoryHierarchy getPluginCategory(PluginKey plugin);
-
-    /**
-     * Return the file path of the dynamic library from which the
-     * given plugin will be loaded (if available).
-     */
-    std::string getLibraryPathForPlugin(PluginKey plugin);
-
-protected:
-    PluginLoader();
-    virtual ~PluginLoader();
-
-    class Impl;
-    Impl *m_impl;
-
-    static PluginLoader *m_instance;
-};
-
-}
-
-}
-
-#endif
-
--- a/vamp-sdk/hostext/PluginSummarisingAdapter.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,913 +0,0 @@
-/* -*- 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-2008 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.
-*/
-
-#include "PluginSummarisingAdapter.h"
-
-#include <map>
-#include <algorithm>
-#include <cmath>
-#include <climits>
-
-#define DEBUG_PLUGIN_SUMMARISING_ADAPTER 1
-//#define DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT 1
-
-namespace Vamp {
-
-namespace HostExt {
-
-class PluginSummarisingAdapter::Impl
-{
-public:
-    Impl(Plugin *plugin, float inputSampleRate);
-    ~Impl();
-
-    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
-
-    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
-    FeatureSet getRemainingFeatures();
-
-    void setSummarySegmentBoundaries(const SegmentBoundaries &);
-
-    FeatureList getSummaryForOutput(int output,
-                                    SummaryType type,
-                                    AveragingMethod avg);
-
-    FeatureSet getSummaryForAllOutputs(SummaryType type,
-                                       AveragingMethod avg);
-
-protected:
-    Plugin *m_plugin;
-    float m_inputSampleRate;
-    size_t m_stepSize;
-    size_t m_blockSize;
-
-    SegmentBoundaries m_boundaries;
-
-    typedef std::vector<float> ValueList;
-
-    struct Result { // smaller than Feature
-        RealTime time;
-        RealTime duration;
-        ValueList values; // bin number -> value
-    };
-
-    typedef std::vector<Result> ResultList;
-
-    struct OutputAccumulator {
-        int bins;
-        ResultList results;
-        OutputAccumulator() : bins(0) { }
-    };
-
-    typedef std::map<int, OutputAccumulator> OutputAccumulatorMap;
-    OutputAccumulatorMap m_accumulators; // output number -> accumulator
-
-    typedef std::map<RealTime, OutputAccumulator> SegmentAccumulatorMap;
-    typedef std::map<int, SegmentAccumulatorMap> OutputSegmentAccumulatorMap;
-    OutputSegmentAccumulatorMap m_segmentedAccumulators; // output -> segmented
-
-    typedef std::map<int, RealTime> OutputTimestampMap;
-    OutputTimestampMap m_prevTimestamps; // output number -> timestamp
-    OutputTimestampMap m_prevDurations; // output number -> durations
-
-    struct OutputBinSummary {
-
-        int count;
-
-        // extents
-        double minimum;
-        double maximum;
-        double sum;
-
-        // sample-average results
-        double median;
-        double mode;
-        double variance;
-
-        // continuous-time average results
-        double median_c;
-        double mode_c;
-        double mean_c;
-        double variance_c;
-    };
-
-    typedef std::map<int, OutputBinSummary> OutputSummary;
-    typedef std::map<RealTime, OutputSummary> SummarySegmentMap;
-    typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap;
-
-    OutputSummarySegmentMap m_summaries;
-
-    bool m_reduced;
-    RealTime m_endTime;
-
-    void accumulate(const FeatureSet &fs, RealTime, bool final);
-    void accumulate(int output, const Feature &f, RealTime, bool final);
-    void accumulateFinalDurations();
-    void findSegmentBounds(RealTime t, RealTime &start, RealTime &end);
-    void segment();
-    void reduce();
-
-    std::string getSummaryLabel(SummaryType type, AveragingMethod avg);
-};
-
-static RealTime INVALID_DURATION(INT_MIN, INT_MIN);
-    
-PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) :
-    PluginWrapper(plugin)
-{
-    m_impl = new Impl(plugin, m_inputSampleRate);
-}
-
-PluginSummarisingAdapter::~PluginSummarisingAdapter()
-{
-    delete m_impl;
-}
-
-bool
-PluginSummarisingAdapter::initialise(size_t channels,
-                                     size_t stepSize, size_t blockSize)
-{
-    return
-        PluginWrapper::initialise(channels, stepSize, blockSize) &&
-        m_impl->initialise(channels, stepSize, blockSize);
-}
-
-Plugin::FeatureSet
-PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp)
-{
-    return m_impl->process(inputBuffers, timestamp);
-}
-
-Plugin::FeatureSet
-PluginSummarisingAdapter::getRemainingFeatures()
-{
-    return m_impl->getRemainingFeatures();
-}
-
-void
-PluginSummarisingAdapter::setSummarySegmentBoundaries(const SegmentBoundaries &b)
-{
-    m_impl->setSummarySegmentBoundaries(b);
-}
-
-Plugin::FeatureList
-PluginSummarisingAdapter::getSummaryForOutput(int output,
-                                              SummaryType type,
-                                              AveragingMethod avg)
-{
-    return m_impl->getSummaryForOutput(output, type, avg);
-}
-
-Plugin::FeatureSet
-PluginSummarisingAdapter::getSummaryForAllOutputs(SummaryType type,
-                                                  AveragingMethod avg)
-{
-    return m_impl->getSummaryForAllOutputs(type, avg);
-}
-
-PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
-    m_plugin(plugin),
-    m_inputSampleRate(inputSampleRate),
-    m_reduced(false)
-{
-}
-
-PluginSummarisingAdapter::Impl::~Impl()
-{
-}
-
-bool
-PluginSummarisingAdapter::Impl::initialise(size_t channels,
-                                           size_t stepSize, size_t blockSize)
-{
-    m_stepSize = stepSize;
-    m_blockSize = blockSize;
-    return true;
-}
-
-Plugin::FeatureSet
-PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers,
-                                        RealTime timestamp)
-{
-    if (m_reduced) {
-        std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
-    }
-    FeatureSet fs = m_plugin->process(inputBuffers, timestamp);
-    accumulate(fs, timestamp, false);
-    m_endTime = timestamp + 
-        RealTime::frame2RealTime(m_stepSize, m_inputSampleRate);
-    return fs;
-}
-
-Plugin::FeatureSet
-PluginSummarisingAdapter::Impl::getRemainingFeatures()
-{
-    if (m_reduced) {
-        std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
-    }
-    FeatureSet fs = m_plugin->getRemainingFeatures();
-    accumulate(fs, m_endTime, true);
-    return fs;
-}
-
-void
-PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b)
-{
-    m_boundaries = b;
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-    std::cerr << "PluginSummarisingAdapter::setSummarySegmentBoundaries: boundaries are:" << std::endl;
-    for (SegmentBoundaries::const_iterator i = m_boundaries.begin();
-         i != m_boundaries.end(); ++i) {
-        std::cerr << *i << "  ";
-    }
-    std::cerr << std::endl;
-#endif
-}
-
-Plugin::FeatureList
-PluginSummarisingAdapter::Impl::getSummaryForOutput(int output,
-                                                    SummaryType type,
-                                                    AveragingMethod avg)
-{
-    if (!m_reduced) {
-        accumulateFinalDurations();
-        segment();
-        reduce();
-        m_reduced = true;
-    }
-
-    bool continuous = (avg == ContinuousTimeAverage);
-
-    FeatureList fl;
-    for (SummarySegmentMap::const_iterator i = m_summaries[output].begin();
-         i != m_summaries[output].end(); ++i) {
-
-        Feature f;
-
-        f.hasTimestamp = true;
-        f.timestamp = i->first;
-
-        f.hasDuration = true;
-        SummarySegmentMap::const_iterator ii = i;
-        if (++ii == m_summaries[output].end()) {
-            f.duration = m_endTime - f.timestamp;
-        } else {
-            f.duration = ii->first - f.timestamp;
-        }
-
-        f.label = getSummaryLabel(type, avg);
-
-        for (OutputSummary::const_iterator j = i->second.begin();
-             j != i->second.end(); ++j) {
-
-            // these will be ordered by bin number, and no bin numbers
-            // will be missing except at the end (because of the way
-            // the accumulators were initially filled in accumulate())
-
-            const OutputBinSummary &summary = j->second;
-            double result = 0.f;
-
-            switch (type) {
-
-            case Minimum:
-                result = summary.minimum;
-                break;
-
-            case Maximum:
-                result = summary.maximum;
-                break;
-
-            case Mean:
-                if (continuous) {
-                    result = summary.mean_c;
-                } else if (summary.count) {
-                    result = summary.sum / summary.count;
-                }
-                break;
-
-            case Median:
-                if (continuous) result = summary.median_c;
-                else result = summary.median;
-                break;
-
-            case Mode:
-                if (continuous) result = summary.mode_c;
-                else result = summary.mode;
-                break;
-
-            case Sum:
-                result = summary.sum;
-                break;
-
-            case Variance:
-                if (continuous) result = summary.variance_c;
-                else result = summary.variance;
-                break;
-
-            case StandardDeviation:
-                if (continuous) result = sqrtf(summary.variance_c);
-                else result = sqrtf(summary.variance);
-                break;
-
-            case Count:
-                result = summary.count;
-                break;
-
-            case UnknownSummaryType:
-                break;
-
-            default:
-                break;
-            }
-            
-            f.values.push_back(result);
-        }
-
-        fl.push_back(f);
-    }
-    return fl;
-}
-
-Plugin::FeatureSet
-PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type,
-                                                        AveragingMethod avg)
-{
-    if (!m_reduced) {
-        accumulateFinalDurations();
-        segment();
-        reduce();
-        m_reduced = true;
-    }
-
-    FeatureSet fs;
-    for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin();
-         i != m_summaries.end(); ++i) {
-        fs[i->first] = getSummaryForOutput(i->first, type, avg);
-    }
-    return fs;
-}
-
-void
-PluginSummarisingAdapter::Impl::accumulate(const FeatureSet &fs,
-                                           RealTime timestamp, 
-                                           bool final)
-{
-    for (FeatureSet::const_iterator i = fs.begin(); i != fs.end(); ++i) {
-        for (FeatureList::const_iterator j = i->second.begin();
-             j != i->second.end(); ++j) {
-            if (j->hasTimestamp) {
-                accumulate(i->first, *j, j->timestamp, final);
-            } else {
-                //!!! is this correct?
-                accumulate(i->first, *j, timestamp, final);
-            }
-        }
-    }
-}
-
-std::string
-PluginSummarisingAdapter::Impl::getSummaryLabel(SummaryType type,
-                                                AveragingMethod avg)
-{
-    std::string label;
-    std::string avglabel;
-
-    if (avg == SampleAverage) avglabel = ", sample average";
-    else avglabel = ", continuous-time average";
-
-    switch (type) {
-    case Minimum:  label = "(minimum value)"; break;
-    case Maximum:  label = "(maximum value)"; break;
-    case Mean:     label = "(mean value" + avglabel + ")"; break;
-    case Median:   label = "(median value" + avglabel + ")"; break;
-    case Mode:     label = "(modal value" + avglabel + ")"; break;
-    case Sum:      label = "(sum)"; break;
-    case Variance: label = "(variance" + avglabel + ")"; break;
-    case StandardDeviation: label = "(standard deviation" + avglabel + ")"; break;
-    case Count:    label = "(count)"; break;
-    case UnknownSummaryType: label = "(unknown summary)"; break;
-    }
-    
-    return label;
-}
-
-void
-PluginSummarisingAdapter::Impl::accumulate(int output,
-                                           const Feature &f,
-                                           RealTime timestamp,
-                                           bool final)
-{
-//!!! to do: use timestamp to determine which segment we're on
-    
-//!!! What should happen if a feature's duration spans a segment
-// boundary?  I think we probably want to chop it, and pretend that it
-// appears in both -- don't we? do we?  A very long feature (e.g. key,
-// if the whole audio is in a single key) might span many or all
-// segments, and we want that to be reflected in the results (e.g. it
-// is the modal key in all of those segments, not just the first).
-// That is actually quite complicated to do!
-
-//!!! This affects how we record things.  If features spanning a
-// boundary should be chopped, then we need to have per-segment
-// accumulators (and the feature value goes into both -- perhaps we
-// need a separate phase to split the accumulator up into segments).
-// If features spanning a boundary should be counted only in the first
-// segment, with their full duration, then we should store them in a
-// single accumulator and distribute into segments only on reduce.
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-    std::cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << ", final " << final << std::endl;
-#endif
-
-    // At each process step, accumulate() is called once for each
-    // feature on each output within that process's returned feature
-    // list, and with the timestamp passed in being that of the start
-    // of the process block.
-
-    // At the end (in getRemainingFeatures), accumulate() is called
-    // once for each feature on each output within the feature list
-    // returned by getRemainingFeatures, and with the timestamp being
-    // the same as the last process block and final set to true.
-
-    // (What if getRemainingFeatures doesn't return any features?  We
-    // still need to ensure that the final duration is written.  Need
-    // a separate function to close the durations.)
-
-    // At each call, we pull out the value for the feature and stuff
-    // it into the accumulator's appropriate values array; and we
-    // calculate the duration for the _previous_ feature, or pull it
-    // from the prevDurations array if the previous feature had a
-    // duration in its structure, and stuff that into the
-    // accumulator's appropriate durations array.
-
-    if (m_prevDurations.find(output) != m_prevDurations.end()) {
-
-        // Not the first time accumulate has been called for this
-        // output -- there has been a previous feature
-
-        RealTime prevDuration;
-
-        // Note that m_prevDurations[output] only contains the
-        // duration field that was contained in the previous feature.
-        // If it didn't have an explicit duration,
-        // m_prevDurations[output] should be INVALID_DURATION and we
-        // will have to calculate the duration from the previous and
-        // current timestamps.
-
-        if (m_prevDurations[output] != INVALID_DURATION) {
-            prevDuration = m_prevDurations[output];
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-            std::cerr << "Previous duration from previous feature: " << prevDuration << std::endl;
-#endif
-        } else {
-            prevDuration = timestamp - m_prevTimestamps[output];
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-            std::cerr << "Previous duration from diff: " << timestamp << " - "
-                      << m_prevTimestamps[output] << std::endl;
-#endif
-        }
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-        std::cerr << "output " << output << ": ";
-        std::cerr << "Pushing previous duration as " << prevDuration << std::endl;
-#endif
-        
-        m_accumulators[output].results
-            [m_accumulators[output].results.size() - 1]
-            .duration = prevDuration;
-    }
-
-    if (f.hasDuration) m_prevDurations[output] = f.duration;
-    else m_prevDurations[output] = INVALID_DURATION;
-
-    m_prevTimestamps[output] = timestamp;
-
-    if (f.hasDuration) {
-        RealTime et = timestamp;
-        et = et + f.duration;
-        if (et > m_endTime) m_endTime = et;
-    }
-
-    Result result;
-    result.time = timestamp;
-    result.duration = INVALID_DURATION;
-
-    if (f.values.size() > m_accumulators[output].bins) {
-        m_accumulators[output].bins = f.values.size();
-    }
-
-    for (int i = 0; i < int(f.values.size()); ++i) {
-        result.values.push_back(f.values[i]);
-    }
-
-    m_accumulators[output].results.push_back(result);
-}
-
-void
-PluginSummarisingAdapter::Impl::accumulateFinalDurations()
-{
-    for (OutputTimestampMap::iterator i = m_prevTimestamps.begin();
-         i != m_prevTimestamps.end(); ++i) {
-
-        int output = i->first;
-
-        int acount = m_accumulators[output].results.size();
-
-        if (acount == 0) continue;
-
-        RealTime prevTimestamp = i->second;
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-        std::cerr << "output " << output << ": ";
-#endif
-
-        if (m_prevDurations.find(output) != m_prevDurations.end() &&
-            m_prevDurations[output] != INVALID_DURATION) {
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-            std::cerr << "Pushing final duration from feature as " << m_prevDurations[output] << std::endl;
-#endif
-
-            m_accumulators[output].results[acount - 1].duration =
-                m_prevDurations[output];
-
-        } else {
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-            std::cerr << "Pushing final duration from diff as " << m_endTime << " - " << m_prevTimestamps[output] << std::endl;
-#endif
-
-            m_accumulators[output].results[acount - 1].duration =
-                m_endTime - m_prevTimestamps[output];
-        }
-        
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-        std::cerr << "so duration for result no " << acount-1 << " is "
-                  << m_accumulators[output].results[acount-1].duration
-                  << std::endl;
-#endif
-    }
-}
-
-void
-PluginSummarisingAdapter::Impl::findSegmentBounds(RealTime t,
-                                                  RealTime &start,
-                                                  RealTime &end)
-{
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
-    std::cerr << "findSegmentBounds: t = " << t <<  std::endl;
-#endif
-
-    SegmentBoundaries::const_iterator i = std::upper_bound
-        (m_boundaries.begin(), m_boundaries.end(), t);
-
-    start = RealTime::zeroTime;
-    end = m_endTime;
-
-    if (i != m_boundaries.end()) {
-        end = *i;
-    }
-
-    if (i != m_boundaries.begin()) {
-        start = *--i;
-    }
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
-    std::cerr << "findSegmentBounds: " << t << " is in segment " << start << " -> " << end << std::endl;
-#endif
-}
-
-void
-PluginSummarisingAdapter::Impl::segment()
-{
-    SegmentBoundaries::iterator boundaryitr = m_boundaries.begin();
-    RealTime segmentStart = RealTime::zeroTime;
-    
-    for (OutputAccumulatorMap::iterator i = m_accumulators.begin();
-         i != m_accumulators.end(); ++i) {
-
-        int output = i->first;
-        OutputAccumulator &source = i->second;
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
-        std::cerr << "segment: total results for output " << output << " = "
-                  << source.results.size() << std::endl;
-#endif
-
-        //!!! This is basically nonsense if the results have no values
-        //!!! (i.e. their times and counts are the only things of
-        //!!! interest) but perhaps it's the user's problem if they
-        //!!! ask for segmentation in that case
-
-        for (int n = 0; n < source.results.size(); ++n) {
-            
-            // This result spans source.results[n].time to
-            // source.results[n].time + source.results[n].duration.
-            // We need to dispose it into segments appropriately
-
-            RealTime resultStart = source.results[n].time;
-            RealTime resultEnd = resultStart + source.results[n].duration;
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
-            std::cerr << "output: " << output << ", result start = " << resultStart << ", end = " << resultEnd << std::endl;
-#endif
-
-            RealTime segmentStart = RealTime::zeroTime;
-            RealTime segmentEnd = resultEnd - RealTime(1, 0);
-            
-            while (segmentEnd < resultEnd) {
-
-                findSegmentBounds(resultStart, segmentStart, segmentEnd);
-                
-                RealTime chunkStart = resultStart;
-                if (chunkStart < segmentStart) chunkStart = segmentStart;
-
-                RealTime chunkEnd = resultEnd;
-                if (chunkEnd > segmentEnd) chunkEnd = segmentEnd;
-                
-                m_segmentedAccumulators[output][segmentStart].bins = source.bins;
-
-                Result chunk;
-                chunk.time = chunkStart;
-                chunk.duration = chunkEnd - chunkStart;
-                chunk.values = source.results[n].values;
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
-                std::cerr << "chunk for segment " << segmentStart << ": from " << chunk.time << ", duration " << chunk.duration << std::endl;
-#endif
-
-                m_segmentedAccumulators[output][segmentStart].results
-                    .push_back(chunk);
-
-                resultStart = chunkEnd;
-            }
-        }
-    }
-}
-
-struct ValueDurationFloatPair
-{
-    float value;
-    float duration;
-
-    ValueDurationFloatPair() : value(0), duration(0) { }
-    ValueDurationFloatPair(float v, float d) : value(v), duration(d) { }
-    ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) {
-        value = p.value;
-        duration = p.duration;
-        return *this;
-    }
-    bool operator<(const ValueDurationFloatPair &p) const {
-        return value < p.value;
-    }
-};
-
-static double toSec(const RealTime &r)
-{
-    return r.sec + double(r.nsec) / 1000000000.0;
-}
-
-void
-PluginSummarisingAdapter::Impl::reduce()
-{
-    for (OutputSegmentAccumulatorMap::iterator i =
-             m_segmentedAccumulators.begin();
-         i != m_segmentedAccumulators.end(); ++i) {
-
-        int output = i->first;
-        SegmentAccumulatorMap &segments = i->second;
-
-        for (SegmentAccumulatorMap::iterator j = segments.begin();
-             j != segments.end(); ++j) {
-
-            RealTime segmentStart = j->first;
-            OutputAccumulator &accumulator = j->second;
-
-            int sz = accumulator.results.size();
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-            std::cerr << "reduce: segment starting at " << segmentStart
-                      << " on output " << output << " has " << sz << " result(s)" << std::endl;
-#endif
-
-            double totalDuration = 0.0;
-            //!!! is this right?
-            if (sz > 0) {
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-                std::cerr << "last time = " << accumulator.results[sz-1].time 
-                          << ", duration = " << accumulator.results[sz-1].duration
-                          << " (step = " << m_stepSize << ", block = " << m_blockSize << ")"
-                          << std::endl;
-#endif
-                totalDuration = toSec((accumulator.results[sz-1].time +
-                                       accumulator.results[sz-1].duration) -
-                                      segmentStart);
-            }
-
-            for (int bin = 0; bin < accumulator.bins; ++bin) {
-
-                // work on all values over time for a single bin
-
-                OutputBinSummary summary;
-
-                summary.count = sz;
-
-                summary.minimum = 0.f;
-                summary.maximum = 0.f;
-
-                summary.median = 0.f;
-                summary.mode = 0.f;
-                summary.sum = 0.f;
-                summary.variance = 0.f;
-
-                summary.median_c = 0.f;
-                summary.mode_c = 0.f;
-                summary.mean_c = 0.f;
-                summary.variance_c = 0.f;
-
-                if (sz == 0) continue;
-
-                std::vector<ValueDurationFloatPair> valvec;
-
-                for (int k = 0; k < sz; ++k) {
-                    while (accumulator.results[k].values.size() <
-                           accumulator.bins) {
-                        accumulator.results[k].values.push_back(0.f);
-                    }
-                }
-
-                for (int k = 0; k < sz; ++k) {
-                    float value = accumulator.results[k].values[bin];
-                    valvec.push_back(ValueDurationFloatPair
-                                     (value,
-                                      toSec(accumulator.results[k].duration)));
-                }
-
-                std::sort(valvec.begin(), valvec.end());
-
-                summary.minimum = valvec[0].value;
-                summary.maximum = valvec[sz-1].value;
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-                std::cerr << "total duration = " << totalDuration << std::endl;
-#endif
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-/*
-                std::cerr << "value vector for medians:" << std::endl;
-                for (int k = 0; k < sz; ++k) {
-                    std::cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") ";
-                }
-                std::cerr << std::endl;
-*/
-#endif
-
-                if (sz % 2 == 1) {
-                    summary.median = valvec[sz/2].value;
-                } else {
-                    summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2;
-                }
-            
-                double duracc = 0.0;
-                summary.median_c = valvec[sz-1].value;
-
-                for (int k = 0; k < sz; ++k) {
-                    duracc += valvec[k].duration;
-                    if (duracc > totalDuration/2) {
-                        summary.median_c = valvec[k].value;
-                        break;
-                    }
-                }
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-                std::cerr << "median_c = " << summary.median_c << std::endl;
-                std::cerr << "median = " << summary.median << std::endl;
-#endif
-                
-                std::map<float, int> distribution;
-
-                for (int k = 0; k < sz; ++k) {
-                    summary.sum += accumulator.results[k].values[bin];
-                    distribution[accumulator.results[k].values[bin]] += 1;
-                }
-
-                int md = 0;
-
-                for (std::map<float, int>::iterator di = distribution.begin();
-                     di != distribution.end(); ++di) {
-                    if (di->second > md) {
-                        md = di->second;
-                        summary.mode = di->first;
-                    }
-                }
-
-                distribution.clear();
-
-                std::map<float, double> distribution_c;
-
-                for (int k = 0; k < sz; ++k) {
-                    distribution_c[accumulator.results[k].values[bin]]
-                        += toSec(accumulator.results[k].duration);
-                }
-
-                double mrd = 0.0;
-
-                for (std::map<float, double>::iterator di = distribution_c.begin();
-                     di != distribution_c.end(); ++di) {
-                    if (di->second > mrd) {
-                        mrd = di->second;
-                        summary.mode_c = di->first;
-                    }
-                }
-
-                distribution_c.clear();
-
-                if (totalDuration > 0.0) {
-
-                    double sum_c = 0.0;
-
-                    for (int k = 0; k < sz; ++k) {
-                        double value = accumulator.results[k].values[bin]
-                            * toSec(accumulator.results[k].duration);
-                        sum_c += value;
-                    }
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-                    std::cerr << "mean_c = " << sum_c << " / " << totalDuration << " = "
-                              << sum_c / totalDuration << " (sz = " << sz << ")" << std::endl;
-#endif
-                
-                    summary.mean_c = sum_c / totalDuration;
-
-                    for (int k = 0; k < sz; ++k) {
-                        double value = accumulator.results[k].values[bin];
-//                            * toSec(accumulator.results[k].duration);
-                        summary.variance_c +=
-                            (value - summary.mean_c) * (value - summary.mean_c)
-                            * toSec(accumulator.results[k].duration);
-                    }
-
-//                    summary.variance_c /= summary.count;
-                    summary.variance_c /= totalDuration;
-                }
-
-                double mean = summary.sum / summary.count;
-
-#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
-                std::cerr << "mean = " << summary.sum << " / " << summary.count << " = "
-                          << summary.sum / summary.count << std::endl;
-#endif
-
-                for (int k = 0; k < sz; ++k) {
-                    float value = accumulator.results[k].values[bin];
-                    summary.variance += (value - mean) * (value - mean);
-                }
-                summary.variance /= summary.count;
-
-                m_summaries[output][segmentStart][bin] = summary;
-            }
-        }
-    }
-
-    m_segmentedAccumulators.clear();
-    m_accumulators.clear();
-}
-
-
-}
-
-}
-
--- a/vamp-sdk/hostext/PluginSummarisingAdapter.h	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/* -*- 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-2008 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 _VAMP_PLUGIN_SUMMARISING_ADAPTER_H_
-#define _VAMP_PLUGIN_SUMMARISING_ADAPTER_H_
-
-#include "PluginWrapper.h"
-
-#include <set>
-
-namespace Vamp {
-
-namespace HostExt {
-
-/**
- * \class PluginSummarisingAdapter PluginSummarisingAdapter.h <vamp-sdk/hostext/PluginSummarisingAdapter.h>
- *
- * \note This class was introduced in version 2.0 of the Vamp plugin SDK.
- */
-
-class PluginSummarisingAdapter : public PluginWrapper
-{
-public:
-    PluginSummarisingAdapter(Plugin *plugin); // I take ownership of plugin
-    virtual ~PluginSummarisingAdapter();
-
-    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
-
-    FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
-    FeatureSet getRemainingFeatures();
-
-    typedef std::set<RealTime> SegmentBoundaries;
-    void setSummarySegmentBoundaries(const SegmentBoundaries &);
-
-    enum SummaryType {
-        Minimum            = 0,
-        Maximum            = 1,
-        Mean               = 2,
-        Median             = 3,
-        Mode               = 4,
-        Sum                = 5,
-        Variance           = 6,
-        StandardDeviation  = 7,
-        Count              = 8,
-
-        UnknownSummaryType = 999
-    };
-
-    /**
-     * AveragingMethod indicates how the adapter should handle
-     * average-based summaries of features whose results are not
-     * equally spaced in time.
-     *
-     * If SampleAverage is specified, summary types based on averages
-     * will be calculated by treating each result individually without
-     * regard to its time: for example, the mean will be the sum of
-     * all values divided by the number of values.
-     *
-     * If ContinuousTimeAverage is specified, each feature will be
-     * considered to have a duration, either as specified in the
-     * feature's duration field, or until the following feature: thus,
-     * for example, the mean will be the sum of the products of values
-     * and durations, divided by the total duration.
-     *
-     * Although SampleAverage is useful for many types of feature,
-     * ContinuousTimeAverage is essential for some situations, for
-     * example finding the result that spans the largest proportion of
-     * the input given a feature that emits a new result only when the
-     * value changes (the modal value integrated over time).
-     */
-    enum AveragingMethod {
-        SampleAverage         = 0,
-        ContinuousTimeAverage = 1,
-    };
-
-    FeatureList getSummaryForOutput(int output,
-                                    SummaryType type,
-                                    AveragingMethod method = SampleAverage);
-
-    FeatureSet getSummaryForAllOutputs(SummaryType type,
-                                       AveragingMethod method = SampleAverage);
-
-protected:
-    class Impl;
-    Impl *m_impl;
-};
-
-}
-
-}
-
-#endif
--- a/vamp-sdk/hostext/PluginWrapper.cpp	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,201 +0,0 @@
-/* -*- 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-2007 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.
-*/
-
-#include "PluginWrapper.h"
-
-namespace Vamp {
-
-namespace HostExt {
-
-class PluginRateExtractor : public Plugin
-{
-public:
-    PluginRateExtractor() : Plugin(0) { }
-    float getRate() const { return m_inputSampleRate; }
-};
-
-PluginWrapper::PluginWrapper(Plugin *plugin) :
-    Plugin(((PluginRateExtractor *)plugin)->getRate()),
-    m_plugin(plugin)
-{
-}
-
-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();
-}
-
-}
-
-}
-
--- a/vamp-sdk/hostext/PluginWrapper.h	Thu Nov 06 14:05:33 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/* -*- 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-2007 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 _VAMP_PLUGIN_WRAPPER_H_
-#define _VAMP_PLUGIN_WRAPPER_H_
-
-#include "vamp-sdk/Plugin.h"
-
-namespace Vamp {
-
-namespace HostExt {
-
-/**
- * \class PluginWrapper PluginWrapper.h <vamp-sdk/hostext/PluginWrapper.h>
- * 
- * PluginWrapper is a simple base class for adapter plugins.  It takes
- * a pointer to a "to be wrapped" Vamp plugin on construction, and
- * provides implementations of all the Vamp plugin methods that simply
- * delegate through to the wrapped plugin.  A subclass can therefore
- * override only the methods that are meaningful for the particular
- * adapter.
- *
- * \note This class was introduced in version 1.1 of the Vamp plugin SDK.
- */
-
-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();
-
-    /**
-     * Return a pointer to the plugin wrapper of type WrapperType
-     * surrounding this wrapper's plugin, if present.
-     *
-     * This is useful in situations where a plugin is wrapped by
-     * multiple different wrappers (one inside another) and the host
-     * wants to call some wrapper-specific function on one of the
-     * layers without having to care about the order in which they are
-     * wrapped.  For example, the plugin returned by
-     * PluginLoader::loadPlugin may have more than one wrapper; if the
-     * host wanted to query or fine-tune some property of one of them,
-     * it would be hard to do so without knowing the order of the
-     * wrappers.  This function therefore gives direct access to the
-     * wrapper of a particular type.
-     */
-    template <typename WrapperType>
-    WrapperType *getWrapper() {
-        WrapperType *w = dynamic_cast<WrapperType *>(this);
-        if (w) return w;
-        PluginWrapper *pw = dynamic_cast<PluginWrapper *>(m_plugin);
-        if (pw) return pw->getWrapper<WrapperType>();
-        return 0;
-    }
-
-protected:
-    PluginWrapper(Plugin *plugin); // I take ownership of plugin
-    Plugin *m_plugin;
-};
-
-}
-
-}
-
-#endif