fazekasgy@31: /* fazekasgy@31: */ fazekasgy@31: fazekasgy@31: #include fazekasgy@32: #ifdef HAVE_NUMPY fazekasgy@32: #include "arrayobject.h" fazekasgy@32: #endif fazekasgy@31: #include "PyTypeInterface.h" fazekasgy@31: #include "PyRealTime.h" fazekasgy@31: #include "PyExtensionModule.h" fazekasgy@31: #include fazekasgy@31: #include fazekasgy@31: #include fazekasgy@31: #ifndef SIZE_T_MAX cannam@33: #define SIZE_T_MAX ((size_t) -1) fazekasgy@31: #endif fazekasgy@31: fazekasgy@31: using std::string; fazekasgy@31: using std::vector; fazekasgy@31: using std::cerr; fazekasgy@31: using std::endl; fazekasgy@31: using std::map; fazekasgy@31: fazekasgy@31: static std::map outKeys; fazekasgy@31: static std::map parmKeys; fazekasgy@31: static std::map sampleKeys; fazekasgy@31: static std::map ffKeys; fazekasgy@31: static bool isMapInitialised = false; fazekasgy@31: fazekasgy@31: /* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS fazekasgy@32: (EXCEPT FOR TEMPORARY PYTHON OBJECTS)! */ fazekasgy@31: fazekasgy@31: PyTypeInterface::PyTypeInterface() : fazekasgy@31: m_strict(false), fazekasgy@31: m_error(false), fazekasgy@31: m_lastError(m_noError), fazekasgy@31: error(m_error) fazekasgy@31: { fazekasgy@31: } fazekasgy@31: fazekasgy@31: PyTypeInterface::~PyTypeInterface() fazekasgy@31: { fazekasgy@31: } fazekasgy@31: fazekasgy@31: /// floating point numbers (TODO: check numpy.float128) fazekasgy@31: float fazekasgy@31: PyTypeInterface::PyValue_To_Float(PyObject* pyValue) const fazekasgy@31: { fazekasgy@31: // convert float fazekasgy@31: if (PyFloat_Check(pyValue)) fazekasgy@31: { fazekasgy@31: float rValue = (float) PyFloat_AS_DOUBLE(pyValue); fazekasgy@31: if (PyErr_Occurred()) fazekasgy@31: { fazekasgy@31: PyErr_Print(); PyErr_Clear(); fazekasgy@31: setValueError("Error while converting float object.",m_strict); fazekasgy@31: return 0.0; fazekasgy@31: } fazekasgy@31: return rValue; fazekasgy@31: } fazekasgy@31: fazekasgy@31: // in strict mode we will not try harder fazekasgy@31: if (m_strict) { fazekasgy@31: setValueError("Strict conversion error: object is not float.",m_strict); fazekasgy@31: return 0.0; fazekasgy@31: } fazekasgy@31: fazekasgy@31: // convert other objects supporting the number protocol fazekasgy@31: if (PyNumber_Check(pyValue)) fazekasgy@31: { fazekasgy@31: // PEP353: Py_ssize_t is size_t but signed ! fazekasgy@31: // This will work up to numpy.float64 fazekasgy@31: Py_ssize_t rValue = PyNumber_AsSsize_t(pyValue,NULL); fazekasgy@31: if (PyErr_Occurred()) fazekasgy@31: { fazekasgy@31: PyErr_Print(); PyErr_Clear(); fazekasgy@31: setValueError("Error while converting integer object.",m_strict); fazekasgy@31: return 0.0; fazekasgy@31: } fazekasgy@31: if (rValue > FLT_MAX || rValue < FLT_MIN) fazekasgy@31: { fazekasgy@31: setValueError("Overflow error. Object can not be converted to float.",m_strict); fazekasgy@31: return 0.0; fazekasgy@31: } fazekasgy@31: return (float) rValue; fazekasgy@31: } fazekasgy@31: fazekasgy@31: // convert string fazekasgy@31: if (PyString_Check(pyValue)) fazekasgy@31: { fazekasgy@31: PyObject* pyFloat = PyFloat_FromString(pyValue,NULL); fazekasgy@31: if (!pyFloat) fazekasgy@31: { fazekasgy@31: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@31: setValueError("String value can not be converted to float.",m_strict); fazekasgy@31: return 0.0; fazekasgy@31: } fazekasgy@31: float rValue = (float) PyFloat_AS_DOUBLE(pyFloat); fazekasgy@31: if (PyErr_Occurred()) fazekasgy@31: { fazekasgy@31: PyErr_Print(); PyErr_Clear(); fazekasgy@31: Py_CLEAR(pyFloat); fazekasgy@31: setValueError("Error while converting float object.",m_strict); fazekasgy@31: return 0.0; fazekasgy@31: } fazekasgy@31: Py_DECREF(pyFloat); fazekasgy@31: return rValue; fazekasgy@31: } fazekasgy@31: fazekasgy@31: // convert the first element of any iterable sequence (for convenience and backwards compatibility) cannam@35: if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) fazekasgy@31: { fazekasgy@31: PyObject* item = PySequence_GetItem(pyValue,0); fazekasgy@31: if (item) fazekasgy@31: { fazekasgy@31: float rValue = this->PyValue_To_Float(item); fazekasgy@31: if (!m_error) { fazekasgy@31: Py_DECREF(item); fazekasgy@31: return rValue; fazekasgy@31: } else { fazekasgy@31: Py_CLEAR(item); fazekasgy@31: std::string msg = "Could not convert sequence element. " + lastError().message; fazekasgy@31: setValueError(msg,m_strict); fazekasgy@31: return 0.0; fazekasgy@31: } fazekasgy@31: } fazekasgy@31: } fazekasgy@31: fazekasgy@31: // give up fazekasgy@31: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@31: std::string msg = "Conversion from " + PyValue_Get_TypeName(pyValue) + " to float is not possible."; fazekasgy@31: setValueError(msg,m_strict); fazekasgy@31: return 0.0; fazekasgy@31: } fazekasgy@31: fazekasgy@31: /// size_t (unsigned integer types) fazekasgy@31: size_t fazekasgy@31: PyTypeInterface::PyValue_To_Size_t(PyObject* pyValue) const fazekasgy@31: { fazekasgy@31: // convert objects supporting the number protocol fazekasgy@31: if (PyNumber_Check(pyValue)) fazekasgy@31: { fazekasgy@31: if (m_strict && !PyInt_Check(pyValue) && !PyLong_Check(pyValue)) fazekasgy@31: setValueError("Strict conversion error: object is not integer type.",m_strict); fazekasgy@31: // Note: this function handles Bool,Int,Long,Float fazekasgy@31: // PEP353: Py_ssize_t is size_t but signed ! fazekasgy@31: Py_ssize_t rValue = PyInt_AsSsize_t(pyValue); fazekasgy@31: if (PyErr_Occurred()) fazekasgy@31: { fazekasgy@31: PyErr_Print(); PyErr_Clear(); fazekasgy@31: setValueError("Error while converting integer object.",m_strict); fazekasgy@31: return 0; fazekasgy@31: } fazekasgy@31: if ((unsigned long)rValue > SIZE_T_MAX || (unsigned long)rValue < 0) fazekasgy@31: { fazekasgy@31: setValueError("Overflow error. Object can not be converted to size_t.",m_strict); fazekasgy@31: return 0; fazekasgy@31: } fazekasgy@31: return (size_t) rValue; fazekasgy@31: } fazekasgy@31: fazekasgy@31: // in strict mode we will not try harder and throw an exception fazekasgy@31: // then the caller should decide what to do with it fazekasgy@31: if (m_strict) { fazekasgy@31: setValueError("Strict conversion error: object is not integer.",m_strict); fazekasgy@31: return 0; fazekasgy@31: } fazekasgy@31: fazekasgy@31: // convert string fazekasgy@31: if (PyString_Check(pyValue)) fazekasgy@31: { fazekasgy@31: PyObject* pyLong = PyNumber_Long(pyValue); fazekasgy@31: if (!pyLong) fazekasgy@31: { fazekasgy@31: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@31: setValueError("String object can not be converted to size_t.",m_strict); fazekasgy@31: return 0; fazekasgy@31: } fazekasgy@31: size_t rValue = this->PyValue_To_Size_t(pyLong); fazekasgy@31: if (!m_error) { fazekasgy@31: Py_DECREF(pyLong); fazekasgy@31: return rValue; fazekasgy@31: } else { fazekasgy@31: Py_CLEAR(pyLong); fazekasgy@31: setValueError (lastError().message,m_strict); fazekasgy@31: return 0; fazekasgy@31: } fazekasgy@31: } fazekasgy@31: fazekasgy@31: // convert the first element of iterable sequences cannam@35: if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) fazekasgy@31: { fazekasgy@31: PyObject* item = PySequence_GetItem(pyValue,0); fazekasgy@31: if (item) fazekasgy@31: { fazekasgy@31: size_t rValue = this->PyValue_To_Size_t(item); fazekasgy@31: if (!m_error) { fazekasgy@31: Py_DECREF(item); fazekasgy@31: return rValue; fazekasgy@31: } else { fazekasgy@31: Py_CLEAR(item); fazekasgy@31: std::string msg = "Could not convert sequence element. " + lastError().message; fazekasgy@31: setValueError(msg,m_strict); fazekasgy@31: return 0; fazekasgy@31: } fazekasgy@31: } fazekasgy@31: } fazekasgy@31: fazekasgy@31: // give up fazekasgy@31: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@31: std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to size_t is not possible."; fazekasgy@31: setValueError(msg,m_strict); fazekasgy@31: return 0; fazekasgy@31: } fazekasgy@31: fazekasgy@31: bool fazekasgy@31: PyTypeInterface::PyValue_To_Bool(PyObject* pyValue) const fazekasgy@31: { fazekasgy@31: // convert objects supporting the number protocol fazekasgy@31: // Note: PyBool is a subclass of PyInt fazekasgy@31: if (PyNumber_Check(pyValue)) fazekasgy@31: { fazekasgy@31: if (m_strict && !PyBool_Check(pyValue)) fazekasgy@31: setValueError fazekasgy@31: ("Strict conversion error: object is not boolean type.",m_strict); fazekasgy@31: fazekasgy@31: // Note: this function handles Bool,Int,Long,Float fazekasgy@31: Py_ssize_t rValue = PyInt_AsSsize_t(pyValue); fazekasgy@31: if (PyErr_Occurred()) fazekasgy@31: { fazekasgy@31: PyErr_Print(); PyErr_Clear(); fazekasgy@31: setValueError ("Error while converting boolean object.",m_strict); fazekasgy@31: } fazekasgy@31: if (rValue != 1 && rValue != 0) fazekasgy@31: { fazekasgy@31: setValueError ("Overflow error. Object can not be converted to boolean.",m_strict); fazekasgy@31: } fazekasgy@31: return (bool) rValue; fazekasgy@31: } fazekasgy@31: fazekasgy@31: if (m_strict) { fazekasgy@31: setValueError ("Strict conversion error: object is not numerical type.",m_strict); fazekasgy@31: return false; fazekasgy@31: } fazekasgy@31: fazekasgy@31: // convert iterables: the rule is the same as of the interpreter: fazekasgy@31: // empty sequence evaluates to False, anything else is True fazekasgy@31: if (PySequence_Check(pyValue)) fazekasgy@31: { fazekasgy@31: return PySequence_Size(pyValue)?true:false; fazekasgy@31: } fazekasgy@31: fazekasgy@31: // give up fazekasgy@31: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@31: std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to boolean is not possible."; fazekasgy@31: setValueError(msg,m_strict); fazekasgy@31: return false; fazekasgy@31: } fazekasgy@31: fazekasgy@31: /// string and objects that support .__str__() (TODO: check unicode objects) fazekasgy@31: std::string fazekasgy@31: PyTypeInterface::PyValue_To_String(PyObject* pyValue) const fazekasgy@31: { fazekasgy@31: // convert string fazekasgy@31: if (PyString_Check(pyValue)) fazekasgy@31: { fazekasgy@31: char *cstr = PyString_AS_STRING(pyValue); fazekasgy@31: if (!cstr) fazekasgy@31: { fazekasgy@31: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@31: setValueError("Error while converting string object.",m_strict); fazekasgy@31: return std::string(); fazekasgy@31: } fazekasgy@31: return std::string(cstr); fazekasgy@31: } fazekasgy@31: // TODO: deal with unicode here (argh!) fazekasgy@31: fazekasgy@31: // in strict mode we will not try harder fazekasgy@31: if (m_strict) { fazekasgy@31: setValueError("Strict conversion error: object is not string.",m_strict); fazekasgy@31: return std::string(); fazekasgy@31: } fazekasgy@31: fazekasgy@31: // convert list or tuple: empty lists are turned into empty strings fazekasgy@31: if (PyList_Check(pyValue) || PyTuple_Check(pyValue)) fazekasgy@31: { fazekasgy@31: if (!PySequence_Size(pyValue)) return std::string(); fazekasgy@31: PyObject* item = PySequence_GetItem(pyValue,0); fazekasgy@31: if (item) fazekasgy@31: { fazekasgy@31: std::string rValue = this->PyValue_To_String(item); fazekasgy@31: if (m_error) { fazekasgy@31: Py_DECREF(item); fazekasgy@31: return rValue; fazekasgy@31: } else { fazekasgy@31: Py_CLEAR(item); fazekasgy@31: std::string msg = "Could not convert sequence element. " + lastError().message; fazekasgy@31: setValueError(msg,m_strict); fazekasgy@31: return std::string(); fazekasgy@31: } fazekasgy@31: } fazekasgy@31: } fazekasgy@31: fazekasgy@31: // convert any other object that has .__str__() or .__repr__() fazekasgy@31: PyObject* pyString = PyObject_Str(pyValue); fazekasgy@31: if (pyString && !PyErr_Occurred()) fazekasgy@31: { fazekasgy@31: std::string rValue = this->PyValue_To_String(pyString); fazekasgy@31: if (m_error) { fazekasgy@31: Py_DECREF(pyString); fazekasgy@31: return rValue; fazekasgy@31: } else { fazekasgy@31: Py_CLEAR(pyString); fazekasgy@31: std::string msg = "Object " + this->PyValue_Get_TypeName(pyValue) +" can not be represented as string. " + lastError().message; fazekasgy@31: setValueError (msg,m_strict); fazekasgy@31: return std::string(); fazekasgy@31: } fazekasgy@31: } fazekasgy@31: fazekasgy@31: // give up fazekasgy@31: PyErr_Print(); PyErr_Clear(); fazekasgy@31: std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to string is not possible."; fazekasgy@31: setValueError(msg,m_strict); fazekasgy@31: return std::string(); fazekasgy@31: } fazekasgy@31: fazekasgy@31: /* C Values to Py Values */ fazekasgy@31: fazekasgy@31: fazekasgy@31: PyObject* fazekasgy@31: PyTypeInterface::PyValue_From_CValue(const char* cValue) const fazekasgy@31: { fazekasgy@31: // returns new reference fazekasgy@31: if (!cValue) fazekasgy@31: setValueError("Invalid pointer encountered while converting from char* .",m_strict); fazekasgy@31: PyObject *pyValue = PyString_FromString(cValue); fazekasgy@31: if (!pyValue) fazekasgy@31: { fazekasgy@31: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@31: setValueError("Error while converting from char* or string.",m_strict); fazekasgy@31: return NULL; fazekasgy@31: } fazekasgy@31: return pyValue; fazekasgy@31: } fazekasgy@31: fazekasgy@31: PyObject* fazekasgy@31: PyTypeInterface::PyValue_From_CValue(size_t cValue) const fazekasgy@31: { fazekasgy@31: // returns new reference fazekasgy@31: PyObject *pyValue = PyInt_FromSsize_t((Py_ssize_t)cValue); fazekasgy@31: if (!pyValue) fazekasgy@31: { fazekasgy@31: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@31: setValueError("Error while converting from size_t.",m_strict); fazekasgy@31: return NULL; fazekasgy@31: } fazekasgy@31: return pyValue; fazekasgy@31: } fazekasgy@31: fazekasgy@31: PyObject* fazekasgy@31: PyTypeInterface::PyValue_From_CValue(double cValue) const fazekasgy@31: { fazekasgy@31: // returns new reference fazekasgy@31: PyObject *pyValue = PyFloat_FromDouble(cValue); fazekasgy@31: if (!pyValue) fazekasgy@31: { fazekasgy@31: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@31: setValueError("Error while converting from float or double.",m_strict); fazekasgy@31: return NULL; fazekasgy@31: } fazekasgy@31: return pyValue; fazekasgy@31: } fazekasgy@31: fazekasgy@31: PyObject* fazekasgy@31: PyTypeInterface::PyValue_From_CValue(bool cValue) const fazekasgy@31: { fazekasgy@31: // returns new reference fazekasgy@31: PyObject *pyValue = PyBool_FromLong((long)cValue); fazekasgy@31: if (!pyValue) fazekasgy@31: { fazekasgy@31: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@31: setValueError("Error while converting from bool.",m_strict); fazekasgy@31: return NULL; fazekasgy@31: } fazekasgy@31: return pyValue; fazekasgy@31: } fazekasgy@31: fazekasgy@31: fazekasgy@31: /* Sequence Types to C++ Types */ fazekasgy@31: fazekasgy@31: //convert Python list to C++ vector of strings fazekasgy@31: std::vector fazekasgy@31: PyTypeInterface::PyValue_To_StringVector (PyObject *inputList) const fazekasgy@31: { fazekasgy@31: fazekasgy@31: std::vector Output; fazekasgy@31: std::string ListElement; fazekasgy@31: PyObject *pyString = NULL; fazekasgy@31: fazekasgy@31: if (!PyList_Check(inputList)) return Output; fazekasgy@31: fazekasgy@31: for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) { fazekasgy@31: //Get next list item (Borrowed Reference) fazekasgy@31: pyString = PyList_GET_ITEM(inputList,i); fazekasgy@31: ListElement = (string) PyString_AsString(PyObject_Str(pyString)); fazekasgy@31: Output.push_back(ListElement); fazekasgy@31: } fazekasgy@31: return Output; fazekasgy@31: } fazekasgy@31: fazekasgy@32: //convert PyFeature.value (typically a list or numpy array) to C++ vector of floats fazekasgy@31: std::vector fazekasgy@32: PyTypeInterface::PyValue_To_FloatVector (PyObject *pyValue) const fazekasgy@31: { fazekasgy@31: std::vector Output; fazekasgy@32: fazekasgy@32: #ifdef HAVE_NUMPY fazekasgy@32: /// Check for NumPy Array: this requires linking with numpy fazekasgy@32: /// but, we don't really need this macro fazekasgy@32: // if (PyArray_CheckExact(inputList)) cerr << "PyPyArray_CheckExact OK" << endl; fazekasgy@31: fazekasgy@32: /// numpy array fazekasgy@32: if (PyObject_HasAttrString(pyValue,"__array_struct__")) { fazekasgy@32: return PyArray_To_FloatVector(pyValue); fazekasgy@31: } fazekasgy@32: #endif fazekasgy@32: fazekasgy@32: /// python list fazekasgy@32: if (PyList_Check(pyValue)) { fazekasgy@32: return PyList_To_FloatVector(pyValue); fazekasgy@32: } fazekasgy@32: fazekasgy@32: /// assume a single number fazekasgy@32: /// this allows to write e.g. Feature.values = 5 instead of [5.00] fazekasgy@32: Output.push_back(PyValue_To_Float(pyValue)); fazekasgy@32: return Output; fazekasgy@32: fazekasgy@32: /// TODO : set error fazekasgy@32: fazekasgy@32: } fazekasgy@32: fazekasgy@32: //convert a list of python floats fazekasgy@32: std::vector fazekasgy@32: PyTypeInterface::PyList_To_FloatVector (PyObject *inputList) const fazekasgy@32: { fazekasgy@32: std::vector Output; fazekasgy@31: fazekasgy@31: float ListElement; fazekasgy@31: PyObject *pyFloat = NULL; fazekasgy@31: fazekasgy@31: if (!PyList_Check(inputList)) return Output; fazekasgy@31: fazekasgy@32: for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) { fazekasgy@31: //Get next list item (Borrowed Reference) fazekasgy@32: pyFloat = PyList_GET_ITEM(inputList,i); fazekasgy@31: ListElement = (float) PyFloat_AS_DOUBLE(pyFloat); fazekasgy@31: #ifdef _DEBUG fazekasgy@31: cerr << "value: " << ListElement << endl; fazekasgy@31: #endif fazekasgy@31: Output.push_back(ListElement); fazekasgy@31: } fazekasgy@31: fazekasgy@31: return Output; fazekasgy@31: } fazekasgy@31: fazekasgy@32: #ifdef HAVE_NUMPY fazekasgy@32: std::vector fazekasgy@32: PyTypeInterface::PyArray_To_FloatVector (PyObject *pyValue) const fazekasgy@32: { fazekasgy@32: std::vector Output; fazekasgy@32: fazekasgy@32: /// we don't verify the array here as it'd be duplicated mostly fazekasgy@32: // if (!PyObject_HasAttrString(pyValue,"__array_struct__")) { fazekasgy@32: // return Output; fazekasgy@32: // } fazekasgy@32: fazekasgy@32: PyArrayObject* pyArray = (PyArrayObject*) pyValue; fazekasgy@32: PyArray_Descr* descr = pyArray->descr; fazekasgy@32: fazekasgy@32: /// check raw data pointer fazekasgy@32: if (pyArray->data == 0) return Output; fazekasgy@32: fazekasgy@32: /// check dimensions fazekasgy@32: if (pyArray->nd != 1) { fazekasgy@32: cerr << "Error: array must be 1D" << endl; fazekasgy@32: return Output; fazekasgy@32: } fazekasgy@32: fazekasgy@32: #ifdef _DEBUG fazekasgy@32: cerr << "Numpy array verified." << endl; fazekasgy@32: #endif fazekasgy@32: fazekasgy@32: switch (descr->type_num) fazekasgy@32: { fazekasgy@32: case NPY_FLOAT : fazekasgy@32: return PyArray_Convert(pyArray->data,pyArray->dimensions[0]); fazekasgy@32: case NPY_DOUBLE : fazekasgy@32: return PyArray_Convert(pyArray->data,pyArray->dimensions[0]); fazekasgy@32: case NPY_INT : fazekasgy@32: return PyArray_Convert(pyArray->data,pyArray->dimensions[0]); fazekasgy@32: case NPY_LONG : fazekasgy@32: return PyArray_Convert(pyArray->data,pyArray->dimensions[0]); fazekasgy@32: fazekasgy@32: default : fazekasgy@32: cerr << "Error. Unsupported element type in NumPy array object." << endl; fazekasgy@32: return Output; fazekasgy@32: } fazekasgy@32: } fazekasgy@32: #endif fazekasgy@31: fazekasgy@31: /* Vamp API Specific Types fazekasgy@31: fazekasgy@31: Vamp::Plugin::OutputList fazekasgy@31: PyTypeInterface::PyValue_To_OutputList(PyObject* pyList) const fazekasgy@31: { fazekasgy@31: Vamp::Plugin::OutputList list; fazekasgy@31: Vamp::Plugin::OutputDescriptor od; fazekasgy@31: fazekasgy@31: // Type checking fazekasgy@31: if (! PyList_Check(pyList) ) { fazekasgy@31: Py_CLEAR(pyList); fazekasgy@31: // cerr << "ERROR: In Python plugin [" << m_class << "::" << method fazekasgy@31: // << "] Expected List return type." << endl; fazekasgy@31: return list; fazekasgy@31: } fazekasgy@31: fazekasgy@31: //These will all be borrowed references (no need to DECREF) fazekasgy@31: PyObject *pyDict; fazekasgy@31: fazekasgy@31: //Parse Output List fazekasgy@31: for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) { fazekasgy@31: //Get i-th Vamp output descriptor (Borrowed Reference) fazekasgy@31: pyDict = PyList_GET_ITEM(pyList,i); fazekasgy@31: od = PyValue_To_OutputDescriptor(pyDict); fazekasgy@31: list.push_back(od); fazekasgy@31: } fazekasgy@31: return list; fazekasgy@31: } fazekasgy@31: fazekasgy@31: Vamp::Plugin::ParameterList fazekasgy@31: PyTypeInterface::PyValue_To_ParameterList(PyObject* pyList) const fazekasgy@31: { fazekasgy@31: Vamp::Plugin::ParameterList list; fazekasgy@31: Vamp::Plugin::ParameterDescriptor pd; fazekasgy@31: fazekasgy@31: // Type checking fazekasgy@31: if (! PyList_Check(pyList) ) { fazekasgy@31: Py_CLEAR(pyList); fazekasgy@31: // cerr << "ERROR: In Python plugin [" << m_class << "::" << method fazekasgy@31: // << "] Expected List return type." << endl; fazekasgy@31: return list; fazekasgy@31: } fazekasgy@31: fazekasgy@31: //These will all be borrowed references (no need to DECREF) fazekasgy@31: PyObject *pyDict; fazekasgy@31: fazekasgy@31: //Parse Output List fazekasgy@31: for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) { fazekasgy@31: //Get i-th Vamp output descriptor (Borrowed Reference) fazekasgy@31: pyDict = PyList_GET_ITEM(pyList,i); fazekasgy@31: pd = PyValue_To_ParameterDescriptor(pyDict); fazekasgy@31: list.push_back(pd); fazekasgy@31: } fazekasgy@31: return list; fazekasgy@31: } fazekasgy@31: fazekasgy@31: Vamp::Plugin::OutputDescriptor fazekasgy@31: PyTypeInterface::PyValue_To_OutputDescriptor(PyObject* pyDict) const fazekasgy@31: { fazekasgy@31: //We only care about dictionaries holding output descriptors fazekasgy@31: if (!PyDict_Check(pyDict)) fazekasgy@31: return Vamp::Plugin::OutputDescriptor(); fazekasgy@31: fazekasgy@31: Py_ssize_t pyPos = 0; fazekasgy@31: PyObject *pyKey, *pyValue; fazekasgy@31: initMaps(); fazekasgy@31: Vamp::Plugin::OutputDescriptor od; fazekasgy@31: fazekasgy@31: //Python Dictionary Iterator: fazekasgy@31: while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue)) fazekasgy@31: { fazekasgy@31: std::string key = PyValue_To_String(pyKey); fazekasgy@31: SetValue(od,key,pyValue); fazekasgy@31: if (m_error) { fazekasgy@31: _lastError().location += "parameter: '" fazekasgy@31: + key +"' descriptor: '" + od.identifier + "'"; fazekasgy@31: } fazekasgy@31: } fazekasgy@31: if (!m_errorQueue.empty()) m_error = true; fazekasgy@31: return od; fazekasgy@31: } fazekasgy@31: fazekasgy@31: Vamp::Plugin::ParameterDescriptor fazekasgy@31: PyTypeInterface::PyValue_To_ParameterDescriptor(PyObject* pyDict) const fazekasgy@31: { fazekasgy@31: //We only care about dictionaries holding output descriptors fazekasgy@31: if (!PyDict_Check(pyDict)) fazekasgy@31: return Vamp::Plugin::ParameterDescriptor(); fazekasgy@31: fazekasgy@31: Py_ssize_t pyPos = 0; fazekasgy@31: PyObject *pyKey, *pyValue; fazekasgy@31: initMaps(); fazekasgy@31: Vamp::Plugin::ParameterDescriptor pd; fazekasgy@31: fazekasgy@31: //Python Dictionary Iterator: fazekasgy@31: while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue)) fazekasgy@31: { fazekasgy@31: std::string key = PyValue_To_String(pyKey); fazekasgy@31: SetValue(pd,key,pyValue); fazekasgy@31: if (m_error) { fazekasgy@31: _lastError().location += "parameter: '" fazekasgy@31: + key +"' descriptor: '" + pd.identifier + "'"; fazekasgy@31: } fazekasgy@31: } fazekasgy@31: if (!m_errorQueue.empty()) m_error = true; fazekasgy@31: return pd; fazekasgy@31: } fazekasgy@31: fazekasgy@31: Vamp::Plugin::Feature fazekasgy@31: PyTypeInterface::PyValue_To_Feature(PyObject* pyDict) const fazekasgy@31: { fazekasgy@31: //We only care about dictionaries holding output descriptors fazekasgy@31: if (!PyDict_Check(pyDict)) fazekasgy@31: return Vamp::Plugin::Feature(); fazekasgy@31: fazekasgy@31: Py_ssize_t pyPos = 0; fazekasgy@31: PyObject *pyKey, *pyValue; fazekasgy@31: initMaps(); fazekasgy@31: Vamp::Plugin::Feature feature; fazekasgy@31: fazekasgy@31: //Python Dictionary Iterator: fazekasgy@31: while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue)) fazekasgy@31: { fazekasgy@31: std::string key = PyValue_To_String(pyKey); fazekasgy@31: float isr = 22050.0; fazekasgy@31: Feature_SetValue(feature,key,pyValue,isr); fazekasgy@31: if (m_error) { fazekasgy@31: _lastError().location += "key: '" + key + "'"; fazekasgy@31: // _lastError().location += "parameter: '" fazekasgy@31: // + key +"' descriptor: '" + pd.identifier + "'"; fazekasgy@31: } fazekasgy@31: } fazekasgy@31: if (!m_errorQueue.empty()) m_error = true; fazekasgy@31: return feature; fazekasgy@31: } fazekasgy@31: */ fazekasgy@31: fazekasgy@31: /// FeatureSet (an int map of OutputLists) fazekasgy@31: Vamp::Plugin::FeatureSet fazekasgy@31: PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const fazekasgy@31: { fazekasgy@32: Vamp::Plugin::FeatureSet rFeatureSet; /// map fazekasgy@31: if (pyValue == NULL) { fazekasgy@31: cerr << "NULL FeatureSet" << endl; fazekasgy@31: return rFeatureSet; fazekasgy@31: } fazekasgy@31: fazekasgy@31: cerr << "PyValue_To_FeatureSet" << endl; fazekasgy@31: //Convert PyFeatureSet fazekasgy@31: if (PyFeatureSet_CheckExact(pyValue)) { fazekasgy@31: cerr << "FeatureSet Return type" << endl; fazekasgy@31: Py_ssize_t pyPos = 0; fazekasgy@31: //Borrowed References fazekasgy@31: PyObject *pyKey, *pyDictValue; fazekasgy@31: int key; fazekasgy@31: fazekasgy@31: //Python Dictionary Iterator: fazekasgy@31: while (PyDict_Next(pyValue, &pyPos, &pyKey, &pyDictValue)) fazekasgy@31: { fazekasgy@31: /// DictValue -> Vamp::FeatureList fazekasgy@31: key = (int) PyInt_AS_LONG(pyKey); fazekasgy@31: cerr << "FeatureSet key = " << key << endl; fazekasgy@31: /// Error checking is done at value assignment fazekasgy@31: PyValue_To_rValue(pyDictValue,rFeatureSet[key]); fazekasgy@31: } fazekasgy@31: if (!m_errorQueue.empty()) m_error = true; fazekasgy@31: return rFeatureSet; fazekasgy@31: } fazekasgy@31: cerr << "not FeatureSet Return type" << endl; fazekasgy@31: fazekasgy@31: fazekasgy@31: //Check return type fazekasgy@31: if (pyValue == NULL || !PyList_Check(pyValue) ) { fazekasgy@31: if (pyValue == NULL) { fazekasgy@31: // cerr << "ERROR: In Python plugin [" << m_class << "::" << method << "] Unexpected result." << endl; fazekasgy@31: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@31: } else { fazekasgy@31: // cerr << "ERROR: In Python plugin [" << m_class << "::" << method << "] Expected List return type." << endl; fazekasgy@31: } fazekasgy@31: Py_CLEAR(pyValue); fazekasgy@31: return Vamp::Plugin::FeatureSet(); fazekasgy@31: } fazekasgy@31: fazekasgy@31: // This will be borrowed reference fazekasgy@31: PyObject *pyFeatureList; fazekasgy@31: fazekasgy@31: //Parse Output List for each element (FeatureSet) fazekasgy@31: for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyValue); ++i) { fazekasgy@31: //Get i-th FeatureList (Borrowed Reference) fazekasgy@31: pyFeatureList = PyList_GET_ITEM(pyValue,i); fazekasgy@31: PyValue_To_rValue(pyFeatureList,rFeatureSet[i]); fazekasgy@31: } fazekasgy@31: // Py_CLEAR(pyOutputList); fazekasgy@31: return rFeatureSet; fazekasgy@31: } fazekasgy@31: cannam@34: Vamp::RealTime fazekasgy@31: PyTypeInterface::PyValue_To_RealTime(PyObject* pyValue) const fazekasgy@31: { fazekasgy@31: // We accept integer sample counts (for backwards compatibility) fazekasgy@31: // or PyRealTime objects and convert them to Vamp::RealTime fazekasgy@31: fazekasgy@31: if (PyRealTime_CheckExact(pyValue)) fazekasgy@31: { fazekasgy@31: #ifdef _DEBUG fazekasgy@31: cerr << "Converting from PyRealTime" << endl; fazekasgy@31: #endif fazekasgy@31: /// just create a copy of the wrapped object cannam@34: return Vamp::RealTime( fazekasgy@31: *PyRealTime_AS_REALTIME(pyValue)); fazekasgy@31: } fazekasgy@31: // assume integer sample count fazekasgy@31: long sampleCount = PyLong_AsLong(pyValue); fazekasgy@31: if (PyErr_Occurred()) fazekasgy@31: { fazekasgy@31: PyErr_Print(); PyErr_Clear(); fazekasgy@31: setValueError("Error while converting integer to RealTime.",m_strict); cannam@34: return Vamp::RealTime(); fazekasgy@31: } fazekasgy@31: #ifdef _DEBUG cannam@34: Vamp::RealTime rt = fazekasgy@31: Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate ); fazekasgy@31: cerr << "RealTime: " << (long)sampleCount << ", ->" << rt.toString() << endl; fazekasgy@31: return rt; fazekasgy@31: #else fazekasgy@31: return Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate ); fazekasgy@31: #endif fazekasgy@31: fazekasgy@31: } fazekasgy@31: fazekasgy@31: fazekasgy@31: /// OutputDescriptor fazekasgy@31: void fazekasgy@31: PyTypeInterface::SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const fazekasgy@31: { fazekasgy@31: switch (outKeys[key]) fazekasgy@31: { fazekasgy@31: case o::not_found: fazekasgy@31: cerr << "Unknown key in Vamp OutputDescriptor: " << key << endl; fazekasgy@31: break; fazekasgy@31: case o::identifier: fazekasgy@31: _convert(pyValue,od.identifier); fazekasgy@31: break; fazekasgy@31: case o::name: fazekasgy@31: _convert(pyValue,od.name); fazekasgy@31: break; fazekasgy@31: case o::description: fazekasgy@31: _convert(pyValue,od.description); fazekasgy@31: break; fazekasgy@31: case o::unit: fazekasgy@31: _convert(pyValue,od.unit); fazekasgy@31: break; fazekasgy@31: case o::hasFixedBinCount: fazekasgy@31: _convert(pyValue,od.hasFixedBinCount); fazekasgy@31: break; fazekasgy@31: case o::binCount: fazekasgy@31: _convert(pyValue,od.binCount); fazekasgy@31: break; fazekasgy@31: case o::binNames: fazekasgy@31: _convert(pyValue,od.binNames); fazekasgy@31: break; fazekasgy@31: case o::hasKnownExtents: fazekasgy@31: _convert(pyValue,od.hasKnownExtents); fazekasgy@31: break; fazekasgy@31: case o::minValue: fazekasgy@31: _convert(pyValue,od.minValue); fazekasgy@31: break; fazekasgy@31: case o::maxValue: fazekasgy@31: _convert(pyValue,od.maxValue); fazekasgy@31: break; fazekasgy@31: case o::isQuantized: fazekasgy@31: _convert(pyValue,od.isQuantized); fazekasgy@31: break; fazekasgy@31: case o::quantizeStep: fazekasgy@31: _convert(pyValue,od.quantizeStep); fazekasgy@31: break; fazekasgy@31: case o::sampleType: fazekasgy@31: // implements specific conversion! fazekasgy@31: od.sampleType = (Vamp::Plugin::OutputDescriptor::SampleType) sampleKeys[PyValue_To_String(pyValue)]; fazekasgy@31: break; fazekasgy@31: case o::sampleRate: fazekasgy@31: _convert(pyValue,od.sampleRate); fazekasgy@31: break; fazekasgy@31: case o::hasDuration: fazekasgy@31: _convert(pyValue,od.hasDuration); fazekasgy@31: break; fazekasgy@31: default: fazekasgy@31: cerr << "Invalid key in Vamp OutputDescriptor: " << key << endl; fazekasgy@31: } fazekasgy@31: } fazekasgy@31: fazekasgy@31: /// ParameterDescriptor fazekasgy@31: void fazekasgy@31: PyTypeInterface::SetValue(Vamp::Plugin::ParameterDescriptor& pd, std::string& key, PyObject* pyValue) const fazekasgy@31: { fazekasgy@31: switch (parmKeys[key]) fazekasgy@31: { fazekasgy@31: case p::not_found : fazekasgy@31: cerr << "Unknown key in Vamp ParameterDescriptor: " << key << endl; fazekasgy@31: break; fazekasgy@31: case p::identifier: fazekasgy@31: _convert(pyValue,pd.identifier); fazekasgy@31: break; fazekasgy@31: case p::name: fazekasgy@31: _convert(pyValue,pd.name); fazekasgy@31: break; fazekasgy@31: case p::description: fazekasgy@31: _convert(pyValue,pd.description); fazekasgy@31: break; fazekasgy@31: case p::unit: fazekasgy@31: _convert(pyValue,pd.unit); fazekasgy@31: break; fazekasgy@31: case p::minValue: fazekasgy@31: _convert(pyValue,pd.minValue); fazekasgy@31: break; fazekasgy@31: case p::maxValue: fazekasgy@31: _convert(pyValue,pd.maxValue); fazekasgy@31: break; fazekasgy@31: case p::defaultValue: fazekasgy@31: _convert(pyValue,pd.defaultValue); fazekasgy@31: break; fazekasgy@31: case p::isQuantized: fazekasgy@31: _convert(pyValue,pd.isQuantized); fazekasgy@31: break; fazekasgy@31: case p::quantizeStep: fazekasgy@31: _convert(pyValue,pd.quantizeStep); fazekasgy@31: break; fazekasgy@31: default : fazekasgy@31: cerr << "Invalid key in Vamp ParameterDescriptor: " << key << endl; fazekasgy@31: } fazekasgy@31: } fazekasgy@31: fazekasgy@31: /// Feature (it's like a Descriptor) fazekasgy@31: bool fazekasgy@31: PyTypeInterface::SetValue(Vamp::Plugin::Feature& feature, std::string& key, PyObject* pyValue) const fazekasgy@31: { fazekasgy@31: bool found = true; fazekasgy@31: switch (ffKeys[key]) fazekasgy@31: { fazekasgy@31: case unknown : fazekasgy@31: cerr << "Unknown key in Vamp Feature: " << key << endl; fazekasgy@31: found = false; fazekasgy@31: break; fazekasgy@31: case hasTimestamp: fazekasgy@31: _convert(pyValue,feature.hasTimestamp); fazekasgy@31: break; fazekasgy@31: case timeStamp: fazekasgy@31: _convert(pyValue,feature.timestamp); fazekasgy@31: break; fazekasgy@31: case hasDuration: fazekasgy@31: _convert(pyValue,feature.hasDuration); fazekasgy@31: break; fazekasgy@31: case duration: fazekasgy@31: _convert(pyValue,feature.duration); fazekasgy@31: break; fazekasgy@31: case values: fazekasgy@31: _convert(pyValue,feature.values); fazekasgy@31: break; fazekasgy@31: case label: fazekasgy@31: _convert(pyValue,feature.label); fazekasgy@31: break; fazekasgy@31: default: fazekasgy@31: found = false; fazekasgy@31: } fazekasgy@31: return found; fazekasgy@31: } fazekasgy@31: fazekasgy@31: /* fazekasgy@31: /// Feature (it's like a Descriptor) fazekasgy@31: bool fazekasgy@31: PyTypeInterface::GetValue(Vamp::Plugin::Feature& feature, std::string& key, PyObject* pyValue) const fazekasgy@31: { fazekasgy@31: bool found = true; fazekasgy@31: switch (ffKeys[key]) fazekasgy@31: { fazekasgy@31: case unknown : fazekasgy@31: cerr << "Unknown key in Vamp Feature: " << key << endl; fazekasgy@31: found = false; fazekasgy@31: break; fazekasgy@31: case hasTimestamp: fazekasgy@31: _convert(pyValue,feature.hasTimestamp); fazekasgy@31: // pyValue = PyValue_From_CValue(feature.hasTimestamp) fazekasgy@31: break; fazekasgy@31: case timeStamp: fazekasgy@31: _convert(pyValue,feature.timestamp); fazekasgy@31: break; fazekasgy@31: case hasDuration: fazekasgy@31: _convert(pyValue,feature.hasDuration); fazekasgy@31: break; fazekasgy@31: case duration: fazekasgy@31: _convert(pyValue,feature.duration); fazekasgy@31: break; fazekasgy@31: case values: fazekasgy@31: _convert(pyValue,feature.values); fazekasgy@31: break; fazekasgy@31: case label: fazekasgy@31: _convert(pyValue,feature.label); //vector fazekasgy@31: break; fazekasgy@31: default: fazekasgy@31: found = false; fazekasgy@31: } fazekasgy@31: return found; fazekasgy@31: } fazekasgy@31: */ fazekasgy@31: fazekasgy@31: /* Error handling */ fazekasgy@31: fazekasgy@31: void fazekasgy@31: PyTypeInterface::setValueError (std::string message, bool strict) const fazekasgy@31: { fazekasgy@31: m_error = true; fazekasgy@31: m_errorQueue.push(ValueError(message,strict)); fazekasgy@31: } fazekasgy@31: fazekasgy@31: /// return a reference to the last error or creates a new one. fazekasgy@31: PyTypeInterface::ValueError& fazekasgy@31: PyTypeInterface::_lastError() const fazekasgy@31: { fazekasgy@31: m_error = false; fazekasgy@31: if (!m_errorQueue.empty()) return m_errorQueue.back(); fazekasgy@31: else { fazekasgy@31: m_errorQueue.push(ValueError("Type conversion error.",m_strict)); fazekasgy@31: return m_errorQueue.back(); fazekasgy@31: } fazekasgy@31: } fazekasgy@31: fazekasgy@31: /// return the last error message and clear the error flag fazekasgy@31: const PyTypeInterface::ValueError& fazekasgy@31: PyTypeInterface::lastError() const fazekasgy@31: { fazekasgy@31: // PyTypeInterface *self = const_cast (this); fazekasgy@31: m_error = false; fazekasgy@31: if (!m_errorQueue.empty()) return m_errorQueue.back(); fazekasgy@31: else return m_noError; fazekasgy@31: } fazekasgy@31: fazekasgy@31: /// iterate over the error message queue and pop the oldest item fazekasgy@31: PyTypeInterface::ValueError fazekasgy@31: PyTypeInterface::getError() const fazekasgy@31: { fazekasgy@31: if (!m_errorQueue.empty()) { fazekasgy@31: PyTypeInterface::ValueError e = m_errorQueue.front(); fazekasgy@31: m_errorQueue.pop(); fazekasgy@31: if (m_errorQueue.empty()) m_error = false; fazekasgy@31: return e; fazekasgy@31: } fazekasgy@31: else { fazekasgy@31: m_error = false; fazekasgy@31: return PyTypeInterface::ValueError(); fazekasgy@31: } fazekasgy@31: } fazekasgy@31: fazekasgy@31: /* Utilities */ fazekasgy@31: fazekasgy@31: /// get the type name of an object fazekasgy@31: std::string fazekasgy@31: PyTypeInterface::PyValue_Get_TypeName(PyObject* pyValue) const fazekasgy@31: { fazekasgy@31: PyObject *pyType = PyObject_Type(pyValue); fazekasgy@31: if (!pyType) return std::string ("< unknown type >"); fazekasgy@31: PyObject *pyString = PyObject_Str(pyType); fazekasgy@31: if (!pyString) fazekasgy@31: { fazekasgy@31: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@31: Py_CLEAR(pyType); fazekasgy@31: return std::string ("< unknown type >"); fazekasgy@31: } fazekasgy@31: char *cstr = PyString_AS_STRING(pyString); fazekasgy@31: if (!cstr) fazekasgy@31: { fazekasgy@31: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@31: Py_DECREF(pyType); fazekasgy@31: Py_CLEAR(pyString); fazekasgy@31: cerr << "Warning: Object type name could not be found." << endl; fazekasgy@31: return std::string("< unknown type >"); fazekasgy@31: } fazekasgy@31: Py_DECREF(pyType); fazekasgy@31: Py_DECREF(pyString); fazekasgy@31: return std::string(cstr); fazekasgy@31: } fazekasgy@31: fazekasgy@31: bool fazekasgy@31: PyTypeInterface::initMaps() const fazekasgy@31: { fazekasgy@31: fazekasgy@31: if (isMapInitialised) return true; fazekasgy@31: fazekasgy@31: outKeys["identifier"] = o::identifier; fazekasgy@31: outKeys["name"] = o::name; fazekasgy@31: outKeys["description"] = o::description; fazekasgy@31: outKeys["unit"] = o::unit; fazekasgy@31: outKeys["hasFixedBinCount"] = o::hasFixedBinCount; fazekasgy@31: outKeys["binCount"] = o::binCount; fazekasgy@31: outKeys["binNames"] = o::binNames; fazekasgy@31: outKeys["hasKnownExtents"] = o::hasKnownExtents; fazekasgy@31: outKeys["minValue"] = o::minValue; fazekasgy@31: outKeys["maxValue"] = o::maxValue; fazekasgy@31: outKeys["isQuantized"] = o::isQuantized; fazekasgy@31: outKeys["quantizeStep"] = o::quantizeStep; fazekasgy@31: outKeys["sampleType"] = o::sampleType; fazekasgy@31: outKeys["sampleRate"] = o::sampleRate; fazekasgy@31: outKeys["hasDuration"] = o::hasDuration; fazekasgy@31: fazekasgy@31: sampleKeys["OneSamplePerStep"] = OneSamplePerStep; fazekasgy@31: sampleKeys["FixedSampleRate"] = FixedSampleRate; fazekasgy@31: sampleKeys["VariableSampleRate"] = VariableSampleRate; fazekasgy@31: fazekasgy@31: ffKeys["hasTimestamp"] = hasTimestamp; fazekasgy@31: ffKeys["timeStamp"] = timeStamp; fazekasgy@31: ffKeys["hasDuration"] = hasDuration; fazekasgy@31: ffKeys["duration"] = duration; fazekasgy@31: ffKeys["values"] = values; fazekasgy@31: ffKeys["label"] = label; fazekasgy@31: fazekasgy@31: parmKeys["identifier"] = p::identifier; fazekasgy@31: parmKeys["name"] = p::name; fazekasgy@31: parmKeys["description"] = p::description; fazekasgy@31: parmKeys["unit"] = p::unit; fazekasgy@31: parmKeys["minValue"] = p::minValue; fazekasgy@31: parmKeys["maxValue"] = p::maxValue; fazekasgy@31: parmKeys["defaultValue"] = p::defaultValue; fazekasgy@31: parmKeys["isQuantized"] = p::isQuantized; fazekasgy@31: parmKeys["quantizeStep"] = p::quantizeStep; fazekasgy@31: fazekasgy@31: isMapInitialised = true; fazekasgy@31: return true; fazekasgy@31: }