changeset 22:1eb44d33a371

* Rename simplehost to vamp-simple-host * Add a temporary test for validity of plugin instances with overlapping lifespans
author cannam
date Mon, 24 Apr 2006 12:58:27 +0000
parents 16eeab18bf72
children db01ce9e7657
files Makefile host/simplehost.cpp host/vamp-simple-host.cpp vamp-sdk/PluginAdapter.cpp
diffstat 4 files changed, 529 insertions(+), 430 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Fri Apr 14 09:37:46 2006 +0000
+++ b/Makefile	Mon Apr 24 12:58:27 2006 +0000
@@ -13,7 +13,7 @@
 
 # Compile flags
 #
-CXXFLAGS	:= $(CXXFLAGS) -O2 -Wall -I$(SDKDIR) -I$(APIDIR) -I.
+CXXFLAGS	:= $(CXXFLAGS) -g -Wall -I$(SDKDIR) -I$(APIDIR) -I.
 
 # Libraries required for the host at link time
 #
@@ -74,10 +74,10 @@
 		$(HOSTDIR)/system.h
 
 HOST_OBJECTS	= \
-		$(HOSTDIR)/simplehost.o
+		$(HOSTDIR)/vamp-simple-host.o
 
 HOST_TARGET	= \
-		$(HOSTDIR)/simplehost
+		$(HOSTDIR)/vamp-simple-host
 
 all:		$(SDK_TARGET) $(PLUGIN_TARGET) $(HOST_TARGET) test
 
