changeset 71:40a01bb24209 vampyhost

Pull apart some type conversion classes for possible use in VamPy Host
author Chris Cannam
date Thu, 20 Nov 2014 13:02:50 +0000
parents 6c755f3e1173
children ffaa1fb3d7de
files Makefile.linux PyPlugin.cpp PyPlugin.h PyTypeConversions.cpp PyTypeConversions.h PyTypeInterface.cpp PyTypeInterface.h
diffstat 7 files changed, 1244 insertions(+), 1176 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.linux	Mon Nov 17 14:07:00 2014 +0000
+++ b/Makefile.linux	Thu Nov 20 13:02:50 2014 +0000
@@ -7,16 +7,8 @@
 LDFLAGS		:= -shared -Wl,-Bstatic -lvamp-sdk -Wl,-Bdynamic -lpython2.7 -lpthread -Wl,--version-script=vamp-plugin.map
 
 default: vampy.so 
-all: vampy.so vampymod.so
 
-PyExtensionModule.a: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o 
-	ar cr $@ $^
-
-# The standard python extension is .so (even on the Mac)
-vampymod.so: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o 
-	g++ $^ -o $@ $(LDFLAGS) 
-
-vampy.so: PyPlugin.o PyPlugScanner.o vampy-main.o Mutex.o PyTypeInterface.o PyExtensionModule.a  PyExtensionManager.o
+vampy.so:   PyRealTime.o PyFeature.o PyFeatureSet.o PyParameterDescriptor.o PyOutputDescriptor.o PyTypeConversions.o PyExtensionModule.o PyPlugin.o PyPlugScanner.o Mutex.o PyExtensionManager.o PyTypeInterface.o vampy-main.o
 	g++ $^ -o $@ $(LDFLAGS) 
 
 # Install plugin
@@ -33,9 +25,52 @@
 
 installplug : install
 cleanplug : clean
+depend:
+	makedepend -Y -fMakefile.linux *.cpp *.h
 
 clean:	
 	rm -f *.o
 	rm -f *.a
 	rm -f *$(PLUGIN_EXT)
 
+# DO NOT DELETE
+
+Mutex.o: Mutex.h
+PyExtensionManager.o: PyExtensionModule.h PyRealTime.h PyFeature.h
+PyExtensionManager.o: PyFeatureSet.h PyParameterDescriptor.h
+PyExtensionManager.o: PyOutputDescriptor.h PyExtensionManager.h Debug.h
+PyExtensionModule.o: PyExtensionModule.h PyRealTime.h PyFeature.h
+PyExtensionModule.o: PyFeatureSet.h PyParameterDescriptor.h
+PyExtensionModule.o: PyOutputDescriptor.h Debug.h
+PyFeature.o: PyExtensionModule.h PyRealTime.h PyFeature.h PyFeatureSet.h
+PyFeature.o: PyParameterDescriptor.h PyOutputDescriptor.h
+PyFeatureSet.o: PyFeatureSet.h
+PyOutputDescriptor.o: PyOutputDescriptor.h PyTypeInterface.h
+PyOutputDescriptor.o: PyExtensionModule.h PyRealTime.h PyFeature.h
+PyOutputDescriptor.o: PyFeatureSet.h PyParameterDescriptor.h
+PyParameterDescriptor.o: PyParameterDescriptor.h PyTypeInterface.h
+PyParameterDescriptor.o: PyExtensionModule.h PyRealTime.h PyFeature.h
+PyParameterDescriptor.o: PyFeatureSet.h PyOutputDescriptor.h
+PyPlugin.o: PyPlugin.h PyExtensionModule.h PyRealTime.h PyFeature.h
+PyPlugin.o: PyFeatureSet.h PyParameterDescriptor.h PyOutputDescriptor.h
+PyPlugin.o: PyTypeInterface.h Mutex.h Debug.h
+PyPlugScanner.o: PyPlugScanner.h
+PyRealTime.o: PyRealTime.h
+PyTypeConversions.o: PyTypeConversions.h PyRealTime.h PyExtensionModule.h
+PyTypeConversions.o: PyFeature.h PyFeatureSet.h PyParameterDescriptor.h
+PyTypeConversions.o: PyOutputDescriptor.h
+PyTypeInterface.o: PyTypeInterface.h PyExtensionModule.h PyRealTime.h
+PyTypeInterface.o: PyFeature.h PyFeatureSet.h PyParameterDescriptor.h
+PyTypeInterface.o: PyOutputDescriptor.h
+vampy-main.o: PyPlugScanner.h PyPlugin.h PyExtensionModule.h PyRealTime.h
+vampy-main.o: PyFeature.h PyFeatureSet.h PyParameterDescriptor.h
+vampy-main.o: PyOutputDescriptor.h PyTypeInterface.h Mutex.h
+vampy-main.o: PyExtensionManager.h Debug.h
+PyExtensionModule.o: PyRealTime.h PyFeature.h PyFeatureSet.h
+PyExtensionModule.o: PyParameterDescriptor.h PyOutputDescriptor.h
+PyPlugin.o: PyExtensionModule.h PyRealTime.h PyFeature.h PyFeatureSet.h
+PyPlugin.o: PyParameterDescriptor.h PyOutputDescriptor.h PyTypeInterface.h
+PyPlugin.o: Mutex.h
+PyTypeInterface.o: PyExtensionModule.h PyRealTime.h PyFeature.h
+PyTypeInterface.o: PyFeatureSet.h PyParameterDescriptor.h
+PyTypeInterface.o: PyOutputDescriptor.h
--- a/PyPlugin.cpp	Mon Nov 17 14:07:00 2014 +0000
+++ b/PyPlugin.cpp	Thu Nov 20 13:02:50 2014 +0000
@@ -87,8 +87,12 @@
 	if (m_debugFlag && m_quitOnErrorFlag) cerr << "Quit on type error ON for: " << m_class << endl;
    
 	if (m_debugFlag && st_flag) cerr << "Strict type conversion ON for: " << m_class << endl;
+
 	m_ti.setStrictTypingFlag(st_flag);
+	m_tc.setStrictTypingFlag(st_flag);
+
 	m_ti.setNumpyInstalled(m_numpyInstalled);
+	m_tc.setNumpyInstalled(m_numpyInstalled);
 
 }
 
