diff PyTypeInterface.cpp @ 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
line wrap: on
line diff
--- 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