--- a/host/simplehost.cpp	Fri Apr 14 09:37:46 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,427 +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 "PluginHostAdapter.h"
-#include "vamp.h"
-
-#include <iostream>
-#include <sndfile.h>
-
-#include "system.h"
-
-#include <cmath>
-
-using std::cout;
-using std::cerr;
-using std::endl;
-using std::string;
-
-void printFeatures(int, int, int, Vamp::Plugin::FeatureSet);
-void transformInput(float *, size_t);
-void fft(unsigned int, bool, double *, double *, double *, double *);
-
-/*
-    A very simple Vamp plugin host.  Given the name of a plugin
-    library and the name of a sound file on the command line, it loads
-    the first plugin in the library and runs it on the sound file,
-    dumping the plugin's first output to stdout.
-*/
-
-int main(int argc, char **argv)
-{
-    if (argc < 2 || argc > 4) {
-        cerr << "Usage: " << argv[0] << " pluginlibrary.so[:plugin] [file.wav] [outputno]" << endl;
-        return 2;
-    }
-
-    cerr << endl << argv[0] << ": Running..." << endl;
-
-    string soname = argv[1];
-    string plugname = "";
-    string wavname;
-    if (argc >= 3) wavname = argv[2];
-
-    int sep = soname.find(":");
-    if (sep >= 0 && sep < soname.length()) {
-        plugname = soname.substr(sep + 1);
-        soname = soname.substr(0, sep);
-    }
-
-    void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
-
-    if (!libraryHandle) {
-        cerr << argv[0] << ": Failed to open plugin library " 
-                  << soname << ": " << DLERROR() << endl;
-        return 1;
-    }
-
-    cerr << argv[0] << ": Opened plugin library " << soname << endl;
-
-    VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
-        DLSYM(libraryHandle, "vampGetPluginDescriptor");
-    
-    if (!fn) {
-        cerr << argv[0] << ": No Vamp descriptor function in library "
-                  << soname << endl;
-        DLCLOSE(libraryHandle);
-        return 1;
-    }
-
-    cerr << argv[0] << ": Found plugin descriptor function" << endl;
-
-    int index = 0;
-    int plugnumber = -1;
-    const VampPluginDescriptor *descriptor = 0;
-
-    while ((descriptor = fn(index))) {
-
-        Vamp::PluginHostAdapter plugin(descriptor, 48000);
-        cerr << argv[0] << ": Plugin " << (index+1)
-                  << " is \"" << plugin.getName() << "\"" << endl;
-
-        if (plugin.getName() == plugname) plugnumber = index;
-        
-        ++index;
-    }
-
-    cerr << argv[0] << ": Done\n" << endl;
-
-    if (wavname == "") {
-        DLCLOSE(libraryHandle);
-        return 0;
-    }
-
-    if (plugnumber < 0) {
-        if (plugname != "") {
-            cerr << "ERROR: No such plugin as " << plugname << " in library"
-                 << endl;
-            DLCLOSE(libraryHandle);
-            return 0;
-        } else {
-            plugnumber = 0;
-        }
-    }
-
-    descriptor = fn(plugnumber);
-    if (!descriptor) {
-        DLCLOSE(libraryHandle);
-        return 0;
-    }
-    
-    SNDFILE *sndfile;
-    SF_INFO sfinfo;
-    memset(&sfinfo, 0, sizeof(SF_INFO));
-
-    sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
-    if (!sndfile) {
-	cerr << "ERROR: Failed to open input file \"" << wavname << "\": "
-	     << sf_strerror(sndfile) << endl;
-        DLCLOSE(libraryHandle);
-	return 1;
-    }
-
-    Vamp::PluginHostAdapter *plugin =
-        new Vamp::PluginHostAdapter(descriptor, sfinfo.samplerate);
-
-    cerr << "Running " << plugin->getName() << "..." << endl;
-
-    int blockSize = plugin->getPreferredBlockSize();
-    int stepSize = plugin->getPreferredStepSize();
-
-    cerr << "Preferred block size = " << blockSize << ", step size = "
-              << stepSize << endl;
-
-    if (blockSize == 0) blockSize = 1024;
-    if (stepSize == 0) stepSize = blockSize;
-
-    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];
-
-    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;
-
-    Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors();
-    Vamp::Plugin::OutputDescriptor od;
-
-    int output = 0;
-    if (argc == 4) output = atoi(argv[3]);
-
-    bool mix = false;
-
-    if (minch > channels || maxch < channels) {
-        if (minch == 1) {
-            cerr << "WARNING: Sound file has " << channels << " channels, mixing down to 1" << endl;
-            mix = true;
-            channels = 1;
-        } else {
-            cerr << "ERROR: Sound file has " << channels << " channels, out of range for plugin" << endl;
-            goto done;
-        }
-    }
-
-    if (outputs.empty()) {
-	cerr << "Plugin has no outputs!" << endl;
-        goto done;
-    }
-
-    if (int(outputs.size()) <= output) {
-	cerr << "Output " << output << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
-        goto done;
-    }        
-
-    od = outputs[output];
-    cerr << "Output is " << od.name << endl;
-
-    plugin->initialise(channels, stepSize, blockSize);
-
-    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) {
-            for (int j = 0; j < blockSize; ++j) {
-                plugbuf[c][j] = 0.0f;
-            }
-        }
-
-        for (int c = 0; c < sfinfo.channels; ++c) {
-            int tc = c;
-            if (mix) tc = 0;
-            for (int j = 0; j < blockSize && j < count; ++j) {
-                plugbuf[tc][j] += filebuf[j * channels + c];
-            }
-
-            if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
-                transformInput(plugbuf[tc], blockSize);
-            }
-        }
-
-        printFeatures
-            (i, sfinfo.samplerate, output, plugin->process
-             (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate)));
-    }
-
-    printFeatures(sfinfo.frames, sfinfo.samplerate, output,
-                  plugin->getRemainingFeatures());
-
-done:
-    delete plugin;
-
-    DLCLOSE(libraryHandle);
-    sf_close(sndfile);
-    return 0;
-}
-
-void
-printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features)
-{
-    for (unsigned int i = 0; i < features[output].size(); ++i) {
-        Vamp::RealTime rt = Vamp::RealTime::frame2RealTime(frame, sr);
-        if (features[output][i].hasTimestamp) {
-            rt = features[output][i].timestamp;
-        }
-        cout << rt.toString() << ":";
-        for (unsigned int j = 0; j < features[output][i].values.size(); ++j) {
-            cout << " " << features[output][i].values[j];
-        }
-        cout << endl;
-    }
-}
-
-void
-transformInput(float *buffer, size_t size)
-{
-    double *inbuf = new double[size * 2];
-    double *outbuf = new double[size * 2];
-
-    // Copy across with Hanning window
-    for (size_t i = 0; i < size; ++i) {
-        inbuf[i] = double(buffer[i]) * (0.50 - 0.50 * cos(2 * M_PI * i / size));
-        inbuf[i + size] = 0.0;
-    }
-    
-    for (size_t i = 0; i < size/2; ++i) {
-        double temp = inbuf[i];
-        inbuf[i] = inbuf[i + size/2];
-        inbuf[i + size/2] = temp;
-    }
-
-    fft(size, false, inbuf, inbuf + size, outbuf, outbuf + size);
-
-    for (size_t i = 0; i < size/2; ++i) {
-        buffer[i * 2] = outbuf[i];
-        buffer[i * 2 + 1] = outbuf[i + size];
-    }
-    
-    delete inbuf;
-    delete outbuf;
-}
-
-void
-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;
-	}
-    }
-}
-
-        
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host/vamp-simple-host.cpp	Mon Apr 24 12:58:27 2006 +0000
@@ -0,0 +1,433 @@
+/* -*- 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 "PluginHostAdapter.h"
+#include "vamp.h"
+
+#include <iostream>
+#include <sndfile.h>
+
+#include "system.h"
+
+#include <cmath>
+
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::string;
+
+void printFeatures(int, int, int, Vamp::Plugin::FeatureSet);
+void transformInput(float *, size_t);
+void fft(unsigned int, bool, double *, double *, double *, double *);
+
+/*
+    A very simple Vamp plugin host.  Given the name of a plugin
+    library and the name of a sound file on the command line, it loads
+    the first plugin in the library and runs it on the sound file,
+    dumping the plugin's first output to stdout.
+*/
+
+int main(int argc, char **argv)
+{
+    if (argc < 2 || argc > 4) {
+        cerr << "Usage: " << argv[0] << " pluginlibrary.so[:plugin] [file.wav] [outputno]" << endl;
+        return 2;
+    }
+
+    cerr << endl << argv[0] << ": Running..." << endl;
+
+    string soname = argv[1];
+    string plugname = "";
+    string wavname;
+    if (argc >= 3) wavname = argv[2];
+
+    int sep = soname.find(":");
+    if (sep >= 0 && sep < soname.length()) {
+        plugname = soname.substr(sep + 1);
+        soname = soname.substr(0, sep);
+    }
+
+    void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
+
+    if (!libraryHandle) {
+        cerr << argv[0] << ": Failed to open plugin library " 
+                  << soname << ": " << DLERROR() << endl;
+        return 1;
+    }
+
+    cerr << argv[0] << ": Opened plugin library " << soname << endl;
+
+    VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
+        DLSYM(libraryHandle, "vampGetPluginDescriptor");
+    
+    if (!fn) {
+        cerr << argv[0] << ": No Vamp descriptor function in library "
+                  << soname << endl;
+        DLCLOSE(libraryHandle);
+        return 1;
+    }
+
+    cerr << argv[0] << ": Found plugin descriptor function" << endl;
+
+    int index = 0;
+    int plugnumber = -1;
+    const VampPluginDescriptor *descriptor = 0;
+
+    while ((descriptor = fn(index))) {
+
+        Vamp::PluginHostAdapter plugin(descriptor, 48000);
+        cerr << argv[0] << ": Plugin " << (index+1)
+                  << " is \"" << plugin.getName() << "\"" << endl;
+
+        if (plugin.getName() == plugname) plugnumber = index;
+        
+        cerr << "(testing overlap...)" << endl;
+        {
+            Vamp::PluginHostAdapter otherPlugin(descriptor, 48000);
+            cerr << "(other plugin reports min " << otherPlugin.getMinChannelCount() << " channels)" << endl;
+        }
+
+        ++index;
+    }
+
+    cerr << argv[0] << ": Done\n" << endl;
+
+    if (wavname == "") {
+        DLCLOSE(libraryHandle);
+        return 0;
+    }
+
+    if (plugnumber < 0) {
+        if (plugname != "") {
+            cerr << "ERROR: No such plugin as " << plugname << " in library"
+                 << endl;
+            DLCLOSE(libraryHandle);
+            return 0;
+        } else {
+            plugnumber = 0;
+        }
+    }
+
+    descriptor = fn(plugnumber);
+    if (!descriptor) {
+        DLCLOSE(libraryHandle);
+        return 0;
+    }
+    
+    SNDFILE *sndfile;
+    SF_INFO sfinfo;
+    memset(&sfinfo, 0, sizeof(SF_INFO));
+
+    sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
+    if (!sndfile) {
+	cerr << "ERROR: Failed to open input file \"" << wavname << "\": "
+	     << sf_strerror(sndfile) << endl;
+        DLCLOSE(libraryHandle);
+	return 1;
+    }
+
+    Vamp::PluginHostAdapter *plugin =
+        new Vamp::PluginHostAdapter(descriptor, sfinfo.samplerate);
+
+    cerr << "Running " << plugin->getName() << "..." << endl;
+
+    int blockSize = plugin->getPreferredBlockSize();
+    int stepSize = plugin->getPreferredStepSize();
+
+    cerr << "Preferred block size = " << blockSize << ", step size = "
+              << stepSize << endl;
+
+    if (blockSize == 0) blockSize = 1024;
+    if (stepSize == 0) stepSize = blockSize;
+
+    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];
+
+    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;
+
+    Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors();
+    Vamp::Plugin::OutputDescriptor od;
+
+    int output = 0;
+    if (argc == 4) output = atoi(argv[3]);
+
+    bool mix = false;
+
+    if (minch > channels || maxch < channels) {
+        if (minch == 1) {
+            cerr << "WARNING: Sound file has " << channels << " channels, mixing down to 1" << endl;
+            mix = true;
+            channels = 1;
+        } else {
+            cerr << "ERROR: Sound file has " << channels << " channels, out of range for plugin" << endl;
+            goto done;
+        }
+    }
+
+    if (outputs.empty()) {
+	cerr << "Plugin has no outputs!" << endl;
+        goto done;
+    }
+
+    if (int(outputs.size()) <= output) {
+	cerr << "Output " << output << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
+        goto done;
+    }        
+
+    od = outputs[output];
+    cerr << "Output is " << od.name << endl;
+
+    plugin->initialise(channels, stepSize, blockSize);
+
+    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) {
+            for (int j = 0; j < blockSize; ++j) {
+                plugbuf[c][j] = 0.0f;
+            }
+        }
+
+        for (int c = 0; c < sfinfo.channels; ++c) {
+            int tc = c;
+            if (mix) tc = 0;
+            for (int j = 0; j < blockSize && j < count; ++j) {
+                plugbuf[tc][j] += filebuf[j * channels + c];
+            }
+
+            if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
+                transformInput(plugbuf[tc], blockSize);
+            }
+        }
+
+        printFeatures
+            (i, sfinfo.samplerate, output, plugin->process
+             (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate)));
+    }
+
+    printFeatures(sfinfo.frames, sfinfo.samplerate, output,
+                  plugin->getRemainingFeatures());
+
+done:
+    delete plugin;
+
+    DLCLOSE(libraryHandle);
+    sf_close(sndfile);
+    return 0;
+}
+
+void
+printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features)
+{
+    for (unsigned int i = 0; i < features[output].size(); ++i) {
+        Vamp::RealTime rt = Vamp::RealTime::frame2RealTime(frame, sr);
+        if (features[output][i].hasTimestamp) {
+            rt = features[output][i].timestamp;
+        }
+        cout << rt.toString() << ":";
+        for (unsigned int j = 0; j < features[output][i].values.size(); ++j) {
+            cout << " " << features[output][i].values[j];
+        }
+        cout << endl;
+    }
+}
+
+void
+transformInput(float *buffer, size_t size)
+{
+    double *inbuf = new double[size * 2];
+    double *outbuf = new double[size * 2];
+
+    // Copy across with Hanning window
+    for (size_t i = 0; i < size; ++i) {
+        inbuf[i] = double(buffer[i]) * (0.50 - 0.50 * cos(2 * M_PI * i / size));
+        inbuf[i + size] = 0.0;
+    }
+    
+    for (size_t i = 0; i < size/2; ++i) {
+        double temp = inbuf[i];
+        inbuf[i] = inbuf[i + size/2];
+        inbuf[i + size/2] = temp;
+    }
+
+    fft(size, false, inbuf, inbuf + size, outbuf, outbuf + size);
+
+    for (size_t i = 0; i < size/2; ++i) {
+        buffer[i * 2] = outbuf[i];
+        buffer[i * 2 + 1] = outbuf[i + size];
+    }
+    
+    delete inbuf;
+    delete outbuf;
+}
+
+void
+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;
+	}
+    }
+}
+
+        
--- a/vamp-sdk/PluginAdapter.cpp	Fri Apr 14 09:37:46 2006 +0000
+++ b/vamp-sdk/PluginAdapter.cpp	Mon Apr 24 12:58:27 2006 +0000
@@ -36,16 +36,26 @@
 
 #include "PluginAdapter.h"
 
