changeset 532:569fc23fa37a

Merge from branch c++11-mutex
author Chris Cannam
date Tue, 22 Oct 2019 12:23:53 +0100
parents 0b6802e3b755 (current diff) 347ad7d3527c (diff)
children a7e6d747fd3f
files
diffstat 23 files changed, 518 insertions(+), 500 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG	Wed Aug 14 14:58:04 2019 +0100
+++ b/CHANGELOG	Tue Oct 22 12:23:53 2019 +0100
@@ -1,3 +1,19 @@
+
+Version 2.9, 2019-10-23 (maintenance release)
+
+  * Fix non-thread-safe behaviour in PluginAdapter. Plugins built
+    using the adapter classes in version 2.8 or earlier cannot safely
+    be used simultaneously across threads with other instances of
+    themselves or of other plugins in the same library (i.e. shared
+    object). Hosts have been required to provide synchronisation for
+    such cases. Version 2.9 introduces synchronisation in the plugin,
+    making this usage safe. Unfortunately this does not make host code
+    safe when using older plugin builds, as the problem and its fix
+    are in the plugin side of the SDK. Caution is still required, but
+    this fix does allow updated plugin builds to avoid problems with
+    some existing hosts
+  * Change required C++ language standard from C++98 to C++11. This
+    is because of the use of std::mutex in the above fix
 
 Version 2.8, 2019-02-07 (maintenance and minor feature release)
 
--- a/Makefile.in	Wed Aug 14 14:58:04 2019 +0100
+++ b/Makefile.in	Tue Oct 22 12:23:53 2019 +0100
@@ -41,7 +41,7 @@
 CC		= @CC@
 CXX		= @CXX@
 CFLAGS		= @CFLAGS@
-CXXFLAGS	= -I. @CXXFLAGS@ @SNDFILE_CFLAGS@ 
+CXXFLAGS	= -std=c++11 -I. @CXXFLAGS@ @SNDFILE_CFLAGS@ 
 
 # ar, ranlib
 #
@@ -78,13 +78,13 @@
 INSTALL_PLUGINS		  = $(INSTALL_PREFIX)/lib/vamp
 INSTALL_BINARIES	  = $(INSTALL_PREFIX)/bin 
 
-INSTALL_SDK_LIBNAME	  = libvamp-sdk.so.2.8.0
+INSTALL_SDK_LIBNAME	  = libvamp-sdk.so.2.9.0
 INSTALL_SDK_LINK_ABI	  = libvamp-sdk.so.2
 INSTALL_SDK_LINK_DEV	  = libvamp-sdk.so
 INSTALL_SDK_STATIC        = libvamp-sdk.a
 INSTALL_SDK_LA            = libvamp-sdk.la
 
-INSTALL_HOSTSDK_LIBNAME   = libvamp-hostsdk.so.3.8.0
+INSTALL_HOSTSDK_LIBNAME   = libvamp-hostsdk.so.3.9.0
 INSTALL_HOSTSDK_LINK_ABI  = libvamp-hostsdk.so.3
 INSTALL_HOSTSDK_LINK_DEV  = libvamp-hostsdk.so
 INSTALL_HOSTSDK_STATIC    = libvamp-hostsdk.a
@@ -113,7 +113,7 @@
 	HOSTSDK_DYNAMIC_LDFLAGS	  = $(DYNAMIC_LDFLAGS)
 	PLUGIN_LDFLAGS		  = $(DYNAMIC_LDFLAGS) -exported_symbols_list build/vamp-plugin.list
 
-	INSTALL_HOSTSDK_LIBNAME   = libvamp-hostsdk.3.8.0.dylib
+	INSTALL_HOSTSDK_LIBNAME   = libvamp-hostsdk.3.9.0.dylib
 	INSTALL_HOSTSDK_LINK_ABI  = libvamp-hostsdk.3.dylib
 
 # The OS X linker doesn't allow you to request static linkage when
@@ -122,7 +122,7 @@
 # dynamic, the static library will never be used. That's OK for the
 # host SDK, but we do want plugins to get static linkage of the plugin
 # SDK. So install the dynamic version under a different name.
-	INSTALL_SDK_LIBNAME	  = libvamp-sdk-dynamic.2.8.0.dylib
+	INSTALL_SDK_LIBNAME	  = libvamp-sdk-dynamic.2.9.0.dylib
 	INSTALL_SDK_LINK_ABI	  = libvamp-sdk-dynamic.2.dylib
 
 endif
--- a/README	Wed Aug 14 14:58:04 2019 +0100
+++ b/README	Tue Oct 22 12:23:53 2019 +0100
@@ -9,7 +9,7 @@
 Vamp is an API for C and C++ plugins that process sampled audio data
 to produce descriptive output (measurements or semantic observations).
 
-This is version 2.8 of the Vamp plugin Software Development Kit.
+This is version 2.9 of the Vamp plugin Software Development Kit.
 
 Plugins and hosts built with this SDK are binary compatible with those
 built using any version 2.0 or newer of the SDK.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/acinclude.m4	Tue Oct 22 12:23:53 2019 +0100
@@ -0,0 +1,143 @@
+
+# From autoconf archive:
+
+# ============================================================================
+#  http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the C++11
+#   standard; if necessary, add switches to CXXFLAGS to enable support.
+#
+#   The first argument, if specified, indicates whether you insist on an
+#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+#   -std=c++11).  If neither is specified, you get whatever works, with
+#   preference for an extended mode.
+#
+#   The second argument, if specified 'mandatory' or if left unspecified,
+#   indicates that baseline C++11 support is required and that the macro
+#   should error out if no mode with that support is found.  If specified
+#   'optional', then configuration proceeds regardless, after defining
+#   HAVE_CXX11 if and only if a supporting mode is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+#   Copyright (c) 2014 Alexey Sokolov <sokolov@google.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
+  template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+    struct Base {
+    virtual void f() {}
+    };
+    struct Child : public Base {
+    virtual void f() override {}
+    };
+
+    typedef check<check<bool>> right_angle_brackets;
+
+    int a;
+    decltype(a) b;
+
+    typedef check<int> check_type;
+    check_type c;
+    check_type&& cr = static_cast<check_type&&>(c);
+
+    auto d = a;
+    auto l = [](){};
+]])
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
+  m4_if([$1], [], [],
+        [$1], [ext], [],
+        [$1], [noext], [],
+        [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
+  m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
+        [$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
+        [$2], [optional], [ax_cxx_compile_cxx11_required=false],
+        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
+  AC_LANG_PUSH([C++])dnl
+  ac_success=no
+  AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
+  ax_cv_cxx_compile_cxx11,
+  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+    [ax_cv_cxx_compile_cxx11=yes],
+    [ax_cv_cxx_compile_cxx11=no])])
+  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+    ac_success=yes
+  fi
+
+  m4_if([$1], [noext], [], [dnl
+  if test x$ac_success = xno; then
+    for switch in -std=gnu++11 -std=gnu++0x; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+                     $cachevar,
+        [ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXXFLAGS="$ac_save_CXXFLAGS"])
+      if eval test x\$$cachevar = xyes; then
+        CXXFLAGS="$CXXFLAGS $switch"
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+
+  m4_if([$1], [ext], [], [dnl
+  if test x$ac_success = xno; then
+    for switch in -std=c++11 -std=c++0x; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+                     $cachevar,
+        [ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXXFLAGS="$ac_save_CXXFLAGS"])
+      if eval test x\$$cachevar = xyes; then
+        CXXFLAGS="$CXXFLAGS $switch"
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+  AC_LANG_POP([C++])
+  if test x$ax_cxx_compile_cxx11_required = xtrue; then
+    if test x$ac_success = xno; then
+      AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
+    fi
+  else
+    if test x$ac_success = xno; then
+      HAVE_CXX11=0
+      AC_MSG_NOTICE([No compiler with C++11 support was found])
+    else
+      HAVE_CXX11=1
+      AC_DEFINE(HAVE_CXX11,1,
+                [define if the compiler supports basic C++11 syntax])
+    fi
+
+    AC_SUBST(HAVE_CXX11)
+  fi
+])
--- a/build/Doxyfile	Wed Aug 14 14:58:04 2019 +0100
+++ b/build/Doxyfile	Tue Oct 22 12:23:53 2019 +0100
@@ -31,7 +31,7 @@
 # This could be handy for archiving the generated documentation or 
 # if some version control system is used.
 
-PROJECT_NUMBER         = 2.8
+PROJECT_NUMBER         = 2.9
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
 # base path where the generated documentation will be put. 
