annotate PyTypeInterface.cpp @ 70:6c755f3e1173

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