+#define DEBUG_PLUGIN_ADAPTER 1
+
+
 namespace Vamp {
 
 PluginAdapterBase::PluginAdapterBase() :
     m_populated(false)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase[" << this << "]::PluginAdapterBase" << std::endl;
+#endif
 }
 
 const VampPluginDescriptor *
 PluginAdapterBase::getDescriptor()
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase[" << this << "]::getDescriptor" << std::endl;
+#endif
+
     if (m_populated) return &m_descriptor;
 
     Plugin *plugin = createPlugin(48000);
@@ -134,6 +144,10 @@
 
 PluginAdapterBase::~PluginAdapterBase()
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase[" << this << "]::~PluginAdapterBase" << std::endl;
+#endif
+
     if (!m_populated) return;
 
     free((void *)m_descriptor.name);
@@ -174,6 +188,10 @@
 PluginAdapterBase *
 PluginAdapterBase::lookupAdapter(VampPluginHandle handle)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::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;
@@ -184,6 +202,10 @@
 PluginAdapterBase::vampInstantiate(const VampPluginDescriptor *desc,
                                    float inputSampleRate)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampInstantiate(" << desc << ")" << std::endl;
+#endif
+
     if (!m_adapterMap) {
         m_adapterMap = new AdapterMap();
     }