--- a/build/Makefile.osx	Wed Aug 14 14:58:04 2019 +0100
+++ b/build/Makefile.osx	Tue Oct 22 12:23:53 2019 +0100
@@ -70,7 +70,7 @@
 # Compile flags
 #
 CFLAGS		+= $(ARCHFLAGS) -fPIC
-CXXFLAGS	+= $(ARCHFLAGS) -O2 -Wall -I. -I/usr/local/include -fPIC
+CXXFLAGS	+= $(ARCHFLAGS) -std=c++11 -O2 -Wall -I. -I/usr/local/include -fPIC
 
 # Link flags common to all link targets
 #
--- a/build/Makefile.osx.106	Wed Aug 14 14:58:04 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,400 +0,0 @@
-
-# Makefile for the Vamp plugin SDK.  This builds the SDK objects,
-# libraries, example plugins, and the test host.  Please adjust to
-# suit your operating system requirements.
-#
-# This version of the Makefile is approximately correct for OS/X.
-# Note that it has no "install" target; the following are the
-# library and related files that may be of interest resulting from
-# the build:
-# 
-#   libvamp-sdk.dylib                 [SDK dynamic library for plugins]
-#   libvamp-hostsdk.dylib             [SDK dynamic library for hosts]
-#
-#   libvamp-sdk.a                     [SDK static library for plugins]
-#   libvamp-hostsdk.a                 [SDK static library for hosts]
-#
-#   examples/vamp-example-plugins.cat     [copy this to your Vamp plugin dir]
-#   examples/vamp-example-plugins.dylib   [copy this to your Vamp plugin dir]
-#
-#   host/vamp-simple-host                 [requires libsndfile to build]
-#
-#   rdf/generator/vamp-rdf-template-generator
-
-# Makefile for the Vamp plugin SDK.  This builds the SDK objects,
-# libraries, example plugins, and the test host.  Please adjust to
-# suit your operating system requirements.
-
-APIDIR		= vamp
-
-SDKDIR		= vamp-sdk
-HOSTSDKDIR	= vamp-hostsdk
-
-SRCDIR		= src
-SDKSRCDIR	= src/vamp-sdk
-HOSTSDKSRCDIR	= src/vamp-hostsdk
-
-EXAMPLEDIR	= examples
-HOSTDIR		= host
-PCDIR		= pkgconfig
-LADIR		= build
-RDFGENDIR	= rdf/generator
-
-###
-### Start of user-serviceable parts
-###
-
-# Default build target (or use "make <target>" to select one).
-# Targets are:
-#   all       -- build everything
-#   sdk       -- build all the Vamp SDK libraries for plugins and hosts
-#   sdkstatic -- build only the static versions of the SDK libraries
-#   plugins   -- build the example plugins (and the SDK if required)
-#   host      -- build the simple Vamp plugin host (and the SDK if required)
-#   rdfgen    -- build the RDF template generator (and the SDK if required)
-#   test      -- build the host and example plugins, and run a quick test
-#   clean     -- remove binary targets
-#   distclean -- remove all targets
-#
-default:	all
-
-# Architecture and developer SDK selection flags.  Change these only
-# if you want to select a different OS/X compatibility level from the
-# default.
-#
-# By default, we try to find the oldest available SDK that is newer
-# than 10.4.
-# 
-# If you want to override this to select a particular SDK, change
-# PREFERRED_SDK to the SDK name (e.g. "10.4u") and PREFERRED_MINVERSION
-# to the minimum OS revision (e.g. "10.4").  An example follows this code.
-# 
-SDKPREFIX	:= /Developer/SDKs/MacOSX
-SDKS		:= $(wildcard $(SDKPREFIX)*.sdk)
-SDKVERSIONS	:= $(patsubst $(SDKPREFIX)%.sdk,%,$(SDKS))
-GOOD_SDKS	:= $(filter-out 10.1%,$(filter-out 10.2%,$(filter-out 10.3%,$(filter-out 10.4%,$(SDKVERSIONS)))))
-#
-PREFERRED_SDK	:= $(word 1, $(sort $(GOOD_SDKS)))
-PREFERRED_MINVERSION  := $(patsubst %u,%,$(PREFERRED_SDK))
-#
-# Example: to set your own values, uncomment and adjust:
-# PREFERRED_SDK	:= 10.4u
-# PREFERRED_MINVERSION  := 10.4
-
-SDKFLAGS	= -isysroot /Developer/SDKs/MacOSX$(PREFERRED_SDK).sdk -mmacosx-version-min=$(PREFERRED_MINVERSION)
-
-# Our default is to try to build for all available architectures in a
-# universal binary.
-#
-ARCHFLAGS = $(SDKFLAGS) -arch i386 -arch x86_64 -arch ppc
-
-# Compile flags
-#
-CFLAGS		= $(ARCHFLAGS) -fPIC
-CXXFLAGS	= $(ARCHFLAGS) -O2 -Wall -I. -fPIC
-
-# Link flags common to all link targets
-#
-LDFLAGS		= $(ARCHFLAGS) 
-
-# ar, ranlib
-#
-AR		= ar
-RANLIB		= ranlib
-RM_F		= rm -f
-
-# Libraries required for the plugins.
-#
-PLUGIN_LIBS	= ./libvamp-sdk.a
-
-# File extension for a dynamically loadable object
-#
-PLUGIN_EXT	= .dylib
-
-# Libraries required for the host.
-#
-HOST_LIBS	= ./libvamp-hostsdk.a -lsndfile -ldl
-
-# Libraries required for the RDF template generator.
-#
-RDFGEN_LIBS	= ./libvamp-hostsdk.a -ldl
-
-# Flags required to tell the compiler to create a dynamically loadable object
-#
-DYNAMIC_LDFLAGS		= $(ARCHFLAGS) -dynamiclib 
-
-# Flags for building specific plugin and library targets.  We need to
-# tell the linker the formal name for the library, and for plugins we
-# also want to tell the linker to make all symbols in the library
-# hidden except for the public entry point (making for a tidier library).
-#
-PLUGIN_LDFLAGS		= $(DYNAMIC_LDFLAGS) \
-			  -install_name vamp-example-plugins.dylib \
-			  -exported_symbols_list build/vamp-plugin.list
-SDK_DYNAMIC_LDFLAGS	= $(DYNAMIC_LDFLAGS) -install_name libvamp-sdk.dylib
-HOSTSDK_DYNAMIC_LDFLAGS	= $(DYNAMIC_LDFLAGS) -install_name libvamp-hostsdk.dylib
-
-
-### End of user-serviceable parts
-
-
-API_HEADERS	= \
-		$(APIDIR)/vamp.h
-
-SDK_HEADERS	= \
-		$(SDKDIR)/Plugin.h \
-		$(SDKDIR)/PluginAdapter.h \
-		$(SDKDIR)/PluginBase.h \
-		$(SDKDIR)/RealTime.h \
-		$(SDKDIR)/FFT.h \
-		$(SDKDIR)/plugguard.h \
-		$(SDKDIR)/vamp-sdk.h
-
-HOSTSDK_HEADERS	= \
-		$(HOSTSDKDIR)/Plugin.h \
-		$(HOSTSDKDIR)/PluginBase.h \
-		$(HOSTSDKDIR)/PluginHostAdapter.h \
-		$(HOSTSDKDIR)/RealTime.h \
-		$(HOSTSDKDIR)/PluginBufferingAdapter.h \
-		$(HOSTSDKDIR)/PluginChannelAdapter.h \
-		$(HOSTSDKDIR)/PluginInputDomainAdapter.h \
-		$(HOSTSDKDIR)/PluginLoader.h \
-		$(HOSTSDKDIR)/PluginSummarisingAdapter.h \
-		$(HOSTSDKDIR)/PluginWrapper.h \
-		$(HOSTSDKDIR)/hostguard.h \
-		$(HOSTSDKDIR)/host-c.h \
-		$(HOSTSDKDIR)/vamp-hostsdk.h
-
-SDK_OBJECTS	= \
-		$(SDKSRCDIR)/PluginAdapter.o \
-		$(SDKSRCDIR)/RealTime.o \
-		$(SDKSRCDIR)/FFT.o \
-		$(SDKSRCDIR)/acsymbols.o
-
-HOSTSDK_OBJECTS	= \
-		$(HOSTSDKSRCDIR)/Files.o \
-		$(HOSTSDKSRCDIR)/PluginHostAdapter.o \
-		$(HOSTSDKSRCDIR)/RealTime.o \
-		$(HOSTSDKSRCDIR)/PluginBufferingAdapter.o \
-		$(HOSTSDKSRCDIR)/PluginChannelAdapter.o \
-		$(HOSTSDKSRCDIR)/PluginInputDomainAdapter.o \
-		$(HOSTSDKSRCDIR)/PluginLoader.o \
-		$(HOSTSDKSRCDIR)/PluginSummarisingAdapter.o \
-		$(HOSTSDKSRCDIR)/PluginWrapper.o \
-		$(HOSTSDKSRCDIR)/host-c.o \
-		$(HOSTSDKSRCDIR)/acsymbols.o
-
-SDK_STATIC	= \
-		./libvamp-sdk.a
-
-HOSTSDK_STATIC	= \
-		./libvamp-hostsdk.a
-
-SDK_DYNAMIC	= \
-		./libvamp-sdk$(PLUGIN_EXT)
-
-HOSTSDK_DYNAMIC	= \
-		./libvamp-hostsdk$(PLUGIN_EXT)
-
-SDK_LA		= \
-		$(LADIR)/libvamp-sdk.la
-
-HOSTSDK_LA	= \
-		$(LADIR)/libvamp-hostsdk.la
-
-PLUGIN_HEADERS	= \
-		$(EXAMPLEDIR)/SpectralCentroid.h \
-		$(EXAMPLEDIR)/PowerSpectrum.h \
-		$(EXAMPLEDIR)/PercussionOnsetDetector.h \
-		$(EXAMPLEDIR)/FixedTempoEstimator.h \
-		$(EXAMPLEDIR)/AmplitudeFollower.h \
-		$(EXAMPLEDIR)/ZeroCrossing.h
-
-PLUGIN_OBJECTS	= \
-		$(EXAMPLEDIR)/SpectralCentroid.o \
-		$(EXAMPLEDIR)/PowerSpectrum.o \
-		$(EXAMPLEDIR)/PercussionOnsetDetector.o \
-		$(EXAMPLEDIR)/FixedTempoEstimator.o \
-		$(EXAMPLEDIR)/AmplitudeFollower.o \
-		$(EXAMPLEDIR)/ZeroCrossing.o \
-		$(EXAMPLEDIR)/plugins.o
-
-PLUGIN_TARGET	= \
-		$(EXAMPLEDIR)/vamp-example-plugins$(PLUGIN_EXT)
-
-HOST_HEADERS	= \
-		$(HOSTDIR)/system.h
-
-HOST_OBJECTS	= \
-		$(HOSTDIR)/vamp-simple-host.o
-
-HOST_TARGET	= \
-		$(HOSTDIR)/vamp-simple-host
-
-RDFGEN_OBJECTS	= \
-		$(RDFGENDIR)/vamp-rdf-template-generator.o
-
-RDFGEN_TARGET	= \
-		$(RDFGENDIR)/vamp-rdf-template-generator
-
-show:
-		@echo " *** Found available SDK versions: $(SDKVERSIONS)"
-		@test -n "$(PREFERRED_SDK)" || ( echo "Error: Failed to establish preferred SDK version, please ensure at least one Developer SDK is installed" ; exit 1 )
-		@test -n "$(PREFERRED_MINVERSION)" || ( echo "Error: Failed to establish preferred minimum OS version" ; exit 1 )
-		@echo " *** Default SDK is $(PREFERRED_SDK) for minimum OS/X version $(PREFERRED_MINVERSION)"
-
-sdk:		show sdkstatic $(SDK_DYNAMIC) $(HOSTSDK_DYNAMIC)
-
-sdkstatic:	$(SDK_STATIC) $(HOSTSDK_STATIC)
-		$(RANLIB) $(SDK_STATIC)
-		$(RANLIB) $(HOSTSDK_STATIC)
-
-plugins:	$(PLUGIN_TARGET)
-
-host:		$(HOST_TARGET)
-
-rdfgen:		$(RDFGEN_TARGET)
-
-all:		sdk plugins host rdfgen test
-
-$(SDK_STATIC):	$(SDK_OBJECTS) $(API_HEADERS) $(SDK_HEADERS)
-		$(RM_F) $@
-		$(AR) r $@ $(SDK_OBJECTS)
-
-$(HOSTSDK_STATIC):	$(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS)
-		$(RM_F) $@
-		$(AR) r $@ $(HOSTSDK_OBJECTS)
-
-$(SDK_DYNAMIC):	$(SDK_OBJECTS) $(API_HEADERS) $(SDK_HEADERS)
-		$(CXX) $(LDFLAGS) $(SDK_DYNAMIC_LDFLAGS) -o $@ $(SDK_OBJECTS)
-
-$(HOSTSDK_DYNAMIC):	$(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS)
-		$(CXX) $(LDFLAGS) $(HOSTSDK_DYNAMIC_LDFLAGS) -o $@ $(HOSTSDK_OBJECTS)
-
-$(PLUGIN_TARGET):	$(PLUGIN_OBJECTS) $(SDK_STATIC) $(PLUGIN_HEADERS)
-		$(CXX) $(LDFLAGS) $(PLUGIN_LDFLAGS) -o $@ $(PLUGIN_OBJECTS) $(PLUGIN_LIBS)
-
-$(HOST_TARGET):	$(HOST_OBJECTS) $(HOSTSDK_STATIC) $(HOST_HEADERS)
-		$(CXX) $(LDFLAGS) $(HOST_LDFLAGS) -o $@ $(HOST_OBJECTS) $(HOST_LIBS)
-
-$(RDFGEN_TARGET):	$(RDFGEN_OBJECTS) $(HOSTSDK_STATIC) 
-		$(CXX) $(LDFLAGS) $(RDFGEN_LDFLAGS) -o $@ $(RDFGEN_OBJECTS) $(RDFGEN_LIBS)
-
-test:		plugins host
-		VAMP_PATH=$(EXAMPLEDIR) $(HOST_TARGET) -l
-
-clean:		
-		rm -f $(SDK_OBJECTS) $(HOSTSDK_OBJECTS) $(PLUGIN_OBJECTS) $(HOST_OBJECTS) $(RDFGEN_OBJECTS)
-
-distclean:	clean
-		rm -f $(SDK_STATIC) $(SDK_DYNAMIC) $(HOSTSDK_STATIC) $(HOSTSDK_DYNAMIC) $(PLUGIN_TARGET) $(HOST_TARGET) $(RDFGEN_TARGET) *~ */*~
-
-# DO NOT DELETE
-
-examples/AmplitudeFollower.o: examples/AmplitudeFollower.h vamp-sdk/Plugin.h
-examples/AmplitudeFollower.o: vamp-sdk/PluginBase.h vamp-sdk/plugguard.h
-examples/AmplitudeFollower.o: vamp-sdk/RealTime.h
-examples/FixedTempoEstimator.o: examples/FixedTempoEstimator.h
-examples/FixedTempoEstimator.o: vamp-sdk/Plugin.h vamp-sdk/PluginBase.h
-examples/FixedTempoEstimator.o: vamp-sdk/plugguard.h vamp-sdk/RealTime.h
-examples/PercussionOnsetDetector.o: examples/PercussionOnsetDetector.h
-examples/PercussionOnsetDetector.o: vamp-sdk/Plugin.h vamp-sdk/PluginBase.h
-examples/PercussionOnsetDetector.o: vamp-sdk/plugguard.h vamp-sdk/RealTime.h
-examples/SpectralCentroid.o: examples/SpectralCentroid.h vamp-sdk/Plugin.h
-examples/SpectralCentroid.o: vamp-sdk/PluginBase.h vamp-sdk/plugguard.h
-examples/SpectralCentroid.o: vamp-sdk/RealTime.h
-examples/PowerSpectrum.o: examples/PowerSpectrum.h vamp-sdk/Plugin.h
-examples/PowerSpectrum.o: vamp-sdk/PluginBase.h vamp-sdk/plugguard.h
-examples/PowerSpectrum.o: vamp-sdk/RealTime.h
-examples/ZeroCrossing.o: examples/ZeroCrossing.h vamp-sdk/Plugin.h
-examples/ZeroCrossing.o: vamp-sdk/PluginBase.h vamp-sdk/plugguard.h
-examples/ZeroCrossing.o: vamp-sdk/RealTime.h
-examples/plugins.o: vamp/vamp.h vamp-sdk/PluginAdapter.h vamp-sdk/Plugin.h
-examples/plugins.o: vamp-sdk/PluginBase.h vamp-sdk/plugguard.h
-examples/plugins.o: vamp-sdk/RealTime.h examples/ZeroCrossing.h
-examples/plugins.o: vamp-sdk/Plugin.h examples/SpectralCentroid.h
-examples/plugins.o: examples/PercussionOnsetDetector.h examples/PowerSpectrum.h
-examples/plugins.o: examples/FixedTempoEstimator.h
-examples/plugins.o: examples/AmplitudeFollower.h
-host/vamp-simple-host.o: ./vamp-hostsdk/PluginHostAdapter.h vamp/vamp.h
-host/vamp-simple-host.o: vamp-sdk/Plugin.h vamp-sdk/PluginBase.h
-host/vamp-simple-host.o: vamp-sdk/plugguard.h vamp-sdk/RealTime.h
-host/vamp-simple-host.o: ./vamp-hostsdk/PluginInputDomainAdapter.h
-host/vamp-simple-host.o: ./vamp-hostsdk/PluginWrapper.h
-host/vamp-simple-host.o: ./vamp-hostsdk/Plugin.h ./vamp-hostsdk/hostguard.h
-host/vamp-simple-host.o: vamp-sdk/Plugin.h
-host/vamp-simple-host.o: ./vamp-hostsdk/PluginLoader.h host/system.h
-rdf/generator/vamp-rdf-template-generator.o: ./vamp-hostsdk/PluginHostAdapter.h
-rdf/generator/vamp-rdf-template-generator.o: vamp/vamp.h vamp-sdk/Plugin.h
-rdf/generator/vamp-rdf-template-generator.o: vamp-sdk/PluginBase.h
-rdf/generator/vamp-rdf-template-generator.o: vamp-sdk/plugguard.h vamp-sdk/RealTime.h
-rdf/generator/vamp-rdf-template-generator.o: ./vamp-hostsdk/PluginChannelAdapter.h
-rdf/generator/vamp-rdf-template-generator.o: ./vamp-hostsdk/PluginWrapper.h
-rdf/generator/vamp-rdf-template-generator.o: ./vamp-hostsdk/Plugin.h
-rdf/generator/vamp-rdf-template-generator.o: ./vamp-hostsdk/hostguard.h
-rdf/generator/vamp-rdf-template-generator.o: vamp-sdk/Plugin.h
-rdf/generator/vamp-rdf-template-generator.o: ./vamp-hostsdk/PluginInputDomainAdapter.h
-rdf/generator/vamp-rdf-template-generator.o: ./vamp-hostsdk/PluginLoader.h
-src/vamp-hostsdk/PluginHostAdapter.o: ./vamp-hostsdk/PluginHostAdapter.h
-src/vamp-hostsdk/PluginHostAdapter.o: vamp/vamp.h vamp-sdk/Plugin.h
-src/vamp-hostsdk/PluginHostAdapter.o: vamp-sdk/PluginBase.h
-src/vamp-hostsdk/PluginHostAdapter.o: vamp-sdk/plugguard.h
-src/vamp-hostsdk/PluginHostAdapter.o: vamp-sdk/RealTime.h
-src/vamp-hostsdk/RealTime.o: src/vamp-sdk/RealTime.cpp ./vamp-sdk/RealTime.h
-src/vamp-hostsdk/RealTime.o: vamp-sdk/plugguard.h
-src/vamp-sdk/PluginAdapter.o: vamp-sdk/PluginAdapter.h vamp/vamp.h
-src/vamp-sdk/PluginAdapter.o: vamp-sdk/Plugin.h vamp-sdk/PluginBase.h
-src/vamp-sdk/PluginAdapter.o: vamp-sdk/plugguard.h vamp-sdk/RealTime.h
-src/vamp-sdk/RealTime.o: ./vamp-sdk/RealTime.h vamp-sdk/plugguard.h
-src/vamp-hostsdk/PluginBufferingAdapter.o: ./vamp-hostsdk/PluginBufferingAdapter.h
-src/vamp-hostsdk/PluginBufferingAdapter.o: ./vamp-hostsdk/PluginWrapper.h
-src/vamp-hostsdk/PluginBufferingAdapter.o: ./vamp-hostsdk/Plugin.h
-src/vamp-hostsdk/PluginBufferingAdapter.o: ./vamp-hostsdk/hostguard.h
-src/vamp-hostsdk/PluginBufferingAdapter.o: vamp-sdk/Plugin.h
-src/vamp-hostsdk/PluginBufferingAdapter.o: vamp-sdk/PluginBase.h
-src/vamp-hostsdk/PluginBufferingAdapter.o: vamp-sdk/plugguard.h
-src/vamp-hostsdk/PluginBufferingAdapter.o: vamp-sdk/RealTime.h
-src/vamp-hostsdk/PluginChannelAdapter.o: ./vamp-hostsdk/PluginChannelAdapter.h
-src/vamp-hostsdk/PluginChannelAdapter.o: ./vamp-hostsdk/PluginWrapper.h
-src/vamp-hostsdk/PluginChannelAdapter.o: ./vamp-hostsdk/Plugin.h
-src/vamp-hostsdk/PluginChannelAdapter.o: ./vamp-hostsdk/hostguard.h
-src/vamp-hostsdk/PluginChannelAdapter.o: vamp-sdk/Plugin.h
-src/vamp-hostsdk/PluginChannelAdapter.o: vamp-sdk/PluginBase.h
-src/vamp-hostsdk/PluginChannelAdapter.o: vamp-sdk/plugguard.h
-src/vamp-hostsdk/PluginChannelAdapter.o: vamp-sdk/RealTime.h
-src/vamp-hostsdk/PluginInputDomainAdapter.o: ./vamp-hostsdk/PluginInputDomainAdapter.h
-src/vamp-hostsdk/PluginInputDomainAdapter.o: ./vamp-hostsdk/PluginWrapper.h
-src/vamp-hostsdk/PluginInputDomainAdapter.o: ./vamp-hostsdk/Plugin.h
-src/vamp-hostsdk/PluginInputDomainAdapter.o: ./vamp-hostsdk/hostguard.h
-src/vamp-hostsdk/PluginInputDomainAdapter.o: vamp-sdk/Plugin.h
-src/vamp-hostsdk/PluginInputDomainAdapter.o: vamp-sdk/PluginBase.h
-src/vamp-hostsdk/PluginInputDomainAdapter.o: vamp-sdk/plugguard.h
-src/vamp-hostsdk/PluginInputDomainAdapter.o: vamp-sdk/RealTime.h
-src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginHostAdapter.h
-src/vamp-hostsdk/PluginLoader.o: vamp/vamp.h vamp-sdk/Plugin.h
-src/vamp-hostsdk/PluginLoader.o: vamp-sdk/PluginBase.h
-src/vamp-hostsdk/PluginLoader.o: vamp-sdk/plugguard.h
-src/vamp-hostsdk/PluginLoader.o: vamp-sdk/RealTime.h
-src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginLoader.h
-src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginWrapper.h
-src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/Plugin.h
-src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/hostguard.h
-src/vamp-hostsdk/PluginLoader.o: vamp-sdk/Plugin.h
-src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginInputDomainAdapter.h
-src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginChannelAdapter.h
-src/vamp-hostsdk/PluginLoader.o: ./vamp-hostsdk/PluginBufferingAdapter.h
-src/vamp-hostsdk/PluginSummarisingAdapter.o: ./vamp-hostsdk/PluginSummarisingAdapter.h
-src/vamp-hostsdk/PluginSummarisingAdapter.o: ./vamp-hostsdk/PluginWrapper.h
-src/vamp-hostsdk/PluginSummarisingAdapter.o: ./vamp-hostsdk/Plugin.h
-src/vamp-hostsdk/PluginSummarisingAdapter.o: ./vamp-hostsdk/hostguard.h
-src/vamp-hostsdk/PluginSummarisingAdapter.o: vamp-sdk/Plugin.h
-src/vamp-hostsdk/PluginSummarisingAdapter.o: vamp-sdk/PluginBase.h
-src/vamp-hostsdk/PluginSummarisingAdapter.o: vamp-sdk/plugguard.h
-src/vamp-hostsdk/PluginSummarisingAdapter.o: vamp-sdk/RealTime.h
-src/vamp-hostsdk/PluginWrapper.o: ./vamp-hostsdk/PluginWrapper.h
-src/vamp-hostsdk/PluginWrapper.o: ./vamp-hostsdk/Plugin.h
-src/vamp-hostsdk/PluginWrapper.o: ./vamp-hostsdk/hostguard.h
-src/vamp-hostsdk/PluginWrapper.o: vamp-sdk/Plugin.h
-src/vamp-hostsdk/PluginWrapper.o: vamp-sdk/PluginBase.h
-src/vamp-hostsdk/PluginWrapper.o: vamp-sdk/plugguard.h
-src/vamp-hostsdk/PluginWrapper.o: vamp-sdk/RealTime.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build/docker/Dockerfile_v2.9_ubuntu1604	Tue Oct 22 12:23:53 2019 +0100
@@ -0,0 +1,27 @@
+FROM ubuntu:16.04
+MAINTAINER Chris Cannam <cannam@all-day-breakfast.com>
+RUN apt-get update && \
+    apt-get install -y \
+    locales \
+    build-essential \
+    libsndfile-dev \
+    git \
+    mercurial
+RUN gcc --version
+RUN apt-get clean && rm -rf /var/lib/apt/lists/*
+RUN locale-gen en_US.UTF-8
+ENV LANG en_US.UTF-8  
+ENV LANGUAGE en_US:en  
+ENV LC_ALL en_US.UTF-8
+RUN hg clone -rvamp-plugin-sdk-v2.9 https://code.soundsoftware.ac.uk/hg/vamp-plugin-sdk
+RUN hg clone https://code.soundsoftware.ac.uk/hg/vamp-test-plugin
+WORKDIR vamp-plugin-sdk
+RUN ./configure && make
+WORKDIR ../vamp-test-plugin
+RUN make -f Makefile.linux
+WORKDIR ../vamp-plugin-sdk
+RUN test/run-test-plugin-regression.sh
+RUN mkdir vamp-plugin-sdk-2.9.0-binaries-amd64-linux
+RUN cp libvamp-sdk.a libvamp-hostsdk.a examples/vamp-example-plugins.so host/vamp-simple-host rdf/generator/vamp-rdf-template-generator vamp-plugin-sdk-2.9.0-binaries-amd64-linux
+RUN tar cvzf vamp-plugin-sdk-2.9.0-binaries-amd64-linux.tar.gz vamp-plugin-sdk-2.9.0-binaries-amd64-linux
+RUN tar cvf output.tar *.tar.gz && cp output.tar ..
--- a/build/libvamp-hostsdk.la.in	Wed Aug 14 14:58:04 2019 +0100
+++ b/build/libvamp-hostsdk.la.in	Tue Oct 22 12:23:53 2019 +0100
@@ -8,7 +8,7 @@
 old_library='%STATIC%'
 dependency_libs=''
 current=3
-age=8
+age=9
 revision=0
 installed=yes
 libdir='%LIBS%'
--- a/build/libvamp-sdk.la.in	Wed Aug 14 14:58:04 2019 +0100
+++ b/build/libvamp-sdk.la.in	Tue Oct 22 12:23:53 2019 +0100
@@ -8,7 +8,7 @@
 old_library='%STATIC%'
 dependency_libs=''
 current=2
-age=8
+age=9
 revision=0
 installed=yes
 libdir='%LIBS%'
--- a/configure	Wed Aug 14 14:58:04 2019 +0100
+++ b/configure	Tue Oct 22 12:23:53 2019 +0100
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for vamp-plugin-sdk 2.8.
+# Generated by GNU Autoconf 2.69 for vamp-plugin-sdk 2.9.
 #
 # Report bugs to <cannam@all-day-breakfast.com>.
 #
@@ -580,8 +580,8 @@
 # Identity of this package.
 PACKAGE_NAME='vamp-plugin-sdk'
 PACKAGE_TARNAME='vamp-plugin-sdk'
-PACKAGE_VERSION='2.8'
-PACKAGE_STRING='vamp-plugin-sdk 2.8'
+PACKAGE_VERSION='2.9'
+PACKAGE_STRING='vamp-plugin-sdk 2.9'
 PACKAGE_BUGREPORT='cannam@all-day-breakfast.com'
 PACKAGE_URL=''
 
@@ -630,6 +630,7 @@
 PKG_CONFIG_LIBDIR
 PKG_CONFIG_PATH
 PKG_CONFIG
+HAVE_CXX11
 EGREP
 GREP
 CPP
@@ -1243,7 +1244,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures vamp-plugin-sdk 2.8 to adapt to many kinds of systems.
+\`configure' configures vamp-plugin-sdk 2.9 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1304,7 +1305,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of vamp-plugin-sdk 2.8:";;
+     short | recursive ) echo "Configuration of vamp-plugin-sdk 2.9:";;
    esac
   cat <<\_ACEOF
 
@@ -1402,7 +1403,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-vamp-plugin-sdk configure 2.8
+vamp-plugin-sdk configure 2.9
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1651,7 +1652,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by vamp-plugin-sdk $as_me 2.8, which was
+It was created by vamp-plugin-sdk $as_me 2.9, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3670,6 +3671,147 @@
  esac
 
 
+# We now require C++11
+
+    ax_cxx_compile_cxx11_required=true
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+  ac_success=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5
+$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; }
+if ${ax_cv_cxx_compile_cxx11+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+  template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+    struct Base {
+    virtual void f() {}
+    };
+    struct Child : public Base {
+    virtual void f() override {}
+    };
+
+    typedef check<check<bool>> right_angle_brackets;
+
+    int a;
+    decltype(a) b;
+
+    typedef check<int> check_type;
+    check_type c;
+    check_type&& cr = static_cast<check_type&&>(c);
+
+    auto d = a;
+    auto l = [](){};
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ax_cv_cxx_compile_cxx11=yes
+else
+  ax_cv_cxx_compile_cxx11=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5
+$as_echo "$ax_cv_cxx_compile_cxx11" >&6; }
+  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+    ac_success=yes
+  fi
+
+
+
+    if test x$ac_success = xno; then
+    for switch in -std=c++11 -std=c++0x; do
+      cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh`
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5
+$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; }
+if eval \${$cachevar+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS $switch"
+         cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+  template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+    struct Base {
+    virtual void f() {}
+    };
+    struct Child : public Base {
+    virtual void f() override {}
+    };
+
+    typedef check<check<bool>> right_angle_brackets;
+
+    int a;
+    decltype(a) b;
+
+    typedef check<int> check_type;
+    check_type c;
+    check_type&& cr = static_cast<check_type&&>(c);
+
+    auto d = a;
+    auto l = [](){};
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  eval $cachevar=yes
+else
+  eval $cachevar=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+         CXXFLAGS="$ac_save_CXXFLAGS"
+fi
+eval ac_res=\$$cachevar
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+      if eval test x\$$cachevar = xyes; then
+        CXXFLAGS="$CXXFLAGS $switch"
+        ac_success=yes
+        break
+      fi
+    done
+  fi
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+  if test x$ax_cxx_compile_cxx11_required = xtrue; then
+    if test x$ac_success = xno; then
+      as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5
+    fi
+  else
+    if test x$ac_success = xno; then
+      HAVE_CXX11=0
+      { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5
+$as_echo "$as_me: No compiler with C++11 support was found" >&6;}
+    else
+      HAVE_CXX11=1
+
+$as_echo "#define HAVE_CXX11 1" >>confdefs.h
+
+    fi
+
+
+  fi
+
+
 if pkg-config --modversion vamp-sdk >/dev/null 2>&1; then
   echo "WARNING: A version of the Vamp plugin SDK is already installed."
   echo "         Expect worries and sorrows if you install a new version"
@@ -3956,7 +4098,7 @@
     *[\ \	]-fPIC\ -Wall[\ \	]*) ;;
     *) CFLAGS="$CFLAGS -fPIC -Wall -Wextra" ;;
   esac
-  CXXFLAGS="$CXXFLAGS -std=c++98"
+  CXXFLAGS="$CXXFLAGS -std=c++11"
 fi
 
 
@@ -4506,7 +4648,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by vamp-plugin-sdk $as_me 2.8, which was
+This file was extended by vamp-plugin-sdk $as_me 2.9, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -4559,7 +4701,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-vamp-plugin-sdk config.status 2.8
+vamp-plugin-sdk config.status 2.9
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
--- a/configure.ac	Wed Aug 14 14:58:04 2019 +0100
+++ b/configure.ac	Tue Oct 22 12:23:53 2019 +0100
@@ -1,11 +1,14 @@
 
-AC_INIT(vamp-plugin-sdk, 2.8, cannam@all-day-breakfast.com)
+AC_INIT(vamp-plugin-sdk, 2.9, cannam@all-day-breakfast.com)
 
 AC_CONFIG_SRCDIR(vamp/vamp.h)
 AC_PROG_CXX
 AC_HEADER_STDC
 AC_C_BIGENDIAN
 
+# We now require C++11
+AX_CXX_COMPILE_STDCXX_11(noext)
+
 if pkg-config --modversion vamp-sdk >/dev/null 2>&1; then
   echo "WARNING: A version of the Vamp plugin SDK is already installed."
   echo "         Expect worries and sorrows if you install a new version"
@@ -50,7 +53,7 @@
     *[\ \	]-fPIC\ -Wall[\ \	]*) ;;
     *) CFLAGS="$CFLAGS -fPIC -Wall -Wextra" ;;
   esac
-  CXXFLAGS="$CXXFLAGS -std=c++98"
+  CXXFLAGS="$CXXFLAGS -std=c++11"
 fi
 changequote([,])dnl
 
--- a/pkgconfig/vamp-hostsdk.pc.in	Wed Aug 14 14:58:04 2019 +0100
+++ b/pkgconfig/vamp-hostsdk.pc.in	Tue Oct 22 12:23:53 2019 +0100
@@ -4,7 +4,7 @@
 includedir=${prefix}/include
 
 Name: vamp-hostsdk
-Version: 2.8
+Version: 2.9
 Description: Development library for Vamp audio analysis plugin hosts
 Libs: -L${libdir} -lvamp-hostsdk -ldl
 Cflags: -I${includedir} 
--- a/pkgconfig/vamp-sdk.pc.in	Wed Aug 14 14:58:04 2019 +0100
+++ b/pkgconfig/vamp-sdk.pc.in	Tue Oct 22 12:23:53 2019 +0100
@@ -4,7 +4,7 @@
 includedir=${prefix}/include
 
 Name: vamp-sdk
-Version: 2.8
+Version: 2.9
 Description: Development library for Vamp audio analysis plugins
 Libs: -L${libdir} -lvamp-sdk
 Cflags: -I${includedir} 
--- a/pkgconfig/vamp.pc.in	Wed Aug 14 14:58:04 2019 +0100
+++ b/pkgconfig/vamp.pc.in	Tue Oct 22 12:23:53 2019 +0100
@@ -4,7 +4,7 @@
 includedir=${prefix}/include
 
 Name: vamp
-Version: 2.8
+Version: 2.9
 Description: An API for audio analysis and feature extraction plugins
 Libs: 
 Cflags: -I${includedir} 
--- a/src/vamp-hostsdk/PluginHostAdapter.cpp	Wed Aug 14 14:58:04 2019 +0100
+++ b/src/vamp-hostsdk/PluginHostAdapter.cpp	Tue Oct 22 12:23:53 2019 +0100
@@ -39,7 +39,7 @@
 
 #include "Files.h"
 
-#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 8 )
+#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 9 )
 #error Unexpected version of Vamp SDK header included
 #endif
 
--- a/src/vamp-hostsdk/PluginLoader.cpp	Wed Aug 14 14:58:04 2019 +0100
+++ b/src/vamp-hostsdk/PluginLoader.cpp	Tue Oct 22 12:23:53 2019 +0100
@@ -567,8 +567,18 @@
 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
 {
     void *handle = m_pluginLibraryHandleMap[adapter];
-    if (handle) Files::unloadLibrary(handle);
+    if (!handle) return;
+
     m_pluginLibraryHandleMap.erase(adapter);
+
+    for (auto h: m_pluginLibraryHandleMap) {
+        if (h.second == handle) {
+            // still in use
+            return;
+        }
+    }
+    
+    Files::unloadLibrary(handle);
 }
 
 PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
--- a/src/vamp-hostsdk/acsymbols.c	Wed Aug 14 14:58:04 2019 +0100
+++ b/src/vamp-hostsdk/acsymbols.c	Tue Oct 22 12:23:53 2019 +0100
@@ -1,6 +1,7 @@
 /* These stubs are provided so that autoconf can check library
  * versions using C symbols only */
 
