annotate PyTypeInterface.h @ 33:c4da8d559872 vampy2

* build fixes for Linux
author cannam
date Wed, 23 Sep 2009 11:56:46 +0000
parents a8231788216c
children c905122f79e7
rev   line source
fazekasgy@31 1 /*
fazekasgy@31 2
fazekasgy@31 3 Type safe conversion utilities from Python types to C/C++ types,
fazekasgy@31 4 mainly using Py/C API macros.
fazekasgy@31 5
fazekasgy@31 6 */
fazekasgy@31 7
fazekasgy@31 8 #ifndef _PY_TYPE_INTERFACE_H_
fazekasgy@31 9 #define _PY_TYPE_INTERFACE_H_
fazekasgy@31 10 #include <Python.h>
fazekasgy@32 11 #ifdef HAVE_NUMPY
fazekasgy@32 12 #include "arrayobject.h"
fazekasgy@32 13 #endif
fazekasgy@31 14 #include "PyExtensionModule.h"
fazekasgy@31 15 #include <vector>
fazekasgy@31 16 #include <queue>
fazekasgy@31 17 #include <string>
fazekasgy@32 18 #include "vamp-sdk/Plugin.h"
fazekasgy@31 19 //#include <typeinfo>
fazekasgy@31 20
fazekasgy@31 21
fazekasgy@31 22 using std::cerr;
fazekasgy@31 23 using std::endl;
fazekasgy@31 24
fazekasgy@31 25 namespace o {
fazekasgy@31 26 enum eOutDescriptors {
fazekasgy@31 27 not_found,
fazekasgy@31 28 identifier,
fazekasgy@31 29 name,
fazekasgy@31 30 description,
fazekasgy@31 31 unit,
fazekasgy@31 32 hasFixedBinCount,
fazekasgy@31 33 binCount,
fazekasgy@31 34 binNames,
fazekasgy@31 35 hasKnownExtents,
fazekasgy@31 36 minValue,
fazekasgy@31 37 maxValue,
fazekasgy@31 38 isQuantized,
fazekasgy@31 39 quantizeStep,
fazekasgy@31 40 sampleType,
fazekasgy@31 41 sampleRate,
fazekasgy@31 42 hasDuration,
fazekasgy@31 43 endNode
fazekasgy@31 44 };
fazekasgy@31 45 }
fazekasgy@31 46
fazekasgy@31 47 namespace p {
fazekasgy@31 48 enum eParmDescriptors {
fazekasgy@31 49 not_found,
fazekasgy@31 50 identifier,
fazekasgy@31 51 name,
fazekasgy@31 52 description,
fazekasgy@31 53 unit,
fazekasgy@31 54 minValue,
fazekasgy@31 55 maxValue,
fazekasgy@31 56 defaultValue,
fazekasgy@31 57 isQuantized,
fazekasgy@31 58 quantizeStep
fazekasgy@31 59 };
fazekasgy@31 60 }
fazekasgy@31 61
fazekasgy@31 62 enum eSampleTypes {
fazekasgy@31 63 OneSamplePerStep,
fazekasgy@31 64 FixedSampleRate,
fazekasgy@31 65 VariableSampleRate
fazekasgy@31 66 };
fazekasgy@31 67
fazekasgy@31 68 enum eFeatureFields {
fazekasgy@31 69 unknown,
fazekasgy@31 70 hasTimestamp,
fazekasgy@31 71 timeStamp,
fazekasgy@31 72 hasDuration,
fazekasgy@31 73 duration,
fazekasgy@31 74 values,
fazekasgy@31 75 label
fazekasgy@31 76 };
fazekasgy@31 77
fazekasgy@31 78 /* C++ mapping of PyNone Type*/
cannam@33 79 struct NoneType {};
fazekasgy@31 80
fazekasgy@31 81 class PyTypeInterface
fazekasgy@31 82 {
fazekasgy@31 83 public:
fazekasgy@31 84 PyTypeInterface();
fazekasgy@31 85 ~PyTypeInterface();
fazekasgy@31 86
fazekasgy@31 87 // Data
fazekasgy@31 88 class ValueError
fazekasgy@31 89 {
fazekasgy@31 90 public:
fazekasgy@31 91 ValueError() {}
fazekasgy@31 92 ValueError(std::string m, bool s) : message(m),strict(s) {}
fazekasgy@31 93 std::string location;
fazekasgy@31 94 std::string message;
fazekasgy@31 95 bool strict;
fazekasgy@31 96 std::string get() const { return message + "\nLocation: " + location + "\n";}
fazekasgy@31 97 void print() const { cerr << get(); }
fazekasgy@31 98 };
fazekasgy@31 99
fazekasgy@31 100 // Utilities
fazekasgy@31 101 void setStrictTypingFlag(bool b) {m_strict = b;}
fazekasgy@31 102 const ValueError &lastError() const;
fazekasgy@31 103 ValueError getError() const;
fazekasgy@31 104 std::string PyValue_Get_TypeName(PyObject*) const;
fazekasgy@31 105 bool initMaps() const;
fazekasgy@31 106
fazekasgy@31 107 // Basic type conversion: Python to C++
fazekasgy@31 108 float PyValue_To_Float(PyObject*) const;
fazekasgy@31 109 size_t PyValue_To_Size_t(PyObject*) const;
fazekasgy@31 110 bool PyValue_To_Bool(PyObject*) const;
fazekasgy@31 111 std::string PyValue_To_String(PyObject*) const;
fazekasgy@31 112 // int PyValue_To_Int(PyObject*) const;
fazekasgy@31 113
fazekasgy@31 114 // C++ to Python
fazekasgy@31 115 PyObject *PyValue_From_CValue(const char*) const;
fazekasgy@31 116 PyObject *PyValue_From_CValue(const std::string& x) const { return PyValue_From_CValue(x.c_str()); }
fazekasgy@31 117 PyObject *PyValue_From_CValue(size_t) const;
fazekasgy@31 118 PyObject *PyValue_From_CValue(double) const;
fazekasgy@31 119 PyObject *PyValue_From_CValue(float x) const { return PyValue_From_CValue((double)x); }
fazekasgy@31 120 PyObject *PyValue_From_CValue(bool) const;
fazekasgy@31 121
fazekasgy@31 122 // Sequence types
fazekasgy@31 123 std::vector<std::string> PyValue_To_StringVector (PyObject*) const;
fazekasgy@31 124 std::vector<float> PyValue_To_FloatVector (PyObject*) const;
fazekasgy@32 125 std::vector<float> PyList_To_FloatVector (PyObject*) const;
fazekasgy@31 126
fazekasgy@31 127 // Numpy types
fazekasgy@32 128 #ifdef HAVE_NUMPY
fazekasgy@32 129 std::vector<float> PyArray_To_FloatVector (PyObject *pyValue) const;
fazekasgy@32 130 #endif
fazekasgy@31 131
fazekasgy@31 132
fazekasgy@31 133 /* Template functions */
fazekasgy@31 134
fazekasgy@31 135
fazekasgy@32 136 /// Common wrappers to set values in Vamp API structs. (to be used in template functions)
fazekasgy@31 137 void SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const;
fazekasgy@31 138 void SetValue(Vamp::Plugin::ParameterDescriptor& od, std::string& key, PyObject* pyValue) const;
fazekasgy@31 139 bool SetValue(Vamp::Plugin::Feature& od, std::string& key, PyObject* pyValue) const;
fazekasgy@31 140 PyObject* GetDescriptor_As_Dict(PyObject* pyValue) const
fazekasgy@31 141 {
fazekasgy@31 142 if PyFeature_CheckExact(pyValue) return PyFeature_AS_DICT(pyValue);
fazekasgy@31 143 if PyOutputDescriptor_CheckExact(pyValue) return PyOutputDescriptor_AS_DICT(pyValue);
fazekasgy@31 144 if PyParameterDescriptor_CheckExact(pyValue) return PyParameterDescriptor_AS_DICT(pyValue);
fazekasgy@31 145 return NULL;
fazekasgy@31 146 }
fazekasgy@31 147
fazekasgy@31 148
fazekasgy@31 149 template<typename RET>
cannam@33 150 RET PyValue_To_VampDescriptor(PyObject* pyValue) const
fazekasgy@31 151 //returns e.g. Vamp::Plugin::OutputDescriptor or Vamp::Plugin::Feature
fazekasgy@31 152 {
fazekasgy@31 153 PyObject* pyDict;
fazekasgy@31 154
fazekasgy@31 155 // Descriptors encoded as dicts
fazekasgy@31 156 pyDict = GetDescriptor_As_Dict(pyValue);
fazekasgy@31 157 if (!pyDict) pyDict = pyValue;
fazekasgy@31 158
fazekasgy@31 159 // TODO: support full mapping protocol as fallback.
fazekasgy@31 160 if (!PyDict_Check(pyDict)) {
fazekasgy@31 161 setValueError("Error while converting descriptor or feature object.\nThe value is neither a dictionary nor a Vamp Feature or Descriptor type.",m_strict);
fazekasgy@31 162 return RET();
fazekasgy@31 163 }
fazekasgy@31 164
fazekasgy@31 165 Py_ssize_t pyPos = 0;
fazekasgy@31 166 PyObject *pyKey, *pyDictValue;
fazekasgy@31 167 initMaps();
fazekasgy@31 168 RET rd;
fazekasgy@31 169
fazekasgy@31 170 //Python Dictionary Iterator:
fazekasgy@31 171 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyDictValue))
fazekasgy@31 172 {
fazekasgy@31 173 std::string key = PyValue_To_String(pyKey);
fazekasgy@31 174 SetValue(rd,key,pyDictValue);
fazekasgy@31 175 if (m_error) {
fazekasgy@31 176 _lastError().location += "parameter: '" + key + "'";//"' descriptor: '" + rd.identifier + "'";
fazekasgy@31 177 }
fazekasgy@31 178 }
fazekasgy@31 179 if (!m_errorQueue.empty()) m_error = true;
fazekasgy@31 180 return rd;
fazekasgy@31 181 }
fazekasgy@31 182
fazekasgy@31 183 /// Convert a sequence (tipically list) of PySomething to
fazekasgy@31 184 /// OutputList,ParameterList or FeatureList
fazekasgy@31 185 template<typename RET,typename ELEM> //<OutputList> <OutputDescriptor>
cannam@33 186
cannam@33 187 RET PyValue_To_VampList(PyObject* pyList) const
fazekasgy@31 188 {
fazekasgy@31 189 // Vamp::Plugin::OutputList list;
fazekasgy@31 190 // Vamp::Plugin::OutputDescriptor od;
fazekasgy@31 191 RET list;
fazekasgy@31 192 ELEM element;
fazekasgy@31 193
fazekasgy@31 194 // Type checking
fazekasgy@31 195 if (! PyList_Check(pyList) ) {
fazekasgy@31 196 Py_CLEAR(pyList);
fazekasgy@31 197 // cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@31 198 // << "] Expected List return type." << endl;
fazekasgy@31 199 return list;
fazekasgy@31 200 }
fazekasgy@31 201
fazekasgy@31 202 //This reference will be borrowed
fazekasgy@31 203 PyObject *pyDict;
fazekasgy@31 204
fazekasgy@31 205 //Parse Output List
fazekasgy@31 206 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
fazekasgy@31 207 //Get i-th Vamp output descriptor (Borrowed Reference)
fazekasgy@31 208 pyDict = PyList_GET_ITEM(pyList,i);
fazekasgy@31 209 element = PyValue_To_VampDescriptor<ELEM>(pyDict);
fazekasgy@31 210 // Check for empty Feature/Descriptor as before?
fazekasgy@31 211 list.push_back(element);
fazekasgy@31 212 }
fazekasgy@31 213 return list;
fazekasgy@31 214 }
fazekasgy@31 215
fazekasgy@32 216 /// Convert DTYPE type 1D NumpyArray to std::vector<RET>
fazekasgy@32 217 template<typename RET, typename DTYPE>
cannam@33 218 std::vector<RET> PyArray_Convert(char* raw_data_ptr, long length) const
fazekasgy@32 219 {
fazekasgy@32 220 std::vector<RET> rValue;
fazekasgy@32 221 DTYPE* data = (DTYPE*) raw_data_ptr;
fazekasgy@32 222 for (long i = 0; i<length; ++i){
fazekasgy@32 223 #ifdef _DEBUG
fazekasgy@32 224 cerr << "value: " << (RET)data[i] << endl;
fazekasgy@32 225 #endif
fazekasgy@32 226 rValue.push_back((RET)data[i]);
fazekasgy@32 227 }
fazekasgy@32 228 return rValue;
fazekasgy@32 229 }
fazekasgy@31 230
fazekasgy@31 231 //Vamp specific types
fazekasgy@31 232
fazekasgy@31 233 Vamp::Plugin::FeatureSet PyValue_To_FeatureSet(PyObject*) const;
fazekasgy@31 234 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureSet &r) const
fazekasgy@31 235 { r = this->PyValue_To_FeatureSet(pyValue); }
fazekasgy@31 236
fazekasgy@31 237 Vamp::RealTime::RealTime PyValue_To_RealTime(PyObject*) const;
fazekasgy@31 238 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::RealTime::RealTime &r) const
fazekasgy@31 239 { r = this->PyValue_To_RealTime(pyValue); }
fazekasgy@31 240
fazekasgy@31 241
fazekasgy@31 242 /* Overloaded PyValue_To_rValue() to support generic functions */
fazekasgy@31 243 inline void PyValue_To_rValue(PyObject *pyValue, float &defValue) const
fazekasgy@31 244 { float tmp = this->PyValue_To_Float(pyValue);
fazekasgy@31 245 if(!m_error) defValue = tmp; }
fazekasgy@31 246 inline void PyValue_To_rValue(PyObject *pyValue, size_t &defValue) const
fazekasgy@31 247 { size_t tmp = this->PyValue_To_Size_t(pyValue);
fazekasgy@31 248 if(!m_error) defValue = tmp; }
fazekasgy@31 249 inline void PyValue_To_rValue(PyObject *pyValue, bool &defValue) const
fazekasgy@31 250 { bool tmp = this->PyValue_To_Bool(pyValue);
fazekasgy@31 251 if(!m_error) defValue = tmp; }
fazekasgy@31 252 inline void PyValue_To_rValue(PyObject *pyValue, std::string &defValue) const
fazekasgy@31 253 { std::string tmp = this->PyValue_To_String(pyValue);
fazekasgy@31 254 if(!m_error) defValue = tmp; }
fazekasgy@31 255 /*used by templates where we expect no return value, if there is one it will be ignored*/
fazekasgy@31 256 inline void PyValue_To_rValue(PyObject *pyValue, NoneType &defValue) const
fazekasgy@31 257 { if (m_strict && pyValue != Py_None)
fazekasgy@32 258 setValueError("Strict conversion error: Expected 'None' type.",m_strict);
fazekasgy@31 259 }
fazekasgy@31 260
fazekasgy@31 261 /* convert sequence types to Vamp List types */
fazekasgy@31 262 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::OutputList &r) const
fazekasgy@31 263 { r = this->PyValue_To_VampList<Vamp::Plugin::OutputList,Vamp::Plugin::OutputDescriptor>(pyValue); }
fazekasgy@31 264 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::ParameterList &r) const
fazekasgy@31 265 { r = this->PyValue_To_VampList<Vamp::Plugin::ParameterList,Vamp::Plugin::ParameterDescriptor>(pyValue); }
fazekasgy@31 266 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureList &r) const
fazekasgy@31 267 { r = this->PyValue_To_VampList<Vamp::Plugin::FeatureList,Vamp::Plugin::Feature>(pyValue); }
fazekasgy@31 268
fazekasgy@31 269 /// this is only needed for RealTime->Frame conversion
fazekasgy@31 270 void setInputSampleRate(float inputSampleRate)
fazekasgy@31 271 { m_inputSampleRate = (unsigned int) inputSampleRate; }
fazekasgy@31 272
fazekasgy@31 273 private:
fazekasgy@31 274 bool m_strict;
fazekasgy@31 275 ValueError m_noError;
fazekasgy@31 276 mutable bool m_error;
fazekasgy@31 277 mutable ValueError& m_lastError;
fazekasgy@31 278 mutable std::queue<ValueError> m_errorQueue;
fazekasgy@31 279 // we only use it for RealTime conversion which requires unsigned int
fazekasgy@31 280 unsigned int m_inputSampleRate;
fazekasgy@31 281
fazekasgy@31 282 void setValueError(std::string,bool) const;
fazekasgy@31 283 ValueError& _lastError() const;
fazekasgy@31 284
fazekasgy@31 285 /* Overloaded _convert(), bypasses error checking to avoid doing it twice in internals. */
fazekasgy@31 286 inline void _convert(PyObject *pyValue,float &r) const
fazekasgy@31 287 { r = PyValue_To_Float(pyValue); }
fazekasgy@31 288 inline void _convert(PyObject *pyValue,size_t &r) const
fazekasgy@31 289 { r = PyValue_To_Size_t(pyValue); }
fazekasgy@31 290 inline void _convert(PyObject *pyValue,bool &r) const
fazekasgy@31 291 { r = PyValue_To_Bool(pyValue); }
fazekasgy@31 292 inline void _convert(PyObject *pyValue,std::string &r) const
fazekasgy@31 293 { r = PyValue_To_String(pyValue); }
fazekasgy@31 294 inline void _convert(PyObject *pyValue,std::vector<std::string> &r) const
fazekasgy@31 295 { r = PyValue_To_StringVector(pyValue); }
fazekasgy@31 296 inline void _convert(PyObject *pyValue,std::vector<float> &r) const
fazekasgy@31 297 { r = PyValue_To_FloatVector(pyValue); }
fazekasgy@31 298 inline void _convert(PyObject *pyValue,Vamp::RealTime::RealTime &r) const
fazekasgy@31 299 { r = PyValue_To_RealTime(pyValue); }
fazekasgy@31 300
fazekasgy@31 301 public:
fazekasgy@31 302 const bool& error;
fazekasgy@31 303
fazekasgy@31 304 };
fazekasgy@31 305
fazekasgy@32 306 #ifdef NUMPY_REFERENCE
fazekasgy@32 307 /// This should be all we need to compile without direct dependency,
fazekasgy@32 308 /// but we don't do that. (it may not work on some platforms)
fazekasgy@32 309 typedef struct {
fazekasgy@32 310 int two; /* contains the integer 2 -- simple sanity check */
fazekasgy@32 311 int nd; /* number of dimensions */
fazekasgy@32 312 char typekind; /* kind in array --- character code of typestr */
fazekasgy@32 313 int itemsize; /* size of each element */
fazekasgy@32 314 int flags; /* flags indicating how the data should be interpreted */
fazekasgy@32 315 /* must set ARR_HAS_DESCR bit to validate descr */
fazekasgy@32 316 Py_intptr_t *shape; /* A length-nd array of shape information */
fazekasgy@32 317 Py_intptr_t *strides; /* A length-nd array of stride information */
fazekasgy@32 318 void *data; /* A pointer to the first element of the array */
fazekasgy@32 319 PyObject *descr; /* NULL or data-description (same as descr key */
fazekasgy@32 320 /* of __array_interface__) -- must set ARR_HAS_DESCR */
fazekasgy@32 321 /* flag or this will be ignored. */
fazekasgy@32 322 } PyArrayInterface;
fazekasgy@32 323
fazekasgy@32 324 typedef struct PyArrayObject {
fazekasgy@32 325 PyObject_HEAD
fazekasgy@32 326 char *data; /* pointer to raw data buffer */
fazekasgy@32 327 int nd; /* number of dimensions, also called ndim */
fazekasgy@32 328 npy_intp *dimensions; /* size in each dimension */
fazekasgy@32 329 npy_intp *strides; /* bytes to jump to get to the
fazekasgy@32 330 next element in each dimension */
fazekasgy@32 331 PyObject *base; /* This object should be decref'd
fazekasgy@32 332 upon deletion of array */
fazekasgy@32 333 /* For views it points to the original array */
fazekasgy@32 334 /* For creation from buffer object it points
fazekasgy@32 335 to an object that shold be decref'd on
fazekasgy@32 336 deletion */
fazekasgy@32 337 /* For UPDATEIFCOPY flag this is an array
fazekasgy@32 338 to-be-updated upon deletion of this one */
fazekasgy@32 339 PyArray_Descr *descr; /* Pointer to type structure */
fazekasgy@32 340 int flags; /* Flags describing array -- see below*/
fazekasgy@32 341 PyObject *weakreflist; /* For weakreferences */
fazekasgy@32 342 } PyArrayObject;
fazekasgy@32 343
fazekasgy@32 344 typedef struct _PyArray_Descr {
fazekasgy@32 345 PyObject_HEAD
fazekasgy@32 346 PyTypeObject *typeobj; /* the type object representing an
fazekasgy@32 347 instance of this type -- should not
fazekasgy@32 348 be two type_numbers with the same type
fazekasgy@32 349 object. */
fazekasgy@32 350 char kind; /* kind for this type */
fazekasgy@32 351 char type; /* unique-character representing this type */
fazekasgy@32 352 char byteorder; /* '>' (big), '<' (little), '|'
fazekasgy@32 353 (not-applicable), or '=' (native). */
fazekasgy@32 354 char hasobject; /* non-zero if it has object arrays
fazekasgy@32 355 in fields */
fazekasgy@32 356 int type_num; /* number representing this type */
fazekasgy@32 357 int elsize; /* element size for this type */
fazekasgy@32 358 int alignment; /* alignment needed for this type */
fazekasgy@32 359 struct _arr_descr \
fazekasgy@32 360 *subarray; /* Non-NULL if this type is
fazekasgy@32 361 is an array (C-contiguous)
fazekasgy@32 362 of some other type
fazekasgy@32 363 */
fazekasgy@32 364 PyObject *fields; /* The fields dictionary for this type */
fazekasgy@32 365 /* For statically defined descr this
fazekasgy@32 366 is always Py_None */
fazekasgy@32 367
fazekasgy@32 368 PyObject *names; /* An ordered tuple of field names or NULL
fazekasgy@32 369 if no fields are defined */
fazekasgy@32 370
fazekasgy@32 371 PyArray_ArrFuncs *f; /* a table of functions specific for each
fazekasgy@32 372 basic data descriptor */
fazekasgy@32 373 } PyArray_Descr;
fazekasgy@32 374
fazekasgy@32 375 enum NPY_TYPES { NPY_BOOL=0,
fazekasgy@32 376 NPY_BYTE, NPY_UBYTE,
fazekasgy@32 377 NPY_SHORT, NPY_USHORT,
fazekasgy@32 378 NPY_INT, NPY_UINT,
fazekasgy@32 379 NPY_LONG, NPY_ULONG,
fazekasgy@32 380 NPY_LONGLONG, NPY_ULONGLONG,
fazekasgy@32 381 NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE,
fazekasgy@32 382 NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE,
fazekasgy@32 383 NPY_OBJECT=17,
fazekasgy@32 384 NPY_STRING, NPY_UNICODE,
fazekasgy@32 385 NPY_VOID,
fazekasgy@32 386 NPY_NTYPES,
fazekasgy@32 387 NPY_NOTYPE,
fazekasgy@32 388 NPY_CHAR, /* special flag */
fazekasgy@32 389 NPY_USERDEF=256 /* leave room for characters */
fazekasgy@32 390 };
fazekasgy@32 391 #endif /*NUMPY_REFERENCE*/
cannam@33 392 #endif