changeset 137:648a40f5e322

Merge
author Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 19 Jan 2017 09:27:59 +0000
parents 9b465fa4fcce (current diff) 704b93c2456e (diff)
children 4b593b643918
files examples/Makefile.vamp-example-plugins examples/Makefile.vamp-test-plugin examples/vamp-example-plugins.cpp examples/vamp-test-plugin.cpp
diffstat 13 files changed, 324 insertions(+), 220 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Jan 19 09:27:22 2017 +0000
+++ b/.hgignore	Thu Jan 19 09:27:59 2017 +0000
@@ -1,2 +1,3 @@
 syntax: glob
 *.o
+*~
--- a/Makefile.inc	Thu Jan 19 09:27:22 2017 +0000
+++ b/Makefile.inc	Thu Jan 19 09:27:59 2017 +0000
@@ -7,6 +7,8 @@
 		@echo
 		@echo "$$ make em"
 		@echo "  - build Javascript module using Emscripten"
+		@echo "$$ make test"
+		@echo "  - build and run simple load test of Javascript module using node.js"
 		@echo "$$ make linux"
 		@echo "  - build native-code module on Linux (currently this is mostly for testing)"
 		@echo "$$ make clean"
@@ -65,23 +67,22 @@
 CXX_SOURCES	:= $(MODULE_SOURCE) $(ADAPTER_SOURCES) $(PLUGIN_SOURCES) $(SDK_SOURCES) $(OTHER_SOURCES)
 C_SOURCES	:= $(PLUGIN_C_SOURCES) $(C_SOURCES)
 
-#OPTFLAGS	:= -g3
-OPTFLAGS	:= -O3 -ffast-math
+#OPTFLAGS	?= -g3
+OPTFLAGS	?= -O
 
 DEFINES		:= $(DEFINES)
-
-INCPATH		:= -I$(SRC_DIR) -I$(SDK_DIR) -I$(PIPERCPP_DIR) $(INCPATH)
+INCLUDES	:= -I$(SRC_DIR) -I$(SDK_DIR) -I$(PIPERCPP_DIR) $(INCLUDES)
 
 em:	$(EM_MODULE)
 em:	CXX		:= em++
 em:	CC		:= emcc
-em:	CXXFLAGS	:= -std=c++11 -fPIC -Wall -Wextra $(DEFINES) $(OPTFLAGS) $(EMFLAGS) $(INCPATH)
-em:	CFLAGS		:= -fPIC -Wall -Wextra $(DEFINES) $(OPTFLAGS) $(EMFLAGS) $(INCPATH)
+em:	CXXFLAGS	:= -std=c++11 -fPIC -Wall -Wextra $(DEFINES) $(OPTFLAGS) $(EMFLAGS) $(INCLUDES)
+em:	CFLAGS		:= -fPIC -Wall -Wextra $(DEFINES) $(OPTFLAGS) $(EMFLAGS) $(INCLUDES)
 em:	LDFLAGS		:= $(EMFLAGS)
 
 linux:	$(SO_MODULE)
-linux:	CXXFLAGS	:= -std=c++11 -fPIC -Wall -Wextra $(DEFINES) $(OPTFLAGS) $(INCPATH)
-linux:	CFLAGS		:= -fPIC -Wall -Wextra $(DEFINES) $(OPTFLAGS) $(INCPATH)
+linux:	CXXFLAGS	:= -std=c++11 -fPIC -Wall -Wextra $(DEFINES) $(OPTFLAGS) $(INCLUDES)
+linux:	CFLAGS		:= -fPIC -Wall -Wextra $(DEFINES) $(OPTFLAGS) $(INCLUDES)
 linux:	LDFLAGS		:= -shared -Wl,-Bsymbolic -Wl,-soname=$(SO_MODULE) -Wl,-z,defs -Wl,--version-script=$(SRC_DIR)/piper.map -ldl
 
 OBJDIR          := o
@@ -93,11 +94,11 @@
 
 o/%.o:            %.cpp
 		mkdir -p $(dir $@)
-		$(CXX) -c $(INCPATH) $(CXXFLAGS) -o $@ $<
+		$(CXX) -c $(INCLUDES) $(CXXFLAGS) -o $@ $<
 
 o/%.o:            %.c
 		mkdir -p $(dir $@)