+extern void libvamphostsdk_v_2_9_present(void) { }
 extern void libvamphostsdk_v_2_8_present(void) { }
 extern void libvamphostsdk_v_2_7_1_present(void) { }
 extern void libvamphostsdk_v_2_7_present(void) { }
--- a/src/vamp-sdk/FFT.cpp	Wed Aug 14 14:58:04 2019 +0100
+++ b/src/vamp-sdk/FFT.cpp	Tue Oct 22 12:23:53 2019 +0100
@@ -41,7 +41,7 @@
 #include <math.h>
 #include <string.h>
 
-#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 8 )
+#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 9 )
 #error Unexpected version of Vamp SDK header included
 #endif
 
--- a/src/vamp-sdk/PluginAdapter.cpp	Wed Aug 14 14:58:04 2019 +0100
+++ b/src/vamp-sdk/PluginAdapter.cpp	Tue Oct 22 12:23:53 2019 +0100
@@ -39,10 +39,19 @@
 #include <cstring>
 #include <cstdlib>
 
-#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 8 )
+#include <mutex>
+
+#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 9 )
 #error Unexpected version of Vamp SDK header included
 #endif
 
+using std::map;
+using std::vector;
+using std::string;
+using std::cerr;
+using std::endl;
+using std::mutex;
+using std::lock_guard;
 
 //#define DEBUG_PLUGIN_ADAPTER 1
 