@@ -201,12 +223,20 @@
         (*m_adapterMap)[plugin] = adapter;
     }
 
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampInstantiate(" << desc << "): returning handle " << plugin << std::endl;
+#endif
+
     return plugin;
 }
 
 void
 PluginAdapterBase::vampCleanup(VampPluginHandle handle)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampCleanup(" << handle << ")" << std::endl;
+#endif
+
     PluginAdapterBase *adapter = lookupAdapter(handle);
     if (!adapter) {
         delete ((Plugin *)handle);
@@ -221,6 +251,10 @@
                                   unsigned int stepSize,
                                   unsigned int blockSize)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << std::endl;
+#endif
+
     bool result = ((Plugin *)handle)->initialise
         (channels, stepSize, blockSize);
     return result ? 1 : 0;
@@ -229,6 +263,10 @@
 void
 PluginAdapterBase::vampReset(VampPluginHandle handle) 
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampReset(" << handle << ")" << std::endl;
+#endif
+
     ((Plugin *)handle)->reset();
 }
 
@@ -236,6 +274,10 @@
 PluginAdapterBase::vampGetParameter(VampPluginHandle handle,
                                     int param) 
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampGetParameter(" << handle << ", " << param << ")" << std::endl;
+#endif
+
     PluginAdapterBase *adapter = lookupAdapter(handle);
     if (!adapter) return 0.0;
     Plugin::ParameterList &list = adapter->m_parameters;