-		$(CC) -c $(INCPATH) $(CFLAGS) -o $@ $<
+		$(CC) -c $(INCLUDES) $(CFLAGS) -o $@ $<
 
 $(EM_MODULE):	$(OBJECTS)
 		$(CXX) $(OPTFLAGS) -o $@ $^ $(LDFLAGS) && \
@@ -106,6 +107,9 @@
 $(SO_MODULE):	$(OBJECTS)
 		$(CXX) -o $@ $^ $(LDFLAGS)
 
+test:		em
+		node $(MY_DIR)/test/node-load-test.js $(shell pwd)/$(EM_MODULE)
+
 clean:
 		rm -f $(OBJECTS)
 
--- a/examples/Makefile.vamp-example-plugins	Thu Jan 19 09:27:22 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-
-MODULE_NAME	:= VampExamplePlugins
-
-EXAMPLE_DIR	:= ../../vamp-plugin-sdk/examples
-
-PLUGIN_SOURCES	:= \
-		$(EXAMPLE_DIR)/ZeroCrossing.cpp \
-		$(EXAMPLE_DIR)/SpectralCentroid.cpp \
-		$(EXAMPLE_DIR)/PercussionOnsetDetector.cpp \
-		$(EXAMPLE_DIR)/FixedTempoEstimator.cpp \
-		$(EXAMPLE_DIR)/AmplitudeFollower.cpp \
-		$(EXAMPLE_DIR)/PowerSpectrum.cpp
-
-MODULE_SOURCE	:= vamp-example-plugins.cpp
-
-include ../Makefile.inc
--- a/examples/Makefile.vamp-test-plugin	Thu Jan 19 09:27:22 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-
-MODULE_NAME	:= VampTestPlugin
-
-TESTPLUGIN_DIR	:= ../../vamp-test-plugin
-
-INCPATH		:= -I$(TESTPLUGIN_DIR)
-
-PLUGIN_SOURCES	:= \
-		$(TESTPLUGIN_DIR)/VampTestPlugin.cpp
-
-MODULE_SOURCE	:= vamp-test-plugin.cpp
-
-include ../Makefile.inc
--- a/examples/vamp-example-plugins.cpp	Thu Jan 19 09:27:22 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
-
-/*
-    Piper
-
-    Centre for Digital Music, Queen Mary, University of London.
-    Copyright 2015-2016 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 "PiperAdapter.h"
-#include "PiperPluginLibrary.h"
-
-#include "examples/ZeroCrossing.h"
-#include "examples/SpectralCentroid.h"
-#include "examples/PercussionOnsetDetector.h"
-#include "examples/FixedTempoEstimator.h"
-#include "examples/AmplitudeFollower.h"
-#include "examples/PowerSpectrum.h"
-
-using piper_vamp_js::PiperAdapter;
-using piper_vamp_js::PiperPluginLibrary;
-
-static std::string soname("vamp-example-plugins");
-
-static PiperAdapter<ZeroCrossing> zeroCrossingAdapter(soname);
-static PiperAdapter<SpectralCentroid> spectralCentroidAdapter(soname);
-static PiperAdapter<PercussionOnsetDetector> percussionOnsetAdapter(soname);
-static PiperAdapter<FixedTempoEstimator> fixedTempoAdapter(soname);
-static PiperAdapter<AmplitudeFollower> amplitudeAdapter(soname);
-static PiperAdapter<PowerSpectrum> powerSpectrumAdapter(soname);
-
-static PiperPluginLibrary library({
-    &zeroCrossingAdapter,
-    &spectralCentroidAdapter,
-    &percussionOnsetAdapter,
-    &fixedTempoAdapter,
-    &amplitudeAdapter,
-    &powerSpectrumAdapter
-});
-
-extern "C" {
-
-const char *piperRequestJson(const char *request) {
-    return library.requestJson(request);
-}
-
-const char *piperProcessRaw(int handle,
-                              const float *const *inputBuffers,
-                              int sec,
-                              int nsec) {
-    return library.processRaw(handle, inputBuffers, sec, nsec);
-}
-    
-void piperFreeJson(const char *json) {
-    return library.freeJson(json);
-}
-
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/vamp-example-plugins/Makefile	Thu Jan 19 09:27:59 2017 +0000
@@ -0,0 +1,20 @@
+
+PIPER_VAMP_JS_DIR	:= ../..
+PLUGIN_SRC_DIR		:= ../../../vamp-plugin-sdk/examples
+
+MODULE_NAME		:= VampExamplePlugins
+MODULE_SOURCE		:= vamp-example-plugins.cpp
+
+SOURCE_FILES	:= \
+		ZeroCrossing.cpp \
+		SpectralCentroid.cpp \
+		PercussionOnsetDetector.cpp \
+		FixedTempoEstimator.cpp \
+		AmplitudeFollower.cpp \
+		PowerSpectrum.cpp
+
+PLUGIN_SOURCES	:= $(addprefix $(PLUGIN_SRC_DIR)/,$(SOURCE_FILES))
+
+INCLUDES	:= -I$(PLUGIN_SRC_DIR)
+
+include $(PIPER_VAMP_JS_DIR)/Makefile.inc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/vamp-example-plugins/vamp-example-plugins.cpp	Thu Jan 19 09:27:59 2017 +0000
@@ -0,0 +1,66 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Piper
+
+    Centre for Digital Music, Queen Mary, University of London.
+    Copyright 2015-2016 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 "PiperExport.h"
+
+#include "ZeroCrossing.h"
+#include "SpectralCentroid.h"
+#include "PercussionOnsetDetector.h"
+#include "FixedTempoEstimator.h"
+#include "AmplitudeFollower.h"
+#include "PowerSpectrum.h"
+
+using piper_vamp_js::PiperAdapter;
+using piper_vamp_js::PiperPluginLibrary;
+
+static std::string soname("vamp-example-plugins");
+
+static PiperAdapter<ZeroCrossing> zeroCrossingAdapter(soname);
+static PiperAdapter<SpectralCentroid> spectralCentroidAdapter(soname);
+static PiperAdapter<PercussionOnsetDetector> percussionOnsetAdapter(soname);
+static PiperAdapter<FixedTempoEstimator> fixedTempoAdapter(soname);
+static PiperAdapter<AmplitudeFollower> amplitudeAdapter(soname);
+static PiperAdapter<PowerSpectrum> powerSpectrumAdapter(soname);
+
+static PiperPluginLibrary library({
+    &zeroCrossingAdapter,
+    &spectralCentroidAdapter,
+    &percussionOnsetAdapter,
+    &fixedTempoAdapter,
+    &amplitudeAdapter,
+    &powerSpectrumAdapter
+});
+
+PIPER_EXPORT_LIBRARY(library);
+
--- a/examples/vamp-test-plugin.cpp	Thu Jan 19 09:27:22 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
-/*
-    Vamp Test Plugin
-    Copyright (c) 2013-2016 Queen Mary, University of London
-
-    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 AUTHOR 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 and Queen Mary, University of London shall not be
-    used in advertising or otherwise to promote the sale, use or other
-    dealings in this Software without prior written authorization.
-*/
-
-#include "PiperAdapter.h"
-#include "PiperPluginLibrary.h"
-
-#include "VampTestPlugin.h"
-
-using piper_vamp_js::PiperAdapter;
-using piper_vamp_js::PiperAdapterBase;
-using piper_vamp_js::PiperPluginLibrary;
-
-static std::string soname("vamp-test-plugin");
-
-class Adapter : public PiperAdapterBase<VampTestPlugin>
-{
-public:
-    Adapter(bool freq) :
-        PiperAdapterBase<VampTestPlugin>(soname),
-        m_freq(freq) { }
-
-protected:
-    bool m_freq;
-
-    Vamp::Plugin *createPlugin(float inputSampleRate) const {
-        return new VampTestPlugin(inputSampleRate, m_freq);
-    }
-};
-
-static Adapter timeAdapter(false);
-static Adapter freqAdapter(true);
-
-static PiperPluginLibrary library({
-    &timeAdapter,
-    &freqAdapter
-});
-
-extern "C" {
-
-const char *piperRequestJson(const char *request) {
-    return library.requestJson(request);
-}
-
-const char *piperProcessRaw(int handle,
-                              const float *const *inputBuffers,
-                              int sec,
-                              int nsec) {
-    return library.processRaw(handle, inputBuffers, sec, nsec);
-}
-    
-void piperFreeJson(const char *json) {
-    return library.freeJson(json);
-}
-
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/vamp-test-plugin/Makefile	Thu Jan 19 09:27:59 2017 +0000
@@ -0,0 +1,11 @@
+
+PIPER_VAMP_JS_DIR	:= ../..
+PLUGIN_SRC_DIR		:= ../../../vamp-test-plugin
+
+MODULE_NAME		:= VampTestPlugin
+MODULE_SOURCE		:= vamp-test-plugin.cpp
+
+PLUGIN_SOURCES		:= $(PLUGIN_SRC_DIR)/VampTestPlugin.cpp
+INCLUDES		:= -I$(PLUGIN_SRC_DIR)
+
+include $(PIPER_VAMP_JS_DIR)/Makefile.inc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/vamp-test-plugin/vamp-test-plugin.cpp	Thu Jan 19 09:27:59 2017 +0000
@@ -0,0 +1,82 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+/*
+    Vamp Test Plugin
+    Copyright (c) 2013-2016 Queen Mary, University of London
+
+    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 AUTHOR 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 and Queen Mary, University of London shall not be
+    used in advertising or otherwise to promote the sale, use or other
+    dealings in this Software without prior written authorization.
+*/
+
+#include "PiperExport.h"
+
+#include "VampTestPlugin.h"
+
+using piper_vamp_js::PiperAdapter;
+using piper_vamp_js::PiperAdapterBase;
+using piper_vamp_js::PiperPluginLibrary;
+
+static std::string soname("vamp-test-plugin");
+
+/*
+   This is an example of a library that exports more than one "plugin"
+   from a single C++ class. The VampTestPlugin class is constructed
+   with an argument that determines whether it is a time- or
+   frequency-domain plugin, and the library offers both.
+
+   Where normally a library that offered two plugins would have two
+   static PiperAdapters specialised with the two plugin classes, here
+   we want two static PiperAdapters specialised with the same class
+   but different constructor arguments. This is one way to do that,
+   taking advantage of the fact that PiperAdapterBase exposes
+   createPlugin as a virtual method.
+
+   Note that a very similar mechanism is used in the standard Vamp
+   version of this plugin library.
+*/
+
+class Adapter : public PiperAdapterBase<VampTestPlugin>
+{
+public:
+    Adapter(bool freq) :
+        PiperAdapterBase<VampTestPlugin>(soname),
+        m_freq(freq) { }
+
+protected:
+    bool m_freq;
+
+    Vamp::Plugin *createPlugin(float inputSampleRate) const {
+        return new VampTestPlugin(inputSampleRate, m_freq);
+    }
+};
+
+static Adapter timeAdapter(false);
+static Adapter freqAdapter(true);
+
+static PiperPluginLibrary library({
+    &timeAdapter,
+    &freqAdapter
+});
+
+PIPER_EXPORT_LIBRARY(library);
+
--- a/src/PiperAdapter.h	Thu Jan 19 09:27:22 2017 +0000
+++ b/src/PiperAdapter.h	Thu Jan 19 09:27:59 2017 +0000
@@ -114,12 +114,27 @@
 	if (p->getMinChannelCount() == p->getMaxChannelCount()) {
 	    defaultChannels = p->getMinChannelCount();
 	}
-    
-	response.defaultConfiguration = piper_vamp::PluginConfiguration::fromPlugin
+
+        int defaultBlockSize = p->getPreferredBlockSize();
+        int defaultStepSize = p->getPreferredStepSize();
+
+        if (defaultBlockSize == 0) {
+            defaultBlockSize = 1024;
+        }
+        if (defaultStepSize == 0) {
+            if (p->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
+                defaultStepSize = defaultBlockSize / 2;
+            } else {
+                defaultStepSize = defaultBlockSize;
+            }
+        }
+        
+	response.defaultConfiguration =
+            piper_vamp::PluginConfiguration::fromPlugin
 	    (p,
 	     defaultChannels,
-	     p->getPreferredStepSize(),
-	     p->getPreferredBlockSize());
+	     defaultStepSize,
+             defaultBlockSize);
     
 	return response;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/PiperExport.h	Thu Jan 19 09:27:59 2017 +0000
