annotate PyTypeInterface.cpp @ 53:7e59caea821b

* Make a better job of preloading Python, especially when it's in a framework. Go for the Python file in the frameworks directory in preference to any libpythonX.Y.dylib. Particularly, don't try to preload any library without an absolute path until we've exhausted all our framework possibilities (so as to avoid picking up an ancient system library).
author cannam
date Fri, 09 Oct 2009 13:48:25 +0000
parents c1e4f706ca9a
children 74703a562ce3
rev   line source
fazekasgy@37 1 /*
fazekasgy@37 2
fazekasgy@37 3 * Vampy : This plugin is a wrapper around the Vamp plugin API.
fazekasgy@37 4 * It allows for writing Vamp plugins in Python.
fazekasgy@37 5
fazekasgy@37 6 * Centre for Digital Music, Queen Mary University of London.
fazekasgy@37 7 * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources
fazekasgy@37 8 * for licence information.)
fazekasgy@37 9
fazekasgy@37 10 */
fazekasgy@37 11
fazekasgy@37 12 #include <Python.h>
fazekasgy@37 13
fazekasgy@37 14 #ifdef HAVE_NUMPY
fazekasgy@37 15 #define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API
fazekasgy@37 16 #define NO_IMPORT_ARRAY
fazekasgy@37 17 #include "numpy/arrayobject.h"
fazekasgy@37 18 #endif
fazekasgy@37 19
fazekasgy@37 20 #include "PyTypeInterface.h"
fazekasgy@37 21 #include "PyRealTime.h"
fazekasgy@37 22 #include "PyExtensionModule.h"
fazekasgy@37 23 #include <math.h>
fazekasgy@37 24 #include <float.h>
fazekasgy@37 25 #include <limits.h>
fazekasgy@37 26 #ifndef SIZE_T_MAX
fazekasgy@37 27 #define SIZE_T_MAX ((size_t) -1)
fazekasgy@37 28 #endif
fazekasgy@37 29
fazekasgy@37 30 using std::string;
fazekasgy@37 31 using std::vector;
fazekasgy@37 32 using std::cerr;
fazekasgy@37 33 using std::endl;
fazekasgy@37 34 using std::map;
fazekasgy@37 35
fazekasgy@37 36 static std::map<std::string, o::eOutDescriptors> outKeys;
fazekasgy@37 37 static std::map<std::string, p::eParmDescriptors> parmKeys;
fazekasgy@37 38 static std::map<std::string, eSampleTypes> sampleKeys;
fazekasgy@37 39 static std::map<std::string, eFeatureFields> ffKeys;
fazekasgy@37 40 static bool isMapInitialised = false;
fazekasgy@37 41
fazekasgy@37 42 /* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS
fazekasgy@37 43 (EXCEPT FOR TEMPORARY PYTHON OBJECTS)! */
fazekasgy@37 44
fazekasgy@37 45 PyTypeInterface::PyTypeInterface() :
fazekasgy@37 46 m_strict(false),
fazekasgy@37 47 m_error(false),
fazekasgy@51 48 m_numpyInstalled(false),
fazekasgy@37 49 error(m_error) // const public reference for easy access
fazekasgy@37 50 {
fazekasgy@37 51 }
fazekasgy@37 52
fazekasgy@37 53 PyTypeInterface::~PyTypeInterface()
fazekasgy@37 54 {
fazekasgy@37 55 }
fazekasgy@37 56
fazekasgy@37 57 /// floating point numbers (TODO: check numpy.float128)
fazekasgy@37 58 float
fazekasgy@37 59 PyTypeInterface::PyValue_To_Float(PyObject* pyValue) const
fazekasgy@37 60 {
fazekasgy@37 61 // convert float
fazekasgy@37 62 if (pyValue && PyFloat_Check(pyValue))
fazekasgy@37 63 //TODO: check for limits here (same on most systems)
fazekasgy@37 64 return (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@37 65
fazekasgy@37 66 if (pyValue == NULL)
fazekasgy@37 67 {
fazekasgy@51 68 setValueError("Error while converting object " + PyValue_Get_TypeName(pyValue) + " to float. ",m_strict);
fazekasgy@37 69 return 0.0;
fazekasgy@37 70 }
fazekasgy@37 71
fazekasgy@37 72 // in strict mode we will not try harder
fazekasgy@37 73 if (m_strict) {
fazekasgy@51 74 setValueError("Strict conversion error: object" + PyValue_Get_TypeName(pyValue) +" is not float.",m_strict);
fazekasgy@37 75 return 0.0;
fazekasgy@37 76 }
fazekasgy@37 77
fazekasgy@37 78 // convert other objects supporting the number protocol
fazekasgy@37 79 if (PyNumber_Check(pyValue))
fazekasgy@37 80 {
fazekasgy@37 81 PyObject* pyFloat = PyNumber_Float(pyValue); // new ref
fazekasgy@37 82 if (!pyFloat)
fazekasgy@37 83 {
fazekasgy@37 84 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 85 setValueError("Error while converting " + PyValue_Get_TypeName(pyValue) + " object to float.",m_strict);
fazekasgy@37 86 return 0.0;
fazekasgy@37 87 }
fazekasgy@37 88 float rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
fazekasgy@37 89 Py_DECREF(pyFloat);
fazekasgy@37 90 return rValue;
fazekasgy@37 91 }
fazekasgy@37 92 /*
fazekasgy@37 93 // convert other objects supporting the number protocol
fazekasgy@37 94 if (PyNumber_Check(pyValue))
fazekasgy@37 95 {
fazekasgy@37 96 // PEP353: Py_ssize_t is size_t but signed !
fazekasgy@37 97 // This will work up to numpy.float64
fazekasgy@37 98 Py_ssize_t rValue = PyNumber_AsSsize_t(pyValue,NULL);
fazekasgy@37 99 if (PyErr_Occurred())
fazekasgy@37 100 {
fazekasgy@37 101 PyErr_Print(); PyErr_Clear();
fazekasgy@37 102 setValueError("Error while converting integer object.",m_strict);
fazekasgy@37 103 return 0.0;
fazekasgy@37 104 }
fazekasgy@37 105 if (rValue > (Py_ssize_t)FLT_MAX || rValue < (Py_ssize_t)FLT_MIN)
fazekasgy@37 106 {
fazekasgy@37 107 setValueError("Overflow error. Object can not be converted to float.",m_strict);
fazekasgy@37 108 return 0.0;
fazekasgy@37 109 }
fazekasgy@37 110 return (float) rValue;
fazekasgy@37 111 }
fazekasgy@37 112 */
fazekasgy@37 113 // convert string
fazekasgy@37 114 if (PyString_Check(pyValue))
fazekasgy@37 115 {
fazekasgy@37 116 PyObject* pyFloat = PyFloat_FromString(pyValue,NULL);
fazekasgy@37 117 if (!pyFloat)
fazekasgy@37 118 {
fazekasgy@37 119 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@37 120 setValueError("String value can not be converted to float.",m_strict);
fazekasgy@37 121 return 0.0;
fazekasgy@37 122 }
fazekasgy@37 123 float rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
fazekasgy@37 124 if (PyErr_Occurred())
fazekasgy@37 125 {
fazekasgy@37 126 PyErr_Print(); PyErr_Clear();
fazekasgy@37 127 Py_CLEAR(pyFloat);
fazekasgy@37 128 setValueError("Error while converting float object.",m_strict);
fazekasgy@37 129 return 0.0;
fazekasgy@37 130 }
fazekasgy@37 131 Py_DECREF(pyFloat);
fazekasgy@37 132 return rValue;
fazekasgy@37 133 }
fazekasgy@37 134
fazekasgy@37 135 // convert the first element of any iterable sequence (for convenience and backwards compatibility)
cannam@41 136 if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0)
fazekasgy@37 137 {
fazekasgy@37 138 PyObject* item = PySequence_GetItem(pyValue,0);
fazekasgy@37 139 if (item)
fazekasgy@37 140 {
fazekasgy@37 141 float rValue = this->PyValue_To_Float(item);
fazekasgy@37 142 if (!m_error) {
fazekasgy@37 143 Py_DECREF(item);
fazekasgy@37 144 return rValue;
fazekasgy@37 145 } else {
fazekasgy@37 146 Py_CLEAR(item);
fazekasgy@37 147 std::string msg = "Could not convert sequence element to float. ";
fazekasgy@37 148 setValueError(msg,m_strict);
fazekasgy@37 149 return 0.0;
fazekasgy@37 150 }
fazekasgy@37 151 }
fazekasgy@37 152 }
fazekasgy@37 153
fazekasgy@37 154 // give up
fazekasgy@37 155 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@37 156 std::string msg = "Conversion from " + PyValue_Get_TypeName(pyValue) + " to float is not possible.";
fazekasgy@37 157 setValueError(msg,m_strict);
fazekasgy@37 158 #ifdef _DEBUG
fazekasgy@37 159 cerr << "PyTypeInterface::PyValue_To_Float failed. " << msg << endl;
fazekasgy@37 160 #endif
fazekasgy@37 161 return 0.0;
fazekasgy@37 162 }
fazekasgy@37 163
fazekasgy@37 164 /// size_t (unsigned integer types)
fazekasgy@37 165 size_t
fazekasgy@37 166 PyTypeInterface::PyValue_To_Size_t(PyObject* pyValue) const
fazekasgy@37 167 {
fazekasgy@37 168 // convert objects supporting the number protocol
fazekasgy@37 169 if (PyNumber_Check(pyValue))
fazekasgy@37 170 {
fazekasgy@37 171 if (m_strict && !PyInt_Check(pyValue) && !PyLong_Check(pyValue))
fazekasgy@37 172 setValueError("Strict conversion error: object is not integer type.",m_strict);
fazekasgy@37 173 // Note: this function handles Bool,Int,Long,Float
fazekasgy@37 174 // speed is not critical in the use of this type by Vamp
fazekasgy@37 175 // PEP353: Py_ssize_t is size_t but signed !
fazekasgy@37 176 Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
fazekasgy@37 177 if (PyErr_Occurred())
fazekasgy@37 178 {
fazekasgy@37 179 PyErr_Print(); PyErr_Clear();
fazekasgy@37 180 setValueError("Error while converting integer object.",m_strict);
fazekasgy@37 181 return 0;
fazekasgy@37 182 }
fazekasgy@37 183 if ((unsigned long)rValue > SIZE_T_MAX || (unsigned long)rValue < 0)
fazekasgy@37 184 {
fazekasgy@37 185 setValueError("Overflow error. Object can not be converted to size_t.",m_strict);
fazekasgy@37 186 return 0;
fazekasgy@37 187 }
fazekasgy@37 188 return (size_t) rValue;
fazekasgy@37 189 }
fazekasgy@37 190
fazekasgy@37 191 // in strict mode we will not try harder and throw an exception
fazekasgy@37 192 // then the caller should decide what to do with it
fazekasgy@37 193 if (m_strict) {
fazekasgy@37 194 setValueError("Strict conversion error: object is not integer.",m_strict);
fazekasgy@37 195 return 0;
fazekasgy@37 196 }
fazekasgy@37 197
fazekasgy@37 198 // convert string
fazekasgy@37 199 if (PyString_Check(pyValue))
fazekasgy@37 200 {
fazekasgy@37 201 PyObject* pyLong = PyNumber_Long(pyValue);
fazekasgy@37 202 if (!pyLong)
fazekasgy@37 203 {
fazekasgy@37 204 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@37 205 setValueError("String object can not be converted to size_t.",m_strict);
fazekasgy@37 206 return 0;
fazekasgy@37 207 }
fazekasgy@37 208 size_t rValue = this->PyValue_To_Size_t(pyLong);
fazekasgy@37 209 if (!m_error) {
fazekasgy@37 210 Py_DECREF(pyLong);
fazekasgy@37 211 return rValue;
fazekasgy@37 212 } else {
fazekasgy@37 213 Py_CLEAR(pyLong);
fazekasgy@37 214 setValueError ("Error converting string to size_t.",m_strict);
fazekasgy@37 215 return 0;
fazekasgy@37 216 }
fazekasgy@37 217 }
fazekasgy@37 218
fazekasgy@37 219 // convert the first element of iterable sequences
cannam@41 220 if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0)
fazekasgy@37 221 {
fazekasgy@37 222 PyObject* item = PySequence_GetItem(pyValue,0);
fazekasgy@37 223 if (item)
fazekasgy@37 224 {
fazekasgy@37 225 size_t rValue = this->PyValue_To_Size_t(item);
fazekasgy@37 226 if (!m_error) {
fazekasgy@37 227 Py_DECREF(item);
fazekasgy@37 228 return rValue;
fazekasgy@37 229 } else {
fazekasgy@37 230 Py_CLEAR(item);
fazekasgy@37 231 setValueError("Could not convert sequence element to size_t. ",m_strict);
fazekasgy@37 232 return 0;
fazekasgy@37 233 }
fazekasgy@37 234 }
fazekasgy@37 235 }
fazekasgy@37 236
fazekasgy@37 237 // give up
fazekasgy@37 238 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@37 239 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to size_t is not possible.";
fazekasgy@37 240 setValueError(msg,m_strict);
fazekasgy@37 241 #ifdef _DEBUG
fazekasgy@37 242 cerr << "PyTypeInterface::PyValue_To_Size_t failed. " << msg << endl;
fazekasgy@37 243 #endif
fazekasgy@37 244 return 0;
fazekasgy@37 245 }
fazekasgy@37 246
fazekasgy@37 247 /// long and int
fazekasgy@37 248 long
fazekasgy@37 249 PyTypeInterface::PyValue_To_Long(PyObject* pyValue) const
fazekasgy@37 250 {
fazekasgy@37 251 // most common case: convert int (faster)
fazekasgy@37 252 if (pyValue && PyInt_Check(pyValue)) {
fazekasgy@37 253 // if the object is not NULL and verified, this macro just extracts the value.
fazekasgy@37 254 return PyInt_AS_LONG(pyValue);
fazekasgy@37 255 }
fazekasgy@37 256
fazekasgy@37 257 // long
fazekasgy@37 258 if (PyLong_Check(pyValue)) {
fazekasgy@37 259 long rValue = PyLong_AsLong(pyValue);
fazekasgy@37 260 if (PyErr_Occurred()) {
fazekasgy@37 261 PyErr_Print(); PyErr_Clear();
fazekasgy@37 262 setValueError("Error while converting long object.",m_strict);
fazekasgy@37 263 return 0;
fazekasgy@37 264 }
fazekasgy@37 265 return rValue;
fazekasgy@37 266 }
fazekasgy@37 267
fazekasgy@37 268 if (m_strict) {
fazekasgy@37 269 setValueError("Strict conversion error: object is not integer or long integer.",m_strict);
fazekasgy@37 270 return 0;
fazekasgy@37 271 }
fazekasgy@37 272
fazekasgy@37 273 // convert all objects supporting the number protocol
fazekasgy@37 274 if (PyNumber_Check(pyValue))
fazekasgy@37 275 {
fazekasgy@37 276 // Note: this function handles Bool,Int,Long,Float
fazekasgy@37 277 // PEP353: Py_ssize_t is size_t but signed !
fazekasgy@37 278 Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
fazekasgy@37 279 if (PyErr_Occurred())
fazekasgy@37 280 {
fazekasgy@37 281 PyErr_Print(); PyErr_Clear();
fazekasgy@37 282 setValueError("Error while converting integer object.",m_strict);
fazekasgy@37 283 return 0;
fazekasgy@37 284 }
fazekasgy@37 285 if (rValue > LONG_MAX || rValue < LONG_MIN)
fazekasgy@37 286 {
fazekasgy@37 287 setValueError("Overflow error. Object can not be converted to size_t.",m_strict);
fazekasgy@37 288 return 0;
fazekasgy@37 289 }
fazekasgy@37 290 return (long) rValue;
fazekasgy@37 291 }
fazekasgy@37 292
fazekasgy@37 293 // convert string
fazekasgy@37 294 if (PyString_Check(pyValue))
fazekasgy@37 295 {
fazekasgy@37 296 PyObject* pyLong = PyNumber_Long(pyValue);
fazekasgy@37 297 if (!pyLong)
fazekasgy@37 298 {
fazekasgy@37 299 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@37 300 setValueError("String object can not be converted to long.",m_strict);
fazekasgy@37 301 return 0;
fazekasgy@37 302 }
fazekasgy@37 303 long rValue = this->PyValue_To_Long(pyLong);
fazekasgy@37 304 if (!m_error) {
fazekasgy@37 305 Py_DECREF(pyLong);
fazekasgy@37 306 return rValue;
fazekasgy@37 307 } else {
fazekasgy@37 308 Py_CLEAR(pyLong);
fazekasgy@37 309 setValueError ("Error converting string to long.",m_strict);
fazekasgy@37 310 return 0;
fazekasgy@37 311 }
fazekasgy@37 312 }
fazekasgy@37 313
fazekasgy@37 314 // convert the first element of iterable sequences
cannam@46 315 if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0)
fazekasgy@37 316 {
fazekasgy@37 317 PyObject* item = PySequence_GetItem(pyValue,0);
fazekasgy@37 318 if (item)
fazekasgy@37 319 {
fazekasgy@37 320 size_t rValue = this->PyValue_To_Long(item);
fazekasgy@37 321 if (!m_error) {
fazekasgy@37 322 Py_DECREF(item);
fazekasgy@37 323 return rValue;
fazekasgy@37 324 } else {
fazekasgy@37 325 Py_CLEAR(item);
fazekasgy@37 326 setValueError("Could not convert sequence element to long. ",m_strict);
fazekasgy@37 327 return 0;
fazekasgy@37 328 }
fazekasgy@37 329 }
fazekasgy@37 330 }
fazekasgy@37 331
fazekasgy@37 332 // give up
fazekasgy@37 333 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@37 334 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to long is not possible.";
fazekasgy@37 335 setValueError(msg,m_strict);
fazekasgy@37 336 #ifdef _DEBUG
fazekasgy@37 337 cerr << "PyTypeInterface::PyValue_To_Long failed. " << msg << endl;
fazekasgy@37 338 #endif
fazekasgy@37 339 return 0;
fazekasgy@37 340 }
fazekasgy@37 341
fazekasgy@37 342
fazekasgy@37 343 bool
fazekasgy@37 344 PyTypeInterface::PyValue_To_Bool(PyObject* pyValue) const
fazekasgy@37 345 {
fazekasgy@37 346 // convert objects supporting the number protocol
fazekasgy@37 347 // Note: PyBool is a subclass of PyInt
fazekasgy@37 348 if (PyNumber_Check(pyValue))
fazekasgy@37 349 {
fazekasgy@37 350 if (m_strict && !PyBool_Check(pyValue))
fazekasgy@37 351 setValueError
fazekasgy@37 352 ("Strict conversion error: object is not boolean type.",m_strict);
fazekasgy@37 353
fazekasgy@37 354 // Note: this function handles Bool,Int,Long,Float
fazekasgy@37 355 Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
fazekasgy@37 356 if (PyErr_Occurred())
fazekasgy@37 357 {
fazekasgy@37 358 PyErr_Print(); PyErr_Clear();
fazekasgy@37 359 setValueError ("Error while converting boolean object.",m_strict);
fazekasgy@37 360 }
fazekasgy@37 361 if (rValue != 1 && rValue != 0)
fazekasgy@37 362 {
fazekasgy@37 363 setValueError ("Overflow error. Object can not be converted to boolean.",m_strict);
fazekasgy@37 364 }
fazekasgy@37 365 return (bool) rValue;
fazekasgy@37 366 }
fazekasgy@37 367
fazekasgy@37 368 if (m_strict) {
fazekasgy@37 369 setValueError ("Strict conversion error: object is not numerical type.",m_strict);
fazekasgy@37 370 return false;
fazekasgy@37 371 }
fazekasgy@37 372
fazekasgy@37 373 // convert iterables: the rule is the same as in the interpreter:
fazekasgy@37 374 // empty sequence evaluates to False, anything else is True
fazekasgy@37 375 if (PySequence_Check(pyValue))
fazekasgy@37 376 {
fazekasgy@37 377 return PySequence_Size(pyValue)?true:false;
fazekasgy@37 378 }
fazekasgy@37 379
fazekasgy@37 380 // give up
fazekasgy@37 381 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@37 382 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to boolean is not possible.";
fazekasgy@37 383 setValueError(msg,m_strict);
fazekasgy@37 384 #ifdef _DEBUG
fazekasgy@37 385 cerr << "PyTypeInterface::PyValue_To_Bool failed. " << msg << endl;
fazekasgy@37 386 #endif
fazekasgy@37 387 return false;
fazekasgy@37 388 }
fazekasgy@37 389
fazekasgy@37 390 /// string and objects that support .__str__()
fazekasgy@37 391 /// TODO: check unicode objects
fazekasgy@37 392 std::string
fazekasgy@37 393 PyTypeInterface::PyValue_To_String(PyObject* pyValue) const
fazekasgy@37 394 {
fazekasgy@37 395 // convert string
fazekasgy@37 396 if (PyString_Check(pyValue))
fazekasgy@37 397 {
fazekasgy@37 398 char *cstr = PyString_AS_STRING(pyValue);
fazekasgy@37 399 if (!cstr)
fazekasgy@37 400 {
fazekasgy@37 401 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 402 setValueError("Error while converting string object.",m_strict);
fazekasgy@37 403 return std::string();
fazekasgy@37 404 }
fazekasgy@37 405 return std::string(cstr);
fazekasgy@37 406 }
fazekasgy@37 407 // TODO: deal with unicode here (argh!)
fazekasgy@37 408
fazekasgy@37 409 // in strict mode we will not try harder
fazekasgy@37 410 if (m_strict) {
fazekasgy@37 411 setValueError("Strict conversion error: object is not string.",m_strict);
fazekasgy@37 412 return std::string();
fazekasgy@37 413 }
fazekasgy@37 414
fazekasgy@37 415 // accept None as empty string
fazekasgy@37 416 if (pyValue == Py_None) return std::string();
fazekasgy@37 417
fazekasgy@37 418 // convert list or tuple: empties are turned into empty strings conventionally
fazekasgy@37 419 if (PyList_Check(pyValue) || PyTuple_Check(pyValue))
fazekasgy@37 420 {
fazekasgy@37 421 if (!PySequence_Size(pyValue)) return std::string();
fazekasgy@37 422 PyObject* item = PySequence_GetItem(pyValue,0);
fazekasgy@37 423 if (item)
fazekasgy@37 424 {
fazekasgy@37 425 std::string rValue = this->PyValue_To_String(item);
fazekasgy@37 426 if (!m_error) {
fazekasgy@37 427 Py_DECREF(item);
fazekasgy@37 428 return rValue;
fazekasgy@37 429 } else {
fazekasgy@37 430 Py_CLEAR(item);
fazekasgy@37 431 setValueError("Could not convert sequence element to string.",m_strict);
fazekasgy@37 432 return std::string();
fazekasgy@37 433 }
fazekasgy@37 434 }
fazekasgy@37 435 }
fazekasgy@37 436
fazekasgy@37 437 // convert any other object that has .__str__() or .__repr__()
fazekasgy@37 438 PyObject* pyString = PyObject_Str(pyValue);
fazekasgy@37 439 if (pyString && !PyErr_Occurred())
fazekasgy@37 440 {
fazekasgy@37 441 std::string rValue = this->PyValue_To_String(pyString);
fazekasgy@37 442 if (!m_error) {
fazekasgy@37 443 Py_DECREF(pyString);
fazekasgy@37 444 return rValue;
fazekasgy@37 445 } else {
fazekasgy@37 446 Py_CLEAR(pyString);
fazekasgy@37 447 std::string msg = "Object " + this->PyValue_Get_TypeName(pyValue) +" can not be represented as string. ";
fazekasgy@37 448 setValueError (msg,m_strict);
fazekasgy@37 449 return std::string();
fazekasgy@37 450 }
fazekasgy@37 451 }
fazekasgy@37 452
fazekasgy@37 453 // give up
fazekasgy@37 454 PyErr_Print(); PyErr_Clear();
fazekasgy@37 455 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to string is not possible.";
fazekasgy@37 456 setValueError(msg,m_strict);
fazekasgy@37 457 #ifdef _DEBUG
fazekasgy@37 458 cerr << "PyTypeInterface::PyValue_To_String failed. " << msg << endl;
fazekasgy@37 459 #endif
fazekasgy@37 460 return std::string();
fazekasgy@37 461 }
fazekasgy@37 462
fazekasgy@37 463 /* C Values to Py Values */
fazekasgy@37 464
fazekasgy@37 465
fazekasgy@37 466 PyObject*
fazekasgy@37 467 PyTypeInterface::PyValue_From_CValue(const char* cValue) const
fazekasgy@37 468 {
fazekasgy@37 469 // returns new reference
fazekasgy@37 470 #ifdef _DEBUG
fazekasgy@37 471 if (!cValue) {
fazekasgy@37 472 std::string msg = "PyTypeInterface::PyValue_From_CValue: Null pointer encountered while converting from const char* .";
fazekasgy@37 473 cerr << msg << endl;
fazekasgy@37 474 setValueError(msg,m_strict);
fazekasgy@37 475 return NULL;
fazekasgy@37 476 }
fazekasgy@37 477 #endif
fazekasgy@37 478 PyObject *pyValue = PyString_FromString(cValue);
fazekasgy@37 479 if (!pyValue)
fazekasgy@37 480 {
fazekasgy@37 481 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 482 setValueError("Error while converting from char* or string.",m_strict);
fazekasgy@37 483 #ifdef _DEBUG
fazekasgy@37 484 cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from const char*" << endl;
fazekasgy@37 485 #endif
fazekasgy@37 486 return NULL;
fazekasgy@37 487 }
fazekasgy@37 488 return pyValue;
fazekasgy@37 489 }
fazekasgy@37 490
fazekasgy@37 491 PyObject*
fazekasgy@37 492 PyTypeInterface::PyValue_From_CValue(size_t cValue) const
fazekasgy@37 493 {
fazekasgy@37 494 // returns new reference
fazekasgy@37 495 PyObject *pyValue = PyInt_FromSsize_t((Py_ssize_t)cValue);
fazekasgy@37 496 if (!pyValue)
fazekasgy@37 497 {
fazekasgy@37 498 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 499 setValueError("Error while converting from size_t.",m_strict);
fazekasgy@37 500 #ifdef _DEBUG
fazekasgy@37 501 cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from size_t" << endl;
fazekasgy@37 502 #endif
fazekasgy@37 503 return NULL;
fazekasgy@37 504 }
fazekasgy@37 505 return pyValue;
fazekasgy@37 506 }
fazekasgy@37 507
fazekasgy@37 508 PyObject*
fazekasgy@37 509 PyTypeInterface::PyValue_From_CValue(double cValue) const
fazekasgy@37 510 {
fazekasgy@37 511 // returns new reference
fazekasgy@37 512 PyObject *pyValue = PyFloat_FromDouble(cValue);
fazekasgy@37 513 if (!pyValue)
fazekasgy@37 514 {
fazekasgy@37 515 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 516 setValueError("Error while converting from float or double.",m_strict);
fazekasgy@37 517 #ifdef _DEBUG
fazekasgy@37 518 cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from float or double" << endl;
fazekasgy@37 519 #endif
fazekasgy@37 520 return NULL;
fazekasgy@37 521 }
fazekasgy@37 522 return pyValue;
fazekasgy@37 523 }
fazekasgy@37 524
fazekasgy@37 525 PyObject*
fazekasgy@37 526 PyTypeInterface::PyValue_From_CValue(bool cValue) const
fazekasgy@37 527 {
fazekasgy@37 528 // returns new reference
fazekasgy@37 529 PyObject *pyValue = PyBool_FromLong((long)cValue);
fazekasgy@37 530 if (!pyValue)
fazekasgy@37 531 {
fazekasgy@37 532 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 533 setValueError("Error while converting from bool.",m_strict);
fazekasgy@37 534 #ifdef _DEBUG
fazekasgy@37 535 cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from bool" << endl;
fazekasgy@37 536 #endif
fazekasgy@37 537 return NULL;
fazekasgy@37 538 }
fazekasgy@37 539 return pyValue;
fazekasgy@37 540 }
fazekasgy@37 541
fazekasgy@37 542
fazekasgy@37 543 /* Sequence Types to C++ Types */
fazekasgy@37 544
fazekasgy@37 545 //convert Python list to C++ vector of strings
fazekasgy@37 546 std::vector<std::string>
fazekasgy@37 547 PyTypeInterface::PyValue_To_StringVector (PyObject *pyList) const
fazekasgy@37 548 {
fazekasgy@37 549
fazekasgy@37 550 std::vector<std::string> Output;
fazekasgy@37 551 std::string ListElement;
fazekasgy@37 552 PyObject *pyString = NULL;
fazekasgy@37 553
fazekasgy@37 554 if (PyList_Check(pyList)) {
fazekasgy@37 555
fazekasgy@37 556 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
fazekasgy@37 557 //Get next list item (Borrowed Reference)
fazekasgy@37 558 pyString = PyList_GET_ITEM(pyList,i);
fazekasgy@37 559 ListElement = (string) PyString_AsString(PyObject_Str(pyString));
fazekasgy@37 560 Output.push_back(ListElement);
fazekasgy@37 561 }
fazekasgy@37 562 return Output;
fazekasgy@37 563 }
fazekasgy@51 564
fazekasgy@51 565 // #ifdef _DEBUG
fazekasgy@51 566 // cerr << "PyTypeInterface::PyValue_To_StringVector: Warning: Value is not list of strings." << endl;
fazekasgy@51 567 // #endif
fazekasgy@37 568
fazekasgy@37 569 /// Assume a single value that can be casted as string
fazekasgy@37 570 /// this allows to write e.g. Feature.label = 5.2 instead of ['5.2']
fazekasgy@37 571 Output.push_back(PyValue_To_String(pyList));
fazekasgy@37 572 if (m_error) {
fazekasgy@37 573 std::string msg = "Value is not list of strings nor can be casted as string. ";
fazekasgy@37 574 setValueError(msg,m_strict);
fazekasgy@37 575 #ifdef _DEBUG
fazekasgy@37 576 cerr << "PyTypeInterface::PyValue_To_StringVector failed. " << msg << endl;
fazekasgy@37 577 #endif
fazekasgy@37 578 }
fazekasgy@37 579 return Output;
fazekasgy@37 580 }
fazekasgy@37 581
fazekasgy@37 582 //convert PyFeature.value (typically a list or numpy array) to C++ vector of floats
fazekasgy@37 583 std::vector<float>
fazekasgy@37 584 PyTypeInterface::PyValue_To_FloatVector (PyObject *pyValue) const
fazekasgy@37 585 {
fazekasgy@37 586
fazekasgy@37 587 #ifdef HAVE_NUMPY
fazekasgy@51 588 if (m_numpyInstalled)
fazekasgy@51 589 {
fazekasgy@37 590 // there are four types of values we may receive from a numpy process:
fazekasgy@37 591 // * a python scalar,
fazekasgy@37 592 // * an array scalar, (e.g. numpy.float32)
fazekasgy@37 593 // * an array with nd = 0 (0D array)
fazekasgy@37 594 // * an array with nd > 0
fazekasgy@37 595
fazekasgy@37 596 /// check for scalars
fazekasgy@37 597 if (PyArray_CheckScalar(pyValue) || PyFloat_Check(pyValue)) {
fazekasgy@37 598
fazekasgy@37 599 std::vector<float> Output;
fazekasgy@37 600
fazekasgy@37 601 // we rely on the behaviour the scalars are either floats
fazekasgy@37 602 // or support the number protocol
fazekasgy@37 603 // TODO: a potential optimisation is to handle them directly
fazekasgy@37 604 Output.push_back(PyValue_To_Float(pyValue));
fazekasgy@37 605 return Output;
fazekasgy@37 606 }
fazekasgy@37 607
fazekasgy@37 608 /// numpy array
fazekasgy@37 609 if (PyArray_CheckExact(pyValue))
fazekasgy@37 610 return PyArray_To_FloatVector(pyValue);
fazekasgy@51 611 }
fazekasgy@37 612 #endif
fazekasgy@37 613
fazekasgy@37 614 /// python list of floats (backward compatible)
fazekasgy@37 615 if (PyList_Check(pyValue)) {
fazekasgy@37 616 return PyList_To_FloatVector(pyValue);
fazekasgy@37 617 }
fazekasgy@37 618
fazekasgy@37 619 std::vector<float> Output;
fazekasgy@37 620
fazekasgy@37 621 /// finally assume a single value supporting the number protocol
fazekasgy@37 622 /// this allows to write e.g. Feature.values = 5 instead of [5.00]
fazekasgy@37 623 Output.push_back(PyValue_To_Float(pyValue));
fazekasgy@37 624 if (m_error) {
fazekasgy@37 625 std::string msg = "Value is not list or array of floats nor can be casted as float. ";
fazekasgy@37 626 setValueError(msg,m_strict);
fazekasgy@37 627 #ifdef _DEBUG
fazekasgy@51 628 cerr << "PyTypeInterface::PyValue_To_FloatVector failed. " << msg << endl;
fazekasgy@37 629 #endif
fazekasgy@37 630 }
fazekasgy@37 631 return Output;
fazekasgy@37 632 }
fazekasgy@37 633
fazekasgy@37 634 //convert a list of python floats
fazekasgy@37 635 std::vector<float>
fazekasgy@37 636 PyTypeInterface::PyList_To_FloatVector (PyObject *inputList) const
fazekasgy@37 637 {
fazekasgy@37 638 std::vector<float> Output;
fazekasgy@37 639
fazekasgy@37 640 #ifdef _DEBUG
fazekasgy@37 641 // This is a low level function normally called from
fazekasgy@37 642 // PyValue_To_FloatVector(). Checking for list is not required.
fazekasgy@37 643 if (!PyList_Check(inputList)) {
fazekasgy@37 644 std::string msg = "Value is not list.";
fazekasgy@37 645 setValueError(msg,true);
fazekasgy@37 646 cerr << "PyTypeInterface::PyList_To_FloatVector failed. " << msg << endl;
fazekasgy@37 647 return Output;
fazekasgy@37 648 }
fazekasgy@37 649 #endif
fazekasgy@37 650
fazekasgy@37 651 float ListElement;
fazekasgy@37 652 PyObject *pyFloat = NULL;
fazekasgy@37 653 PyObject **pyObjectArray = PySequence_Fast_ITEMS(inputList);
fazekasgy@37 654
fazekasgy@37 655 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
fazekasgy@37 656
fazekasgy@37 657 // pyFloat = PyList_GET_ITEM(inputList,i);
fazekasgy@37 658 pyFloat = pyObjectArray[i];
fazekasgy@37 659
fazekasgy@37 660 #ifdef _DEBUG
fazekasgy@37 661 if (!pyFloat) {
fazekasgy@37 662 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 663 cerr << "PyTypeInterface::PyList_To_FloatVector: Could not obtain list element: "
fazekasgy@37 664 << i << " PyList_GetItem returned NULL! Skipping value." << endl;
fazekasgy@37 665 continue;
fazekasgy@37 666 }
fazekasgy@37 667 #endif
fazekasgy@37 668
fazekasgy@37 669 // ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
fazekasgy@37 670 ListElement = PyValue_To_Float(pyFloat);
fazekasgy@37 671
fazekasgy@37 672
fazekasgy@37 673 #ifdef _DEBUG_VALUES
fazekasgy@37 674 cerr << "value: " << ListElement << endl;
fazekasgy@37 675 #endif
fazekasgy@37 676 Output.push_back(ListElement);
fazekasgy@37 677 }
fazekasgy@37 678 return Output;
fazekasgy@37 679 }
fazekasgy@37 680
fazekasgy@51 681 // if numpy is not installed this will not be called,
fazekasgy@51 682 // therefor we do not check again
fazekasgy@51 683 #ifdef HAVE_NUMPY
fazekasgy@37 684 std::vector<float>
fazekasgy@37 685 PyTypeInterface::PyArray_To_FloatVector (PyObject *pyValue) const
fazekasgy@37 686 {
fazekasgy@37 687 std::vector<float> Output;
fazekasgy@37 688
fazekasgy@37 689 #ifdef _DEBUG
fazekasgy@37 690 // This is a low level function, normally called from
fazekasgy@37 691 // PyValue_To_FloatVector(). Checking the array here is not required.
fazekasgy@37 692 if (!PyArray_Check(pyValue)) {
fazekasgy@37 693 std::string msg = "Object has no array interface.";
fazekasgy@37 694 setValueError(msg,true);
fazekasgy@37 695 cerr << "PyTypeInterface::PyArray_To_FloatVector failed. " << msg << endl;
fazekasgy@37 696 return Output;
fazekasgy@37 697 }
fazekasgy@37 698 #endif
fazekasgy@37 699
fazekasgy@37 700 PyArrayObject* pyArray = (PyArrayObject*) pyValue;
fazekasgy@37 701 PyArray_Descr* descr = pyArray->descr;
fazekasgy@37 702
fazekasgy@37 703 /// check raw data and descriptor pointers
fazekasgy@37 704 if (pyArray->data == 0 || descr == 0) {
fazekasgy@37 705 std::string msg = "NumPy array with NULL data or descriptor pointer encountered.";
fazekasgy@37 706 setValueError(msg,m_strict);
fazekasgy@37 707 #ifdef _DEBUG
fazekasgy@37 708 cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << endl;
fazekasgy@37 709 #endif
fazekasgy@37 710 return Output;
fazekasgy@37 711 }
fazekasgy@37 712
fazekasgy@37 713 /// check dimensions
fazekasgy@37 714 if (pyArray->nd != 1) {
fazekasgy@37 715 std::string msg = "NumPy array must be a one dimensional vector.";
fazekasgy@37 716 setValueError(msg,m_strict);
fazekasgy@37 717 #ifdef _DEBUG
fazekasgy@37 718 cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << " Dims: " << (int) pyArray->nd << endl;
fazekasgy@37 719 #endif
fazekasgy@37 720 return Output;
fazekasgy@37 721 }
fazekasgy@37 722
fazekasgy@37 723 #ifdef _DEBUG_VALUES
fazekasgy@37 724 cerr << "PyTypeInterface::PyArray_To_FloatVector: Numpy array verified." << endl;
fazekasgy@37 725 #endif
fazekasgy@37 726
fazekasgy@37 727 /// check strides (useful if array is not continuous)
fazekasgy@37 728 size_t strides = *((size_t*) pyArray->strides);
fazekasgy@37 729
fazekasgy@37 730 /// convert the array
fazekasgy@37 731 switch (descr->type_num)
fazekasgy@37 732 {
fazekasgy@37 733 case NPY_FLOAT : // dtype='float32'
fazekasgy@37 734 return PyArray_Convert<float,float>(pyArray->data,pyArray->dimensions[0],strides);
fazekasgy@37 735 case NPY_DOUBLE : // dtype='float64'
fazekasgy@37 736 return PyArray_Convert<float,double>(pyArray->data,pyArray->dimensions[0],strides);
fazekasgy@37 737 case NPY_INT : // dtype='int'
fazekasgy@37 738 return PyArray_Convert<float,int>(pyArray->data,pyArray->dimensions[0],strides);
fazekasgy@37 739 case NPY_LONG : // dtype='long'
fazekasgy@37 740 return PyArray_Convert<float,long>(pyArray->data,pyArray->dimensions[0],strides);
fazekasgy@37 741 default :
fazekasgy@37 742 std::string msg = "Unsupported value type in NumPy array object.";
fazekasgy@37 743 setValueError(msg,m_strict);
fazekasgy@37 744 #ifdef _DEBUG
fazekasgy@37 745 cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << endl;
fazekasgy@37 746 #endif
fazekasgy@37 747 return Output;
fazekasgy@37 748 }
fazekasgy@37 749 }
fazekasgy@37 750 #endif
fazekasgy@37 751
fazekasgy@37 752
fazekasgy@51 753 /// FeatureSet (an integer map of FeatureLists)
fazekasgy@37 754 Vamp::Plugin::FeatureSet
fazekasgy@37 755 PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const
fazekasgy@37 756 {
fazekasgy@37 757 Vamp::Plugin::FeatureSet rFeatureSet;
fazekasgy@37 758
fazekasgy@37 759 /// Convert PyFeatureSet
fazekasgy@37 760 if (PyFeatureSet_CheckExact(pyValue)) {
fazekasgy@37 761
fazekasgy@37 762 Py_ssize_t pyPos = 0;
fazekasgy@37 763 PyObject *pyKey, *pyDictValue; // Borrowed References
fazekasgy@37 764 int key;
fazekasgy@37 765 // bool it_error = false;
fazekasgy@37 766
fazekasgy@37 767 m_error = false;
fazekasgy@37 768 while (PyDict_Next(pyValue, &pyPos, &pyKey, &pyDictValue))
fazekasgy@37 769 {
fazekasgy@37 770 key = (int) PyInt_AS_LONG(pyKey);
fazekasgy@37 771 #ifdef _DEBUG_VALUES
fazekasgy@37 772 cerr << "key: '" << key << "' value: '" << PyValue_To_String(pyDictValue) << "' " << endl;
fazekasgy@37 773 #endif
fazekasgy@37 774 // DictValue -> Vamp::FeatureList
fazekasgy@37 775 PyValue_To_rValue(pyDictValue,rFeatureSet[key]);
fazekasgy@37 776 if (m_error) {
fazekasgy@37 777 // it_error = true;
fazekasgy@37 778 lastError() << " in output number: " << key;
fazekasgy@37 779 }
fazekasgy@37 780 }
fazekasgy@37 781 // if (it_error) m_error = true;
fazekasgy@37 782 if (!m_errorQueue.empty()) {
fazekasgy@37 783 setValueError("Error while converting FeatureSet.",m_strict);
fazekasgy@37 784 }
fazekasgy@37 785 return rFeatureSet;
fazekasgy@37 786 }
fazekasgy@37 787
fazekasgy@37 788 /// Convert Python list (backward compatibility)
fazekasgy@37 789 if (PyList_Check(pyValue)) {
fazekasgy@37 790
fazekasgy@37 791 PyObject *pyFeatureList; // This will be borrowed reference
fazekasgy@37 792
fazekasgy@37 793 //Parse Output List for each element (FeatureSet)
fazekasgy@37 794 m_error = false;
fazekasgy@37 795 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyValue); ++i) {
fazekasgy@37 796 //Get i-th FeatureList (Borrowed Reference)
fazekasgy@37 797 pyFeatureList = PyList_GET_ITEM(pyValue,i);
fazekasgy@37 798 PyValue_To_rValue(pyFeatureList,rFeatureSet[i]);
fazekasgy@37 799 if (m_error) {
fazekasgy@37 800 lastError() << " in output number: " << i;
fazekasgy@37 801 }
fazekasgy@37 802 }
fazekasgy@37 803 if (!m_errorQueue.empty()) m_error = true;
fazekasgy@37 804 return rFeatureSet;
fazekasgy@37 805 }
fazekasgy@37 806
fazekasgy@51 807 /// accept None return values
fazekasgy@37 808 if (pyValue == Py_None) return rFeatureSet;
fazekasgy@37 809
fazekasgy@37 810 /// give up
fazekasgy@37 811 std::string msg = "Unsupported return type. Expected list or vampy.FeatureSet(). ";
fazekasgy@37 812 setValueError(msg,m_strict);
fazekasgy@37 813 #ifdef _DEBUG
fazekasgy@37 814 cerr << "PyTypeInterface::PyValue_To_FeatureSet failed. Error: " << msg << endl;
fazekasgy@37 815 #endif
fazekasgy@37 816 return rFeatureSet;
fazekasgy@37 817 }
fazekasgy@37 818
fazekasgy@37 819 Vamp::RealTime
fazekasgy@37 820 PyTypeInterface::PyValue_To_RealTime(PyObject* pyValue) const
fazekasgy@37 821 {
fazekasgy@37 822 // We accept integer sample counts (for backward compatibility)
fazekasgy@37 823 // or PyRealTime objects and convert them to Vamp::RealTime
fazekasgy@37 824
fazekasgy@37 825 if (PyRealTime_CheckExact(pyValue))
fazekasgy@37 826 {
fazekasgy@37 827 /// just create a copy of the wrapped object
fazekasgy@37 828 return Vamp::RealTime(*PyRealTime_AS_REALTIME(pyValue));
fazekasgy@37 829 }
fazekasgy@37 830
fazekasgy@37 831 // assume integer sample count
fazekasgy@37 832 long sampleCount = PyValue_To_Long(pyValue);
fazekasgy@37 833 if (m_error) {
fazekasgy@37 834 std::string msg = "Unexpected value passed as RealTime.\nMust be vampy.RealTime type or integer sample count.";
fazekasgy@37 835 setValueError(msg,m_strict);
fazekasgy@37 836 #ifdef _DEBUG
fazekasgy@37 837 cerr << "PyTypeInterface::PyValue_To_RealTime failed. " << msg << endl;
fazekasgy@37 838 #endif
fazekasgy@37 839 return Vamp::RealTime();
fazekasgy@37 840 }
fazekasgy@37 841
fazekasgy@37 842 #ifdef _DEBUG_VALUES
fazekasgy@37 843 Vamp::RealTime rt =
fazekasgy@37 844 Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate );
fazekasgy@37 845 cerr << "RealTime: " << (long)sampleCount << ", ->" << rt.toString() << endl;
fazekasgy@37 846 return rt;
fazekasgy@37 847 #else
fazekasgy@37 848 return Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate );
fazekasgy@37 849 #endif
fazekasgy@37 850
fazekasgy@37 851 }
fazekasgy@37 852
fazekasgy@37 853 Vamp::Plugin::OutputDescriptor::SampleType
fazekasgy@37 854 PyTypeInterface::PyValue_To_SampleType(PyObject* pyValue) const
fazekasgy@37 855 {
fazekasgy@37 856 /// convert simulated enum values
fazekasgy@37 857 /// { OneSamplePerStep,FixedSampleRate,VariableSampleRate }
fazekasgy@37 858 if (PyInt_CheckExact(pyValue)) {
fazekasgy@37 859 long lst = PyInt_AS_LONG(pyValue);
fazekasgy@37 860 if (lst<0 || lst>2) {
fazekasgy@37 861 setValueError("Overflow error. SampleType has to be one of { OneSamplePerStep,FixedSampleRate,VariableSampleRate }\n(an integer in the range of 0..2) or a string value naming the type.",m_strict);
fazekasgy@37 862 return Vamp::Plugin::OutputDescriptor::SampleType();
fazekasgy@37 863 }
fazekasgy@37 864 return (Vamp::Plugin::OutputDescriptor::SampleType) lst;
fazekasgy@37 865 }
fazekasgy@37 866
fazekasgy@37 867 /// convert string (backward compatible)
fazekasgy@37 868 if (PyString_CheckExact(pyValue)) {
fazekasgy@37 869 Vamp::Plugin::OutputDescriptor::SampleType st;
fazekasgy@37 870 st = (Vamp::Plugin::OutputDescriptor::SampleType) sampleKeys[PyValue_To_String(pyValue)];
fazekasgy@37 871 if (m_error) {
fazekasgy@37 872 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.";
fazekasgy@37 873 setValueError(msg,m_strict);
fazekasgy@37 874 return Vamp::Plugin::OutputDescriptor::SampleType();
fazekasgy@37 875 }
fazekasgy@37 876 return st;
fazekasgy@37 877 }
fazekasgy@37 878
fazekasgy@37 879 /// give up
fazekasgy@37 880 std::string msg = "Unsupported return type. Expected one of { OneSamplePerStep,FixedSampleRate,VariableSampleRate }\n(an integer in the range of 0..2) or a string value naming the type.";
fazekasgy@37 881 setValueError(msg,m_strict);
fazekasgy@37 882 #ifdef _DEBUG
fazekasgy@37 883 cerr << "PyTypeInterface::PyValue_To_SampleType failed. Error: " << msg << endl;
fazekasgy@37 884 #endif
fazekasgy@37 885 return Vamp::Plugin::OutputDescriptor::SampleType();
fazekasgy@37 886 }
fazekasgy@37 887
fazekasgy@37 888 Vamp::Plugin::InputDomain
fazekasgy@37 889 PyTypeInterface::PyValue_To_InputDomain(PyObject* pyValue) const
fazekasgy@37 890 {
fazekasgy@37 891 /// convert simulated enum values { TimeDomain,FrequencyDomain }
fazekasgy@37 892 if (PyInt_CheckExact(pyValue)) {
fazekasgy@37 893 long lst = PyInt_AS_LONG(pyValue);
fazekasgy@37 894 if (lst!=0 && lst!=1) {
fazekasgy@37 895 setValueError("Overflow error. InputDomain has to be one of { TimeDomain,FrequencyDomain }\n(an integer in the range of 0..1) or a string value naming the type.",m_strict);
fazekasgy@37 896 return Vamp::Plugin::InputDomain();
fazekasgy@37 897 }
fazekasgy@37 898 return (Vamp::Plugin::InputDomain) lst;
fazekasgy@37 899 }
fazekasgy@37 900
fazekasgy@37 901 /// convert string (backward compatible)
fazekasgy@37 902 if (PyString_CheckExact(pyValue)) {
fazekasgy@37 903 Vamp::Plugin::InputDomain id;
fazekasgy@37 904 id = (PyValue_To_String(pyValue) == "FrequencyDomain")?Vamp::Plugin::FrequencyDomain:Vamp::Plugin::TimeDomain;
fazekasgy@37 905 if (m_error)
fazekasgy@37 906 {
fazekasgy@37 907 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.";
fazekasgy@37 908 setValueError(msg,m_strict);
fazekasgy@37 909 return Vamp::Plugin::InputDomain();
fazekasgy@37 910 }
fazekasgy@37 911 return id;
fazekasgy@37 912 }
fazekasgy@37 913
fazekasgy@37 914 /// give up
fazekasgy@37 915 std::string msg = "Unsupported return type. Expected one of { TimeDomain,FrequencyDomain }\n(an integer in the range of 0..1) or a string value naming the type.";
fazekasgy@37 916 setValueError(msg,m_strict);
fazekasgy@37 917 #ifdef _DEBUG
fazekasgy@37 918 cerr << "PyTypeInterface::PyValue_To_InputDomain failed. Error: " << msg << endl;
fazekasgy@37 919 #endif
fazekasgy@37 920 return Vamp::Plugin::InputDomain();
fazekasgy@37 921 }
fazekasgy@37 922
fazekasgy@37 923
fazekasgy@37 924 /// OutputDescriptor
fazekasgy@37 925 void
fazekasgy@37 926 PyTypeInterface::SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const
fazekasgy@37 927 {
fazekasgy@37 928 switch (outKeys[key])
fazekasgy@37 929 {
fazekasgy@37 930 case o::not_found:
fazekasgy@37 931 setValueError("Unknown key in Vamp OutputDescriptor",m_strict);
fazekasgy@37 932 cerr << "Unknown key in Vamp OutputDescriptor: " << key << endl;
fazekasgy@37 933 break;
fazekasgy@37 934 case o::identifier:
fazekasgy@37 935 _convert(pyValue,od.identifier);
fazekasgy@37 936 break;
fazekasgy@37 937 case o::name:
fazekasgy@37 938 _convert(pyValue,od.name);
fazekasgy@37 939 break;
fazekasgy@37 940 case o::description:
fazekasgy@37 941 _convert(pyValue,od.description);
fazekasgy@37 942 break;
fazekasgy@37 943 case o::unit:
fazekasgy@37 944 _convert(pyValue,od.unit);
fazekasgy@37 945 break;
fazekasgy@37 946 case o::hasFixedBinCount:
fazekasgy@37 947 _convert(pyValue,od.hasFixedBinCount);
fazekasgy@37 948 break;
fazekasgy@37 949 case o::binCount:
fazekasgy@37 950 _convert(pyValue,od.binCount);
fazekasgy@37 951 break;
fazekasgy@37 952 case o::binNames:
fazekasgy@37 953 _convert(pyValue,od.binNames);
fazekasgy@37 954 break;
fazekasgy@37 955 case o::hasKnownExtents:
fazekasgy@37 956 _convert(pyValue,od.hasKnownExtents);
fazekasgy@37 957 break;
fazekasgy@37 958 case o::minValue:
fazekasgy@37 959 _convert(pyValue,od.minValue);
fazekasgy@37 960 break;
fazekasgy@37 961 case o::maxValue:
fazekasgy@37 962 _convert(pyValue,od.maxValue);
fazekasgy@37 963 break;
fazekasgy@37 964 case o::isQuantized:
fazekasgy@37 965 _convert(pyValue,od.isQuantized);
fazekasgy@37 966 break;
fazekasgy@37 967 case o::quantizeStep:
fazekasgy@37 968 _convert(pyValue,od.quantizeStep);
fazekasgy@37 969 break;
fazekasgy@37 970 case o::sampleType:
fazekasgy@37 971 _convert(pyValue,od.sampleType);
fazekasgy@37 972 break;
fazekasgy@37 973 case o::sampleRate:
fazekasgy@37 974 _convert(pyValue,od.sampleRate);
fazekasgy@37 975 break;
fazekasgy@37 976 case o::hasDuration:
fazekasgy@37 977 _convert(pyValue,od.hasDuration);
fazekasgy@37 978 break;
fazekasgy@37 979 default:
fazekasgy@37 980 setValueError("Unknown key in Vamp OutputDescriptor",m_strict);
fazekasgy@37 981 cerr << "Invalid key in Vamp OutputDescriptor: " << key << endl;
fazekasgy@37 982 }
fazekasgy@37 983 }
fazekasgy@37 984
fazekasgy@37 985 /// ParameterDescriptor
fazekasgy@37 986 void
fazekasgy@37 987 PyTypeInterface::SetValue(Vamp::Plugin::ParameterDescriptor& pd, std::string& key, PyObject* pyValue) const
fazekasgy@37 988 {
fazekasgy@37 989 switch (parmKeys[key])
fazekasgy@37 990 {
fazekasgy@37 991 case p::not_found :
fazekasgy@37 992 setValueError("Unknown key in Vamp ParameterDescriptor",m_strict);
fazekasgy@37 993 cerr << "Unknown key in Vamp ParameterDescriptor: " << key << endl;
fazekasgy@37 994 break;
fazekasgy@37 995 case p::identifier:
fazekasgy@37 996 _convert(pyValue,pd.identifier);
fazekasgy@37 997 break;
fazekasgy@37 998 case p::name:
fazekasgy@37 999 _convert(pyValue,pd.name);
fazekasgy@37 1000 break;
fazekasgy@37 1001 case p::description:
fazekasgy@37 1002 _convert(pyValue,pd.description);
fazekasgy@37 1003 break;
fazekasgy@37 1004 case p::unit:
fazekasgy@37 1005 _convert(pyValue,pd.unit);
fazekasgy@37 1006 break;
fazekasgy@37 1007 case p::minValue:
fazekasgy@37 1008 _convert(pyValue,pd.minValue);
fazekasgy@37 1009 break;
fazekasgy@37 1010 case p::maxValue:
fazekasgy@37 1011 _convert(pyValue,pd.maxValue);
fazekasgy@37 1012 break;
fazekasgy@37 1013 case p::defaultValue:
fazekasgy@37 1014 _convert(pyValue,pd.defaultValue);
fazekasgy@37 1015 break;
fazekasgy@37 1016 case p::isQuantized:
fazekasgy@37 1017 _convert(pyValue,pd.isQuantized);
fazekasgy@37 1018 break;
fazekasgy@37 1019 case p::quantizeStep:
fazekasgy@37 1020 _convert(pyValue,pd.quantizeStep);
fazekasgy@37 1021 break;
fazekasgy@37 1022 default :
fazekasgy@37 1023 setValueError("Unknown key in Vamp ParameterDescriptor",m_strict);
fazekasgy@37 1024 cerr << "Invalid key in Vamp ParameterDescriptor: " << key << endl;
fazekasgy@37 1025 }
fazekasgy@37 1026 }
fazekasgy@37 1027
fazekasgy@37 1028 /// Feature (it's like a Descriptor)
fazekasgy@37 1029 bool
fazekasgy@37 1030 PyTypeInterface::SetValue(Vamp::Plugin::Feature& feature, std::string& key, PyObject* pyValue) const
fazekasgy@37 1031 {
fazekasgy@37 1032 bool found = true;
fazekasgy@37 1033 switch (ffKeys[key])
fazekasgy@37 1034 {
fazekasgy@37 1035 case unknown :
fazekasgy@37 1036 setValueError("Unknown key in Vamp Feature",m_strict);
fazekasgy@37 1037 cerr << "Unknown key in Vamp Feature: " << key << endl;
fazekasgy@37 1038 found = false;
fazekasgy@37 1039 break;
fazekasgy@37 1040 case hasTimestamp:
fazekasgy@37 1041 _convert(pyValue,feature.hasTimestamp);
fazekasgy@37 1042 break;
fazekasgy@37 1043 case timestamp:
fazekasgy@37 1044 _convert(pyValue,feature.timestamp);
fazekasgy@37 1045 break;
fazekasgy@37 1046 case hasDuration:
fazekasgy@37 1047 _convert(pyValue,feature.hasDuration);
fazekasgy@37 1048 break;
fazekasgy@37 1049 case duration:
fazekasgy@37 1050 _convert(pyValue,feature.duration);
fazekasgy@37 1051 break;
fazekasgy@37 1052 case values:
fazekasgy@37 1053 _convert(pyValue,feature.values);
fazekasgy@37 1054 break;
fazekasgy@37 1055 case label:
fazekasgy@37 1056 _convert(pyValue,feature.label);
fazekasgy@37 1057 break;
fazekasgy@37 1058 default:
fazekasgy@37 1059 setValueError("Unknown key in Vamp Feature",m_strict);
fazekasgy@37 1060 found = false;
fazekasgy@37 1061 }
fazekasgy@37 1062 return found;
fazekasgy@37 1063 }
fazekasgy@37 1064
fazekasgy@37 1065
fazekasgy@37 1066 /* Error handling */
fazekasgy@37 1067
fazekasgy@37 1068 void
fazekasgy@37 1069 PyTypeInterface::setValueError (std::string message, bool strict) const
fazekasgy@37 1070 {
fazekasgy@37 1071 m_error = true;
fazekasgy@37 1072 m_errorQueue.push(ValueError(message,strict));
fazekasgy@37 1073 }
fazekasgy@37 1074
fazekasgy@37 1075 /// return a reference to the last error or creates a new one.
fazekasgy@37 1076 PyTypeInterface::ValueError&
fazekasgy@37 1077 PyTypeInterface::lastError() const
fazekasgy@37 1078 {
fazekasgy@37 1079 m_error = false;
fazekasgy@37 1080 if (!m_errorQueue.empty()) return m_errorQueue.back();
fazekasgy@37 1081 else {
fazekasgy@37 1082 m_errorQueue.push(ValueError("Type conversion error.",m_strict));
fazekasgy@37 1083 return m_errorQueue.back();
fazekasgy@37 1084 }
fazekasgy@37 1085 }
fazekasgy@37 1086
fazekasgy@37 1087 /// helper function to iterate over the error message queue:
fazekasgy@37 1088 /// pops the oldest item
fazekasgy@37 1089 PyTypeInterface::ValueError
fazekasgy@37 1090 PyTypeInterface::getError() const
fazekasgy@37 1091 {
fazekasgy@37 1092 if (!m_errorQueue.empty()) {
fazekasgy@37 1093 PyTypeInterface::ValueError e = m_errorQueue.front();
fazekasgy@37 1094 m_errorQueue.pop();
fazekasgy@37 1095 if (m_errorQueue.empty()) m_error = false;
fazekasgy@37 1096 return e;
fazekasgy@37 1097 }
fazekasgy@37 1098 else {
fazekasgy@37 1099 m_error = false;
fazekasgy@37 1100 return PyTypeInterface::ValueError();
fazekasgy@37 1101 }
fazekasgy@37 1102 }
fazekasgy@37 1103
fazekasgy@37 1104 /* Utilities */
fazekasgy@37 1105
fazekasgy@37 1106 /// get the type name of an object
fazekasgy@37 1107 std::string
fazekasgy@37 1108 PyTypeInterface::PyValue_Get_TypeName(PyObject* pyValue) const
fazekasgy@37 1109 {
fazekasgy@37 1110 PyObject *pyType = PyObject_Type(pyValue);
fazekasgy@37 1111 if (!pyType)
fazekasgy@37 1112 {
fazekasgy@37 1113 cerr << "Warning: Object type name could not be found." << endl;
fazekasgy@37 1114 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 1115 return std::string ("< unknown type >");
fazekasgy@37 1116 }
fazekasgy@37 1117 PyObject *pyString = PyObject_Str(pyType);
fazekasgy@37 1118 if (!pyString)
fazekasgy@37 1119 {
fazekasgy@37 1120 cerr << "Warning: Object type name could not be found." << endl;
fazekasgy@37 1121 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 1122 Py_CLEAR(pyType);
fazekasgy@37 1123 return std::string ("< unknown type >");
fazekasgy@37 1124 }
fazekasgy@37 1125 char *cstr = PyString_AS_STRING(pyString);
fazekasgy@37 1126 if (!cstr)
fazekasgy@37 1127 {
fazekasgy@37 1128 cerr << "Warning: Object type name could not be found." << endl;
fazekasgy@37 1129 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 1130 Py_DECREF(pyType);
fazekasgy@37 1131 Py_CLEAR(pyString);
fazekasgy@37 1132 return std::string("< unknown type >");
fazekasgy@37 1133 }
fazekasgy@37 1134 Py_DECREF(pyType);
fazekasgy@37 1135 Py_DECREF(pyString);
fazekasgy@37 1136 return std::string(cstr);
fazekasgy@37 1137
fazekasgy@37 1138 }
fazekasgy@37 1139
fazekasgy@37 1140 bool
fazekasgy@37 1141 PyTypeInterface::initMaps() const
fazekasgy@37 1142 {
fazekasgy@37 1143
fazekasgy@37 1144 if (isMapInitialised) return true;
fazekasgy@37 1145
fazekasgy@37 1146 outKeys["identifier"] = o::identifier;
fazekasgy@37 1147 outKeys["name"] = o::name;
fazekasgy@37 1148 outKeys["description"] = o::description;
fazekasgy@37 1149 outKeys["unit"] = o::unit;
fazekasgy@37 1150 outKeys["hasFixedBinCount"] = o::hasFixedBinCount;
fazekasgy@37 1151 outKeys["binCount"] = o::binCount;
fazekasgy@37 1152 outKeys["binNames"] = o::binNames;
fazekasgy@37 1153 outKeys["hasKnownExtents"] = o::hasKnownExtents;
fazekasgy@37 1154 outKeys["minValue"] = o::minValue;
fazekasgy@37 1155 outKeys["maxValue"] = o::maxValue;
fazekasgy@37 1156 outKeys["isQuantized"] = o::isQuantized;
fazekasgy@37 1157 outKeys["quantizeStep"] = o::quantizeStep;
fazekasgy@37 1158 outKeys["sampleType"] = o::sampleType;
fazekasgy@37 1159 outKeys["sampleRate"] = o::sampleRate;
fazekasgy@37 1160 outKeys["hasDuration"] = o::hasDuration;
fazekasgy@37 1161
fazekasgy@37 1162 sampleKeys["OneSamplePerStep"] = OneSamplePerStep;
fazekasgy@37 1163 sampleKeys["FixedSampleRate"] = FixedSampleRate;
fazekasgy@37 1164 sampleKeys["VariableSampleRate"] = VariableSampleRate;
fazekasgy@37 1165
fazekasgy@37 1166 ffKeys["hasTimestamp"] = hasTimestamp;
fazekasgy@37 1167 ffKeys["timestamp"] = timestamp; // this is the correct one
fazekasgy@37 1168 ffKeys["timeStamp"] = timestamp; // backward compatible
fazekasgy@37 1169 ffKeys["hasDuration"] = hasDuration;
fazekasgy@37 1170 ffKeys["duration"] = duration;
fazekasgy@37 1171 ffKeys["values"] = values;
fazekasgy@37 1172 ffKeys["label"] = label;
fazekasgy@37 1173
fazekasgy@37 1174 parmKeys["identifier"] = p::identifier;
fazekasgy@37 1175 parmKeys["name"] = p::name;
fazekasgy@37 1176 parmKeys["description"] = p::description;
fazekasgy@37 1177 parmKeys["unit"] = p::unit;
fazekasgy@37 1178 parmKeys["minValue"] = p::minValue;
fazekasgy@37 1179 parmKeys["maxValue"] = p::maxValue;
fazekasgy@37 1180 parmKeys["defaultValue"] = p::defaultValue;
fazekasgy@37 1181 parmKeys["isQuantized"] = p::isQuantized;
fazekasgy@37 1182 parmKeys["quantizeStep"] = p::quantizeStep;
fazekasgy@37 1183
fazekasgy@37 1184 isMapInitialised = true;
fazekasgy@37 1185 return true;
fazekasgy@37 1186 }