@@ -103,8 +112,7 @@
 
     void cleanup(Plugin *plugin);
     unsigned int getOutputCount(Plugin *plugin);
-    VampOutputDescriptor *getOutputDescriptor(Plugin *plugin,
-                                             unsigned int i);
+    VampOutputDescriptor *getOutputDescriptor(Plugin *plugin, unsigned int i);
     VampFeatureList *process(Plugin *plugin,
                              const float *const *inputBuffers,
                              int sec, int nsec);
@@ -113,21 +121,38 @@
                                      const Plugin::FeatureSet &features);
     
     // maps both plugins and descriptors to adapters
-    typedef std::map<const void *, Impl *> AdapterMap;
+    typedef map<const void *, Impl *> AdapterMap;
+
     static AdapterMap *m_adapterMap;
+
+    static mutex &adapterMapMutex() {
+        // If this mutex was a global static, then it might be
+        // destroyed before the last adapter, and we would end up
+        // trying to lock an invalid mutex when removing an adapter
+        // from the adapter map. To ensure it outlasts the adapters,
+        // we need to ensure it is constructed before the construction
+        // of any of them is complete, since destruction order is
+        // reverse of construction. So we have to make sure this is
+        // called from the PluginAdapterBase::Impl constructor below.
+        static mutex m;
+        return m;
+    }
+        
     static Impl *lookupAdapter(VampPluginHandle);
 