@@ -246,6 +288,10 @@
 PluginAdapterBase::vampSetParameter(VampPluginHandle handle,
                                     int param, float value)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << std::endl;
+#endif
+
     PluginAdapterBase *adapter = lookupAdapter(handle);
     if (!adapter) return;
     Plugin::ParameterList &list = adapter->m_parameters;
@@ -255,6 +301,10 @@
 unsigned int
 PluginAdapterBase::vampGetCurrentProgram(VampPluginHandle handle)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampGetCurrentProgram(" << handle << ")" << std::endl;
+#endif
+
     PluginAdapterBase *adapter = lookupAdapter(handle);
     if (!adapter) return 0;
     Plugin::ProgramList &list = adapter->m_programs;
@@ -269,6 +319,10 @@
 PluginAdapterBase::vampSelectProgram(VampPluginHandle handle,
                                      unsigned int program)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampSelectProgram(" << handle << ", " << program << ")" << std::endl;
+#endif
+
     PluginAdapterBase *adapter = lookupAdapter(handle);
     if (!adapter) return;
     Plugin::ProgramList &list = adapter->m_programs;
@@ -278,30 +332,50 @@
 unsigned int
 PluginAdapterBase::vampGetPreferredStepSize(VampPluginHandle handle)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampGetPreferredStepSize(" << handle << ")" << std::endl;