@@ -318,8 +322,8 @@
 		{
 			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
 		} else {
-			rValue = m_ti.PyValue_To_Bool(pyValue);
-			if (m_ti.error) { 
+			rValue = m_tc.PyValue_To_Bool(pyValue);
+			if (m_tc.error) { 
 				Py_CLEAR(pyValue);
 				typeErrorHandler(flagName);
 				rValue = defValue;
@@ -341,8 +345,8 @@
 		{
 			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
 		} else {
-			rValue |= (int) m_ti.PyValue_To_Size_t(pyValue);
-			if (m_ti.error) { 
+			rValue |= (int) m_tc.PyValue_To_Size_t(pyValue);
+			if (m_tc.error) { 
 				Py_CLEAR(pyValue);
 				typeErrorHandler(flagName);
 				rValue = defValue;
@@ -430,8 +434,10 @@
 PyPlugin::typeErrorHandler(const char *method, bool process) const
 {
 	bool strict = false;
-	while (m_ti.error) { 
-		PyTypeInterface::ValueError e = m_ti.getError();
+	while (m_tc.error || m_ti.error) {
+	    ValueError e;
+	    if (m_tc.error) e = m_tc.getError();
+	    else e = m_ti.getError();
 #ifdef HAVE_NUMPY
 		// disable the process completely if numpy types are returned 
 		// but a compatible version was not loaded.
--- a/PyPlugin.h	Mon Nov 17 14:07:00 2014 +0000
+++ b/PyPlugin.h	Thu Nov 20 13:02:50 2014 +0000
@@ -9,40 +9,6 @@
 
 */
 
-/*
-    Vamp
-
-    An API for audio analysis and feature extraction plugins.
-
-    Centre for Digital Music, Queen Mary, University of London.
-    Copyright 2006 Chris Cannam.
-  
-    Permission is hereby granted, free of charge, to any person
-    obtaining a copy of this software and associated documentation
-    files (the "Software"), to deal in the Software without
-    restriction, including without limitation the rights to use, copy,
-    modify, merge, publish, distribute, sublicense, and/or sell copies
-    of the Software, and to permit persons to whom the Software is
-    furnished to do so, subject to the following conditions:
-
-    The above copyright notice and this permission notice shall be
-    included in all copies or substantial portions of the Software.
-
-    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
-    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
-    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-    Except as contained in this notice, the names of the Centre for
-    Digital Music; Queen Mary, University of London; and Chris Cannam
-    shall not be used in advertising or otherwise to promote the sale,
-    use or other dealings in this Software without prior written
-    authorization.
-*/
-
 #ifndef _PYTHON_WRAPPER_PLUGIN_H_
 #define _PYTHON_WRAPPER_PLUGIN_H_
 
@@ -55,6 +21,7 @@
 #include <Python.h>
 #include "PyExtensionModule.h"
 #include "PyTypeInterface.h"
+#include "PyTypeConversions.h"
 #include "vamp-sdk/Plugin.h"
 #include "Mutex.h"
 
@@ -117,6 +84,7 @@
 	PyObject *m_pyProcess;
 	PyObject *m_pyProcessCallable;
 	mutable InputDomain m_inputDomain;
+	PyTypeConversions m_tc;
 	PyTypeInterface m_ti;
 	int m_vampyFlags;
 	bool m_quitOnErrorFlag;
@@ -187,7 +155,7 @@
 		}
 		
 		/// prepare arguments for fast method call
-		PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
+		PyObject *pyMethod = m_tc.PyValue_From_CValue(method);
 		PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
 		PyObject* pyArgs = PyTuple_New(1);
 		if (!(pyArgs && pyCallable && pyMethod)) {
@@ -198,8 +166,8 @@
 			return rValue;
 		}
 		
-		PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
-		if (m_ti.error) {
+		PyObject *pyArg1 = m_tc.PyValue_From_CValue(arg1);
+		if (m_tc.error) {
 			cerr << PLUGIN_ERROR << "Failed to convert argument for calling method." << endl;
 			typeErrorHandler(method);
 			Py_CLEAR(pyMethod);
@@ -253,7 +221,7 @@
 		}
 		
 		/// prepare arguments for fast method call
-		PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
+		PyObject *pyMethod = m_tc.PyValue_From_CValue(method);
 		PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
 		PyObject* pyArgs = PyTuple_New(2);
 		if (!(pyArgs && pyCallable && pyMethod)) {
@@ -264,9 +232,9 @@
 			return rValue;
 		}
 		
-		PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
-		PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
-		if (m_ti.error) {
+		PyObject *pyArg1 = m_tc.PyValue_From_CValue(arg1);
+		PyObject *pyArg2 = m_tc.PyValue_From_CValue(arg2);
+		if (m_tc.error) {
 			cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl;
 			typeErrorHandler(method);
 			Py_CLEAR(pyMethod);
@@ -325,7 +293,7 @@
 		}
 		
 		/// prepare arguments for fast method call
-		PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
+		PyObject *pyMethod = m_tc.PyValue_From_CValue(method);
 		PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
 		PyObject* pyArgs = PyTuple_New(3);
 		if (!(pyArgs && pyCallable && pyMethod)) {
@@ -336,10 +304,10 @@
 			return rValue;
 		}
 		
-		PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
-		PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
-		PyObject *pyArg3 = m_ti.PyValue_From_CValue(arg3);
-		if (m_ti.error) {
+		PyObject *pyArg1 = m_tc.PyValue_From_CValue(arg1);
+		PyObject *pyArg2 = m_tc.PyValue_From_CValue(arg2);
+		PyObject *pyArg3 = m_tc.PyValue_From_CValue(arg3);
+		if (m_tc.error) {
 			cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl;
 			typeErrorHandler(method);
 			Py_CLEAR(pyMethod);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyTypeConversions.cpp	Thu Nov 20 13:02:50 2014 +0000
@@ -0,0 +1,818 @@
+/* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+#include <Python.h>
+
+#include "PyTypeConversions.h"
+
+#include <math.h>
+#include <float.h>
+#include <limits.h>
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX ((size_t) -1)
+#endif
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+
+/*  Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS
+	(EXCEPT FOR TEMPORARY PYTHON OBJECTS)! */
+
+PyTypeConversions::PyTypeConversions() : 
+	m_strict(false),
+	m_error(false),
+	m_numpyInstalled(false),
+	error(m_error) // const public reference for easy access
+{
+}
+
+PyTypeConversions::~PyTypeConversions()
+{
+}
+
+/// floating point numbers (TODO: check numpy.float128)
+float 
+PyTypeConversions::PyValue_To_Float(PyObject* pyValue) const
+{
+	// convert float
+	if (pyValue && PyFloat_Check(pyValue)) 
+		//TODO: check for limits here (same on most systems)
+		return (float) PyFloat_AS_DOUBLE(pyValue);
+	
+	if (pyValue == NULL)
+	{
+		setValueError("Error while converting object " + PyValue_Get_TypeName(pyValue) + " to float. ",m_strict);
+		return 0.0;		
+	}
+		
+	// in strict mode we will not try harder
+	if (m_strict) {
+		setValueError("Strict conversion error: object" + PyValue_Get_TypeName(pyValue) +" is not float.",m_strict);
+		return 0.0;
+	}
+
+	// convert other objects supporting the number protocol
+	if (PyNumber_Check(pyValue))
+	{
+		PyObject* pyFloat = PyNumber_Float(pyValue); // new ref
+		if (!pyFloat)
+		{
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			setValueError("Error while converting " + PyValue_Get_TypeName(pyValue) + " object to float.",m_strict);
+			return 0.0;
+		}
+		float rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
+		Py_DECREF(pyFloat);
+		return rValue;
+	}
+/*	
+	// convert other objects supporting the number protocol
+	if (PyNumber_Check(pyValue)) 
+	{	
+		// PEP353: Py_ssize_t is size_t but signed !
+		// This will work up to numpy.float64
+		Py_ssize_t rValue = PyNumber_AsSsize_t(pyValue,NULL);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError("Error while converting integer object.",m_strict);
+			return 0.0;
+		}
+		if (rValue > (Py_ssize_t)FLT_MAX || rValue < (Py_ssize_t)FLT_MIN)
+		{
+			setValueError("Overflow error. Object can not be converted to float.",m_strict);
+			return 0.0;
+		}
+		return (float) rValue;
+	}
+*/	
+    // convert string
+	if (PyString_Check(pyValue))
+	{
+		PyObject* pyFloat = PyFloat_FromString(pyValue,NULL);
+		if (!pyFloat) 
+		{
+			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+			setValueError("String value can not be converted to float.",m_strict);
+			return 0.0;
+		}
+		float rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear(); 
+			Py_CLEAR(pyFloat);
+			setValueError("Error while converting float object.",m_strict);
+			return 0.0;
+		}
+		Py_DECREF(pyFloat);
+		return rValue;
+	}
+	
+	// convert the first element of any iterable sequence (for convenience and backwards compatibility)
+	if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) 
+	{
+		PyObject* item = PySequence_GetItem(pyValue,0);
+		if (item)
+		{
+			float rValue = this->PyValue_To_Float(item);
+			if (!m_error) {
+				Py_DECREF(item);
+				return rValue;
+			} else {
+				Py_CLEAR(item);
+				std::string msg = "Could not convert sequence element to float. ";
+				setValueError(msg,m_strict);
+				return 0.0;
+			}
+		}
+	}
+
+    // give up
+	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+	std::string msg = "Conversion from " + PyValue_Get_TypeName(pyValue) + " to float is not possible.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeConversions::PyValue_To_Float failed. " << msg << endl;
+#endif	
+	return 0.0;
+}
+
+/// size_t (unsigned integer types)
+size_t 
+PyTypeConversions::PyValue_To_Size_t(PyObject* pyValue) const
+{
+	// convert objects supporting the number protocol 
+	if (PyNumber_Check(pyValue)) 
+	{	
+		if (m_strict && !PyInt_Check(pyValue) && !PyLong_Check(pyValue)) 
+			setValueError("Strict conversion error: object is not integer type.",m_strict);
+		// Note: this function handles Bool,Int,Long,Float
+		// speed is not critical in the use of this type by Vamp
+		// PEP353: Py_ssize_t is size_t but signed ! 
+		Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError("Error while converting integer object.",m_strict);
+			return 0;
+		}
+		// this test is nonsense -- neither part can occur
+		// owing to range of data types -- size_t is at least
+		// as big as long, and unsigned is always non-negative
+/*
+		if ((unsigned long)rValue > SIZE_T_MAX || (unsigned long)rValue < 0)
+		{
+			setValueError("Overflow error. Object can not be converted to size_t.",m_strict);
+			return 0;
+		}
+*/
+		return (size_t) rValue;
+	}
+	
+	// in strict mode we will not try harder and throw an exception
+	// then the caller should decide what to do with it
+	if (m_strict) {
+		setValueError("Strict conversion error: object is not integer.",m_strict);
+		return 0;
+	}
+	
+	// convert string
+	if (PyString_Check(pyValue))
+	{
+		PyObject* pyLong = PyNumber_Long(pyValue);
+		if (!pyLong) 
+		{
+			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+			setValueError("String object can not be converted to size_t.",m_strict);
+			return 0;
+		}
+		size_t rValue = this->PyValue_To_Size_t(pyLong);
+		if (!m_error) {
+			Py_DECREF(pyLong);
+			return rValue;
+		} else {
+			Py_CLEAR(pyLong);
+			setValueError ("Error converting string to size_t.",m_strict);
+			return 0;
+		}
+	}
+	
+	// convert the first element of iterable sequences
+	if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) 
+	{
+		PyObject* item = PySequence_GetItem(pyValue,0);
+		if (item)
+		{
+			size_t rValue = this->PyValue_To_Size_t(item);
+			if (!m_error) {
+				Py_DECREF(item);
+				return rValue;
+			} else {
+				Py_CLEAR(item);
+				setValueError("Could not convert sequence element to size_t. ",m_strict);
+				return 0;
+			}
+		}
+	}
+	
+    // give up
+	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to size_t is not possible.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeConversions::PyValue_To_Size_t failed. " << msg << endl;
+#endif	
+	return 0;
+}
+
+/// long and int
+long 
+PyTypeConversions::PyValue_To_Long(PyObject* pyValue) const
+{
+	// most common case: convert int (faster)
+	if (pyValue && PyInt_Check(pyValue)) {
+		// if the object is not NULL and verified, this macro just extracts the value.
+		return PyInt_AS_LONG(pyValue);
+	} 
+	
+	// long
+	if (PyLong_Check(pyValue)) {
+		long rValue = PyLong_AsLong(pyValue);
+		if (PyErr_Occurred()) { 
+			PyErr_Print(); PyErr_Clear(); 
+			setValueError("Error while converting long object.",m_strict);
+			return 0;
+		}
+		return rValue;
+	}
+	
+	if (m_strict) {
+		setValueError("Strict conversion error: object is not integer or long integer.",m_strict);
+		return 0;
+	}
+	
+	// convert all objects supporting the number protocol
+	if (PyNumber_Check(pyValue)) 
+	{	
+		// Note: this function handles Bool,Int,Long,Float
+		// PEP353: Py_ssize_t is size_t but signed ! 
+		Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError("Error while converting integer object.",m_strict);
+			return 0;
+		}
+		if (rValue > LONG_MAX || rValue < LONG_MIN)
+		{
+			setValueError("Overflow error. Object can not be converted to size_t.",m_strict);
+			return 0;
+		}
+		return (long) rValue;
+	}
+	
+	// convert string
+	if (PyString_Check(pyValue))
+	{
+		PyObject* pyLong = PyNumber_Long(pyValue);
+		if (!pyLong) 
+		{
+			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+			setValueError("String object can not be converted to long.",m_strict);
+			return 0;
+		}
+		long rValue = this->PyValue_To_Long(pyLong);
+		if (!m_error) {
+			Py_DECREF(pyLong);
+			return rValue;
+		} else {
+			Py_CLEAR(pyLong);
+			setValueError ("Error converting string to long.",m_strict);
+			return 0;
+		}
+	}
+	
+	// convert the first element of iterable sequences
+	if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) 
+	{
+		PyObject* item = PySequence_GetItem(pyValue,0);
+		if (item)
+		{
+			size_t rValue = this->PyValue_To_Long(item);
+			if (!m_error) {
+				Py_DECREF(item);
+				return rValue;
+			} else {
+				Py_CLEAR(item);
+				setValueError("Could not convert sequence element to long. ",m_strict);
+				return 0;
+			}
+		}
+	}
+	
+    // give up
+	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to long is not possible.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeConversions::PyValue_To_Long failed. " << msg << endl;
+#endif	
+	return 0;
+}
+
+
+bool 
+PyTypeConversions::PyValue_To_Bool(PyObject* pyValue) const
+{
+	// convert objects supporting the number protocol
+	// Note: PyBool is a subclass of PyInt
+	if (PyNumber_Check(pyValue)) 
+	{	
+		if (m_strict && !PyBool_Check(pyValue)) 
+			setValueError
+			("Strict conversion error: object is not boolean type.",m_strict);
+
+		// Note: this function handles Bool,Int,Long,Float
+		Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError ("Error while converting boolean object.",m_strict);
+		}
+		if (rValue != 1 && rValue != 0)
+		{
+			setValueError ("Overflow error. Object can not be converted to boolean.",m_strict);
+		}
+		return (bool) rValue;
+	}
+	
+	if (m_strict) {
+		setValueError ("Strict conversion error: object is not numerical type.",m_strict);
+		return false;
+	}
+	
+	// convert iterables: the rule is the same as in the interpreter:
+	// empty sequence evaluates to False, anything else is True
+	if (PySequence_Check(pyValue)) 
+	{
+		return PySequence_Size(pyValue)?true:false;
+	}
+	
+    // give up
+	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to boolean is not possible.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeConversions::PyValue_To_Bool failed. " << msg << endl;
+#endif	
+	return false;
+}
+
+/// string and objects that support .__str__() 
+/// TODO: check unicode objects
+std::string 
+PyTypeConversions::PyValue_To_String(PyObject* pyValue) const
+{
+	// convert string
+	if (PyString_Check(pyValue)) 
+	{	
+		char *cstr = PyString_AS_STRING(pyValue);
+		if (!cstr) 
+		{
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			setValueError("Error while converting string object.",m_strict);
+			return std::string();
+		}
+		return std::string(cstr);
+	}
+	// TODO: deal with unicode here (argh!)
+	
+	// in strict mode we will not try harder
+	if (m_strict) {
+		setValueError("Strict conversion error: object is not string.",m_strict);
+		return std::string();
+	}
+	
+	// accept None as empty string
+	if (pyValue == Py_None) return std::string();
+			
+	// convert list or tuple: empties are turned into empty strings conventionally
+	if (PyList_Check(pyValue) || PyTuple_Check(pyValue)) 
+	{
+		if (!PySequence_Size(pyValue)) return std::string();
+		PyObject* item = PySequence_GetItem(pyValue,0);
+		if (item)
+		{
+			std::string rValue = this->PyValue_To_String(item);
+			if (!m_error) {
+				Py_DECREF(item);
+				return rValue;
+			} else {
+				Py_CLEAR(item);
+				setValueError("Could not convert sequence element to string.",m_strict);
+				return std::string();
+			}
+		}
+	}
+
+	// convert any other object that has .__str__() or .__repr__()
+	PyObject* pyString = PyObject_Str(pyValue);
+	if (pyString && !PyErr_Occurred())
+	{
+		std::string rValue = this->PyValue_To_String(pyString);
+		if (!m_error) {
+			Py_DECREF(pyString);
+			return rValue;
+		} else {
+			Py_CLEAR(pyString);
+			std::string msg = "Object " + this->PyValue_Get_TypeName(pyValue) +" can not be represented as string. ";
+			setValueError (msg,m_strict);
+			return std::string();
+		}
+	}
+
+	// give up
+	PyErr_Print(); PyErr_Clear();
+	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to string is not possible.";
+	setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeConversions::PyValue_To_String failed. " << msg << endl;
+#endif	
+	return std::string();
+}
+
+/*			 			C Values to Py Values				  		*/
+
+
+PyObject*
+PyTypeConversions::PyValue_From_CValue(const char* cValue) const
+{
+	// returns new reference
+#ifdef _DEBUG
+	if (!cValue) {
+		std::string msg = "PyTypeConversions::PyValue_From_CValue: Null pointer encountered while converting from const char* .";
+		cerr << msg << endl;
+		setValueError(msg,m_strict);
+		return NULL;
+	}
+#endif
+	PyObject *pyValue = PyString_FromString(cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from char* or string.",m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from const char*" << endl;
+#endif
+		return NULL;
+	}
+	return pyValue;
+}
+
+PyObject*
+PyTypeConversions::PyValue_From_CValue(size_t cValue) const
+{
+	// returns new reference
+	PyObject *pyValue = PyInt_FromSsize_t((Py_ssize_t)cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from size_t.",m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from size_t" << endl;
+#endif
+		return NULL;
+	}
+	return pyValue;
+}
+
+PyObject*
+PyTypeConversions::PyValue_From_CValue(double cValue) const
+{
+	// returns new reference
+	PyObject *pyValue = PyFloat_FromDouble(cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from float or double.",m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from float or double" << endl;
+#endif
+		return NULL;
+	}
+	return pyValue;
+}
+
+PyObject*
+PyTypeConversions::PyValue_From_CValue(bool cValue) const
+{
+	// returns new reference
+	PyObject *pyValue = PyBool_FromLong((long)cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from bool.",m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from bool" << endl;
+#endif
+		return NULL;
+	}
+	return pyValue;
+}
+
+
+/*			 			Sequence Types to C++ Types	    		  	*/
+
+//convert Python list to C++ vector of strings
+std::vector<std::string> 
+PyTypeConversions::PyValue_To_StringVector (PyObject *pyList) const 
+{
+	
+	std::vector<std::string> Output;
+	std::string ListElement;
+	PyObject *pyString = NULL;
+	
+	if (PyList_Check(pyList)) {
+
+		for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
+			//Get next list item (Borrowed Reference)
+			pyString = PyList_GET_ITEM(pyList,i);
+			ListElement = (string) PyString_AsString(PyObject_Str(pyString));
+			Output.push_back(ListElement);
+		}
+		return Output;
+	}
+
+// #ifdef _DEBUG
+// 	cerr << "PyTypeConversions::PyValue_To_StringVector: Warning: Value is not list of strings." << endl;
+// #endif
+
+	/// Assume a single value that can be casted as string 
+	/// this allows to write e.g. Feature.label = 5.2 instead of ['5.2']
+	Output.push_back(PyValue_To_String(pyList));
+	if (m_error) {
+		std::string msg = "Value is not list of strings nor can be casted as string. ";
+		setValueError(msg,m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeConversions::PyValue_To_StringVector failed. " << msg << endl;
+#endif
+	}
+	return Output;
+}
+
+//convert PyFeature.value (typically a list or numpy array) to C++ vector of floats
+std::vector<float> 
+PyTypeConversions::PyValue_To_FloatVector (PyObject *pyValue) const 
+{
+
+#ifdef HAVE_NUMPY
+if (m_numpyInstalled) 
+{
+	// there are four types of values we may receive from a numpy process:
+	// * a python scalar, 
+	// * an array scalar, (e.g. numpy.float32)
+	// * an array with nd = 0  (0D array)
+	// * an array with nd > 0
+
+	/// check for scalars
+	if (PyArray_CheckScalar(pyValue) || PyFloat_Check(pyValue)) {
+
+		std::vector<float> Output;
+
+		// we rely on the behaviour the scalars are either floats
+		// or support the number protocol
+		// TODO: a potential optimisation is to handle them directly
+		Output.push_back(PyValue_To_Float(pyValue));
+		return Output;
+	}
+
+	/// numpy array
+	if (PyArray_CheckExact(pyValue)) 
+		return PyArray_To_FloatVector(pyValue);
+}
+#endif
+
+	/// python list of floats (backward compatible)
+	if (PyList_Check(pyValue)) {
+		return PyList_To_FloatVector(pyValue);
+	}
+
+	std::vector<float> Output;
+	
+	/// finally assume a single value supporting the number protocol 
+	/// this allows to write e.g. Feature.values = 5 instead of [5.00]
+	Output.push_back(PyValue_To_Float(pyValue));
+	if (m_error) {
+		std::string msg = "Value is not list or array of floats nor can be casted as float. ";
+		setValueError(msg,m_strict);
+#ifdef _DEBUG
+	cerr << "PyTypeConversions::PyValue_To_FloatVector failed. " << msg << endl;
+#endif
+	}
+	return Output;
+}
+
+//convert a list of python floats
+std::vector<float> 
+PyTypeConversions::PyList_To_FloatVector (PyObject *inputList) const 
+{
+	std::vector<float> Output;
+	
+#ifdef _DEBUG
+	// This is a low level function normally called from 
+	// PyValue_To_FloatVector(). Checking for list is not required.
+	if (!PyList_Check(inputList)) {
+		std::string msg = "Value is not list.";
+		setValueError(msg,true);
+		cerr << "PyTypeConversions::PyList_To_FloatVector failed. " << msg << endl;
+		return Output; 
+	} 
+#endif
+
+	float ListElement;
+	PyObject *pyFloat = NULL;
+	PyObject **pyObjectArray = PySequence_Fast_ITEMS(inputList);
+
+	for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
+
+		// pyFloat = PyList_GET_ITEM(inputList,i);
+		pyFloat = pyObjectArray[i];
+
+#ifdef _DEBUG
+		if (!pyFloat) {
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			cerr << "PyTypeConversions::PyList_To_FloatVector: Could not obtain list element: " 
+			<< i << " PyList_GetItem returned NULL! Skipping value." << endl;
+			continue;
+		}
+#endif		
+
+		// ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
+		ListElement = PyValue_To_Float(pyFloat);
+		
+
+#ifdef _DEBUG_VALUES
+		cerr << "value: " << ListElement << endl;
+#endif
+		Output.push_back(ListElement);
+	}
+	return Output;
+}
+
+// if numpy is not installed this will not be called, 
+// therefor we do not check again
+#ifdef HAVE_NUMPY 
+std::vector<float> 
+PyTypeConversions::PyArray_To_FloatVector (PyObject *pyValue) const 
+{
+	std::vector<float> Output;
+	
+#ifdef _DEBUG
+	// This is a low level function, normally called from 
+	// PyValue_To_FloatVector(). Checking the array here is not required.
+	if (!PyArray_Check(pyValue)) {
+		std::string msg = "Object has no array conversions.";
+		setValueError(msg,true);
+		cerr << "PyTypeConversions::PyArray_To_FloatVector failed. " << msg << endl;
+		return Output; 
+	} 
+#endif
+
+	PyArrayObject* pyArray = (PyArrayObject*) pyValue;
+	PyArray_Descr* descr = PyArray_DESCR(pyArray);
+	
+	/// check raw data and descriptor pointers
+	if (PyArray_DATA(pyArray) == 0 || descr == 0) {
+		std::string msg = "NumPy array with NULL data or descriptor pointer encountered.";
+		setValueError(msg,m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeConversions::PyArray_To_FloatVector failed. Error: " << msg << endl;
+#endif		
+		return Output;
+	}
+
+	/// check dimensions
+	if (PyArray_NDIM(pyArray) != 1) {
+		std::string msg = "NumPy array must be a one dimensional vector.";
+		setValueError(msg,m_strict);
+#ifdef _DEBUG
+		cerr << "PyTypeConversions::PyArray_To_FloatVector failed. Error: " << msg << " Dims: " << (int) PyArray_NDIM(pyArray) << endl;
+#endif	
+		return Output;
+	}
+
+#ifdef _DEBUG_VALUES
+	cerr << "PyTypeConversions::PyArray_To_FloatVector: Numpy array verified." << endl;
+#endif
+	
+	/// check strides (useful if array is not continuous)
+	size_t strides =  *((size_t*) PyArray_STRIDES(pyArray));
+    
+	/// convert the array
+	switch (descr->type_num)
+	{
+		case NPY_FLOAT : // dtype='float32'
+			return PyArray_Convert<float,float>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
+		case NPY_DOUBLE : // dtype='float64'
+			return PyArray_Convert<float,double>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
+		case NPY_INT : // dtype='int'
+			return PyArray_Convert<float,int>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
+		case NPY_LONG : // dtype='long'
+			return PyArray_Convert<float,long>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
+		default :
+			std::string msg = "Unsupported value type in NumPy array object.";
+			setValueError(msg,m_strict);
+#ifdef _DEBUG
+			cerr << "PyTypeConversions::PyArray_To_FloatVector failed. Error: " << msg << endl;
+#endif			
+			return Output;
+	}
+}
+#endif
+
+
+
+/*			   			  	Error handling		   			  		*/
+
+void
+PyTypeConversions::setValueError (std::string message, bool strict) const
+{
+	m_error = true;
+	m_errorQueue.push(ValueError(message,strict));
+}
+
+/// return a reference to the last error or creates a new one.
+ValueError&
+PyTypeConversions::lastError() const 
+{
+	m_error = false;
+	if (!m_errorQueue.empty()) return m_errorQueue.back();
+	else {
+		m_errorQueue.push(ValueError("Type conversion error.",m_strict));
+		return m_errorQueue.back();
+	}
+}
+
+/// helper function to iterate over the error message queue:
+/// pops the oldest item
+ValueError 
+PyTypeConversions::getError() const
+{
+	if (!m_errorQueue.empty()) {
+		ValueError e = m_errorQueue.front();
+		m_errorQueue.pop();
+		if (m_errorQueue.empty()) m_error = false;
+		return e;
+	}
+	else {
+		m_error = false;
+		return ValueError();
+	}
+}
+
+/*			   			  	Utilities						  		*/
+
+/// get the type name of an object
+std::string
+PyTypeConversions::PyValue_Get_TypeName(PyObject* pyValue) const
+{
+	PyObject *pyType = PyObject_Type(pyValue);
+	if (!pyType) 
+	{
+		cerr << "Warning: Object type name could not be found." << endl;
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		return std::string ("< unknown type >");
+	}
+	PyObject *pyString = PyObject_Str(pyType);
+	if (!pyString)
+	{
+		cerr << "Warning: Object type name could not be found." << endl;
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		Py_CLEAR(pyType);
+		return std::string ("< unknown type >");
+	}
+	char *cstr = PyString_AS_STRING(pyString);
+	if (!cstr)
+	{
+		cerr << "Warning: Object type name could not be found." << endl;
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		Py_DECREF(pyType);
+		Py_CLEAR(pyString);
+		return std::string("< unknown type >");
+	}
+	Py_DECREF(pyType);
+	Py_DECREF(pyString);
+	return std::string(cstr);
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyTypeConversions.h	Thu Nov 20 13:02:50 2014 +0000
@@ -0,0 +1,168 @@
+/* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */
+/*
+
+ * Vampy : This plugin is a wrapper around the Vamp plugin API.
+ * It allows for writing Vamp plugins in Python.
+
+ * Centre for Digital Music, Queen Mary University of London.
+ * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
+ * for licence information.)
+
+*/
+
+/*
+PyTypeConversions: Type safe conversion utilities between Python types 
+and basic C/C++ types.
+*/
+
+#ifndef _PY_TYPE_CONVERSIONS_H_
+#define _PY_TYPE_CONVERSIONS_H_
+#include <Python.h>
+#ifdef HAVE_NUMPY
+#define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API
+#define NO_IMPORT_ARRAY
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+#include "numpy/arrayobject.h"
+#endif
+
+#include <vector>
+#include <queue>
+#include <string>
+#include <sstream>
+#include <iostream>
+
+using std::cerr;
+using std::endl;
+
+#ifdef HAVE_NUMPY
+enum eArrayDataType {
+	dtype_float32 = (int) NPY_FLOAT,
+	dtype_complex64 = (int) NPY_CFLOAT 
+	};
+#endif 
+
+/* C++ mapping of PyNone Type */
+struct NoneType {};
+	
+// Data
+class ValueError
+{
+public:
+	ValueError() {}
+	ValueError(std::string m, bool s) : message(m),strict(s) {}
+	std::string location;
+	std::string message;
+	bool strict;
+	std::string str() const { 
+		return (location.empty()) ? message : message + "\nLocation: " + location;}
+	void print() const { cerr << str() << endl; }
+	template<typename V> ValueError &operator<< (const V& v)
+	{
+		std::ostringstream ss;
+		ss << v;
+		location += ss.str();
+		return *this;
+	}
+};
+
+class PyTypeConversions
+{
+public:
+	PyTypeConversions();
+	~PyTypeConversions();
+	
+	// Utilities
+	void setStrictTypingFlag(bool b) {m_strict = b;}
+	void setNumpyInstalled(bool b) {m_numpyInstalled = b;}
+	ValueError getError() const;
+	std::string PyValue_Get_TypeName(PyObject*) const;
+
+	// Basic type conversion: Python to C++ 
+	float 	PyValue_To_Float(PyObject*) const;
+	size_t 	PyValue_To_Size_t(PyObject*) const;
+	bool 	PyValue_To_Bool(PyObject*) const;
+	std::string PyValue_To_String(PyObject*) const;
+	long 	PyValue_To_Long(PyObject*) const;
+	// int 	PyValue_To_Int(PyObject* pyValue) const;
+	
+	// C++ to Python
+	PyObject *PyValue_From_CValue(const char*) const;
+	PyObject *PyValue_From_CValue(const std::string& x) const { return PyValue_From_CValue(x.c_str()); }
+	PyObject *PyValue_From_CValue(size_t) const;
+	PyObject *PyValue_From_CValue(double) const;
+	PyObject *PyValue_From_CValue(float x) const { return PyValue_From_CValue((double)x); }
+	PyObject *PyValue_From_CValue(bool) const;
+	
+	// Sequence types
+	std::vector<std::string> PyValue_To_StringVector (PyObject*) const;
+	std::vector<float> PyValue_To_FloatVector (PyObject*) const;
+	std::vector<float> PyList_To_FloatVector (PyObject*) const;
+
+	// Numpy types
+#ifdef HAVE_NUMPY
+	std::vector<float> PyArray_To_FloatVector (PyObject *pyValue) const;
+#endif
+
+	/// Convert DTYPE type 1D NumpyArray to std::vector<RET>
+	template<typename RET, typename DTYPE>
+	std::vector<RET> PyArray_Convert(void* raw_data_ptr, long length, size_t strides) const
+	{
+		std::vector<RET> rValue;
+		
+		/// check if the array is continuous, if not use strides info
+		if (sizeof(DTYPE)!=strides) {
+#ifdef _DEBUG_VALUES
+			cerr << "Warning: discontinuous numpy array. Strides: " << strides << " bytes. sizeof(dtype): " << sizeof(DTYPE) << endl;
+#endif
+			char* data = (char*) raw_data_ptr;
+			for (long i = 0; i<length; ++i){
+				rValue.push_back((RET)(*((DTYPE*)data)));
+#ifdef _DEBUG_VALUES
+				cerr << "value: " << (RET)(*((DTYPE*)data)) << endl;
+#endif				
+				data+=strides;
+			}
+			return rValue;
+		}
+
+		DTYPE* data = (DTYPE*) raw_data_ptr;
+		for (long i = 0; i<length; ++i){
+#ifdef _DEBUG_VALUES
+			cerr << "value: " << (RET)data[i] << endl;
+#endif
+			rValue.push_back((RET)data[i]);
+		}
+		return rValue;
+	}
+
+	/// this is a special case. numpy.float64 has an array conversions but no array descriptor
+	inline std::vector<float> PyArray0D_Convert(PyArrayInterface *ai) const
+	{
+		std::vector<float> rValue;
+		if ((ai->typekind) == *"f") 
+			rValue.push_back((float)*(double*)(ai->data));
+		else { 
+			setValueError("Unsupported NumPy data type.",m_strict); 
+			return rValue;
+		}
+#ifdef _DEBUG_VALUES
+		cerr << "value: " << rValue[0] << endl;
+#endif
+		return rValue;
+	}
+
+private:
+	bool m_strict;
+	mutable bool m_error;
+	mutable std::queue<ValueError> m_errorQueue;
+	bool m_numpyInstalled;
+	
+	void setValueError(std::string,bool) const;
+	ValueError& lastError() const;
+
+public:
+	const bool& error;
+
+};
+
+#endif
--- a/PyTypeInterface.cpp	Mon Nov 17 14:07:00 2014 +0000
+++ b/PyTypeInterface.cpp	Thu Nov 20 13:02:50 2014 +0000
@@ -56,707 +56,6 @@
 {
 }
 
-/// floating point numbers (TODO: check numpy.float128)
-float 
-PyTypeInterface::PyValue_To_Float(PyObject* pyValue) const
-{
-	// convert float
-	if (pyValue && PyFloat_Check(pyValue)) 
-		//TODO: check for limits here (same on most systems)
-		return (float) PyFloat_AS_DOUBLE(pyValue);
-	
-	if (pyValue == NULL)
-	{
-		setValueError("Error while converting object " + PyValue_Get_TypeName(pyValue) + " to float. ",m_strict);
-		return 0.0;		
-	}
-		
-	// in strict mode we will not try harder
-	if (m_strict) {
-		setValueError("Strict conversion error: object" + PyValue_Get_TypeName(pyValue) +" is not float.",m_strict);
-		return 0.0;
-	}
-
-	// convert other objects supporting the number protocol
-	if (PyNumber_Check(pyValue))
-	{
-		PyObject* pyFloat = PyNumber_Float(pyValue); // new ref
-		if (!pyFloat)
-		{
-			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
-			setValueError("Error while converting " + PyValue_Get_TypeName(pyValue) + " object to float.",m_strict);
-			return 0.0;
-		}
-		float rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
-		Py_DECREF(pyFloat);
-		return rValue;
-	}
-/*	
-	// convert other objects supporting the number protocol
-	if (PyNumber_Check(pyValue)) 
-	{	
-		// PEP353: Py_ssize_t is size_t but signed !
-		// This will work up to numpy.float64
-		Py_ssize_t rValue = PyNumber_AsSsize_t(pyValue,NULL);
-		if (PyErr_Occurred()) 
-		{
-			PyErr_Print(); PyErr_Clear();
-			setValueError("Error while converting integer object.",m_strict);
-			return 0.0;
-		}
-		if (rValue > (Py_ssize_t)FLT_MAX || rValue < (Py_ssize_t)FLT_MIN)
-		{
-			setValueError("Overflow error. Object can not be converted to float.",m_strict);
-			return 0.0;
-		}
-		return (float) rValue;
-	}
-*/	
-    // convert string
-	if (PyString_Check(pyValue))
-	{
-		PyObject* pyFloat = PyFloat_FromString(pyValue,NULL);
-		if (!pyFloat) 
-		{
-			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
-			setValueError("String value can not be converted to float.",m_strict);
-			return 0.0;
-		}
-		float rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
-		if (PyErr_Occurred()) 
-		{
-			PyErr_Print(); PyErr_Clear(); 
-			Py_CLEAR(pyFloat);
-			setValueError("Error while converting float object.",m_strict);
-			return 0.0;
-		}
-		Py_DECREF(pyFloat);
-		return rValue;
-	}
-	
-	// convert the first element of any iterable sequence (for convenience and backwards compatibility)
-	if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) 
-	{
-		PyObject* item = PySequence_GetItem(pyValue,0);
-		if (item)
-		{
-			float rValue = this->PyValue_To_Float(item);
-			if (!m_error) {
-				Py_DECREF(item);
-				return rValue;
-			} else {
-				Py_CLEAR(item);
-				std::string msg = "Could not convert sequence element to float. ";
-				setValueError(msg,m_strict);
-				return 0.0;
-			}
-		}
-	}
-
-    // give up
-	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
-	std::string msg = "Conversion from " + PyValue_Get_TypeName(pyValue) + " to float is not possible.";
-	setValueError(msg,m_strict);
-#ifdef _DEBUG
-	cerr << "PyTypeInterface::PyValue_To_Float failed. " << msg << endl;
-#endif	
-	return 0.0;
-}
-
-/// size_t (unsigned integer types)
-size_t 
-PyTypeInterface::PyValue_To_Size_t(PyObject* pyValue) const
-{
-	// convert objects supporting the number protocol 
-	if (PyNumber_Check(pyValue)) 
-	{	
-		if (m_strict && !PyInt_Check(pyValue) && !PyLong_Check(pyValue)) 
-			setValueError("Strict conversion error: object is not integer type.",m_strict);
-		// Note: this function handles Bool,Int,Long,Float
-		// speed is not critical in the use of this type by Vamp
-		// PEP353: Py_ssize_t is size_t but signed ! 
-		Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
-		if (PyErr_Occurred()) 
-		{
-			PyErr_Print(); PyErr_Clear();
-			setValueError("Error while converting integer object.",m_strict);
-			return 0;
-		}
-		// this test is nonsense -- neither part can occur
-		// owing to range of data types -- size_t is at least
-		// as big as long, and unsigned is always non-negative
-/*
-		if ((unsigned long)rValue > SIZE_T_MAX || (unsigned long)rValue < 0)
-		{
-			setValueError("Overflow error. Object can not be converted to size_t.",m_strict);
-			return 0;
-		}
-*/
-		return (size_t) rValue;
-	}
-	
-	// in strict mode we will not try harder and throw an exception
-	// then the caller should decide what to do with it
-	if (m_strict) {
-		setValueError("Strict conversion error: object is not integer.",m_strict);
-		return 0;
-	}
-	
-	// convert string
-	if (PyString_Check(pyValue))
-	{
-		PyObject* pyLong = PyNumber_Long(pyValue);
-		if (!pyLong) 
-		{
-			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
-			setValueError("String object can not be converted to size_t.",m_strict);
-			return 0;
-		}
-		size_t rValue = this->PyValue_To_Size_t(pyLong);
-		if (!m_error) {
-			Py_DECREF(pyLong);
-			return rValue;
-		} else {
-			Py_CLEAR(pyLong);
-			setValueError ("Error converting string to size_t.",m_strict);
-			return 0;
-		}
-	}
-	
-	// convert the first element of iterable sequences
-	if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) 
-	{
-		PyObject* item = PySequence_GetItem(pyValue,0);
-		if (item)
-		{
-			size_t rValue = this->PyValue_To_Size_t(item);
-			if (!m_error) {
-				Py_DECREF(item);
-				return rValue;
-			} else {
-				Py_CLEAR(item);
-				setValueError("Could not convert sequence element to size_t. ",m_strict);
-				return 0;
-			}
-		}
-	}
-	
-    // give up
-	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
-	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to size_t is not possible.";
-	setValueError(msg,m_strict);
-#ifdef _DEBUG
-	cerr << "PyTypeInterface::PyValue_To_Size_t failed. " << msg << endl;
-#endif	
-	return 0;
-}
-
-/// long and int
-long 
-PyTypeInterface::PyValue_To_Long(PyObject* pyValue) const
-{
-	// most common case: convert int (faster)
-	if (pyValue && PyInt_Check(pyValue)) {
-		// if the object is not NULL and verified, this macro just extracts the value.
-		return PyInt_AS_LONG(pyValue);
-	} 
-	
-	// long
-	if (PyLong_Check(pyValue)) {
-		long rValue = PyLong_AsLong(pyValue);
-		if (PyErr_Occurred()) { 
-			PyErr_Print(); PyErr_Clear(); 
-			setValueError("Error while converting long object.",m_strict);
-			return 0;
-		}
-		return rValue;
-	}
-	
-	if (m_strict) {
-		setValueError("Strict conversion error: object is not integer or long integer.",m_strict);
-		return 0;
-	}
-	
-	// convert all objects supporting the number protocol
-	if (PyNumber_Check(pyValue)) 
-	{	
-		// Note: this function handles Bool,Int,Long,Float
-		// PEP353: Py_ssize_t is size_t but signed ! 
-		Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
-		if (PyErr_Occurred()) 
-		{
-			PyErr_Print(); PyErr_Clear();
-			setValueError("Error while converting integer object.",m_strict);
-			return 0;
-		}
-		if (rValue > LONG_MAX || rValue < LONG_MIN)
-		{
-			setValueError("Overflow error. Object can not be converted to size_t.",m_strict);
-			return 0;
-		}
-		return (long) rValue;
-	}
-	
-	// convert string
-	if (PyString_Check(pyValue))
-	{
-		PyObject* pyLong = PyNumber_Long(pyValue);
-		if (!pyLong) 
-		{
-			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
-			setValueError("String object can not be converted to long.",m_strict);
-			return 0;
-		}
-		long rValue = this->PyValue_To_Long(pyLong);
-		if (!m_error) {
-			Py_DECREF(pyLong);
-			return rValue;
-		} else {
-			Py_CLEAR(pyLong);
-			setValueError ("Error converting string to long.",m_strict);
-			return 0;
-		}
-	}
-	
-	// convert the first element of iterable sequences
-	if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) 
-	{
-		PyObject* item = PySequence_GetItem(pyValue,0);
-		if (item)
-		{
-			size_t rValue = this->PyValue_To_Long(item);
-			if (!m_error) {
-				Py_DECREF(item);
-				return rValue;
-			} else {
-				Py_CLEAR(item);
-				setValueError("Could not convert sequence element to long. ",m_strict);
-				return 0;
-			}
-		}
-	}
-	
-    // give up
-	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
-	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to long is not possible.";
-	setValueError(msg,m_strict);
-#ifdef _DEBUG
-	cerr << "PyTypeInterface::PyValue_To_Long failed. " << msg << endl;
-#endif	
-	return 0;
-}
-
-
-bool 
-PyTypeInterface::PyValue_To_Bool(PyObject* pyValue) const
-{
-	// convert objects supporting the number protocol
-	// Note: PyBool is a subclass of PyInt
-	if (PyNumber_Check(pyValue)) 
-	{	
-		if (m_strict && !PyBool_Check(pyValue)) 
-			setValueError
-			("Strict conversion error: object is not boolean type.",m_strict);
-
-		// Note: this function handles Bool,Int,Long,Float
-		Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
-		if (PyErr_Occurred()) 
-		{
-			PyErr_Print(); PyErr_Clear();
-			setValueError ("Error while converting boolean object.",m_strict);
-		}
-		if (rValue != 1 && rValue != 0)
-		{
-			setValueError ("Overflow error. Object can not be converted to boolean.",m_strict);
-		}
-		return (bool) rValue;
-	}
-	
-	if (m_strict) {
-		setValueError ("Strict conversion error: object is not numerical type.",m_strict);
-		return false;
-	}
-	
-	// convert iterables: the rule is the same as in the interpreter:
-	// empty sequence evaluates to False, anything else is True
-	if (PySequence_Check(pyValue)) 
-	{
-		return PySequence_Size(pyValue)?true:false;
-	}
-	
-    // give up
-	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
-	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to boolean is not possible.";
-	setValueError(msg,m_strict);
-#ifdef _DEBUG
-	cerr << "PyTypeInterface::PyValue_To_Bool failed. " << msg << endl;
-#endif	
-	return false;
-}
-
-/// string and objects that support .__str__() 
-/// TODO: check unicode objects
-std::string 
-PyTypeInterface::PyValue_To_String(PyObject* pyValue) const
-{
-	// convert string
-	if (PyString_Check(pyValue)) 
-	{	
-		char *cstr = PyString_AS_STRING(pyValue);
-		if (!cstr) 
-		{
-			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
-			setValueError("Error while converting string object.",m_strict);
-			return std::string();
-		}
-		return std::string(cstr);
-	}
-	// TODO: deal with unicode here (argh!)
-	
-	// in strict mode we will not try harder
-	if (m_strict) {
-		setValueError("Strict conversion error: object is not string.",m_strict);
-		return std::string();
-	}
-	
-	// accept None as empty string
-	if (pyValue == Py_None) return std::string();
-			
-	// convert list or tuple: empties are turned into empty strings conventionally
-	if (PyList_Check(pyValue) || PyTuple_Check(pyValue)) 
-	{
-		if (!PySequence_Size(pyValue)) return std::string();
-		PyObject* item = PySequence_GetItem(pyValue,0);
-		if (item)
-		{
-			std::string rValue = this->PyValue_To_String(item);
-			if (!m_error) {
-				Py_DECREF(item);
-				return rValue;
-			} else {
-				Py_CLEAR(item);
-				setValueError("Could not convert sequence element to string.",m_strict);
-				return std::string();
-			}
-		}
-	}
-
-	// convert any other object that has .__str__() or .__repr__()
-	PyObject* pyString = PyObject_Str(pyValue);
-	if (pyString && !PyErr_Occurred())
-	{
-		std::string rValue = this->PyValue_To_String(pyString);
-		if (!m_error) {
-			Py_DECREF(pyString);
-			return rValue;
-		} else {
-			Py_CLEAR(pyString);
-			std::string msg = "Object " + this->PyValue_Get_TypeName(pyValue) +" can not be represented as string. ";
-			setValueError (msg,m_strict);
-			return std::string();
-		}
-	}
-
-	// give up
-	PyErr_Print(); PyErr_Clear();
-	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to string is not possible.";
-	setValueError(msg,m_strict);
-#ifdef _DEBUG
-	cerr << "PyTypeInterface::PyValue_To_String failed. " << msg << endl;
-#endif	
-	return std::string();
-}
-
-/*			 			C Values to Py Values				  		*/
-
-
-PyObject*
-PyTypeInterface::PyValue_From_CValue(const char* cValue) const
-{
-	// returns new reference
-#ifdef _DEBUG
-	if (!cValue) {
-		std::string msg = "PyTypeInterface::PyValue_From_CValue: Null pointer encountered while converting from const char* .";
-		cerr << msg << endl;
-		setValueError(msg,m_strict);
-		return NULL;
-	}
-#endif
-	PyObject *pyValue = PyString_FromString(cValue);
-	if (!pyValue)
-	{
-		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
-		setValueError("Error while converting from char* or string.",m_strict);
-#ifdef _DEBUG
-		cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from const char*" << endl;
-#endif
-		return NULL;
-	}
-	return pyValue;
-}
-
-PyObject*
-PyTypeInterface::PyValue_From_CValue(size_t cValue) const
-{
-	// returns new reference
-	PyObject *pyValue = PyInt_FromSsize_t((Py_ssize_t)cValue);
-	if (!pyValue)
-	{
-		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
-		setValueError("Error while converting from size_t.",m_strict);
-#ifdef _DEBUG
-		cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from size_t" << endl;
-#endif
-		return NULL;
-	}
-	return pyValue;
-}
-
-PyObject*
-PyTypeInterface::PyValue_From_CValue(double cValue) const
-{
-	// returns new reference
-	PyObject *pyValue = PyFloat_FromDouble(cValue);
-	if (!pyValue)
-	{
-		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
-		setValueError("Error while converting from float or double.",m_strict);
-#ifdef _DEBUG
-		cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from float or double" << endl;
-#endif
-		return NULL;
-	}
-	return pyValue;
-}
-
-PyObject*
-PyTypeInterface::PyValue_From_CValue(bool cValue) const
-{
-	// returns new reference
-	PyObject *pyValue = PyBool_FromLong((long)cValue);
-	if (!pyValue)
-	{
-		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
-		setValueError("Error while converting from bool.",m_strict);
-#ifdef _DEBUG
-		cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from bool" << endl;
-#endif
-		return NULL;
-	}
-	return pyValue;
-}
-
-
-/*			 			Sequence Types to C++ Types	    		  	*/
-
-//convert Python list to C++ vector of strings
-std::vector<std::string> 
-PyTypeInterface::PyValue_To_StringVector (PyObject *pyList) const 
-{
-	
-	std::vector<std::string> Output;
-	std::string ListElement;
-	PyObject *pyString = NULL;
-	
-	if (PyList_Check(pyList)) {
-
-		for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
-			//Get next list item (Borrowed Reference)
-			pyString = PyList_GET_ITEM(pyList,i);
-			ListElement = (string) PyString_AsString(PyObject_Str(pyString));
-			Output.push_back(ListElement);
-		}
-		return Output;
-	}
-
-// #ifdef _DEBUG
-// 	cerr << "PyTypeInterface::PyValue_To_StringVector: Warning: Value is not list of strings." << endl;
-// #endif
-
-	/// Assume a single value that can be casted as string 
-	/// this allows to write e.g. Feature.label = 5.2 instead of ['5.2']
-	Output.push_back(PyValue_To_String(pyList));
-	if (m_error) {
-		std::string msg = "Value is not list of strings nor can be casted as string. ";
-		setValueError(msg,m_strict);
-#ifdef _DEBUG
-		cerr << "PyTypeInterface::PyValue_To_StringVector failed. " << msg << endl;
-#endif
-	}
-	return Output;
-}
-
-//convert PyFeature.value (typically a list or numpy array) to C++ vector of floats
-std::vector<float> 
-PyTypeInterface::PyValue_To_FloatVector (PyObject *pyValue) const 
-{
-
-#ifdef HAVE_NUMPY
-if (m_numpyInstalled) 
-{
-	// there are four types of values we may receive from a numpy process:
-	// * a python scalar, 
-	// * an array scalar, (e.g. numpy.float32)
-	// * an array with nd = 0  (0D array)
-	// * an array with nd > 0
-
-	/// check for scalars
-	if (PyArray_CheckScalar(pyValue) || PyFloat_Check(pyValue)) {
-
-		std::vector<float> Output;
-
-		// we rely on the behaviour the scalars are either floats
-		// or support the number protocol
-		// TODO: a potential optimisation is to handle them directly
-		Output.push_back(PyValue_To_Float(pyValue));
-		return Output;
-	}
-
-	/// numpy array
-	if (PyArray_CheckExact(pyValue)) 
-		return PyArray_To_FloatVector(pyValue);
-}
-#endif
-
-	/// python list of floats (backward compatible)
-	if (PyList_Check(pyValue)) {
-		return PyList_To_FloatVector(pyValue);
-	}
-
-	std::vector<float> Output;
-	
-	/// finally assume a single value supporting the number protocol 
-	/// this allows to write e.g. Feature.values = 5 instead of [5.00]
-	Output.push_back(PyValue_To_Float(pyValue));
-	if (m_error) {
-		std::string msg = "Value is not list or array of floats nor can be casted as float. ";
-		setValueError(msg,m_strict);
-#ifdef _DEBUG
-	cerr << "PyTypeInterface::PyValue_To_FloatVector failed. " << msg << endl;
-#endif
-	}
-	return Output;
-}
-
-//convert a list of python floats
-std::vector<float> 
-PyTypeInterface::PyList_To_FloatVector (PyObject *inputList) const 
-{
-	std::vector<float> Output;
-	
-#ifdef _DEBUG
-	// This is a low level function normally called from 
-	// PyValue_To_FloatVector(). Checking for list is not required.
-	if (!PyList_Check(inputList)) {
-		std::string msg = "Value is not list.";
-		setValueError(msg,true);
-		cerr << "PyTypeInterface::PyList_To_FloatVector failed. " << msg << endl;
-		return Output; 
-	} 
-#endif
-
-	float ListElement;
-	PyObject *pyFloat = NULL;
-	PyObject **pyObjectArray = PySequence_Fast_ITEMS(inputList);
-
-	for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
-
-		// pyFloat = PyList_GET_ITEM(inputList,i);
-		pyFloat = pyObjectArray[i];
-
-#ifdef _DEBUG
-		if (!pyFloat) {
-			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
-			cerr << "PyTypeInterface::PyList_To_FloatVector: Could not obtain list element: " 
-			<< i << " PyList_GetItem returned NULL! Skipping value." << endl;
-			continue;
-		}
-#endif		
-
-		// ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
-		ListElement = PyValue_To_Float(pyFloat);
-		
-
-#ifdef _DEBUG_VALUES
-		cerr << "value: " << ListElement << endl;
-#endif
-		Output.push_back(ListElement);
-	}
-	return Output;
-}
-
-// if numpy is not installed this will not be called, 
-// therefor we do not check again
-#ifdef HAVE_NUMPY 
-std::vector<float> 
-PyTypeInterface::PyArray_To_FloatVector (PyObject *pyValue) const 
-{
-	std::vector<float> Output;
-	
-#ifdef _DEBUG
-	// This is a low level function, normally called from 
-	// PyValue_To_FloatVector(). Checking the array here is not required.
-	if (!PyArray_Check(pyValue)) {
-		std::string msg = "Object has no array interface.";
-		setValueError(msg,true);
-		cerr << "PyTypeInterface::PyArray_To_FloatVector failed. " << msg << endl;
-		return Output; 
-	} 
-#endif
-
-	PyArrayObject* pyArray = (PyArrayObject*) pyValue;
-	PyArray_Descr* descr = PyArray_DESCR(pyArray);
-	
-	/// check raw data and descriptor pointers
-	if (PyArray_DATA(pyArray) == 0 || descr == 0) {
-		std::string msg = "NumPy array with NULL data or descriptor pointer encountered.";
-		setValueError(msg,m_strict);
-#ifdef _DEBUG
-		cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << endl;
-#endif		
-		return Output;
-	}
-
-	/// check dimensions
-	if (PyArray_NDIM(pyArray) != 1) {
-		std::string msg = "NumPy array must be a one dimensional vector.";
-		setValueError(msg,m_strict);
-#ifdef _DEBUG
-		cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << " Dims: " << (int) PyArray_NDIM(pyArray) << endl;
-#endif	
-		return Output;
-	}
-
-#ifdef _DEBUG_VALUES
-	cerr << "PyTypeInterface::PyArray_To_FloatVector: Numpy array verified." << endl;
-#endif
-	
-	/// check strides (useful if array is not continuous)
-	size_t strides =  *((size_t*) PyArray_STRIDES(pyArray));
-    
-	/// convert the array
-	switch (descr->type_num)
-	{
-		case NPY_FLOAT : // dtype='float32'
-			return PyArray_Convert<float,float>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
-		case NPY_DOUBLE : // dtype='float64'
-			return PyArray_Convert<float,double>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
-		case NPY_INT : // dtype='int'
-			return PyArray_Convert<float,int>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
-		case NPY_LONG : // dtype='long'
-			return PyArray_Convert<float,long>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
-		default :
-			std::string msg = "Unsupported value type in NumPy array object.";
-			setValueError(msg,m_strict);
-#ifdef _DEBUG
-			cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << endl;
-#endif			
-			return Output;
-	}
-}
-#endif
-
-
 /// FeatureSet (an integer map of FeatureLists)
 Vamp::Plugin::FeatureSet
 PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const
@@ -836,8 +135,8 @@
 	}
 
 	// assume integer sample count
