fazekasgy@37: /* fazekasgy@37: fazekasgy@37: * Vampy : This plugin is a wrapper around the Vamp plugin API. fazekasgy@37: * It allows for writing Vamp plugins in Python. fazekasgy@37: fazekasgy@37: * Centre for Digital Music, Queen Mary University of London. fazekasgy@37: * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources fazekasgy@37: * for licence information.) fazekasgy@37: fazekasgy@37: */ fazekasgy@37: fazekasgy@37: #include fazekasgy@37: fazekasgy@37: #ifdef HAVE_NUMPY fazekasgy@37: #define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API fazekasgy@37: #define NO_IMPORT_ARRAY fazekasgy@37: #include "numpy/arrayobject.h" fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: #include "PyTypeInterface.h" fazekasgy@37: #include "PyRealTime.h" fazekasgy@37: #include "PyExtensionModule.h" fazekasgy@37: #include fazekasgy@37: #include fazekasgy@37: #include fazekasgy@37: #ifndef SIZE_T_MAX fazekasgy@37: #define SIZE_T_MAX ((size_t) -1) fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: using std::string; fazekasgy@37: using std::vector; fazekasgy@37: using std::cerr; fazekasgy@37: using std::endl; fazekasgy@37: using std::map; fazekasgy@37: fazekasgy@37: static std::map outKeys; fazekasgy@37: static std::map parmKeys; fazekasgy@37: static std::map sampleKeys; fazekasgy@37: static std::map ffKeys; fazekasgy@37: static bool isMapInitialised = false; fazekasgy@37: fazekasgy@37: /* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS fazekasgy@37: (EXCEPT FOR TEMPORARY PYTHON OBJECTS)! */ fazekasgy@37: fazekasgy@37: PyTypeInterface::PyTypeInterface() : fazekasgy@37: m_strict(false), fazekasgy@37: m_error(false), fazekasgy@51: m_numpyInstalled(false), fazekasgy@37: error(m_error) // const public reference for easy access fazekasgy@37: { fazekasgy@37: } fazekasgy@37: fazekasgy@37: PyTypeInterface::~PyTypeInterface() fazekasgy@37: { fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// floating point numbers (TODO: check numpy.float128) fazekasgy@37: float fazekasgy@37: PyTypeInterface::PyValue_To_Float(PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: // convert float fazekasgy@37: if (pyValue && PyFloat_Check(pyValue)) fazekasgy@37: //TODO: check for limits here (same on most systems) fazekasgy@37: return (float) PyFloat_AS_DOUBLE(pyValue); fazekasgy@37: fazekasgy@37: if (pyValue == NULL) fazekasgy@37: { fazekasgy@51: setValueError("Error while converting object " + PyValue_Get_TypeName(pyValue) + " to float. ",m_strict); fazekasgy@37: return 0.0; fazekasgy@37: } fazekasgy@37: fazekasgy@37: // in strict mode we will not try harder fazekasgy@37: if (m_strict) { fazekasgy@51: setValueError("Strict conversion error: object" + PyValue_Get_TypeName(pyValue) +" is not float.",m_strict); fazekasgy@37: return 0.0; fazekasgy@37: } fazekasgy@37: fazekasgy@37: // convert other objects supporting the number protocol fazekasgy@37: if (PyNumber_Check(pyValue)) fazekasgy@37: { fazekasgy@37: PyObject* pyFloat = PyNumber_Float(pyValue); // new ref fazekasgy@37: if (!pyFloat) fazekasgy@37: { fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: setValueError("Error while converting " + PyValue_Get_TypeName(pyValue) + " object to float.",m_strict); fazekasgy@37: return 0.0; fazekasgy@37: } fazekasgy@37: float rValue = (float) PyFloat_AS_DOUBLE(pyFloat); fazekasgy@37: Py_DECREF(pyFloat); fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: /* fazekasgy@37: // convert other objects supporting the number protocol fazekasgy@37: if (PyNumber_Check(pyValue)) fazekasgy@37: { fazekasgy@37: // PEP353: Py_ssize_t is size_t but signed ! fazekasgy@37: // This will work up to numpy.float64 fazekasgy@37: Py_ssize_t rValue = PyNumber_AsSsize_t(pyValue,NULL); fazekasgy@37: if (PyErr_Occurred()) fazekasgy@37: { fazekasgy@37: PyErr_Print(); PyErr_Clear(); fazekasgy@37: setValueError("Error while converting integer object.",m_strict); fazekasgy@37: return 0.0; fazekasgy@37: } fazekasgy@37: if (rValue > (Py_ssize_t)FLT_MAX || rValue < (Py_ssize_t)FLT_MIN) fazekasgy@37: { fazekasgy@37: setValueError("Overflow error. Object can not be converted to float.",m_strict); fazekasgy@37: return 0.0; fazekasgy@37: } fazekasgy@37: return (float) rValue; fazekasgy@37: } fazekasgy@37: */ fazekasgy@37: // convert string fazekasgy@37: if (PyString_Check(pyValue)) fazekasgy@37: { fazekasgy@37: PyObject* pyFloat = PyFloat_FromString(pyValue,NULL); fazekasgy@37: if (!pyFloat) fazekasgy@37: { fazekasgy@37: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@37: setValueError("String value can not be converted to float.",m_strict); fazekasgy@37: return 0.0; fazekasgy@37: } fazekasgy@37: float rValue = (float) PyFloat_AS_DOUBLE(pyFloat); fazekasgy@37: if (PyErr_Occurred()) fazekasgy@37: { fazekasgy@37: PyErr_Print(); PyErr_Clear(); fazekasgy@37: Py_CLEAR(pyFloat); fazekasgy@37: setValueError("Error while converting float object.",m_strict); fazekasgy@37: return 0.0; fazekasgy@37: } fazekasgy@37: Py_DECREF(pyFloat); fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: // convert the first element of any iterable sequence (for convenience and backwards compatibility) cannam@41: if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) fazekasgy@37: { fazekasgy@37: PyObject* item = PySequence_GetItem(pyValue,0); fazekasgy@37: if (item) fazekasgy@37: { fazekasgy@37: float rValue = this->PyValue_To_Float(item); fazekasgy@37: if (!m_error) { fazekasgy@37: Py_DECREF(item); fazekasgy@37: return rValue; fazekasgy@37: } else { fazekasgy@37: Py_CLEAR(item); fazekasgy@37: std::string msg = "Could not convert sequence element to float. "; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: return 0.0; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: // give up fazekasgy@37: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@37: std::string msg = "Conversion from " + PyValue_Get_TypeName(pyValue) + " to float is not possible."; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_To_Float failed. " << msg << endl; fazekasgy@37: #endif fazekasgy@37: return 0.0; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// size_t (unsigned integer types) fazekasgy@37: size_t fazekasgy@37: PyTypeInterface::PyValue_To_Size_t(PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: // convert objects supporting the number protocol fazekasgy@37: if (PyNumber_Check(pyValue)) fazekasgy@37: { fazekasgy@37: if (m_strict && !PyInt_Check(pyValue) && !PyLong_Check(pyValue)) fazekasgy@37: setValueError("Strict conversion error: object is not integer type.",m_strict); fazekasgy@37: // Note: this function handles Bool,Int,Long,Float fazekasgy@37: // speed is not critical in the use of this type by Vamp fazekasgy@37: // PEP353: Py_ssize_t is size_t but signed ! fazekasgy@37: Py_ssize_t rValue = PyInt_AsSsize_t(pyValue); fazekasgy@37: if (PyErr_Occurred()) fazekasgy@37: { fazekasgy@37: PyErr_Print(); PyErr_Clear(); fazekasgy@37: setValueError("Error while converting integer object.",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: if ((unsigned long)rValue > SIZE_T_MAX || (unsigned long)rValue < 0) fazekasgy@37: { fazekasgy@37: setValueError("Overflow error. Object can not be converted to size_t.",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: return (size_t) rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: // in strict mode we will not try harder and throw an exception fazekasgy@37: // then the caller should decide what to do with it fazekasgy@37: if (m_strict) { fazekasgy@37: setValueError("Strict conversion error: object is not integer.",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: fazekasgy@37: // convert string fazekasgy@37: if (PyString_Check(pyValue)) fazekasgy@37: { fazekasgy@37: PyObject* pyLong = PyNumber_Long(pyValue); fazekasgy@37: if (!pyLong) fazekasgy@37: { fazekasgy@37: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@37: setValueError("String object can not be converted to size_t.",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: size_t rValue = this->PyValue_To_Size_t(pyLong); fazekasgy@37: if (!m_error) { fazekasgy@37: Py_DECREF(pyLong); fazekasgy@37: return rValue; fazekasgy@37: } else { fazekasgy@37: Py_CLEAR(pyLong); fazekasgy@37: setValueError ("Error converting string to size_t.",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: // convert the first element of iterable sequences cannam@41: if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) fazekasgy@37: { fazekasgy@37: PyObject* item = PySequence_GetItem(pyValue,0); fazekasgy@37: if (item) fazekasgy@37: { fazekasgy@37: size_t rValue = this->PyValue_To_Size_t(item); fazekasgy@37: if (!m_error) { fazekasgy@37: Py_DECREF(item); fazekasgy@37: return rValue; fazekasgy@37: } else { fazekasgy@37: Py_CLEAR(item); fazekasgy@37: setValueError("Could not convert sequence element to size_t. ",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: // give up fazekasgy@37: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@37: std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to size_t is not possible."; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_To_Size_t failed. " << msg << endl; fazekasgy@37: #endif fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// long and int fazekasgy@37: long fazekasgy@37: PyTypeInterface::PyValue_To_Long(PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: // most common case: convert int (faster) fazekasgy@37: if (pyValue && PyInt_Check(pyValue)) { fazekasgy@37: // if the object is not NULL and verified, this macro just extracts the value. fazekasgy@37: return PyInt_AS_LONG(pyValue); fazekasgy@37: } fazekasgy@37: fazekasgy@37: // long fazekasgy@37: if (PyLong_Check(pyValue)) { fazekasgy@37: long rValue = PyLong_AsLong(pyValue); fazekasgy@37: if (PyErr_Occurred()) { fazekasgy@37: PyErr_Print(); PyErr_Clear(); fazekasgy@37: setValueError("Error while converting long object.",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: if (m_strict) { fazekasgy@37: setValueError("Strict conversion error: object is not integer or long integer.",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: fazekasgy@37: // convert all objects supporting the number protocol fazekasgy@37: if (PyNumber_Check(pyValue)) fazekasgy@37: { fazekasgy@37: // Note: this function handles Bool,Int,Long,Float fazekasgy@37: // PEP353: Py_ssize_t is size_t but signed ! fazekasgy@37: Py_ssize_t rValue = PyInt_AsSsize_t(pyValue); fazekasgy@37: if (PyErr_Occurred()) fazekasgy@37: { fazekasgy@37: PyErr_Print(); PyErr_Clear(); fazekasgy@37: setValueError("Error while converting integer object.",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: if (rValue > LONG_MAX || rValue < LONG_MIN) fazekasgy@37: { fazekasgy@37: setValueError("Overflow error. Object can not be converted to size_t.",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: return (long) rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: // convert string fazekasgy@37: if (PyString_Check(pyValue)) fazekasgy@37: { fazekasgy@37: PyObject* pyLong = PyNumber_Long(pyValue); fazekasgy@37: if (!pyLong) fazekasgy@37: { fazekasgy@37: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@37: setValueError("String object can not be converted to long.",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: long rValue = this->PyValue_To_Long(pyLong); fazekasgy@37: if (!m_error) { fazekasgy@37: Py_DECREF(pyLong); fazekasgy@37: return rValue; fazekasgy@37: } else { fazekasgy@37: Py_CLEAR(pyLong); fazekasgy@37: setValueError ("Error converting string to long.",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: // convert the first element of iterable sequences cannam@46: if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) fazekasgy@37: { fazekasgy@37: PyObject* item = PySequence_GetItem(pyValue,0); fazekasgy@37: if (item) fazekasgy@37: { fazekasgy@37: size_t rValue = this->PyValue_To_Long(item); fazekasgy@37: if (!m_error) { fazekasgy@37: Py_DECREF(item); fazekasgy@37: return rValue; fazekasgy@37: } else { fazekasgy@37: Py_CLEAR(item); fazekasgy@37: setValueError("Could not convert sequence element to long. ",m_strict); fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: // give up fazekasgy@37: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@37: std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to long is not possible."; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_To_Long failed. " << msg << endl; fazekasgy@37: #endif fazekasgy@37: return 0; fazekasgy@37: } fazekasgy@37: fazekasgy@37: fazekasgy@37: bool fazekasgy@37: PyTypeInterface::PyValue_To_Bool(PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: // convert objects supporting the number protocol fazekasgy@37: // Note: PyBool is a subclass of PyInt fazekasgy@37: if (PyNumber_Check(pyValue)) fazekasgy@37: { fazekasgy@37: if (m_strict && !PyBool_Check(pyValue)) fazekasgy@37: setValueError fazekasgy@37: ("Strict conversion error: object is not boolean type.",m_strict); fazekasgy@37: fazekasgy@37: // Note: this function handles Bool,Int,Long,Float fazekasgy@37: Py_ssize_t rValue = PyInt_AsSsize_t(pyValue); fazekasgy@37: if (PyErr_Occurred()) fazekasgy@37: { fazekasgy@37: PyErr_Print(); PyErr_Clear(); fazekasgy@37: setValueError ("Error while converting boolean object.",m_strict); fazekasgy@37: } fazekasgy@37: if (rValue != 1 && rValue != 0) fazekasgy@37: { fazekasgy@37: setValueError ("Overflow error. Object can not be converted to boolean.",m_strict); fazekasgy@37: } fazekasgy@37: return (bool) rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: if (m_strict) { fazekasgy@37: setValueError ("Strict conversion error: object is not numerical type.",m_strict); fazekasgy@37: return false; fazekasgy@37: } fazekasgy@37: fazekasgy@37: // convert iterables: the rule is the same as in the interpreter: fazekasgy@37: // empty sequence evaluates to False, anything else is True fazekasgy@37: if (PySequence_Check(pyValue)) fazekasgy@37: { fazekasgy@37: return PySequence_Size(pyValue)?true:false; fazekasgy@37: } fazekasgy@37: fazekasgy@37: // give up fazekasgy@37: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@37: std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to boolean is not possible."; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_To_Bool failed. " << msg << endl; fazekasgy@37: #endif fazekasgy@37: return false; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// string and objects that support .__str__() fazekasgy@37: /// TODO: check unicode objects fazekasgy@37: std::string fazekasgy@37: PyTypeInterface::PyValue_To_String(PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: // convert string fazekasgy@37: if (PyString_Check(pyValue)) fazekasgy@37: { fazekasgy@37: char *cstr = PyString_AS_STRING(pyValue); fazekasgy@37: if (!cstr) fazekasgy@37: { fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: setValueError("Error while converting string object.",m_strict); fazekasgy@37: return std::string(); fazekasgy@37: } fazekasgy@37: return std::string(cstr); fazekasgy@37: } fazekasgy@37: // TODO: deal with unicode here (argh!) fazekasgy@37: fazekasgy@37: // in strict mode we will not try harder fazekasgy@37: if (m_strict) { fazekasgy@37: setValueError("Strict conversion error: object is not string.",m_strict); fazekasgy@37: return std::string(); fazekasgy@37: } fazekasgy@37: fazekasgy@37: // accept None as empty string fazekasgy@37: if (pyValue == Py_None) return std::string(); fazekasgy@37: fazekasgy@37: // convert list or tuple: empties are turned into empty strings conventionally fazekasgy@37: if (PyList_Check(pyValue) || PyTuple_Check(pyValue)) fazekasgy@37: { fazekasgy@37: if (!PySequence_Size(pyValue)) return std::string(); fazekasgy@37: PyObject* item = PySequence_GetItem(pyValue,0); fazekasgy@37: if (item) fazekasgy@37: { fazekasgy@37: std::string rValue = this->PyValue_To_String(item); fazekasgy@37: if (!m_error) { fazekasgy@37: Py_DECREF(item); fazekasgy@37: return rValue; fazekasgy@37: } else { fazekasgy@37: Py_CLEAR(item); fazekasgy@37: setValueError("Could not convert sequence element to string.",m_strict); fazekasgy@37: return std::string(); fazekasgy@37: } fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: // convert any other object that has .__str__() or .__repr__() fazekasgy@37: PyObject* pyString = PyObject_Str(pyValue); fazekasgy@37: if (pyString && !PyErr_Occurred()) fazekasgy@37: { fazekasgy@37: std::string rValue = this->PyValue_To_String(pyString); fazekasgy@37: if (!m_error) { fazekasgy@37: Py_DECREF(pyString); fazekasgy@37: return rValue; fazekasgy@37: } else { fazekasgy@37: Py_CLEAR(pyString); fazekasgy@37: std::string msg = "Object " + this->PyValue_Get_TypeName(pyValue) +" can not be represented as string. "; fazekasgy@37: setValueError (msg,m_strict); fazekasgy@37: return std::string(); fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: // give up fazekasgy@37: PyErr_Print(); PyErr_Clear(); fazekasgy@37: std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to string is not possible."; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_To_String failed. " << msg << endl; fazekasgy@37: #endif fazekasgy@37: return std::string(); fazekasgy@37: } fazekasgy@37: fazekasgy@37: /* C Values to Py Values */ fazekasgy@37: fazekasgy@37: fazekasgy@37: PyObject* fazekasgy@37: PyTypeInterface::PyValue_From_CValue(const char* cValue) const fazekasgy@37: { fazekasgy@37: // returns new reference fazekasgy@37: #ifdef _DEBUG fazekasgy@37: if (!cValue) { fazekasgy@37: std::string msg = "PyTypeInterface::PyValue_From_CValue: Null pointer encountered while converting from const char* ."; fazekasgy@37: cerr << msg << endl; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: return NULL; fazekasgy@37: } fazekasgy@37: #endif fazekasgy@37: PyObject *pyValue = PyString_FromString(cValue); fazekasgy@37: if (!pyValue) fazekasgy@37: { fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: setValueError("Error while converting from char* or string.",m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from const char*" << endl; fazekasgy@37: #endif fazekasgy@37: return NULL; fazekasgy@37: } fazekasgy@37: return pyValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: PyObject* fazekasgy@37: PyTypeInterface::PyValue_From_CValue(size_t cValue) const fazekasgy@37: { fazekasgy@37: // returns new reference fazekasgy@37: PyObject *pyValue = PyInt_FromSsize_t((Py_ssize_t)cValue); fazekasgy@37: if (!pyValue) fazekasgy@37: { fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: setValueError("Error while converting from size_t.",m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from size_t" << endl; fazekasgy@37: #endif fazekasgy@37: return NULL; fazekasgy@37: } fazekasgy@37: return pyValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: PyObject* fazekasgy@37: PyTypeInterface::PyValue_From_CValue(double cValue) const fazekasgy@37: { fazekasgy@37: // returns new reference fazekasgy@37: PyObject *pyValue = PyFloat_FromDouble(cValue); fazekasgy@37: if (!pyValue) fazekasgy@37: { fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: setValueError("Error while converting from float or double.",m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from float or double" << endl; fazekasgy@37: #endif fazekasgy@37: return NULL; fazekasgy@37: } fazekasgy@37: return pyValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: PyObject* fazekasgy@37: PyTypeInterface::PyValue_From_CValue(bool cValue) const fazekasgy@37: { fazekasgy@37: // returns new reference fazekasgy@37: PyObject *pyValue = PyBool_FromLong((long)cValue); fazekasgy@37: if (!pyValue) fazekasgy@37: { fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: setValueError("Error while converting from bool.",m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from bool" << endl; fazekasgy@37: #endif fazekasgy@37: return NULL; fazekasgy@37: } fazekasgy@37: return pyValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: fazekasgy@37: /* Sequence Types to C++ Types */ fazekasgy@37: fazekasgy@37: //convert Python list to C++ vector of strings fazekasgy@37: std::vector fazekasgy@37: PyTypeInterface::PyValue_To_StringVector (PyObject *pyList) const fazekasgy@37: { fazekasgy@37: fazekasgy@37: std::vector Output; fazekasgy@37: std::string ListElement; fazekasgy@37: PyObject *pyString = NULL; fazekasgy@37: fazekasgy@37: if (PyList_Check(pyList)) { fazekasgy@37: fazekasgy@37: for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) { fazekasgy@37: //Get next list item (Borrowed Reference) fazekasgy@37: pyString = PyList_GET_ITEM(pyList,i); fazekasgy@37: ListElement = (string) PyString_AsString(PyObject_Str(pyString)); fazekasgy@37: Output.push_back(ListElement); fazekasgy@37: } fazekasgy@37: return Output; fazekasgy@37: } fazekasgy@51: fazekasgy@51: // #ifdef _DEBUG fazekasgy@51: // cerr << "PyTypeInterface::PyValue_To_StringVector: Warning: Value is not list of strings." << endl; fazekasgy@51: // #endif fazekasgy@37: fazekasgy@37: /// Assume a single value that can be casted as string fazekasgy@37: /// this allows to write e.g. Feature.label = 5.2 instead of ['5.2'] fazekasgy@37: Output.push_back(PyValue_To_String(pyList)); fazekasgy@37: if (m_error) { fazekasgy@37: std::string msg = "Value is not list of strings nor can be casted as string. "; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_To_StringVector failed. " << msg << endl; fazekasgy@37: #endif fazekasgy@37: } fazekasgy@37: return Output; fazekasgy@37: } fazekasgy@37: fazekasgy@37: //convert PyFeature.value (typically a list or numpy array) to C++ vector of floats fazekasgy@37: std::vector fazekasgy@37: PyTypeInterface::PyValue_To_FloatVector (PyObject *pyValue) const fazekasgy@37: { fazekasgy@37: fazekasgy@37: #ifdef HAVE_NUMPY fazekasgy@51: if (m_numpyInstalled) fazekasgy@51: { fazekasgy@37: // there are four types of values we may receive from a numpy process: fazekasgy@37: // * a python scalar, fazekasgy@37: // * an array scalar, (e.g. numpy.float32) fazekasgy@37: // * an array with nd = 0 (0D array) fazekasgy@37: // * an array with nd > 0 fazekasgy@37: fazekasgy@37: /// check for scalars fazekasgy@37: if (PyArray_CheckScalar(pyValue) || PyFloat_Check(pyValue)) { fazekasgy@37: fazekasgy@37: std::vector Output; fazekasgy@37: fazekasgy@37: // we rely on the behaviour the scalars are either floats fazekasgy@37: // or support the number protocol fazekasgy@37: // TODO: a potential optimisation is to handle them directly fazekasgy@37: Output.push_back(PyValue_To_Float(pyValue)); fazekasgy@37: return Output; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// numpy array fazekasgy@37: if (PyArray_CheckExact(pyValue)) fazekasgy@37: return PyArray_To_FloatVector(pyValue); fazekasgy@51: } fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: /// python list of floats (backward compatible) fazekasgy@37: if (PyList_Check(pyValue)) { fazekasgy@37: return PyList_To_FloatVector(pyValue); fazekasgy@37: } fazekasgy@37: fazekasgy@37: std::vector Output; fazekasgy@37: fazekasgy@37: /// finally assume a single value supporting the number protocol fazekasgy@37: /// this allows to write e.g. Feature.values = 5 instead of [5.00] fazekasgy@37: Output.push_back(PyValue_To_Float(pyValue)); fazekasgy@37: if (m_error) { fazekasgy@37: std::string msg = "Value is not list or array of floats nor can be casted as float. "; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@51: cerr << "PyTypeInterface::PyValue_To_FloatVector failed. " << msg << endl; fazekasgy@37: #endif fazekasgy@37: } fazekasgy@37: return Output; fazekasgy@37: } fazekasgy@37: fazekasgy@37: //convert a list of python floats fazekasgy@37: std::vector fazekasgy@37: PyTypeInterface::PyList_To_FloatVector (PyObject *inputList) const fazekasgy@37: { fazekasgy@37: std::vector Output; fazekasgy@37: fazekasgy@37: #ifdef _DEBUG fazekasgy@37: // This is a low level function normally called from fazekasgy@37: // PyValue_To_FloatVector(). Checking for list is not required. fazekasgy@37: if (!PyList_Check(inputList)) { fazekasgy@37: std::string msg = "Value is not list."; fazekasgy@37: setValueError(msg,true); fazekasgy@37: cerr << "PyTypeInterface::PyList_To_FloatVector failed. " << msg << endl; fazekasgy@37: return Output; fazekasgy@37: } fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: float ListElement; fazekasgy@37: PyObject *pyFloat = NULL; fazekasgy@37: PyObject **pyObjectArray = PySequence_Fast_ITEMS(inputList); fazekasgy@37: fazekasgy@37: for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) { fazekasgy@37: fazekasgy@37: // pyFloat = PyList_GET_ITEM(inputList,i); fazekasgy@37: pyFloat = pyObjectArray[i]; fazekasgy@37: fazekasgy@37: #ifdef _DEBUG fazekasgy@37: if (!pyFloat) { fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: cerr << "PyTypeInterface::PyList_To_FloatVector: Could not obtain list element: " fazekasgy@37: << i << " PyList_GetItem returned NULL! Skipping value." << endl; fazekasgy@37: continue; fazekasgy@37: } fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: // ListElement = (float) PyFloat_AS_DOUBLE(pyFloat); fazekasgy@37: ListElement = PyValue_To_Float(pyFloat); fazekasgy@37: fazekasgy@37: fazekasgy@37: #ifdef _DEBUG_VALUES fazekasgy@37: cerr << "value: " << ListElement << endl; fazekasgy@37: #endif fazekasgy@37: Output.push_back(ListElement); fazekasgy@37: } fazekasgy@37: return Output; fazekasgy@37: } fazekasgy@37: fazekasgy@51: // if numpy is not installed this will not be called, fazekasgy@51: // therefor we do not check again fazekasgy@51: #ifdef HAVE_NUMPY fazekasgy@37: std::vector fazekasgy@37: PyTypeInterface::PyArray_To_FloatVector (PyObject *pyValue) const fazekasgy@37: { fazekasgy@37: std::vector Output; fazekasgy@37: fazekasgy@37: #ifdef _DEBUG fazekasgy@37: // This is a low level function, normally called from fazekasgy@37: // PyValue_To_FloatVector(). Checking the array here is not required. fazekasgy@37: if (!PyArray_Check(pyValue)) { fazekasgy@37: std::string msg = "Object has no array interface."; fazekasgy@37: setValueError(msg,true); fazekasgy@37: cerr << "PyTypeInterface::PyArray_To_FloatVector failed. " << msg << endl; fazekasgy@37: return Output; fazekasgy@37: } fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: PyArrayObject* pyArray = (PyArrayObject*) pyValue; fazekasgy@37: PyArray_Descr* descr = pyArray->descr; fazekasgy@37: fazekasgy@37: /// check raw data and descriptor pointers fazekasgy@37: if (pyArray->data == 0 || descr == 0) { fazekasgy@37: std::string msg = "NumPy array with NULL data or descriptor pointer encountered."; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << endl; fazekasgy@37: #endif fazekasgy@37: return Output; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// check dimensions fazekasgy@37: if (pyArray->nd != 1) { fazekasgy@37: std::string msg = "NumPy array must be a one dimensional vector."; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << " Dims: " << (int) pyArray->nd << endl; fazekasgy@37: #endif fazekasgy@37: return Output; fazekasgy@37: } fazekasgy@37: fazekasgy@37: #ifdef _DEBUG_VALUES fazekasgy@37: cerr << "PyTypeInterface::PyArray_To_FloatVector: Numpy array verified." << endl; fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: /// check strides (useful if array is not continuous) fazekasgy@37: size_t strides = *((size_t*) pyArray->strides); fazekasgy@37: fazekasgy@37: /// convert the array fazekasgy@37: switch (descr->type_num) fazekasgy@37: { fazekasgy@37: case NPY_FLOAT : // dtype='float32' fazekasgy@37: return PyArray_Convert(pyArray->data,pyArray->dimensions[0],strides); fazekasgy@37: case NPY_DOUBLE : // dtype='float64' fazekasgy@37: return PyArray_Convert(pyArray->data,pyArray->dimensions[0],strides); fazekasgy@37: case NPY_INT : // dtype='int' fazekasgy@37: return PyArray_Convert(pyArray->data,pyArray->dimensions[0],strides); fazekasgy@37: case NPY_LONG : // dtype='long' fazekasgy@37: return PyArray_Convert(pyArray->data,pyArray->dimensions[0],strides); fazekasgy@37: default : fazekasgy@37: std::string msg = "Unsupported value type in NumPy array object."; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << endl; fazekasgy@37: #endif fazekasgy@37: return Output; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: fazekasgy@51: /// FeatureSet (an integer map of FeatureLists) fazekasgy@37: Vamp::Plugin::FeatureSet fazekasgy@37: PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: Vamp::Plugin::FeatureSet rFeatureSet; fazekasgy@37: fazekasgy@37: /// Convert PyFeatureSet fazekasgy@37: if (PyFeatureSet_CheckExact(pyValue)) { fazekasgy@37: fazekasgy@37: Py_ssize_t pyPos = 0; fazekasgy@37: PyObject *pyKey, *pyDictValue; // Borrowed References fazekasgy@37: int key; fazekasgy@37: // bool it_error = false; fazekasgy@37: fazekasgy@37: m_error = false; fazekasgy@37: while (PyDict_Next(pyValue, &pyPos, &pyKey, &pyDictValue)) fazekasgy@37: { fazekasgy@37: key = (int) PyInt_AS_LONG(pyKey); fazekasgy@37: #ifdef _DEBUG_VALUES fazekasgy@37: cerr << "key: '" << key << "' value: '" << PyValue_To_String(pyDictValue) << "' " << endl; fazekasgy@37: #endif fazekasgy@37: // DictValue -> Vamp::FeatureList fazekasgy@37: PyValue_To_rValue(pyDictValue,rFeatureSet[key]); fazekasgy@37: if (m_error) { fazekasgy@37: // it_error = true; fazekasgy@37: lastError() << " in output number: " << key; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: // if (it_error) m_error = true; fazekasgy@37: if (!m_errorQueue.empty()) { fazekasgy@37: setValueError("Error while converting FeatureSet.",m_strict); fazekasgy@37: } fazekasgy@37: return rFeatureSet; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// Convert Python list (backward compatibility) fazekasgy@37: if (PyList_Check(pyValue)) { fazekasgy@37: fazekasgy@37: PyObject *pyFeatureList; // This will be borrowed reference fazekasgy@37: fazekasgy@37: //Parse Output List for each element (FeatureSet) fazekasgy@37: m_error = false; fazekasgy@37: for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyValue); ++i) { fazekasgy@37: //Get i-th FeatureList (Borrowed Reference) fazekasgy@37: pyFeatureList = PyList_GET_ITEM(pyValue,i); fazekasgy@37: PyValue_To_rValue(pyFeatureList,rFeatureSet[i]); fazekasgy@37: if (m_error) { fazekasgy@37: lastError() << " in output number: " << i; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: if (!m_errorQueue.empty()) m_error = true; fazekasgy@37: return rFeatureSet; fazekasgy@37: } fazekasgy@37: fazekasgy@51: /// accept None return values fazekasgy@37: if (pyValue == Py_None) return rFeatureSet; fazekasgy@37: fazekasgy@37: /// give up fazekasgy@37: std::string msg = "Unsupported return type. Expected list or vampy.FeatureSet(). "; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_To_FeatureSet failed. Error: " << msg << endl; fazekasgy@37: #endif fazekasgy@37: return rFeatureSet; fazekasgy@37: } fazekasgy@37: fazekasgy@37: Vamp::RealTime fazekasgy@37: PyTypeInterface::PyValue_To_RealTime(PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: // We accept integer sample counts (for backward compatibility) fazekasgy@37: // or PyRealTime objects and convert them to Vamp::RealTime fazekasgy@37: fazekasgy@37: if (PyRealTime_CheckExact(pyValue)) fazekasgy@37: { fazekasgy@37: /// just create a copy of the wrapped object fazekasgy@37: return Vamp::RealTime(*PyRealTime_AS_REALTIME(pyValue)); fazekasgy@37: } fazekasgy@37: fazekasgy@37: // assume integer sample count fazekasgy@37: long sampleCount = PyValue_To_Long(pyValue); fazekasgy@37: if (m_error) { fazekasgy@37: std::string msg = "Unexpected value passed as RealTime.\nMust be vampy.RealTime type or integer sample count."; fazekasgy@37: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_To_RealTime failed. " << msg << endl; fazekasgy@37: #endif fazekasgy@37: return Vamp::RealTime(); fazekasgy@37: } fazekasgy@37: fazekasgy@37: #ifdef _DEBUG_VALUES fazekasgy@37: Vamp::RealTime rt = fazekasgy@37: Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate ); fazekasgy@37: cerr << "RealTime: " << (long)sampleCount << ", ->" << rt.toString() << endl; fazekasgy@37: return rt; fazekasgy@37: #else fazekasgy@37: return Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate ); fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: } fazekasgy@37: fazekasgy@37: Vamp::Plugin::OutputDescriptor::SampleType fazekasgy@37: PyTypeInterface::PyValue_To_SampleType(PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: /// convert simulated enum values fazekasgy@37: /// { OneSamplePerStep,FixedSampleRate,VariableSampleRate } fazekasgy@37: if (PyInt_CheckExact(pyValue)) { fazekasgy@37: long lst = PyInt_AS_LONG(pyValue); fazekasgy@37: if (lst<0 || lst>2) { fazekasgy@37: 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: return Vamp::Plugin::OutputDescriptor::SampleType(); fazekasgy@37: } fazekasgy@37: return (Vamp::Plugin::OutputDescriptor::SampleType) lst; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// convert string (backward compatible) fazekasgy@37: if (PyString_CheckExact(pyValue)) { fazekasgy@37: Vamp::Plugin::OutputDescriptor::SampleType st; fazekasgy@37: st = (Vamp::Plugin::OutputDescriptor::SampleType) sampleKeys[PyValue_To_String(pyValue)]; fazekasgy@37: if (m_error) { fazekasgy@37: 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: setValueError(msg,m_strict); fazekasgy@37: return Vamp::Plugin::OutputDescriptor::SampleType(); fazekasgy@37: } fazekasgy@37: return st; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// give up fazekasgy@37: 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: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_To_SampleType failed. Error: " << msg << endl; fazekasgy@37: #endif fazekasgy@37: return Vamp::Plugin::OutputDescriptor::SampleType(); fazekasgy@37: } fazekasgy@37: fazekasgy@37: Vamp::Plugin::InputDomain fazekasgy@37: PyTypeInterface::PyValue_To_InputDomain(PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: /// convert simulated enum values { TimeDomain,FrequencyDomain } fazekasgy@37: if (PyInt_CheckExact(pyValue)) { fazekasgy@37: long lst = PyInt_AS_LONG(pyValue); fazekasgy@37: if (lst!=0 && lst!=1) { fazekasgy@37: 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: return Vamp::Plugin::InputDomain(); fazekasgy@37: } fazekasgy@37: return (Vamp::Plugin::InputDomain) lst; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// convert string (backward compatible) fazekasgy@37: if (PyString_CheckExact(pyValue)) { fazekasgy@37: Vamp::Plugin::InputDomain id; fazekasgy@37: id = (PyValue_To_String(pyValue) == "FrequencyDomain")?Vamp::Plugin::FrequencyDomain:Vamp::Plugin::TimeDomain; fazekasgy@37: if (m_error) fazekasgy@37: { fazekasgy@37: 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: setValueError(msg,m_strict); fazekasgy@37: return Vamp::Plugin::InputDomain(); fazekasgy@37: } fazekasgy@37: return id; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// give up fazekasgy@37: 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: setValueError(msg,m_strict); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: cerr << "PyTypeInterface::PyValue_To_InputDomain failed. Error: " << msg << endl; fazekasgy@37: #endif fazekasgy@37: return Vamp::Plugin::InputDomain(); fazekasgy@37: } fazekasgy@37: fazekasgy@37: fazekasgy@37: /// OutputDescriptor fazekasgy@37: void fazekasgy@37: PyTypeInterface::SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: switch (outKeys[key]) fazekasgy@37: { fazekasgy@37: case o::not_found: fazekasgy@37: setValueError("Unknown key in Vamp OutputDescriptor",m_strict); fazekasgy@37: cerr << "Unknown key in Vamp OutputDescriptor: " << key << endl; fazekasgy@37: break; fazekasgy@37: case o::identifier: fazekasgy@37: _convert(pyValue,od.identifier); fazekasgy@37: break; fazekasgy@37: case o::name: fazekasgy@37: _convert(pyValue,od.name); fazekasgy@37: break; fazekasgy@37: case o::description: fazekasgy@37: _convert(pyValue,od.description); fazekasgy@37: break; fazekasgy@37: case o::unit: fazekasgy@37: _convert(pyValue,od.unit); fazekasgy@37: break; fazekasgy@37: case o::hasFixedBinCount: fazekasgy@37: _convert(pyValue,od.hasFixedBinCount); fazekasgy@37: break; fazekasgy@37: case o::binCount: fazekasgy@37: _convert(pyValue,od.binCount); fazekasgy@37: break; fazekasgy@37: case o::binNames: fazekasgy@37: _convert(pyValue,od.binNames); fazekasgy@37: break; fazekasgy@37: case o::hasKnownExtents: fazekasgy@37: _convert(pyValue,od.hasKnownExtents); fazekasgy@37: break; fazekasgy@37: case o::minValue: fazekasgy@37: _convert(pyValue,od.minValue); fazekasgy@37: break; fazekasgy@37: case o::maxValue: fazekasgy@37: _convert(pyValue,od.maxValue); fazekasgy@37: break; fazekasgy@37: case o::isQuantized: fazekasgy@37: _convert(pyValue,od.isQuantized); fazekasgy@37: break; fazekasgy@37: case o::quantizeStep: fazekasgy@37: _convert(pyValue,od.quantizeStep); fazekasgy@37: break; fazekasgy@37: case o::sampleType: fazekasgy@37: _convert(pyValue,od.sampleType); fazekasgy@37: break; fazekasgy@37: case o::sampleRate: fazekasgy@37: _convert(pyValue,od.sampleRate); fazekasgy@37: break; fazekasgy@37: case o::hasDuration: fazekasgy@37: _convert(pyValue,od.hasDuration); fazekasgy@37: break; fazekasgy@37: default: fazekasgy@37: setValueError("Unknown key in Vamp OutputDescriptor",m_strict); fazekasgy@37: cerr << "Invalid key in Vamp OutputDescriptor: " << key << endl; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// ParameterDescriptor fazekasgy@37: void fazekasgy@37: PyTypeInterface::SetValue(Vamp::Plugin::ParameterDescriptor& pd, std::string& key, PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: switch (parmKeys[key]) fazekasgy@37: { fazekasgy@37: case p::not_found : fazekasgy@37: setValueError("Unknown key in Vamp ParameterDescriptor",m_strict); fazekasgy@37: cerr << "Unknown key in Vamp ParameterDescriptor: " << key << endl; fazekasgy@37: break; fazekasgy@37: case p::identifier: fazekasgy@37: _convert(pyValue,pd.identifier); fazekasgy@37: break; fazekasgy@37: case p::name: fazekasgy@37: _convert(pyValue,pd.name); fazekasgy@37: break; fazekasgy@37: case p::description: fazekasgy@37: _convert(pyValue,pd.description); fazekasgy@37: break; fazekasgy@37: case p::unit: fazekasgy@37: _convert(pyValue,pd.unit); fazekasgy@37: break; fazekasgy@37: case p::minValue: fazekasgy@37: _convert(pyValue,pd.minValue); fazekasgy@37: break; fazekasgy@37: case p::maxValue: fazekasgy@37: _convert(pyValue,pd.maxValue); fazekasgy@37: break; fazekasgy@37: case p::defaultValue: fazekasgy@37: _convert(pyValue,pd.defaultValue); fazekasgy@37: break; fazekasgy@37: case p::isQuantized: fazekasgy@37: _convert(pyValue,pd.isQuantized); fazekasgy@37: break; fazekasgy@37: case p::quantizeStep: fazekasgy@37: _convert(pyValue,pd.quantizeStep); fazekasgy@37: break; fazekasgy@37: default : fazekasgy@37: setValueError("Unknown key in Vamp ParameterDescriptor",m_strict); fazekasgy@37: cerr << "Invalid key in Vamp ParameterDescriptor: " << key << endl; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// Feature (it's like a Descriptor) fazekasgy@37: bool fazekasgy@37: PyTypeInterface::SetValue(Vamp::Plugin::Feature& feature, std::string& key, PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: bool found = true; fazekasgy@37: switch (ffKeys[key]) fazekasgy@37: { fazekasgy@37: case unknown : fazekasgy@37: setValueError("Unknown key in Vamp Feature",m_strict); fazekasgy@37: cerr << "Unknown key in Vamp Feature: " << key << endl; fazekasgy@37: found = false; fazekasgy@37: break; fazekasgy@37: case hasTimestamp: fazekasgy@37: _convert(pyValue,feature.hasTimestamp); fazekasgy@37: break; fazekasgy@37: case timestamp: fazekasgy@37: _convert(pyValue,feature.timestamp); fazekasgy@37: break; fazekasgy@37: case hasDuration: fazekasgy@37: _convert(pyValue,feature.hasDuration); fazekasgy@37: break; fazekasgy@37: case duration: fazekasgy@37: _convert(pyValue,feature.duration); fazekasgy@37: break; fazekasgy@37: case values: fazekasgy@37: _convert(pyValue,feature.values); fazekasgy@37: break; fazekasgy@37: case label: fazekasgy@37: _convert(pyValue,feature.label); fazekasgy@37: break; fazekasgy@37: default: fazekasgy@37: setValueError("Unknown key in Vamp Feature",m_strict); fazekasgy@37: found = false; fazekasgy@37: } fazekasgy@37: return found; fazekasgy@37: } fazekasgy@37: fazekasgy@37: fazekasgy@37: /* Error handling */ fazekasgy@37: fazekasgy@37: void fazekasgy@37: PyTypeInterface::setValueError (std::string message, bool strict) const fazekasgy@37: { fazekasgy@37: m_error = true; fazekasgy@37: m_errorQueue.push(ValueError(message,strict)); fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// return a reference to the last error or creates a new one. fazekasgy@37: PyTypeInterface::ValueError& fazekasgy@37: PyTypeInterface::lastError() const fazekasgy@37: { fazekasgy@37: m_error = false; fazekasgy@37: if (!m_errorQueue.empty()) return m_errorQueue.back(); fazekasgy@37: else { fazekasgy@37: m_errorQueue.push(ValueError("Type conversion error.",m_strict)); fazekasgy@37: return m_errorQueue.back(); fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// helper function to iterate over the error message queue: fazekasgy@37: /// pops the oldest item fazekasgy@37: PyTypeInterface::ValueError fazekasgy@37: PyTypeInterface::getError() const fazekasgy@37: { fazekasgy@37: if (!m_errorQueue.empty()) { fazekasgy@37: PyTypeInterface::ValueError e = m_errorQueue.front(); fazekasgy@37: m_errorQueue.pop(); fazekasgy@37: if (m_errorQueue.empty()) m_error = false; fazekasgy@37: return e; fazekasgy@37: } fazekasgy@37: else { fazekasgy@37: m_error = false; fazekasgy@37: return PyTypeInterface::ValueError(); fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: /* Utilities */ fazekasgy@37: fazekasgy@37: /// get the type name of an object fazekasgy@37: std::string fazekasgy@37: PyTypeInterface::PyValue_Get_TypeName(PyObject* pyValue) const fazekasgy@37: { fazekasgy@37: PyObject *pyType = PyObject_Type(pyValue); fazekasgy@37: if (!pyType) fazekasgy@37: { fazekasgy@37: cerr << "Warning: Object type name could not be found." << endl; fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: return std::string ("< unknown type >"); fazekasgy@37: } fazekasgy@37: PyObject *pyString = PyObject_Str(pyType); fazekasgy@37: if (!pyString) fazekasgy@37: { fazekasgy@37: cerr << "Warning: Object type name could not be found." << endl; fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: Py_CLEAR(pyType); fazekasgy@37: return std::string ("< unknown type >"); fazekasgy@37: } fazekasgy@37: char *cstr = PyString_AS_STRING(pyString); fazekasgy@37: if (!cstr) fazekasgy@37: { fazekasgy@37: cerr << "Warning: Object type name could not be found." << endl; fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: Py_DECREF(pyType); fazekasgy@37: Py_CLEAR(pyString); fazekasgy@37: return std::string("< unknown type >"); fazekasgy@37: } fazekasgy@37: Py_DECREF(pyType); fazekasgy@37: Py_DECREF(pyString); fazekasgy@37: return std::string(cstr); fazekasgy@37: fazekasgy@37: } fazekasgy@37: fazekasgy@37: bool fazekasgy@37: PyTypeInterface::initMaps() const fazekasgy@37: { fazekasgy@37: fazekasgy@37: if (isMapInitialised) return true; fazekasgy@37: fazekasgy@37: outKeys["identifier"] = o::identifier; fazekasgy@37: outKeys["name"] = o::name; fazekasgy@37: outKeys["description"] = o::description; fazekasgy@37: outKeys["unit"] = o::unit; fazekasgy@37: outKeys["hasFixedBinCount"] = o::hasFixedBinCount; fazekasgy@37: outKeys["binCount"] = o::binCount; fazekasgy@37: outKeys["binNames"] = o::binNames; fazekasgy@37: outKeys["hasKnownExtents"] = o::hasKnownExtents; fazekasgy@37: outKeys["minValue"] = o::minValue; fazekasgy@37: outKeys["maxValue"] = o::maxValue; fazekasgy@37: outKeys["isQuantized"] = o::isQuantized; fazekasgy@37: outKeys["quantizeStep"] = o::quantizeStep; fazekasgy@37: outKeys["sampleType"] = o::sampleType; fazekasgy@37: outKeys["sampleRate"] = o::sampleRate; fazekasgy@37: outKeys["hasDuration"] = o::hasDuration; fazekasgy@37: fazekasgy@37: sampleKeys["OneSamplePerStep"] = OneSamplePerStep; fazekasgy@37: sampleKeys["FixedSampleRate"] = FixedSampleRate; fazekasgy@37: sampleKeys["VariableSampleRate"] = VariableSampleRate; fazekasgy@37: fazekasgy@37: ffKeys["hasTimestamp"] = hasTimestamp; fazekasgy@37: ffKeys["timestamp"] = timestamp; // this is the correct one fazekasgy@37: ffKeys["timeStamp"] = timestamp; // backward compatible fazekasgy@37: ffKeys["hasDuration"] = hasDuration; fazekasgy@37: ffKeys["duration"] = duration; fazekasgy@37: ffKeys["values"] = values; fazekasgy@37: ffKeys["label"] = label; fazekasgy@37: fazekasgy@37: parmKeys["identifier"] = p::identifier; fazekasgy@37: parmKeys["name"] = p::name; fazekasgy@37: parmKeys["description"] = p::description; fazekasgy@37: parmKeys["unit"] = p::unit; fazekasgy@37: parmKeys["minValue"] = p::minValue; fazekasgy@37: parmKeys["maxValue"] = p::maxValue; fazekasgy@37: parmKeys["defaultValue"] = p::defaultValue; fazekasgy@37: parmKeys["isQuantized"] = p::isQuantized; fazekasgy@37: parmKeys["quantizeStep"] = p::quantizeStep; fazekasgy@37: fazekasgy@37: isMapInitialised = true; fazekasgy@37: return true; fazekasgy@37: }