+    mutex m_mutex; // guards all of the below
+    
     bool m_populated;
     VampPluginDescriptor m_descriptor;
     Plugin::ParameterList m_parameters;
     Plugin::ProgramList m_programs;
     
-    typedef std::map<Plugin *, Plugin::OutputList *> OutputMap;
+    typedef 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;
+    map<Plugin *, VampFeatureList *> m_fs;
+    map<Plugin *, vector<size_t> > m_fsizes;
+    map<Plugin *, vector<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);
@@ -154,35 +179,39 @@
     m_populated(false)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl[" << this << "]::Impl" << std::endl;
+    cerr << "PluginAdapterBase::Impl[" << this << "]::Impl" << endl;
 #endif
+
+    (void)adapterMapMutex(); // see comment in adapterMapMutex function above
 }
 
 const VampPluginDescriptor *
 PluginAdapterBase::Impl::getDescriptor()
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl[" << this << "]::getDescriptor" << std::endl;
+    cerr << "PluginAdapterBase::Impl[" << this << "]::getDescriptor" << endl;
 #endif
 
+    lock_guard<mutex> guard(m_mutex);
+    
     if (m_populated) return &m_descriptor;
     
     Plugin *plugin = m_base->createPlugin(48000);
   
     if (!plugin) {
-        std::cerr << "PluginAdapterBase::Impl::getDescriptor: Failed to create plugin" << std::endl;
+        cerr << "PluginAdapterBase::Impl::getDescriptor: Failed to create plugin" << endl;
         return 0;
     }
 
     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;
