# HG changeset patch # User fazekasgy # Date 1253541388 0 # Node ID a8231788216cb0bf5d1fea33ac93d17bdb169a74 # Parent 4f1894c7591ba2637458e29b30d4da28a22adb91 Vampy2: accept numpy array return types. diff -r 4f1894c7591b -r a8231788216c Makefile --- a/Makefile Sun Sep 20 17:31:20 2009 +0000 +++ b/Makefile Mon Sep 21 13:56:28 2009 +0000 @@ -1,17 +1,20 @@ -CXXFLAGS := -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5 #-I../host/pyRealTime.h #-fvisibility=hidden +CXXFLAGS := -DHAVE_NUMPY -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5 -I/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/numpy/core/include/numpy/ #-fvisibility=hidden +#without numpy headers available: +#CXXFLAGS := -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5 #-I../host/pyRealTime.h #-fvisibility=hidden LDFLAGS := -L../vamp-plugin-sdk/vamp-sdk -lvamp-sdk -dynamiclib -lpython2.5 -lpthread -all: vampy.dylib +default: vampy.dylib +all: vampy.dylib vampymod.so PyExtensionModule.a: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o libtool -static $^ -o $@ # The standard python extension is .so (even on the Mac) -PyExtensionModule.so: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o +vampymod.so: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o g++ -shared $^ -o $@ $(LDFLAGS) -vampy.dylib: PyPlugin.o PyPlugScanner.o vampy-main.o Mutex.o PyTypeInterface.o PyExtensionModule.a +vampy.dylib: PyPlugin.o PyPlugScanner.o vampy-main.o Mutex.o PyTypeInterface.o PyExtensionModule.a g++ -shared $^ -o $@ $(LDFLAGS) # Install plugin diff -r 4f1894c7591b -r a8231788216c PyFeatureSet.cpp --- a/PyFeatureSet.cpp Sun Sep 20 17:31:20 2009 +0000 +++ b/PyFeatureSet.cpp Mon Sep 21 13:56:28 2009 +0000 @@ -9,8 +9,6 @@ { if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0) return -1; - self->state = 0; - cerr << "FeatureSet initialised" << endl; return 0; } @@ -20,7 +18,7 @@ // cerr << "called FeatureSetObject_ass_sub" << endl; if (!PyInt_CheckExact(v)) { /// TODO: Set ValueError here. - cerr << "Output index must be positive integer" << endl; + cerr << "ValueError: Output index must be positive integer" << endl; return 0; } if (w == NULL) diff -r 4f1894c7591b -r a8231788216c PyFeatureSet.h --- a/PyFeatureSet.h Sun Sep 20 17:31:20 2009 +0000 +++ b/PyFeatureSet.h Mon Sep 21 13:56:28 2009 +0000 @@ -5,7 +5,6 @@ typedef struct { PyDictObject dict; - int state; } FeatureSetObject; PyAPI_DATA(PyTypeObject) FeatureSet_Type; @@ -14,7 +13,6 @@ #define PyFeatureSet_Check(v) PyObject_TypeCheck(v, &FeatureSet_Type) // #define PyFeatureSet_CheckExact(v) ((v)->ob_type == &PyDict_Type) // #define PyFeatureSet_Check(v) PyObject_TypeCheck(v, &PyDict_Type) - // #define PyFeature_AS_DICT(v) ((const FeatureObject* const) (v))->dict void initFeatureSetType(void); diff -r 4f1894c7591b -r a8231788216c PyPlugin.cpp --- a/PyPlugin.cpp Sun Sep 20 17:31:20 2009 +0000 +++ b/PyPlugin.cpp Mon Sep 21 13:56:28 2009 +0000 @@ -364,8 +364,8 @@ PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels); for (size_t i=0; i < m_channels; ++i) { //Expose memory using the Buffer Interface of C/API - //This will virtually pass a pointer which can be - //recasted in Python code as float or complex array + //This will pass a pointer which can be recasted + //in Python code as float or complex array PyObject *pyBuffer = PyBuffer_FromMemory ((void *) (float *) inputBuffers[i], (Py_ssize_t) sizeof(float) * m_blockSize); diff -r 4f1894c7591b -r a8231788216c PyTypeInterface.cpp --- a/PyTypeInterface.cpp Sun Sep 20 17:31:20 2009 +0000 +++ b/PyTypeInterface.cpp Mon Sep 21 13:56:28 2009 +0000 @@ -2,6 +2,9 @@ */ #include +#ifdef HAVE_NUMPY +#include "arrayobject.h" +#endif #include "PyTypeInterface.h" #include "PyRealTime.h" #include "PyExtensionModule.h" @@ -25,7 +28,7 @@ static bool isMapInitialised = false; /* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS - (EXCEPT FOR TEMPORARY PYOBJECTS)! */ + (EXCEPT FOR TEMPORARY PYTHON OBJECTS)! */ PyTypeInterface::PyTypeInterface() : m_strict(false), @@ -405,29 +408,51 @@ return Output; } -//convert Python list to C++ vector of floats +//convert PyFeature.value (typically a list or numpy array) to C++ vector of floats std::vector -PyTypeInterface::PyValue_To_FloatVector (PyObject *inputList) const +PyTypeInterface::PyValue_To_FloatVector (PyObject *pyValue) const { - typedef std::vector floatVector; std::vector Output; + +#ifdef HAVE_NUMPY + /// Check for NumPy Array: this requires linking with numpy + /// but, we don't really need this macro + // if (PyArray_CheckExact(inputList)) cerr << "PyPyArray_CheckExact OK" << endl; - /// Check for NumPy Array - if (PyObject_HasAttrString(inputList,"__array_struct__")) { - int vectorLength; - float *dataptr = getNumPyObjectData(inputList,vectorLength); - if (dataptr != 0) cerr << "Numpy array found: " << vectorLength << endl; - // Output = *dataptr; + /// numpy array + if (PyObject_HasAttrString(pyValue,"__array_struct__")) { + return PyArray_To_FloatVector(pyValue); } +#endif + + /// python list + if (PyList_Check(pyValue)) { + return PyList_To_FloatVector(pyValue); + } + + /// assume a single number + /// this allows to write e.g. Feature.values = 5 instead of [5.00] + Output.push_back(PyValue_To_Float(pyValue)); + return Output; + + /// TODO : set error + +} + +//convert a list of python floats +std::vector +PyTypeInterface::PyList_To_FloatVector (PyObject *inputList) const +{ + std::vector Output; float ListElement; PyObject *pyFloat = NULL; if (!PyList_Check(inputList)) return Output; - for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) { + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) { //Get next list item (Borrowed Reference) - pyFloat = PyList_GET_ITEM(inputList,k); + pyFloat = PyList_GET_ITEM(inputList,i); ListElement = (float) PyFloat_AS_DOUBLE(pyFloat); #ifdef _DEBUG cerr << "value: " << ListElement << endl; @@ -438,6 +463,50 @@ return Output; } +#ifdef HAVE_NUMPY +std::vector +PyTypeInterface::PyArray_To_FloatVector (PyObject *pyValue) const +{ + std::vector Output; + + /// we don't verify the array here as it'd be duplicated mostly + // if (!PyObject_HasAttrString(pyValue,"__array_struct__")) { + // return Output; + // } + + PyArrayObject* pyArray = (PyArrayObject*) pyValue; + PyArray_Descr* descr = pyArray->descr; + + /// check raw data pointer + if (pyArray->data == 0) return Output; + + /// check dimensions + if (pyArray->nd != 1) { + cerr << "Error: array must be 1D" << endl; + return Output; + } + +#ifdef _DEBUG + cerr << "Numpy array verified." << endl; +#endif + + switch (descr->type_num) + { + case NPY_FLOAT : + return PyArray_Convert(pyArray->data,pyArray->dimensions[0]); + case NPY_DOUBLE : + return PyArray_Convert(pyArray->data,pyArray->dimensions[0]); + case NPY_INT : + return PyArray_Convert(pyArray->data,pyArray->dimensions[0]); + case NPY_LONG : + return PyArray_Convert(pyArray->data,pyArray->dimensions[0]); + + default : + cerr << "Error. Unsupported element type in NumPy array object." << endl; + return Output; + } +} +#endif /* Vamp API Specific Types @@ -580,7 +649,7 @@ Vamp::Plugin::FeatureSet PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const { - Vamp::Plugin::FeatureSet rFeatureSet; /// PyFeatureSet is an int map + Vamp::Plugin::FeatureSet rFeatureSet; /// map if (pyValue == NULL) { cerr << "NULL FeatureSet" << endl; return rFeatureSet; @@ -893,77 +962,6 @@ /* Utilities */ -//return a pointer to the data in the numPy array -float* -PyTypeInterface::getNumPyObjectData(PyObject *object, int &length) const -{ - - char attr_name[]="__array_struct__"; - - //check if we passed in a NumPy array object - if (!PyObject_HasAttrString(object,attr_name)) { - // PyErr_SetString(PyExc_TypeError, - // "Input object has no __array_struct__ attribute. NumPy array required."); - return NULL; - } - - //retrieve __array_struct__ interface - object = PyObject_GetAttrString(object,attr_name); - - //check whether we found CObjects - if (!PyCObject_Check(object)) { - PyErr_SetString(PyExc_TypeError, - "The passed __array_struct__ interface is not a valid C Object."); - return NULL; - } - - - //check if the pointers directed to the integer '2' - int *check = (int *) PyCObject_AsVoidPtr (object); - - if (*check != 2 ) { - PyErr_SetString(PyExc_TypeError, - "A C Object __array_struct__ required as inputs"); - return NULL; - } - - //convert CObjects to Array interfaces - PyArrayInterface *arrayInterface = - (PyArrayInterface *) PyCObject_AsVoidPtr (object); - - //check array dimension: should be 1 - int inputDim = arrayInterface->nd; - - if (inputDim > 1 ) { - PyErr_SetString(PyExc_TypeError, - "Array dimensions must not exceed one."); - return NULL; - } - - // check if vector size is sane - Py_intptr_t arrayLength = arrayInterface->shape[0]; - length = (int) arrayLength; - - // if (arrayLength < 8 || arrayLength > 65536 ) { - // PyErr_SetString(PyExc_TypeError, - // "Array length is out of bounds."); - // return NULL; - // } - - //check type; must be float32 - char arrayType = arrayInterface->typekind; - - if (arrayType != 'f' ) { - PyErr_SetString(PyExc_TypeError, - "Floating point arrays required."); - return NULL; - } - - //return data vector address - return (float*) arrayInterface->data; - -} - /// get the type name of an object std::string PyTypeInterface::PyValue_Get_TypeName(PyObject* pyValue) const diff -r 4f1894c7591b -r a8231788216c PyTypeInterface.h --- a/PyTypeInterface.h Sun Sep 20 17:31:20 2009 +0000 +++ b/PyTypeInterface.h Mon Sep 21 13:56:28 2009 +0000 @@ -7,13 +7,15 @@ #ifndef _PY_TYPE_INTERFACE_H_ #define _PY_TYPE_INTERFACE_H_ - -#include "vamp-sdk/Plugin.h" #include +#ifdef HAVE_NUMPY +#include "arrayobject.h" +#endif #include "PyExtensionModule.h" #include #include #include +#include "vamp-sdk/Plugin.h" //#include @@ -73,24 +75,6 @@ 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 {}; @@ -138,15 +122,18 @@ // Sequence types std::vector PyValue_To_StringVector (PyObject*) const; std::vector PyValue_To_FloatVector (PyObject*) const; + std::vector PyList_To_FloatVector (PyObject*) const; // Numpy types - float* getNumPyObjectData(PyObject *object, int &length) const; +#ifdef HAVE_NUMPY + std::vector PyArray_To_FloatVector (PyObject *pyValue) const; +#endif /* Template functions */ - /// Common wrappers to set a value in one of these structs. (to be used in template functions) + /// Common wrappers to set values in Vamp API 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; @@ -225,6 +212,20 @@ return list; } + /// Convert DTYPE type 1D NumpyArray to std::vector + template + std::vector PyTypeInterface::PyArray_Convert(char* raw_data_ptr, long length) const + { + std::vector rValue; + DTYPE* data = (DTYPE*) raw_data_ptr; + for (long i = 0; i' (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 \ No newline at end of file