@@ -0,0 +1,68 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Piper Vamp JSON Adapter
+
+    Centre for Digital Music, Queen Mary, University of London.
+    Copyright 2015-2016 QMUL.
+  
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+    Except as contained in this notice, the names of the Centre for
+    Digital Music; Queen Mary, University of London; and Chris Cannam
+    shall not be used in advertising or otherwise to promote the sale,
+    use or other dealings in this Software without prior written
+    authorization.
+*/
+
+#ifndef PIPER_EXPORT_H
+#define PIPER_EXPORT_H
+
+#ifdef _VAMP_IN_PLUGINSDK
+#error You must include PiperExport.h before any other files that use the Vamp SDK
+#endif
+
+// Include all the Piper headers that an export program may need here:
+// for a simple Vamp plugin library, this one should be the only Piper
+// #include
+
+#include "PiperAdapter.h"
+#include "PiperPluginLibrary.h"
+
+// Convenience macros for the usual case with a static
+// PiperPluginLibrary object to export C wrappers for
+
+#define PIPER_EXPORT_LIBRARY(library)					\
+    extern "C" {							\
+	const char *piperRequestJson(const char *request) {		\
+	    return library.requestJson(request);			\
+	}								\
+	const char *piperProcessRaw(int handle,				\
+				    const float *const *inputBuffers,	\
+				    int sec,				\
+				    int nsec) {				\
+	    return library.processRaw(handle, inputBuffers, sec, nsec);	\
+	}								\
+	void piperFreeJson(const char *json) {				\
+	    return library.freeJson(json);				\
+	}								\
+    }
+
+#endif
--- a/test/node-load-test.js	Thu Jan 19 09:27:22 2017 +0000
+++ b/test/node-load-test.js	Thu Jan 19 09:27:59 2017 +0000
@@ -4,14 +4,19 @@
     console.log(blah);
 }
 
