annotate PyTypeInterface.cpp @ 92:a6718f9fe942

If a module appears to redefine one of our own types, refuse to load it. Also clear out the class dict for all refused modules now, so that we don't get stale names on the next scan due to not having cleared the module on unload
author Chris Cannam
date Mon, 14 Jan 2019 16:19:44 +0000
parents 6c755f3e1173
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 }