-	long sampleCount = PyValue_To_Long(pyValue);
-	if (m_error) {
+	long sampleCount = m_conv.PyValue_To_Long(pyValue);
+	if (m_conv.error) {
 		std::string msg = "Unexpected value passed as RealTime.\nMust be vampy.RealTime type or integer sample count.";
 		setValueError(msg,m_strict);
 #ifdef _DEBUG
@@ -874,8 +173,8 @@
 	/// convert string (backward compatible)
 	if (PyString_CheckExact(pyValue)) {
 		Vamp::Plugin::OutputDescriptor::SampleType st;
-		st = (Vamp::Plugin::OutputDescriptor::SampleType) sampleKeys[PyValue_To_String(pyValue)]; 
-		if (m_error) {
+		st = (Vamp::Plugin::OutputDescriptor::SampleType) sampleKeys[m_conv.PyValue_To_String(pyValue)]; 
+		if (m_conv.error) {
 			std::string msg = "Unexpected value passed as SampleType. Must be one of { OneSamplePerStep,FixedSampleRate,VariableSampleRate }\n(an integer in the range of 0..2) or a string value naming the type.";
 			setValueError(msg,m_strict);
 			return Vamp::Plugin::OutputDescriptor::SampleType();
@@ -908,8 +207,8 @@
 	/// convert string (backward compatible)
 	if (PyString_CheckExact(pyValue)) {
 		Vamp::Plugin::InputDomain id;
-		id = (PyValue_To_String(pyValue) == "FrequencyDomain")?Vamp::Plugin::FrequencyDomain:Vamp::Plugin::TimeDomain;
-		if (m_error) 
+		id = (m_conv.PyValue_To_String(pyValue) == "FrequencyDomain")?Vamp::Plugin::FrequencyDomain:Vamp::Plugin::TimeDomain;
+		if (m_conv.error) 
 		{
 			std::string msg = "Unexpected value passed as SampleType. Must be one of { TimeDomain,FrequencyDomain }\n(an integer in the range of 0..1) or a string value naming the type.";
 			setValueError(msg,m_strict);
@@ -927,6 +226,159 @@
 	return Vamp::Plugin::InputDomain();
 }
 
+/* Convert Sample Buffers to Python */
+
+/// passing the sample buffers as builtin python lists
+/// Optimization: using fast sequence protocol
+inline PyObject*
+PyTypeInterface::InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
+{
+	//create a list of lists (new references)
+	PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
+	
+	// Pack samples into a Python List Object
+	// pyFloat/pyComplex types will always be new references, 
+	// they will be freed when the lists are deallocated.
+	
+	PyObject **pyChannelListArray =  PySequence_Fast_ITEMS(pyChannelList);
+	for (size_t i=0; i < channels; ++i) {
+		
+        size_t arraySize;
+		if (dtype==Vamp::Plugin::FrequencyDomain) 
+			arraySize = (blockSize / 2) + 1; //blockSize + 2; if cplx list isn't used
+		else 
+			arraySize = blockSize;
+
+		PyObject *pySampleList = PyList_New((Py_ssize_t) arraySize);
+		PyObject **pySampleListArray =  PySequence_Fast_ITEMS(pySampleList);
+		
+		// Note: passing a complex list crashes the C-style plugin
+		// when it tries to convert it to a numpy array directly.
+		// This plugin will be obsolete, but we have to find a way
+		// to prevent such crash: possibly a numpy bug, 
+		// works fine above 1.0.4
+		
+		switch (dtype) //(Vamp::Plugin::TimeDomain)
+		{
+			case Vamp::Plugin::TimeDomain :
+
+			for (size_t j = 0; j < arraySize; ++j) {
+				PyObject *pyFloat=PyFloat_FromDouble(
+					(double) inputBuffers[i][j]);
+				pySampleListArray[j] = pyFloat;
+			}
+			break;
+
+			case Vamp::Plugin::FrequencyDomain :
+
+			size_t k = 0;
+			for (size_t j = 0; j < arraySize; ++j) {
+				PyObject *pyComplex=PyComplex_FromDoubles(
+					(double) inputBuffers[i][k], 
+					(double) inputBuffers[i][k+1]);
+				pySampleListArray[j] = pyComplex;
+				k += 2;
+			}
+			break;
+			
+		}
+		pyChannelListArray[i] = pySampleList;
+	}
+	return pyChannelList;
+}
+
+/// numpy buffer interface: passing the sample buffers as shared memory buffers
+/// Optimization: using sequence protocol for creating the buffer list
+inline PyObject*
+PyTypeInterface::InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
+{	
+	//create a list of buffers (returns new references)
+	PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
+	PyObject **pyChannelListArray =  PySequence_Fast_ITEMS(pyChannelList);
+
+	// Expose memory using the Buffer Interface.		
+	// This will pass a pointer which can be recasted in Python code 
+	// as complex or float array using Numpy's frombuffer() method
+	// (this will not copy values just keep the starting adresses 
+	// for each channel in a list)
+	Py_ssize_t bufferSize;
+	
+	if (dtype==Vamp::Plugin::FrequencyDomain) 
+		bufferSize = (Py_ssize_t) sizeof(float) * (blockSize+2);
+	else 
+		bufferSize = (Py_ssize_t) sizeof(float) * blockSize;
+	
+	for (size_t i=0; i < channels; ++i) {
+		PyObject *pyBuffer = PyBuffer_FromMemory
+		((void *) (float *) inputBuffers[i],bufferSize);
+		pyChannelListArray[i] = pyBuffer;
+	}
+	return pyChannelList;
+}
+
+
+/// numpy array interface: passing the sample buffers as 2D numpy array
+/// Optimization: using array API (needs numpy headers)
+#ifdef HAVE_NUMPY
+inline PyObject*
+PyTypeInterface::InputBuffers_As_NumpyArray(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
+{	
+/*
+NOTE: We create a list of 1D Numpy arrays for each channel instead
+of a matrix, because the address space of inputBuffers doesn't seem
+to be continuous. Although the array strides could be calculated for
+2 channels (i.e. inputBuffers[1] - inputBuffers[0]) i'm not sure
+if this can be trusted, especially for more than 2 channels.
+
+	cerr << "First channel: " << inputBuffers[0][0] << " address: " <<  inputBuffers[0] << endl;
+	if (channels == 2)
+		cerr << "Second channel: " << inputBuffers[1][0] << " address: " <<  inputBuffers[1] << endl;
+
+*/	
+	
+	// create a list of arrays (returns new references)
+	PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
+	PyObject **pyChannelListArray =  PySequence_Fast_ITEMS(pyChannelList);
+	
+	// Expose memory using the Numpy Array Interface.		
+	// This will wrap an array objects around the data.
+	// (will not copy values just steal the starting adresses)
+
+	int arraySize, typenum;
+	
+	switch (dtype)
+	{
+		case Vamp::Plugin::TimeDomain :
+		typenum = dtype_float32; //NPY_FLOAT; 
+		arraySize = (int) blockSize;
+		break;
+
+		case Vamp::Plugin::FrequencyDomain :
+		typenum = dtype_complex64; //NPY_CFLOAT;
+		arraySize = (int) (blockSize / 2) + 1;
+		break;
+		
+		default :
+		cerr << "PyTypeInterface::InputBuffers_As_NumpyArray: Error: Unsupported numpy array data type." << endl;
+		return pyChannelList;
+	}
+
+	// size for each dimension
+	npy_intp ndims[1]={arraySize}; 
+	
+	for (size_t i=0; i < channels; ++i) {
+		PyObject *pyChannelArray = 
+			//args: (dimensions, size in each dim, type kind, pointer to continuous array)
+			PyArray_SimpleNewFromData(1, ndims, typenum, (void*) inputBuffers[i]);
+		// make it read-only: set all flags to false except NPY_C_CONTIGUOUS
+		//!!! what about NPY_ARRAY_OWNDATA?
+		PyArray_CLEARFLAGS((PyArrayObject *)pyChannelArray, 0xff);
+		PyArray_ENABLEFLAGS((PyArrayObject *)pyChannelArray, NPY_ARRAY_C_CONTIGUOUS);
+		pyChannelListArray[i] = pyChannelArray;
+	}
+	return pyChannelList;
+}
+#endif
 
 /// OutputDescriptor
 void
@@ -1073,7 +525,7 @@
 }
 
 
-/*			   			  	Error handling		   			  		*/
+/* Error handling */
 
 void
 PyTypeInterface::setValueError (std::string message, bool strict) const
@@ -1083,7 +535,7 @@
 }
 
 /// return a reference to the last error or creates a new one.
-PyTypeInterface::ValueError&
+ValueError&
 PyTypeInterface::lastError() const 
 {
 	m_error = false;
@@ -1096,56 +548,22 @@
 
 /// helper function to iterate over the error message queue:
 /// pops the oldest item
-PyTypeInterface::ValueError 
+ValueError 
 PyTypeInterface::getError() const
 {
 	if (!m_errorQueue.empty()) {
-		PyTypeInterface::ValueError e = m_errorQueue.front();
+		ValueError e = m_errorQueue.front();
 		m_errorQueue.pop();
 		if (m_errorQueue.empty()) m_error = false;
 		return e;
 	}
 	else {
 		m_error = false;
-		return PyTypeInterface::ValueError();
+		return ValueError();
 	}
 }
 
-/*			   			  	Utilities						  		*/
-
-/// get the type name of an object
-std::string
-PyTypeInterface::PyValue_Get_TypeName(PyObject* pyValue) const
-{
-	PyObject *pyType = PyObject_Type(pyValue);
-	if (!pyType) 
-	{
-		cerr << "Warning: Object type name could not be found." << endl;
-		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
-		return std::string ("< unknown type >");
-	}
-	PyObject *pyString = PyObject_Str(pyType);
-	if (!pyString)
-	{
-		cerr << "Warning: Object type name could not be found." << endl;
-		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
-		Py_CLEAR(pyType);
-		return std::string ("< unknown type >");
-	}
-	char *cstr = PyString_AS_STRING(pyString);
-	if (!cstr)
-	{
-		cerr << "Warning: Object type name could not be found." << endl;
-		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
-		Py_DECREF(pyType);
-		Py_CLEAR(pyString);
-		return std::string("< unknown type >");
-	}
-	Py_DECREF(pyType);
-	Py_DECREF(pyString);
-	return std::string(cstr);
-	
-}
+/* Utilities */
 
 bool
 PyTypeInterface::initMaps() const
--- a/PyTypeInterface.h	Mon Nov 17 14:07:00 2014 +0000
+++ b/PyTypeInterface.h	Thu Nov 20 13:02:50 2014 +0000
@@ -12,7 +12,7 @@
 
 /*
 PyTypeInterface: Type safe conversion utilities between Python types 
-and basic C/C++ types and Vamp API types.
+and Vamp API types. See PyTypeConversions for basic C/C++ types.
 */
 
 #ifndef _PY_TYPE_INTERFACE_H_
@@ -25,6 +25,7 @@
 #include "numpy/arrayobject.h"
 #endif
 #include "PyExtensionModule.h"
+#include "PyTypeConversions.h"
 #include <vector>
 #include <queue>
 #include <string>
@@ -34,13 +35,6 @@
 using std::cerr;
 using std::endl;
 
-#ifdef HAVE_NUMPY
-enum eArrayDataType {
-	dtype_float32 = (int) NPY_FLOAT,
-	dtype_complex64 = (int) NPY_CFLOAT 
-	};
-#endif 
-
 namespace o {
 enum eOutDescriptors {
 	not_found,
@@ -95,79 +89,31 @@
 	label
 	};
 
-/* C++ mapping of PyNone Type */
-struct NoneType {};
-
 class PyTypeInterface
 {
+	PyTypeConversions m_conv;
+	
 public:
 	PyTypeInterface();
 	~PyTypeInterface();
 	
-	// Data
- 	class ValueError
-	{
-	public:
-		ValueError() {}
-		ValueError(std::string m, bool s) : message(m),strict(s) {}
-		std::string location;
-		std::string message;
-		bool strict;
-		std::string str() const { 
-			return (location.empty()) ? message : message + "\nLocation: " + location;}
-		void print() const { cerr << str() << endl; }
-		template<typename V> ValueError &operator<< (const V& v)
-		{
-			std::ostringstream ss;
-			ss << v;
-			location += ss.str();
-			return *this;
-		}
-	};
-	
 	// Utilities
-	void setStrictTypingFlag(bool b) {m_strict = b;}
-	void setNumpyInstalled(bool b) {m_numpyInstalled = b;}
+	void setStrictTypingFlag(bool b) {m_strict = b; m_conv.setStrictTypingFlag(b);}
+	void setNumpyInstalled(bool b) {m_numpyInstalled = b; m_conv.setNumpyInstalled(b); }
 	ValueError getError() const;
 	std::string PyValue_Get_TypeName(PyObject*) const;
 	bool initMaps() const;
 
-	// Basic type conversion: Python to C++ 
-	float 	PyValue_To_Float(PyObject*) const;
-	size_t 	PyValue_To_Size_t(PyObject*) const;
-	bool 	PyValue_To_Bool(PyObject*) const;
-	std::string PyValue_To_String(PyObject*) const;
-	long 	PyValue_To_Long(PyObject*) const;
-	// int 	PyValue_To_Int(PyObject* pyValue) const;
-	
-	
-	// C++ to Python
-	PyObject *PyValue_From_CValue(const char*) const;
-	PyObject *PyValue_From_CValue(const std::string& x) const { return PyValue_From_CValue(x.c_str()); }
-	PyObject *PyValue_From_CValue(size_t) const;
-	PyObject *PyValue_From_CValue(double) const;
-	PyObject *PyValue_From_CValue(float x) const { return PyValue_From_CValue((double)x); }
-	PyObject *PyValue_From_CValue(bool) const;
-	
-	// Sequence types
-	std::vector<std::string> PyValue_To_StringVector (PyObject*) const;
-	std::vector<float> PyValue_To_FloatVector (PyObject*) const;
-	std::vector<float> PyList_To_FloatVector (PyObject*) const;
-
 	// Input buffers to Python
 	PyObject* InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype);
 	PyObject* InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype);
 
 	// Numpy types
 #ifdef HAVE_NUMPY
-	std::vector<float> PyArray_To_FloatVector (PyObject *pyValue) const;
 	PyObject* InputBuffers_As_NumpyArray(const float *const *inputBuffers, const size_t&, const size_t&, const Vamp::Plugin::InputDomain& dtype);
 #endif
 
-	
-
-
-/* 						Template functions 							*/
+/* Template functions */
 
 
 	/// Common wrappers to set values in Vamp API structs. (to be used in template functions)
@@ -211,9 +157,9 @@
 		//Python Dictionary Iterator:
 		while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyDictValue))
 		{
-			std::string key = PyValue_To_String(pyKey);
+			std::string key = m_conv.PyValue_To_String(pyKey);
 #ifdef _DEBUG_VALUES			
-			cerr << "key: '" << key << "' value: '" << PyValue_To_String(pyDictValue) << "' " << endl;
+			cerr << "key: '" << key << "' value: '" << m_conv.PyValue_To_String(pyDictValue) << "' " << endl;
 #endif			
 			SetValue(rd,key,pyDictValue);
 			if (m_error) {
@@ -296,54 +242,6 @@
 
 	}
 
-	/// Convert DTYPE type 1D NumpyArray to std::vector<RET>
-	template<typename RET, typename DTYPE>
-	std::vector<RET> PyArray_Convert(void* raw_data_ptr, long length, size_t strides) const
-	{
-		std::vector<RET> rValue;
-		
-		/// check if the array is continuous, if not use strides info
-		if (sizeof(DTYPE)!=strides) {
-#ifdef _DEBUG_VALUES
-			cerr << "Warning: discontinuous numpy array. Strides: " << strides << " bytes. sizeof(dtype): " << sizeof(DTYPE) << endl;
-#endif
-			char* data = (char*) raw_data_ptr;
-			for (long i = 0; i<length; ++i){
-				rValue.push_back((RET)(*((DTYPE*)data)));
-#ifdef _DEBUG_VALUES
-				cerr << "value: " << (RET)(*((DTYPE*)data)) << endl;
-#endif				
-				data+=strides;
-			}
-			return rValue;
-		}
-
-		DTYPE* data = (DTYPE*) raw_data_ptr;
-		for (long i = 0; i<length; ++i){
-#ifdef _DEBUG_VALUES
-			cerr << "value: " << (RET)data[i] << endl;
-#endif
-			rValue.push_back((RET)data[i]);
-		}
-		return rValue;
-	}
-
-	/// this is a special case. numpy.float64 has an array interface but no array descriptor
-	inline std::vector<float> PyArray0D_Convert(PyArrayInterface *ai) const
-	{
-		std::vector<float> rValue;
-		if ((ai->typekind) == *"f") 
-			rValue.push_back((float)*(double*)(ai->data));
-		else { 
-			setValueError("Unsupported NumPy data type.",m_strict); 
-			return rValue;
-		}
-#ifdef _DEBUG_VALUES
-		cerr << "value: " << rValue[0] << endl;
-#endif
-		return rValue;
-	}
-
 	//Vamp specific types
 	Vamp::Plugin::FeatureSet PyValue_To_FeatureSet(PyObject*) const;
 	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureSet &r) const
@@ -359,26 +257,25 @@
 	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::InputDomain &r) const
 		{ r = this->PyValue_To_InputDomain(pyValue); }
 	
-	
 	/* Overloaded PyValue_To_rValue() to support generic functions */
 	inline void PyValue_To_rValue(PyObject *pyValue, float &defValue) const 
-		{ float tmp = this->PyValue_To_Float(pyValue);                                              
+		{ float tmp = m_conv.PyValue_To_Float(pyValue);                                              
 			if(!m_error) defValue = tmp; }
 	inline void PyValue_To_rValue(PyObject *pyValue, size_t &defValue) const
-		{ size_t tmp = this->PyValue_To_Size_t(pyValue); 
+		{ size_t tmp = m_conv.PyValue_To_Size_t(pyValue); 
 			if(!m_error) defValue = tmp; }
 	inline void PyValue_To_rValue(PyObject *pyValue, bool &defValue) const
-		{ bool tmp = this->PyValue_To_Bool(pyValue); 
+		{ bool tmp = m_conv.PyValue_To_Bool(pyValue); 
 			if(!m_error) defValue = tmp; }
 	inline void PyValue_To_rValue(PyObject *pyValue, std::string &defValue) const
-		{ std::string tmp = this->PyValue_To_String(pyValue); 
+		{ std::string tmp = m_conv.PyValue_To_String(pyValue); 
 			if(!m_error) defValue = tmp; }
 	/*used by templates where we expect no return value, if there is one it will be ignored*/			
 	inline void PyValue_To_rValue(PyObject *pyValue, NoneType &defValue) const
 		{ if (m_strict && pyValue != Py_None) 
 				setValueError("Strict conversion error: Expected 'None' type.",m_strict); 
 		}
-
+	
 	/* convert sequence types to Vamp List types */			
 	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::OutputList &r) const
 		{ r = this->PyValue_To_VampList<Vamp::Plugin::OutputList,Vamp::Plugin::OutputDescriptor>(pyValue); }
@@ -403,23 +300,23 @@
 
 	/* Overloaded _convert(), bypasses error checking to avoid doing it twice in internals. */
 	inline void _convert(PyObject *pyValue,float &r) const 
-		{ r = PyValue_To_Float(pyValue); }
+		{ r = m_conv.PyValue_To_Float(pyValue); }
 	inline void _convert(PyObject *pyValue,size_t &r) const 
-		{ r = PyValue_To_Size_t(pyValue); }
-    inline void _convert(PyObject *pyValue,bool &r) const 
-		{ r = PyValue_To_Bool(pyValue); }
+		{ r = m_conv.PyValue_To_Size_t(pyValue); }
+	inline void _convert(PyObject *pyValue,bool &r) const 
+		{ r = m_conv.PyValue_To_Bool(pyValue); }
 	inline void _convert(PyObject *pyValue,std::string &r) const
-		{ r = PyValue_To_String(pyValue); }
+		{ r = m_conv.PyValue_To_String(pyValue); }
 	inline void _convert(PyObject *pyValue,std::vector<std::string> &r) const
-		{ r = PyValue_To_StringVector(pyValue); }
+		{ r = m_conv.PyValue_To_StringVector(pyValue); }
 	inline void _convert(PyObject *pyValue,std::vector<float> &r) const
-		{ r = PyValue_To_FloatVector(pyValue); }
-    inline void _convert(PyObject *pyValue,Vamp::RealTime &r) const 
+		{ r = m_conv.PyValue_To_FloatVector(pyValue); }
+	inline void _convert(PyObject *pyValue,Vamp::RealTime &r) const 
 		{ r = PyValue_To_RealTime(pyValue); }
 	inline void _convert(PyObject *pyValue,Vamp::Plugin::OutputDescriptor::SampleType &r) const 
 		{ r = PyValue_To_SampleType(pyValue); }
 	// inline void _convert(PyObject *pyValue,Vamp::Plugin::InputDomain &r) const 
-	// 	{ r = PyValue_To_InputDomain(pyValue); }
+	// 	{ r = m_conv.PyValue_To_InputDomain(pyValue); }
 	    
 
 	/* Identify descriptors for error reporting */
@@ -435,246 +332,4 @@
 
 };
 
-/* 		   		  Convert Sample Buffers to Python 	         		*/
-
-/// passing the sample buffers as builtin python lists
-/// Optimization: using fast sequence protocol
-inline PyObject*
-PyTypeInterface::InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
-{
-	//create a list of lists (new references)
-	PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
-	
-	// Pack samples into a Python List Object
-	// pyFloat/pyComplex types will always be new references, 
-	// they will be freed when the lists are deallocated.
-	
-	PyObject **pyChannelListArray =  PySequence_Fast_ITEMS(pyChannelList);
-	for (size_t i=0; i < channels; ++i) {
-		
-        size_t arraySize;
-		if (dtype==Vamp::Plugin::FrequencyDomain) 
-			arraySize = (blockSize / 2) + 1; //blockSize + 2; if cplx list isn't used
-		else 
-			arraySize = blockSize;
-
-		PyObject *pySampleList = PyList_New((Py_ssize_t) arraySize);
-		PyObject **pySampleListArray =  PySequence_Fast_ITEMS(pySampleList);
-		
-		// Note: passing a complex list crashes the C-style plugin
-		// when it tries to convert it to a numpy array directly.
-		// This plugin will be obsolete, but we have to find a way
-		// to prevent such crash: possibly a numpy bug, 
-		// works fine above 1.0.4
-		
-		switch (dtype) //(Vamp::Plugin::TimeDomain)
-		{
-			case Vamp::Plugin::TimeDomain :
-
-			for (size_t j = 0; j < arraySize; ++j) {
-				PyObject *pyFloat=PyFloat_FromDouble(
-					(double) inputBuffers[i][j]);
-				pySampleListArray[j] = pyFloat;
-			}
-			break;
-
-			case Vamp::Plugin::FrequencyDomain :
-
-			size_t k = 0;
-			for (size_t j = 0; j < arraySize; ++j) {
-				PyObject *pyComplex=PyComplex_FromDoubles(
-					(double) inputBuffers[i][k], 
-					(double) inputBuffers[i][k+1]);
-				pySampleListArray[j] = pyComplex;
-				k += 2;
-			}
-			break;
-			
-		}
-		pyChannelListArray[i] = pySampleList;
-	}
-	return pyChannelList;
-}
-
-/// numpy buffer interface: passing the sample buffers as shared memory buffers
-/// Optimization: using sequence protocol for creating the buffer list
-inline PyObject*
-PyTypeInterface::InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
-{	
-	//create a list of buffers (returns new references)
-	PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
-	PyObject **pyChannelListArray =  PySequence_Fast_ITEMS(pyChannelList);
-
-	// Expose memory using the Buffer Interface.		
-	// This will pass a pointer which can be recasted in Python code 
-	// as complex or float array using Numpy's frombuffer() method
-	// (this will not copy values just keep the starting adresses 
-	// for each channel in a list)
-	Py_ssize_t bufferSize;
-	
-	if (dtype==Vamp::Plugin::FrequencyDomain) 
-		bufferSize = (Py_ssize_t) sizeof(float) * (blockSize+2);
-	else 
-		bufferSize = (Py_ssize_t) sizeof(float) * blockSize;
-	
-	for (size_t i=0; i < channels; ++i) {
-		PyObject *pyBuffer = PyBuffer_FromMemory
-		((void *) (float *) inputBuffers[i],bufferSize);
-		pyChannelListArray[i] = pyBuffer;
-	}
-	return pyChannelList;
-}
-
-
-/// numpy array interface: passing the sample buffers as 2D numpy array
-/// Optimization: using array API (needs numpy headers)
-#ifdef HAVE_NUMPY
-inline PyObject*
-PyTypeInterface::InputBuffers_As_NumpyArray(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
-{	
-/*
-NOTE: We create a list of 1D Numpy arrays for each channel instead
-of a matrix, because the address space of inputBuffers doesn't seem
-to be continuous. Although the array strides could be calculated for
-2 channels (i.e. inputBuffers[1] - inputBuffers[0]) i'm not sure
-if this can be trusted, especially for more than 2 channels.
-
-	cerr << "First channel: " << inputBuffers[0][0] << " address: " <<  inputBuffers[0] << endl;
-	if (channels == 2)
-		cerr << "Second channel: " << inputBuffers[1][0] << " address: " <<  inputBuffers[1] << endl;
-
-*/	
-	
-	// create a list of arrays (returns new references)
-	PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
-	PyObject **pyChannelListArray =  PySequence_Fast_ITEMS(pyChannelList);
-	
-	// Expose memory using the Numpy Array Interface.		
-	// This will wrap an array objects around the data.
-	// (will not copy values just steal the starting adresses)
-
-	int arraySize, typenum;
-	
-	switch (dtype)
-	{
-		case Vamp::Plugin::TimeDomain :
-		typenum = dtype_float32; //NPY_FLOAT; 
-		arraySize = (int) blockSize;
-		break;
-
-		case Vamp::Plugin::FrequencyDomain :
-		typenum = dtype_complex64; //NPY_CFLOAT;
-		arraySize = (int) (blockSize / 2) + 1;
-		break;
-		
-		default :
-		cerr << "PyTypeInterface::InputBuffers_As_NumpyArray: Error: Unsupported numpy array data type." << endl;
-		return pyChannelList;
-	}
-
-	// size for each dimension
-	npy_intp ndims[1]={arraySize}; 
-	
-	for (size_t i=0; i < channels; ++i) {
-		PyObject *pyChannelArray = 
-			//args: (dimensions, size in each dim, type kind, pointer to continuous array)
-			PyArray_SimpleNewFromData(1, ndims, typenum, (void*) inputBuffers[i]);
-		// make it read-only: set all flags to false except NPY_C_CONTIGUOUS
-		//!!! what about NPY_ARRAY_OWNDATA?
-		PyArray_CLEARFLAGS((PyArrayObject *)pyChannelArray, 0xff);
-		PyArray_ENABLEFLAGS((PyArrayObject *)pyChannelArray, NPY_ARRAY_C_CONTIGUOUS);
-		pyChannelListArray[i] = pyChannelArray;
-	}
-	return pyChannelList;
-}
 #endif
-
-
-
-#ifdef NUMPY_REFERENCE
-/// This should be all we need to compile without direct dependency,
-/// but we don't do that. (it may not work on some platforms)
-typedef struct {
-    int two;              /* contains the integer 2 -- simple sanity check */
-    int nd;               /* number of dimensions */
-    char typekind;        /* kind in array --- character code of typestr */
-    int itemsize;         /* size of each element */
-    int flags;            /* flags indicating how the data should be interpreted */
-                          /*   must set ARR_HAS_DESCR bit to validate descr */
-    Py_intptr_t *shape;   /* A length-nd array of shape information */
-    Py_intptr_t *strides; /* A length-nd array of stride information */
-    void *data;           /* A pointer to the first element of the array */
-    PyObject *descr;      /* NULL or data-description (same as descr key */
-                          /*        of __array_interface__) -- must set ARR_HAS_DESCR */
-                          /*        flag or this will be ignored. */
-} PyArrayInterface;
-
-typedef struct PyArrayObject {
-        PyObject_HEAD
-        char *data;             /* pointer to raw data buffer */
-        int nd;                 /* number of dimensions, also called ndim */
-        npy_intp *dimensions;       /* size in each dimension */
-        npy_intp *strides;          /* bytes to jump to get to the
-                                   next element in each dimension */
-        PyObject *base;         /* This object should be decref'd
-                                   upon deletion of array */
-                                /* For views it points to the original array */
-                                /* For creation from buffer object it points
-                                   to an object that shold be decref'd on
-                                   deletion */
-                                /* For UPDATEIFCOPY flag this is an array
-                                   to-be-updated upon deletion of this one */
-        PyArray_Descr *descr;   /* Pointer to type structure */
-        int flags;              /* Flags describing array -- see below*/
-        PyObject *weakreflist;  /* For weakreferences */
-} PyArrayObject;
-
-typedef struct _PyArray_Descr {
-        PyObject_HEAD
-        PyTypeObject *typeobj;  /* the type object representing an
-                                   instance of this type -- should not
-                                   be two type_numbers with the same type
-                                   object. */
-        char kind;              /* kind for this type */
-        char type;              /* unique-character representing this type */
-        char byteorder;         /* '>' (big), '<' (little), '|'
-                                   (not-applicable), or '=' (native). */
-        char hasobject;         /* non-zero if it has object arrays
-                                   in fields */
-        int type_num;          /* number representing this type */
-        int elsize;             /* element size for this type */
-        int alignment;          /* alignment needed for this type */
-        struct _arr_descr                                       \
-        *subarray;              /* Non-NULL if this type is
-                                   is an array (C-contiguous)
-                                   of some other type
-                                */
-        PyObject *fields;       /* The fields dictionary for this type */
-                                /* For statically defined descr this
-                                   is always Py_None */
-
-        PyObject *names;        /* An ordered tuple of field names or NULL
-                                   if no fields are defined */
-
-        PyArray_ArrFuncs *f;     /* a table of functions specific for each
-                                    basic data descriptor */
-} PyArray_Descr;
-
-enum NPY_TYPES {    NPY_BOOL=0,
-                    NPY_BYTE, NPY_UBYTE,
-                    NPY_SHORT, NPY_USHORT,
-                    NPY_INT, NPY_UINT,
-                    NPY_LONG, NPY_ULONG,
-                    NPY_LONGLONG, NPY_ULONGLONG,
-                    NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE,
-                    NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE,
-                    NPY_OBJECT=17,
-                    NPY_STRING, NPY_UNICODE,
-                    NPY_VOID,
-                    NPY_NTYPES,
-                    NPY_NOTYPE,
-                    NPY_CHAR,      /* special flag */
-                    NPY_USERDEF=256  /* leave room for characters */
-};
-#endif /*NUMPY_REFERENCE*/
-#endif