+#endif
+
     return ((Plugin *)handle)->getPreferredStepSize();
 }
 
 unsigned int
 PluginAdapterBase::vampGetPreferredBlockSize(VampPluginHandle handle) 
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampGetPreferredBlockSize(" << handle << ")" << std::endl;
+#endif
+
     return ((Plugin *)handle)->getPreferredBlockSize();
 }
 
 unsigned int
 PluginAdapterBase::vampGetMinChannelCount(VampPluginHandle handle)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampGetMinChannelCount(" << handle << ")" << std::endl;
+#endif
+
     return ((Plugin *)handle)->getMinChannelCount();
 }
 
 unsigned int
 PluginAdapterBase::vampGetMaxChannelCount(VampPluginHandle handle)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampGetMaxChannelCount(" << handle << ")" << std::endl;
+#endif
+
     return ((Plugin *)handle)->getMaxChannelCount();
 }
 
 unsigned int
 PluginAdapterBase::vampGetOutputCount(VampPluginHandle handle)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampGetOutputCount(" << handle << ")" << std::endl;
+#endif
+
     PluginAdapterBase *adapter = lookupAdapter(handle);
 
 //    std::cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << std::endl;
@@ -314,6 +388,10 @@
 PluginAdapterBase::vampGetOutputDescriptor(VampPluginHandle handle,
                                            unsigned int i)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampGetOutputDescriptor(" << handle << ", " << i << ")" << std::endl;
+#endif
+
     PluginAdapterBase *adapter = lookupAdapter(handle);
 
 //    std::cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << std::endl;
@@ -325,6 +403,10 @@
 void
 PluginAdapterBase::vampReleaseOutputDescriptor(VampOutputDescriptor *desc)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampReleaseOutputDescriptor(" << desc << ")" << std::endl;
+#endif
+
     if (desc->name) free((void *)desc->name);
     if (desc->description) free((void *)desc->description);
     if (desc->unit) free((void *)desc->unit);
@@ -341,6 +423,10 @@
                                int sec,
                                int nsec)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << std::endl;
+#endif
+
     PluginAdapterBase *adapter = lookupAdapter(handle);
     if (!adapter) return 0;
     return adapter->process((Plugin *)handle,
@@ -350,6 +436,10 @@
 VampFeatureList *
 PluginAdapterBase::vampGetRemainingFeatures(VampPluginHandle handle)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampGetRemainingFeatures(" << handle << ")" << std::endl;
+#endif
+
     PluginAdapterBase *adapter = lookupAdapter(handle);
     if (!adapter) return 0;
     return adapter->getRemainingFeatures((Plugin *)handle);
@@ -358,6 +448,9 @@
 void
 PluginAdapterBase::vampReleaseFeatureSet(VampFeatureList *fs)
 {
+#ifdef DEBUG_PLUGIN_ADAPTER
+    std::cerr << "PluginAdapterBase::vampReleaseFeatureSet" << std::endl;
+#endif
 }
 
 void