-if (process.argv.length < 4) {
-    note("\nUsage: " + process.argv[0] + " <LibraryPath> <pluginKey>");
+if (process.argv.length < 3 || process.argv.length > 4) {
+    note("\nUsage: " + process.argv[0] + " <librarypath> [<pluginkey>]");
+    note("e.g. " + process.argv[0] + " ./VampExamplePlugins.js");
     note("e.g. " + process.argv[0] + " ./VampExamplePlugins.js vamp-example-plugins:zerocrossing");
-    throw "Wrong number of command-line args (2 expected)"
+    throw "Wrong number of command-line args (1 or 2 expected)"
 }
 
 var libraryPath = process.argv[2];
-var pluginKey = process.argv[3];
+
+var pluginKey = "";
+if (process.argv.length > 3) {
+    pluginKey = process.argv[3];
+}
 
 var base64 = require("./base64");
 
@@ -141,12 +146,34 @@
     return features;
 }
 
+function checkSuccess(response) {
+    if (response.error) {
+	console.log("Request type " + response.method + " failed: " +
+		    response.error.message);
+	throw response.error.message;
+    }
+}
+
 function test() {
 
+    let start = (new Date()).getTime();
+
     const rate = 44100;
+
+    note("Listing plugins...");
+    let response = request({
+	method: "list"
+    });
+    checkSuccess(response);
+
+    if (pluginKey === "") {
+	pluginKey = response.result.available[0].key;
+	note("Loading first plugin \"" + pluginKey + "\"...");
+    } else {
+	note("Loading requested plugin \"" + pluginKey + "\"...");
+    }
     
-    note("Loading plugin \"" + pluginKey + "\"...");
-    let response = request({
+    response = request({
         method: "load",
         params: {
             key: pluginKey,
@@ -154,8 +181,10 @@
             adapterFlags: ["AdaptAllSafe"]
         }
     });
+    checkSuccess(response);
 
-    const blockSize = 1024;
+    const blockSize = response.result.defaultConfiguration.blockSize;
+    const stepSize = response.result.defaultConfiguration.stepSize;
 
     response = request({
         method: "configure",
@@ -163,11 +192,12 @@
             handle: 1,
             configuration: {
                 blockSize: blockSize,
-                channelCount: 1,
-                stepSize: blockSize
+                stepSize: stepSize,
+                channelCount: 1
             }
         }
     });
+    checkSuccess(response);
 
     const nblocks = 1000;
 
@@ -196,7 +226,6 @@
         for (let featureList of features.values()) {
             featureCount += featureList.length;
         }
-        console.log(i);
     }
 
     note("Cleaning up the plugin and getting any remaining features...");
@@ -206,6 +235,7 @@
             handle: 1
         }
     });
+    checkSuccess(response);
 
     let features = responseToFeatureSet(response);
     for (let featureList of features.values()) {
@@ -213,6 +243,9 @@
     }
     
     note("Done, total number of features across all outputs = " + featureCount);
+
+    let finish = (new Date()).getTime();
+    note("Total time taken " + (finish - start) + " ms");
 }
 
 test();