diff PyTypeInterface.h @ 31:4f1894c7591b vampy2

Created Vampy2 branch
author fazekasgy
date Sun, 20 Sep 2009 17:31:20 +0000
parents
children a8231788216c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyTypeInterface.h	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,304 @@
+/*
+
+Type safe conversion utilities from Python types to C/C++ types,
+mainly using Py/C API macros.
+
+*/
+
+#ifndef _PY_TYPE_INTERFACE_H_
+#define _PY_TYPE_INTERFACE_H_
+
+#include "vamp-sdk/Plugin.h"
+#include <Python.h>
+#include "PyExtensionModule.h"
+#include <vector>
+#include <queue>
+#include <string>
+//#include <typeinfo>
+
+
+using std::cerr;
+using std::endl;
+
+namespace o {
+enum eOutDescriptors {
+	not_found,
+	identifier,
+	name,
+	description,
+	unit, 
+	hasFixedBinCount,
+	binCount,
+	binNames,
+	hasKnownExtents,
+	minValue,
+	maxValue,
+	isQuantized,
+	quantizeStep,
+	sampleType,	
+	sampleRate,
+	hasDuration,
+	endNode
+	}; 
+}
+
+namespace p {
+enum eParmDescriptors {
+	not_found,
+	identifier,
+	name,
+	description,
+	unit, 
+	minValue,
+	maxValue,
+	defaultValue,
+	isQuantized,
+	quantizeStep
+	};
+}
+
+enum eSampleTypes {
+	OneSamplePerStep,
+	FixedSampleRate,
+	VariableSampleRate
+	};
+
+enum eFeatureFields {
+	unknown,
+	hasTimestamp,
+	timeStamp,
+	hasDuration,
+	duration,
+	values,
+	label
+	};
+
+
+/// sutructure of NumPy array interface:
+/// this is all we need to support numpy without direct dependency
+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;
+
+/* C++ mapping of PyNone Type*/
+typedef struct NoneType {};
+
+class PyTypeInterface
+{
+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 get() const { return message + "\nLocation: " + location + "\n";}
+		void print() const { cerr << get(); }
+	};
+	
+	// Utilities
+	void setStrictTypingFlag(bool b) {m_strict = b;}
+	const ValueError &lastError() const;
+	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;
+	// int PyValue_To_Int(PyObject*) 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;
+
+	// Numpy types
+	float* getNumPyObjectData(PyObject *object, int &length) const; 
+	
+
+/* 						Template functions 							*/
+
+
+	/// Common wrappers to set a value in one of these structs. (to be used in template functions)
+	void SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const;
+	void SetValue(Vamp::Plugin::ParameterDescriptor& od, std::string& key, PyObject* pyValue) const;
+	bool SetValue(Vamp::Plugin::Feature& od, std::string& key, PyObject* pyValue) const;
+    PyObject* GetDescriptor_As_Dict(PyObject* pyValue) const 
+	{
+		if PyFeature_CheckExact(pyValue) return PyFeature_AS_DICT(pyValue);
+		if PyOutputDescriptor_CheckExact(pyValue) return PyOutputDescriptor_AS_DICT(pyValue);
+		if PyParameterDescriptor_CheckExact(pyValue) return PyParameterDescriptor_AS_DICT(pyValue);
+		return NULL;
+	}
+	
+
+	template<typename RET> 
+	RET PyTypeInterface::PyValue_To_VampDescriptor(PyObject* pyValue) const
+	//returns e.g. Vamp::Plugin::OutputDescriptor or Vamp::Plugin::Feature
+	{
+		PyObject* pyDict;
+
+		// Descriptors encoded as dicts
+		pyDict = GetDescriptor_As_Dict(pyValue);
+		if (!pyDict) pyDict = pyValue;
+	
+		// TODO: support full mapping protocol as fallback.
+		if (!PyDict_Check(pyDict)) {
+			setValueError("Error while converting descriptor or feature object.\nThe value is neither a dictionary nor a Vamp Feature or Descriptor type.",m_strict);
+			return RET();
+		}
+
+		Py_ssize_t pyPos = 0;
+		PyObject *pyKey, *pyDictValue;
+		initMaps();
+		RET rd;
+
+		//Python Dictionary Iterator:
+		while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyDictValue))
+		{
+			std::string key = PyValue_To_String(pyKey);
+			SetValue(rd,key,pyDictValue);
+			if (m_error) {
+				_lastError().location += "parameter: '" + key + "'";//"' descriptor: '" + rd.identifier + "'";
+			}
+		}
+		if (!m_errorQueue.empty()) m_error = true;
+		return rd;
+	}
+
+	/// Convert a sequence (tipically list) of PySomething to 
+	/// OutputList,ParameterList or FeatureList
+	template<typename RET,typename ELEM> //<OutputList> <OutputDescriptor>
+	RET PyTypeInterface::PyValue_To_VampList(PyObject* pyList) const
+	{
+		// Vamp::Plugin::OutputList list;
+		// Vamp::Plugin::OutputDescriptor od;
+		RET list;
+		ELEM element;
+
+		// Type checking
+		if (! PyList_Check(pyList) ) {
+			Py_CLEAR(pyList);
+			// cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
+			// << "] Expected List return type." << endl;
+			return list;
+		}
+
+		//This reference will be borrowed
+		PyObject *pyDict;
+
+		//Parse Output List
+		for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
+			//Get i-th Vamp output descriptor (Borrowed Reference)
+			pyDict = PyList_GET_ITEM(pyList,i);
+			element = PyValue_To_VampDescriptor<ELEM>(pyDict);
+			// Check for empty Feature/Descriptor as before?
+			list.push_back(element);
+		}
+		return list;
+	}
+
+	
+	//Vamp specific types
+
+	Vamp::Plugin::FeatureSet PyValue_To_FeatureSet(PyObject*) const;
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureSet &r) const
+		{ r = this->PyValue_To_FeatureSet(pyValue); }
+
+	Vamp::RealTime::RealTime PyValue_To_RealTime(PyObject*) const;
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::RealTime::RealTime &r) const
+		{ r = this->PyValue_To_RealTime(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);                                              
+			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); 
+			if(!m_error) defValue = tmp; }
+	inline void PyValue_To_rValue(PyObject *pyValue, bool &defValue) const
+		{ bool tmp = this->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); 
+			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); }
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::ParameterList &r) const
+		{ r = this->PyValue_To_VampList<Vamp::Plugin::ParameterList,Vamp::Plugin::ParameterDescriptor>(pyValue); }
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureList &r) const
+		{ r = this->PyValue_To_VampList<Vamp::Plugin::FeatureList,Vamp::Plugin::Feature>(pyValue); }
+	
+	/// this is only needed for RealTime->Frame conversion
+	void setInputSampleRate(float inputSampleRate)
+		{ m_inputSampleRate = (unsigned int) inputSampleRate; }
+	
+private:
+	bool m_strict;
+	ValueError m_noError;
+	mutable bool m_error;
+	mutable ValueError& m_lastError;
+	mutable std::queue<ValueError> m_errorQueue;
+	// we only use it for RealTime conversion which requires unsigned int
+	unsigned int m_inputSampleRate; 
+	
+	void setValueError(std::string,bool) const;
+	ValueError& _lastError() const;
+
+	/* 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); }
+	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); }
+	inline void _convert(PyObject *pyValue,std::string &r) const
+		{ r = PyValue_To_String(pyValue); }
+	inline void _convert(PyObject *pyValue,std::vector<std::string> &r) const
+		{ r = 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::RealTime &r) const 
+		{ r = PyValue_To_RealTime(pyValue); }
+	
+public:
+	const bool& error;
+
+};
+
+#endif
\ No newline at end of file