+        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." << endl;
         delete plugin;
         return 0;
     }
@@ -260,6 +289,8 @@
     m_descriptor.process = vampProcess;
     m_descriptor.getRemainingFeatures = vampGetRemainingFeatures;
     m_descriptor.releaseFeatureSet = vampReleaseFeatureSet;
+
+    lock_guard<mutex> adapterMapGuard(adapterMapMutex());
     
     if (!m_adapterMap) {
         m_adapterMap = new AdapterMap;
@@ -275,9 +306,11 @@
 PluginAdapterBase::Impl::~Impl()
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl[" << this << "]::~Impl" << std::endl;
+    cerr << "PluginAdapterBase::Impl[" << this << "]::~Impl" << endl;
 #endif
 
+    lock_guard<mutex> guard(m_mutex);
+
     if (!m_populated) return;
 
     free((void *)m_descriptor.identifier);
@@ -307,10 +340,12 @@
     }
     free((void *)m_descriptor.programs);
 
+    lock_guard<mutex> adapterMapGuard(adapterMapMutex());
+    
     if (m_adapterMap) {
         
         m_adapterMap->erase(&m_descriptor);
-
+        
         if (m_adapterMap->empty()) {
             delete m_adapterMap;
             m_adapterMap = 0;
@@ -322,9 +357,11 @@
 PluginAdapterBase::Impl::lookupAdapter(VampPluginHandle handle)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::lookupAdapter(" << handle << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::lookupAdapter(" << handle << ")" << endl;
 #endif
 
+    lock_guard<mutex> adapterMapGuard(adapterMapMutex());
+    
     if (!m_adapterMap) return 0;
     AdapterMap::const_iterator i = m_adapterMap->find(handle);
     if (i == m_adapterMap->end()) return 0;
@@ -336,15 +373,17 @@
                                          float inputSampleRate)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << ")" << endl;
 #endif
 
+    lock_guard<mutex> adapterMapGuard(adapterMapMutex());
+    
     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;
+        cerr << "WARNING: PluginAdapterBase::Impl::vampInstantiate: Descriptor " << desc << " not in adapter map" << endl;
         return 0;
     }
 
@@ -357,7 +396,7 @@
     }
 
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << "): returning handle " << plugin << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << "): returning handle " << plugin << endl;
 #endif
 
     return plugin;
