fazekasgy@31: /* fazekasgy@31: */ fazekasgy@31: fazekasgy@31: #include 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 fazekasgy@31: #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@31: (EXCEPT FOR TEMPORARY PYOBJECTS)! */ 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) fazekasgy@31: if (PySequence_Check(pyValue) and 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 fazekasgy@31: if (PySequence_Check(pyValue) and 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@31: //convert Python list to C++ vector of floats fazekasgy@31: std::vector fazekasgy@31: PyTypeInterface::PyValue_To_FloatVector (PyObject *inputList) const fazekasgy@31: { fazekasgy@31: typedef std::vector floatVector; fazekasgy@31: std::vector Output; fazekasgy@31: fazekasgy@31: /// Check for NumPy Array fazekasgy@31: if (PyObject_HasAttrString(inputList,"__array_struct__")) { fazekasgy@31: int vectorLength; fazekasgy@31: float *dataptr = getNumPyObjectData(inputList,vectorLength); fazekasgy@31: if (dataptr != 0) cerr << "Numpy array found: " << vectorLength << endl; fazekasgy@31: // Output = *dataptr; fazekasgy@31: } fazekasgy@31: fazekasgy@31: float ListElement; fazekasgy@31: PyObject *pyFloat = NULL; fazekasgy@31: fazekasgy@31: if (!PyList_Check(inputList)) return Output; fazekasgy@31: fazekasgy@31: for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) { fazekasgy@31: //Get next list item (Borrowed Reference) fazekasgy@31: pyFloat = PyList_GET_ITEM(inputList,k); 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@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@31: Vamp::Plugin::FeatureSet rFeatureSet; /// PyFeatureSet is an int 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: fazekasgy@31: Vamp::RealTime::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 fazekasgy@31: return Vamp::RealTime::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); fazekasgy@31: return Vamp::RealTime::RealTime(); fazekasgy@31: } fazekasgy@31: #ifdef _DEBUG fazekasgy@31: Vamp::RealTime::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: //return a pointer to the data in the numPy array fazekasgy@31: float* fazekasgy@31: PyTypeInterface::getNumPyObjectData(PyObject *object, int &length) const fazekasgy@31: { fazekasgy@31: fazekasgy@31: char attr_name[]="__array_struct__"; fazekasgy@31: fazekasgy@31: //check if we passed in a NumPy array object fazekasgy@31: if (!PyObject_HasAttrString(object,attr_name)) { fazekasgy@31: // PyErr_SetString(PyExc_TypeError, fazekasgy@31: // "Input object has no __array_struct__ attribute. NumPy array required."); fazekasgy@31: return NULL; fazekasgy@31: } fazekasgy@31: fazekasgy@31: //retrieve __array_struct__ interface fazekasgy@31: object = PyObject_GetAttrString(object,attr_name); fazekasgy@31: fazekasgy@31: //check whether we found CObjects fazekasgy@31: if (!PyCObject_Check(object)) { fazekasgy@31: PyErr_SetString(PyExc_TypeError, fazekasgy@31: "The passed __array_struct__ interface is not a valid C Object."); fazekasgy@31: return NULL; fazekasgy@31: } fazekasgy@31: fazekasgy@31: fazekasgy@31: //check if the pointers directed to the integer '2' fazekasgy@31: int *check = (int *) PyCObject_AsVoidPtr (object); fazekasgy@31: fazekasgy@31: if (*check != 2 ) { fazekasgy@31: PyErr_SetString(PyExc_TypeError, fazekasgy@31: "A C Object __array_struct__ required as inputs"); fazekasgy@31: return NULL; fazekasgy@31: } fazekasgy@31: fazekasgy@31: //convert CObjects to Array interfaces fazekasgy@31: PyArrayInterface *arrayInterface = fazekasgy@31: (PyArrayInterface *) PyCObject_AsVoidPtr (object); fazekasgy@31: fazekasgy@31: //check array dimension: should be 1 fazekasgy@31: int inputDim = arrayInterface->nd; fazekasgy@31: fazekasgy@31: if (inputDim > 1 ) { fazekasgy@31: PyErr_SetString(PyExc_TypeError, fazekasgy@31: "Array dimensions must not exceed one."); fazekasgy@31: return NULL; fazekasgy@31: } fazekasgy@31: fazekasgy@31: // check if vector size is sane fazekasgy@31: Py_intptr_t arrayLength = arrayInterface->shape[0]; fazekasgy@31: length = (int) arrayLength; fazekasgy@31: fazekasgy@31: // if (arrayLength < 8 || arrayLength > 65536 ) { fazekasgy@31: // PyErr_SetString(PyExc_TypeError, fazekasgy@31: // "Array length is out of bounds."); fazekasgy@31: // return NULL; fazekasgy@31: // } fazekasgy@31: fazekasgy@31: //check type; must be float32 fazekasgy@31: char arrayType = arrayInterface->typekind; fazekasgy@31: fazekasgy@31: if (arrayType != 'f' ) { fazekasgy@31: PyErr_SetString(PyExc_TypeError, fazekasgy@31: "Floating point arrays required."); fazekasgy@31: return NULL; fazekasgy@31: } fazekasgy@31: fazekasgy@31: //return data vector address fazekasgy@31: return (float*) arrayInterface->data; fazekasgy@31: fazekasgy@31: } 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: }