annotate PyTypeInterface.cpp @ 46:af9c4cee95a8

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