@@ -367,7 +406,7 @@
 PluginAdapterBase::Impl::vampCleanup(VampPluginHandle handle)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampCleanup(" << handle << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampCleanup(" << handle << ")" << endl;
 #endif
 
     Impl *adapter = lookupAdapter(handle);
@@ -385,7 +424,7 @@
                                         unsigned int blockSize)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << endl;
 #endif
 
     Impl *adapter = lookupAdapter(handle);
@@ -399,7 +438,7 @@
 PluginAdapterBase::Impl::vampReset(VampPluginHandle handle) 
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampReset(" << handle << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampReset(" << handle << ")" << endl;
 #endif
 
     ((Plugin *)handle)->reset();
@@ -410,7 +449,7 @@
                                     int param) 
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetParameter(" << handle << ", " << param << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampGetParameter(" << handle << ", " << param << ")" << endl;
 #endif
 
     Impl *adapter = lookupAdapter(handle);
@@ -424,7 +463,7 @@
                                     int param, float value)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << endl;
 #endif
 
     Impl *adapter = lookupAdapter(handle);
@@ -438,13 +477,13 @@
 PluginAdapterBase::Impl::vampGetCurrentProgram(VampPluginHandle handle)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetCurrentProgram(" << handle << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampGetCurrentProgram(" << handle << ")" << endl;
 #endif
 
     Impl *adapter = lookupAdapter(handle);
     if (!adapter) return 0;
     Plugin::ProgramList &list = adapter->m_programs;
-    std::string program = ((Plugin *)handle)->getCurrentProgram();
+    string program = ((Plugin *)handle)->getCurrentProgram();
     for (unsigned int i = 0; i < list.size(); ++i) {
         if (list[i] == program) return i;
     }
@@ -456,7 +495,7 @@
                                            unsigned int program)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << endl;
 #endif
 
     Impl *adapter = lookupAdapter(handle);
@@ -472,7 +511,7 @@
 PluginAdapterBase::Impl::vampGetPreferredStepSize(VampPluginHandle handle)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetPreferredStepSize(" << handle << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampGetPreferredStepSize(" << handle << ")" << endl;
 #endif
 
     return ((Plugin *)handle)->getPreferredStepSize();
@@ -482,7 +521,7 @@
 PluginAdapterBase::Impl::vampGetPreferredBlockSize(VampPluginHandle handle) 
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetPreferredBlockSize(" << handle << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampGetPreferredBlockSize(" << handle << ")" << endl;
 #endif
 
     return ((Plugin *)handle)->getPreferredBlockSize();
@@ -492,7 +531,7 @@
 PluginAdapterBase::Impl::vampGetMinChannelCount(VampPluginHandle handle)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetMinChannelCount(" << handle << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampGetMinChannelCount(" << handle << ")" << endl;
 #endif
 
     return ((Plugin *)handle)->getMinChannelCount();
@@ -502,7 +541,7 @@
 PluginAdapterBase::Impl::vampGetMaxChannelCount(VampPluginHandle handle)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetMaxChannelCount(" << handle << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampGetMaxChannelCount(" << handle << ")" << endl;
 #endif
 
     return ((Plugin *)handle)->getMaxChannelCount();
@@ -512,12 +551,12 @@
 PluginAdapterBase::Impl::vampGetOutputCount(VampPluginHandle handle)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetOutputCount(" << handle << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampGetOutputCount(" << handle << ")" << endl;
 #endif
 
     Impl *adapter = lookupAdapter(handle);
 
-//    std::cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << std::endl;
+//    cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << endl;
 
     if (!adapter) return 0;
     return adapter->getOutputCount((Plugin *)handle);
@@ -528,12 +567,12 @@
                                                  unsigned int i)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetOutputDescriptor(" << handle << ", " << i << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampGetOutputDescriptor(" << handle << ", " << i << ")" << endl;
 #endif
 
     Impl *adapter = lookupAdapter(handle);
 
-//    std::cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << std::endl;
+//    cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << endl;
 
     if (!adapter) return 0;
     return adapter->getOutputDescriptor((Plugin *)handle, i);
@@ -543,7 +582,7 @@
 PluginAdapterBase::Impl::vampReleaseOutputDescriptor(VampOutputDescriptor *desc)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampReleaseOutputDescriptor(" << desc << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampReleaseOutputDescriptor(" << desc << ")" << endl;
 #endif
 
     if (desc->identifier) free((void *)desc->identifier);
@@ -568,7 +607,7 @@
                                      int nsec)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << endl;
 #endif
 
     Impl *adapter = lookupAdapter(handle);
@@ -580,7 +619,7 @@
 PluginAdapterBase::Impl::vampGetRemainingFeatures(VampPluginHandle handle)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampGetRemainingFeatures(" << handle << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampGetRemainingFeatures(" << handle << ")" << endl;
 #endif
 
     Impl *adapter = lookupAdapter(handle);
@@ -592,20 +631,25 @@
 PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *)
 {
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << std::endl;
+    cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << endl;
 #endif
 }
 
 void 
 PluginAdapterBase::Impl::cleanup(Plugin *plugin)
 {
+    // at this point no mutex is held
+    
+    lock_guard<mutex> adapterMapGuard(adapterMapMutex());
+    lock_guard<mutex> guard(m_mutex);
+    
     if (m_fs.find(plugin) != m_fs.end()) {
         size_t outputCount = 0;
         if (m_pluginOutputs[plugin]) {
             outputCount = m_pluginOutputs[plugin]->size();
         }
 #ifdef DEBUG_PLUGIN_ADAPTER
-        std::cerr << "PluginAdapterBase::Impl::cleanup: " << outputCount << " output(s)" << std::endl;
+        cerr << "PluginAdapterBase::Impl::cleanup: " << outputCount << " output(s)" << endl;
 #endif
         VampFeatureList *list = m_fs[plugin];
         for (unsigned int i = 0; i < outputCount; ++i) {
@@ -645,6 +689,8 @@
 void 
 PluginAdapterBase::Impl::checkOutputMap(Plugin *plugin)
 {
+    // must be called with m_mutex held
+    
     OutputMap::iterator i = m_pluginOutputs.find(plugin);
 
     if (i == m_pluginOutputs.end() || !i->second) {
@@ -652,16 +698,18 @@
         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;
+//        cerr << "PluginAdapterBase::Impl::checkOutputMap: Have " << m_pluginOutputs[plugin]->size() << " outputs for plugin " << plugin->getIdentifier() << endl;
     }
 }
 
 void
 PluginAdapterBase::Impl::markOutputsChanged(Plugin *plugin)
 {
+    lock_guard<mutex> guard(m_mutex);
+
     OutputMap::iterator i = m_pluginOutputs.find(plugin);
 
-//    std::cerr << "PluginAdapterBase::Impl::markOutputsChanged" << std::endl;
+//    cerr << "PluginAdapterBase::Impl::markOutputsChanged" << endl;
 
     if (i != m_pluginOutputs.end()) {
 
@@ -674,6 +722,8 @@
 unsigned int 
 PluginAdapterBase::Impl::getOutputCount(Plugin *plugin)
 {
+    lock_guard<mutex> guard(m_mutex);
+
     checkOutputMap(plugin);
 
     return m_pluginOutputs[plugin]->size();
@@ -683,6 +733,8 @@
 PluginAdapterBase::Impl::getOutputDescriptor(Plugin *plugin,
                                              unsigned int i)
 {
+    lock_guard<mutex> guard(m_mutex);
+
     checkOutputMap(plugin);
 
     Plugin::OutputDescriptor &od =
@@ -744,17 +796,32 @@
                                  const float *const *inputBuffers,
                                  int sec, int nsec)
 {
-//    std::cerr << "PluginAdapterBase::Impl::process" << std::endl;
+//    cerr << "PluginAdapterBase::Impl::process" << endl;
+
     RealTime rt(sec, nsec);
-    checkOutputMap(plugin);
+
+    // We don't want to hold the mutex during the actual process call,
+    // only while looking up the associated metadata
+    {    
+        lock_guard<mutex> guard(m_mutex);
+        checkOutputMap(plugin);
+    }
+
     return convertFeatures(plugin, plugin->process(inputBuffers, rt));
 }
     
 VampFeatureList *
 PluginAdapterBase::Impl::getRemainingFeatures(Plugin *plugin)
 {
-//    std::cerr << "PluginAdapterBase::Impl::getRemainingFeatures" << std::endl;
-    checkOutputMap(plugin);
+//    cerr << "PluginAdapterBase::Impl::getRemainingFeatures" << endl;
+
+    // We don't want to hold the mutex during the actual call, only
+    // while looking up the associated metadata
+    {    
+        lock_guard<mutex> guard(m_mutex);
+        checkOutputMap(plugin);
+    }
+
     return convertFeatures(plugin, plugin->getRemainingFeatures());
 }
 
@@ -762,6 +829,8 @@
 PluginAdapterBase::Impl::convertFeatures(Plugin *plugin,
                                          const Plugin::FeatureSet &features)
 {
+    lock_guard<mutex> guard(m_mutex);
+
     int lastN = -1;
 
     int outputCount = 0;
@@ -770,17 +839,17 @@
     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;
+//    cerr << "PluginAdapter(v2)::convertFeatures: NOTE: sizeof(Feature) == " << sizeof(Plugin::Feature) << ", sizeof(VampFeature) == " << sizeof(VampFeature) << ", sizeof(VampFeatureList) == " << sizeof(VampFeatureList) << 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;
+//        cerr << "PluginAdapterBase::Impl::convertFeatures: n = " << n << endl;
 
         if (n >= int(outputCount)) {
-            std::cerr << "WARNING: PluginAdapterBase::Impl::convertFeatures: Too many outputs from plugin (" << n+1 << ", only should be " << outputCount << ")" << std::endl;
+            cerr << "WARNING: PluginAdapterBase::Impl::convertFeatures: Too many outputs from plugin (" << n+1 << ", only should be " << outputCount << ")" << endl;
             continue;
         }
 
@@ -798,7 +867,7 @@
         
         for (size_t j = 0; j < sz; ++j) {
 
-//            std::cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << std::endl;
+//            cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << endl;
 
             VampFeature *feature = &fs[n].features[j].v1;
 
@@ -826,7 +895,7 @@
             }
 
             for (unsigned int k = 0; k < feature->valueCount; ++k) {
-//                std::cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << std::endl;
+//                cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << endl;
                 feature->values[k] = fl[j].values[k];
             }
         }
@@ -842,9 +911,9 @@
         }
     }
 
-//    std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: have " << outputCount << " outputs" << std::endl;
+//    cerr << "PluginAdapter(v2)::convertFeatures: NOTE: have " << outputCount << " outputs" << endl;
 //    for (int i = 0; i < outputCount; ++i) {
-//        std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: output " << i << " has " << fs[i].featureCount << " features" << std::endl;
+//        cerr << "PluginAdapter(v2)::convertFeatures: NOTE: output " << i << " has " << fs[i].featureCount << " features" << endl;
 //    }
 
 
@@ -854,15 +923,17 @@
 void
 PluginAdapterBase::Impl::resizeFS(Plugin *plugin, int n)
 {
+    // called with m_mutex held
+    
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::resizeFS(" << plugin << ", " << n << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::resizeFS(" << plugin << ", " << n << ")" << endl;
 #endif
 
     int i = m_fsizes[plugin].size();
     if (i >= n) return;
 
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "resizing from " << i << std::endl;
+    cerr << "resizing from " << i << endl;
 #endif
 
     m_fs[plugin] = (VampFeatureList *)realloc
@@ -872,7 +943,7 @@
         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>());
+        m_fvsizes[plugin].push_back(vector<size_t>());
         i++;
     }
 }
@@ -880,16 +951,18 @@
 void
 PluginAdapterBase::Impl::resizeFL(Plugin *plugin, int n, size_t sz)
 {
+    // called with m_mutex held
+    
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::resizeFL(" << plugin << ", " << n << ", "
-              << sz << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::resizeFL(" << plugin << ", " << n << ", "
+              << sz << ")" << endl;
 #endif
     
     size_t i = m_fsizes[plugin][n];
     if (i >= sz) return;
 
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "resizing from " << i << std::endl;
+    cerr << "resizing from " << i << endl;
 #endif
 
     m_fs[plugin][n].features = (VampFeatureUnion *)realloc
@@ -909,16 +982,18 @@
 void
 PluginAdapterBase::Impl::resizeFV(Plugin *plugin, int n, int j, size_t sz)
 {
+    // called with m_mutex held
+    
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "PluginAdapterBase::Impl::resizeFV(" << plugin << ", " << n << ", "
-              << j << ", " << sz << ")" << std::endl;
+    cerr << "PluginAdapterBase::Impl::resizeFV(" << plugin << ", " << n << ", "
+              << j << ", " << sz << ")" << endl;
 #endif
     
     size_t i = m_fvsizes[plugin][n][j];
     if (i >= sz) return;
 
 #ifdef DEBUG_PLUGIN_ADAPTER
-    std::cerr << "resizing from " << i << std::endl;
+    cerr << "resizing from " << i << endl;
 #endif
     
     m_fs[plugin][n].features[j].v1.values = (float *)realloc
--- a/src/vamp-sdk/acsymbols.c	Wed Aug 14 14:58:04 2019 +0100
+++ b/src/vamp-sdk/acsymbols.c	Tue Oct 22 12:23:53 2019 +0100
@@ -1,6 +1,7 @@
 /* These stubs are provided so that autoconf can check library
  * versions using C symbols only */
 
+extern void libvampsdk_v_2_9_present(void) { }
 extern void libvampsdk_v_2_8_present(void) { }
 extern void libvampsdk_v_2_7_1_present(void) { }
 extern void libvampsdk_v_2_7_present(void) { }
--- a/vamp-hostsdk/hostguard.h	Wed Aug 14 14:58:04 2019 +0100
+++ b/vamp-hostsdk/hostguard.h	Tue Oct 22 12:23:53 2019 +0100
@@ -43,9 +43,9 @@
 
 #define _VAMP_IN_HOSTSDK 1
 
-#define VAMP_SDK_VERSION "2.8"
+#define VAMP_SDK_VERSION "2.9"
 #define VAMP_SDK_MAJOR_VERSION 2
-#define VAMP_SDK_MINOR_VERSION 8
+#define VAMP_SDK_MINOR_VERSION 9
 
 #ifdef _VAMP_NO_HOST_NAMESPACE
 #define _VAMP_SDK_HOSTSPACE_BEGIN(h)
--- a/vamp-sdk/plugguard.h	Wed Aug 14 14:58:04 2019 +0100
+++ b/vamp-sdk/plugguard.h	Tue Oct 22 12:23:53 2019 +0100
@@ -71,9 +71,9 @@
 
 #define _VAMP_IN_PLUGINSDK 1
 
-#define VAMP_SDK_VERSION "2.8"
+#define VAMP_SDK_VERSION "2.9"
 #define VAMP_SDK_MAJOR_VERSION 2
-#define VAMP_SDK_MINOR_VERSION 8
+#define VAMP_SDK_MINOR_VERSION 9
 
 #ifdef _VAMP_NO_PLUGIN_NAMESPACE
 #define _VAMP_SDK_PLUGSPACE_BEGIN(h)