Mercurial > hg > vampy
diff PyTypeInterface.cpp @ 31:4f1894c7591b vampy2
Created Vampy2 branch
author | fazekasgy |
---|---|
date | Sun, 20 Sep 2009 17:31:20 +0000 |
parents | |
children | a8231788216c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PyTypeInterface.cpp Sun Sep 20 17:31:20 2009 +0000 @@ -0,0 +1,1039 @@ +/* +*/ + +#include <Python.h> +#include "PyTypeInterface.h" +#include "PyRealTime.h" +#include "PyExtensionModule.h" +#include <math.h> +#include <float.h> +#include <limits.h> +#ifndef SIZE_T_MAX +#define (SIZE_T_MAX (size_t) -1) +#endif + +using std::string; +using std::vector; +using std::cerr; +using std::endl; +using std::map; + +static std::map<std::string, o::eOutDescriptors> outKeys; +static std::map<std::string, p::eParmDescriptors> parmKeys; +static std::map<std::string, eSampleTypes> sampleKeys; +static std::map<std::string, eFeatureFields> ffKeys; +static bool isMapInitialised = false; + +/* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS + (EXCEPT FOR TEMPORARY PYOBJECTS)! */ + +PyTypeInterface::PyTypeInterface() : + m_strict(false), + m_error(false), + m_lastError(m_noError), + error(m_error) +{ +} + +PyTypeInterface::~PyTypeInterface() +{ +} + +/// floating point numbers (TODO: check numpy.float128) +float +PyTypeInterface::PyValue_To_Float(PyObject* pyValue) const +{ + // convert float + if (PyFloat_Check(pyValue)) + { + float rValue = (float) PyFloat_AS_DOUBLE(pyValue); + if (PyErr_Occurred()) + { + PyErr_Print(); PyErr_Clear(); + setValueError("Error while converting float object.",m_strict); + return 0.0; + } + return rValue; + } + + // in strict mode we will not try harder + if (m_strict) { + setValueError("Strict conversion error: object is not float.",m_strict); + return 0.0; + } + + // convert other objects supporting the number protocol + if (PyNumber_Check(pyValue)) + { + // PEP353: Py_ssize_t is size_t but signed ! + // This will work up to numpy.float64 + Py_ssize_t rValue = PyNumber_AsSsize_t(pyValue,NULL); + if (PyErr_Occurred()) + { + PyErr_Print(); PyErr_Clear(); + setValueError("Error while converting integer object.",m_strict); + return 0.0; + } + if (rValue > FLT_MAX || rValue < FLT_MIN) + { + setValueError("Overflow error. Object can not be converted to float.",m_strict); + return 0.0; + } + return (float) rValue; + } + + // convert string + if (PyString_Check(pyValue)) + { + PyObject* pyFloat = PyFloat_FromString(pyValue,NULL); + if (!pyFloat) + { + if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } + setValueError("String value can not be converted to float.",m_strict); + return 0.0; + } + float rValue = (float) PyFloat_AS_DOUBLE(pyFloat); + if (PyErr_Occurred()) + { + PyErr_Print(); PyErr_Clear(); + Py_CLEAR(pyFloat); + setValueError("Error while converting float object.",m_strict); + return 0.0; + } + Py_DECREF(pyFloat); + return rValue; + } + + // convert the first element of any iterable sequence (for convenience and backwards compatibility) + if (PySequence_Check(pyValue) and PySequence_Size(pyValue) > 0) + { + PyObject* item = PySequence_GetItem(pyValue,0); + if (item) + { + float rValue = this->PyValue_To_Float(item); + if (!m_error) { + Py_DECREF(item); + return rValue; + } else { + Py_CLEAR(item); + std::string msg = "Could not convert sequence element. " + lastError().message; + setValueError(msg,m_strict); + return 0.0; + } + } + } + + // give up + if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } + std::string msg = "Conversion from " + PyValue_Get_TypeName(pyValue) + " to float is not possible."; + setValueError(msg,m_strict); + return 0.0; +} + +/// size_t (unsigned integer types) +size_t +PyTypeInterface::PyValue_To_Size_t(PyObject* pyValue) const +{ + // convert objects supporting the number protocol + if (PyNumber_Check(pyValue)) + { + if (m_strict && !PyInt_Check(pyValue) && !PyLong_Check(pyValue)) + setValueError("Strict conversion error: object is not integer type.",m_strict); + // Note: this function handles Bool,Int,Long,Float + // PEP353: Py_ssize_t is size_t but signed ! + Py_ssize_t rValue = PyInt_AsSsize_t(pyValue); + if (PyErr_Occurred()) + { + PyErr_Print(); PyErr_Clear(); + setValueError("Error while converting integer object.",m_strict); + return 0; + } + if ((unsigned long)rValue > SIZE_T_MAX || (unsigned long)rValue < 0) + { + setValueError("Overflow error. Object can not be converted to size_t.",m_strict); + return 0; + } + return (size_t) rValue; + } + + // in strict mode we will not try harder and throw an exception + // then the caller should decide what to do with it + if (m_strict) { + setValueError("Strict conversion error: object is not integer.",m_strict); + return 0; + } + + // convert string + if (PyString_Check(pyValue)) + { + PyObject* pyLong = PyNumber_Long(pyValue); + if (!pyLong) + { + if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } + setValueError("String object can not be converted to size_t.",m_strict); + return 0; + } + size_t rValue = this->PyValue_To_Size_t(pyLong); + if (!m_error) { + Py_DECREF(pyLong); + return rValue; + } else { + Py_CLEAR(pyLong); + setValueError (lastError().message,m_strict); + return 0; + } + } + + // convert the first element of iterable sequences + if (PySequence_Check(pyValue) and PySequence_Size(pyValue) > 0) + { + PyObject* item = PySequence_GetItem(pyValue,0); + if (item) + { + size_t rValue = this->PyValue_To_Size_t(item); + if (!m_error) { + Py_DECREF(item); + return rValue; + } else { + Py_CLEAR(item); + std::string msg = "Could not convert sequence element. " + lastError().message; + setValueError(msg,m_strict); + return 0; + } + } + } + + // give up + if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } + std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to size_t is not possible."; + setValueError(msg,m_strict); + return 0; +} + +bool +PyTypeInterface::PyValue_To_Bool(PyObject* pyValue) const +{ + // convert objects supporting the number protocol + // Note: PyBool is a subclass of PyInt + if (PyNumber_Check(pyValue)) + { + if (m_strict && !PyBool_Check(pyValue)) + setValueError + ("Strict conversion error: object is not boolean type.",m_strict); + + // Note: this function handles Bool,Int,Long,Float + Py_ssize_t rValue = PyInt_AsSsize_t(pyValue); + if (PyErr_Occurred()) + { + PyErr_Print(); PyErr_Clear(); + setValueError ("Error while converting boolean object.",m_strict); + } + if (rValue != 1 && rValue != 0) + { + setValueError ("Overflow error. Object can not be converted to boolean.",m_strict); + } + return (bool) rValue; + } + + if (m_strict) { + setValueError ("Strict conversion error: object is not numerical type.",m_strict); + return false; + } + + // convert iterables: the rule is the same as of the interpreter: + // empty sequence evaluates to False, anything else is True + if (PySequence_Check(pyValue)) + { + return PySequence_Size(pyValue)?true:false; + } + + // give up + if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } + std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to boolean is not possible."; + setValueError(msg,m_strict); + return false; +} + +/// string and objects that support .__str__() (TODO: check unicode objects) +std::string +PyTypeInterface::PyValue_To_String(PyObject* pyValue) const +{ + // convert string + if (PyString_Check(pyValue)) + { + char *cstr = PyString_AS_STRING(pyValue); + if (!cstr) + { + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + setValueError("Error while converting string object.",m_strict); + return std::string(); + } + return std::string(cstr); + } + // TODO: deal with unicode here (argh!) + + // in strict mode we will not try harder + if (m_strict) { + setValueError("Strict conversion error: object is not string.",m_strict); + return std::string(); + } + + // convert list or tuple: empty lists are turned into empty strings + if (PyList_Check(pyValue) || PyTuple_Check(pyValue)) + { + if (!PySequence_Size(pyValue)) return std::string(); + PyObject* item = PySequence_GetItem(pyValue,0); + if (item) + { + std::string rValue = this->PyValue_To_String(item); + if (m_error) { + Py_DECREF(item); + return rValue; + } else { + Py_CLEAR(item); + std::string msg = "Could not convert sequence element. " + lastError().message; + setValueError(msg,m_strict); + return std::string(); + } + } + } + + // convert any other object that has .__str__() or .__repr__() + PyObject* pyString = PyObject_Str(pyValue); + if (pyString && !PyErr_Occurred()) + { + std::string rValue = this->PyValue_To_String(pyString); + if (m_error) { + Py_DECREF(pyString); + return rValue; + } else { + Py_CLEAR(pyString); + std::string msg = "Object " + this->PyValue_Get_TypeName(pyValue) +" can not be represented as string. " + lastError().message; + setValueError (msg,m_strict); + return std::string(); + } + } + + // give up + PyErr_Print(); PyErr_Clear(); + std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to string is not possible."; + setValueError(msg,m_strict); + return std::string(); +} + +/* C Values to Py Values */ + + +PyObject* +PyTypeInterface::PyValue_From_CValue(const char* cValue) const +{ + // returns new reference + if (!cValue) + setValueError("Invalid pointer encountered while converting from char* .",m_strict); + PyObject *pyValue = PyString_FromString(cValue); + if (!pyValue) + { + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + setValueError("Error while converting from char* or string.",m_strict); + return NULL; + } + return pyValue; +} + +PyObject* +PyTypeInterface::PyValue_From_CValue(size_t cValue) const +{ + // returns new reference + PyObject *pyValue = PyInt_FromSsize_t((Py_ssize_t)cValue); + if (!pyValue) + { + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + setValueError("Error while converting from size_t.",m_strict); + return NULL; + } + return pyValue; +} + +PyObject* +PyTypeInterface::PyValue_From_CValue(double cValue) const +{ + // returns new reference + PyObject *pyValue = PyFloat_FromDouble(cValue); + if (!pyValue) + { + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + setValueError("Error while converting from float or double.",m_strict); + return NULL; + } + return pyValue; +} + +PyObject* +PyTypeInterface::PyValue_From_CValue(bool cValue) const +{ + // returns new reference + PyObject *pyValue = PyBool_FromLong((long)cValue); + if (!pyValue) + { + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + setValueError("Error while converting from bool.",m_strict); + return NULL; + } + return pyValue; +} + + +/* Sequence Types to C++ Types */ + +//convert Python list to C++ vector of strings +std::vector<std::string> +PyTypeInterface::PyValue_To_StringVector (PyObject *inputList) const +{ + + std::vector<std::string> Output; + std::string ListElement; + PyObject *pyString = NULL; + + if (!PyList_Check(inputList)) return Output; + + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) { + //Get next list item (Borrowed Reference) + pyString = PyList_GET_ITEM(inputList,i); + ListElement = (string) PyString_AsString(PyObject_Str(pyString)); + Output.push_back(ListElement); + } + return Output; +} + +//convert Python list to C++ vector of floats +std::vector<float> +PyTypeInterface::PyValue_To_FloatVector (PyObject *inputList) const +{ + typedef std::vector<float> floatVector; + std::vector<float> Output; + + /// Check for NumPy Array + if (PyObject_HasAttrString(inputList,"__array_struct__")) { + int vectorLength; + float *dataptr = getNumPyObjectData(inputList,vectorLength); + if (dataptr != 0) cerr << "Numpy array found: " << vectorLength << endl; + // Output = *dataptr; + } + + float ListElement; + PyObject *pyFloat = NULL; + + if (!PyList_Check(inputList)) return Output; + + for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) { + //Get next list item (Borrowed Reference) + pyFloat = PyList_GET_ITEM(inputList,k); + ListElement = (float) PyFloat_AS_DOUBLE(pyFloat); +#ifdef _DEBUG + cerr << "value: " << ListElement << endl; +#endif + Output.push_back(ListElement); + } + + return Output; +} + + +/* Vamp API Specific Types + +Vamp::Plugin::OutputList +PyTypeInterface::PyValue_To_OutputList(PyObject* pyList) const +{ + Vamp::Plugin::OutputList list; + Vamp::Plugin::OutputDescriptor od; + + // Type checking + if (! PyList_Check(pyList) ) { + Py_CLEAR(pyList); + // cerr << "ERROR: In Python plugin [" << m_class << "::" << method + // << "] Expected List return type." << endl; + return list; + } + + //These will all be borrowed references (no need to DECREF) + PyObject *pyDict; + + //Parse Output List + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) { + //Get i-th Vamp output descriptor (Borrowed Reference) + pyDict = PyList_GET_ITEM(pyList,i); + od = PyValue_To_OutputDescriptor(pyDict); + list.push_back(od); + } + return list; +} + +Vamp::Plugin::ParameterList +PyTypeInterface::PyValue_To_ParameterList(PyObject* pyList) const +{ + Vamp::Plugin::ParameterList list; + Vamp::Plugin::ParameterDescriptor pd; + + // Type checking + if (! PyList_Check(pyList) ) { + Py_CLEAR(pyList); + // cerr << "ERROR: In Python plugin [" << m_class << "::" << method + // << "] Expected List return type." << endl; + return list; + } + + //These will all be borrowed references (no need to DECREF) + PyObject *pyDict; + + //Parse Output List + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) { + //Get i-th Vamp output descriptor (Borrowed Reference) + pyDict = PyList_GET_ITEM(pyList,i); + pd = PyValue_To_ParameterDescriptor(pyDict); + list.push_back(pd); + } + return list; +} + +Vamp::Plugin::OutputDescriptor +PyTypeInterface::PyValue_To_OutputDescriptor(PyObject* pyDict) const +{ + //We only care about dictionaries holding output descriptors + if (!PyDict_Check(pyDict)) + return Vamp::Plugin::OutputDescriptor(); + + Py_ssize_t pyPos = 0; + PyObject *pyKey, *pyValue; + initMaps(); + Vamp::Plugin::OutputDescriptor od; + + //Python Dictionary Iterator: + while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue)) + { + std::string key = PyValue_To_String(pyKey); + SetValue(od,key,pyValue); + if (m_error) { + _lastError().location += "parameter: '" + + key +"' descriptor: '" + od.identifier + "'"; + } + } + if (!m_errorQueue.empty()) m_error = true; + return od; +} + +Vamp::Plugin::ParameterDescriptor +PyTypeInterface::PyValue_To_ParameterDescriptor(PyObject* pyDict) const +{ + //We only care about dictionaries holding output descriptors + if (!PyDict_Check(pyDict)) + return Vamp::Plugin::ParameterDescriptor(); + + Py_ssize_t pyPos = 0; + PyObject *pyKey, *pyValue; + initMaps(); + Vamp::Plugin::ParameterDescriptor pd; + + //Python Dictionary Iterator: + while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue)) + { + std::string key = PyValue_To_String(pyKey); + SetValue(pd,key,pyValue); + if (m_error) { + _lastError().location += "parameter: '" + + key +"' descriptor: '" + pd.identifier + "'"; + } + } + if (!m_errorQueue.empty()) m_error = true; + return pd; +} + +Vamp::Plugin::Feature +PyTypeInterface::PyValue_To_Feature(PyObject* pyDict) const +{ + //We only care about dictionaries holding output descriptors + if (!PyDict_Check(pyDict)) + return Vamp::Plugin::Feature(); + + Py_ssize_t pyPos = 0; + PyObject *pyKey, *pyValue; + initMaps(); + Vamp::Plugin::Feature feature; + + //Python Dictionary Iterator: + while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue)) + { + std::string key = PyValue_To_String(pyKey); + float isr = 22050.0; + Feature_SetValue(feature,key,pyValue,isr); + if (m_error) { + _lastError().location += "key: '" + key + "'"; + // _lastError().location += "parameter: '" + // + key +"' descriptor: '" + pd.identifier + "'"; + } + } + if (!m_errorQueue.empty()) m_error = true; + return feature; +} +*/ + +/// FeatureSet (an int map of OutputLists) +Vamp::Plugin::FeatureSet +PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const +{ + Vamp::Plugin::FeatureSet rFeatureSet; /// PyFeatureSet is an int map + if (pyValue == NULL) { + cerr << "NULL FeatureSet" << endl; + return rFeatureSet; + } + + cerr << "PyValue_To_FeatureSet" << endl; + //Convert PyFeatureSet + if (PyFeatureSet_CheckExact(pyValue)) { + cerr << "FeatureSet Return type" << endl; + Py_ssize_t pyPos = 0; + //Borrowed References + PyObject *pyKey, *pyDictValue; + int key; + + //Python Dictionary Iterator: + while (PyDict_Next(pyValue, &pyPos, &pyKey, &pyDictValue)) + { + /// DictValue -> Vamp::FeatureList + key = (int) PyInt_AS_LONG(pyKey); + cerr << "FeatureSet key = " << key << endl; + /// Error checking is done at value assignment + PyValue_To_rValue(pyDictValue,rFeatureSet[key]); + } + if (!m_errorQueue.empty()) m_error = true; + return rFeatureSet; + } + cerr << "not FeatureSet Return type" << endl; + + + //Check return type + if (pyValue == NULL || !PyList_Check(pyValue) ) { + if (pyValue == NULL) { + // cerr << "ERROR: In Python plugin [" << m_class << "::" << method << "] Unexpected result." << endl; + if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } + } else { + // cerr << "ERROR: In Python plugin [" << m_class << "::" << method << "] Expected List return type." << endl; + } + Py_CLEAR(pyValue); + return Vamp::Plugin::FeatureSet(); + } + + // This will be borrowed reference + PyObject *pyFeatureList; + + //Parse Output List for each element (FeatureSet) + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyValue); ++i) { + //Get i-th FeatureList (Borrowed Reference) + pyFeatureList = PyList_GET_ITEM(pyValue,i); + PyValue_To_rValue(pyFeatureList,rFeatureSet[i]); + } + // Py_CLEAR(pyOutputList); + return rFeatureSet; +} + +Vamp::RealTime::RealTime +PyTypeInterface::PyValue_To_RealTime(PyObject* pyValue) const +{ +// We accept integer sample counts (for backwards compatibility) +// or PyRealTime objects and convert them to Vamp::RealTime + + if (PyRealTime_CheckExact(pyValue)) + { +#ifdef _DEBUG + cerr << "Converting from PyRealTime" << endl; +#endif + /// just create a copy of the wrapped object + return Vamp::RealTime::RealTime( + *PyRealTime_AS_REALTIME(pyValue)); + } + // assume integer sample count + long sampleCount = PyLong_AsLong(pyValue); + if (PyErr_Occurred()) + { + PyErr_Print(); PyErr_Clear(); + setValueError("Error while converting integer to RealTime.",m_strict); + return Vamp::RealTime::RealTime(); + } +#ifdef _DEBUG + Vamp::RealTime::RealTime rt = + Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate ); + cerr << "RealTime: " << (long)sampleCount << ", ->" << rt.toString() << endl; + return rt; +#else + return Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate ); +#endif + +} + + +/// OutputDescriptor +void +PyTypeInterface::SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const +{ + switch (outKeys[key]) + { + case o::not_found: + cerr << "Unknown key in Vamp OutputDescriptor: " << key << endl; + break; + case o::identifier: + _convert(pyValue,od.identifier); + break; + case o::name: + _convert(pyValue,od.name); + break; + case o::description: + _convert(pyValue,od.description); + break; + case o::unit: + _convert(pyValue,od.unit); + break; + case o::hasFixedBinCount: + _convert(pyValue,od.hasFixedBinCount); + break; + case o::binCount: + _convert(pyValue,od.binCount); + break; + case o::binNames: + _convert(pyValue,od.binNames); + break; + case o::hasKnownExtents: + _convert(pyValue,od.hasKnownExtents); + break; + case o::minValue: + _convert(pyValue,od.minValue); + break; + case o::maxValue: + _convert(pyValue,od.maxValue); + break; + case o::isQuantized: + _convert(pyValue,od.isQuantized); + break; + case o::quantizeStep: + _convert(pyValue,od.quantizeStep); + break; + case o::sampleType: + // implements specific conversion! + od.sampleType = (Vamp::Plugin::OutputDescriptor::SampleType) sampleKeys[PyValue_To_String(pyValue)]; + break; + case o::sampleRate: + _convert(pyValue,od.sampleRate); + break; + case o::hasDuration: + _convert(pyValue,od.hasDuration); + break; + default: + cerr << "Invalid key in Vamp OutputDescriptor: " << key << endl; + } +} + +/// ParameterDescriptor +void +PyTypeInterface::SetValue(Vamp::Plugin::ParameterDescriptor& pd, std::string& key, PyObject* pyValue) const +{ + switch (parmKeys[key]) + { + case p::not_found : + cerr << "Unknown key in Vamp ParameterDescriptor: " << key << endl; + break; + case p::identifier: + _convert(pyValue,pd.identifier); + break; + case p::name: + _convert(pyValue,pd.name); + break; + case p::description: + _convert(pyValue,pd.description); + break; + case p::unit: + _convert(pyValue,pd.unit); + break; + case p::minValue: + _convert(pyValue,pd.minValue); + break; + case p::maxValue: + _convert(pyValue,pd.maxValue); + break; + case p::defaultValue: + _convert(pyValue,pd.defaultValue); + break; + case p::isQuantized: + _convert(pyValue,pd.isQuantized); + break; + case p::quantizeStep: + _convert(pyValue,pd.quantizeStep); + break; + default : + cerr << "Invalid key in Vamp ParameterDescriptor: " << key << endl; + } +} + +/// Feature (it's like a Descriptor) +bool +PyTypeInterface::SetValue(Vamp::Plugin::Feature& feature, std::string& key, PyObject* pyValue) const +{ + bool found = true; + switch (ffKeys[key]) + { + case unknown : + cerr << "Unknown key in Vamp Feature: " << key << endl; + found = false; + break; + case hasTimestamp: + _convert(pyValue,feature.hasTimestamp); + break; + case timeStamp: + _convert(pyValue,feature.timestamp); + break; + case hasDuration: + _convert(pyValue,feature.hasDuration); + break; + case duration: + _convert(pyValue,feature.duration); + break; + case values: + _convert(pyValue,feature.values); + break; + case label: + _convert(pyValue,feature.label); + break; + default: + found = false; + } + return found; +} + +/* +/// Feature (it's like a Descriptor) +bool +PyTypeInterface::GetValue(Vamp::Plugin::Feature& feature, std::string& key, PyObject* pyValue) const +{ + bool found = true; + switch (ffKeys[key]) + { + case unknown : + cerr << "Unknown key in Vamp Feature: " << key << endl; + found = false; + break; + case hasTimestamp: + _convert(pyValue,feature.hasTimestamp); + // pyValue = PyValue_From_CValue(feature.hasTimestamp) + break; + case timeStamp: + _convert(pyValue,feature.timestamp); + break; + case hasDuration: + _convert(pyValue,feature.hasDuration); + break; + case duration: + _convert(pyValue,feature.duration); + break; + case values: + _convert(pyValue,feature.values); + break; + case label: + _convert(pyValue,feature.label); //vector<string> + break; + default: + found = false; + } + return found; +} +*/ + +/* Error handling */ + +void +PyTypeInterface::setValueError (std::string message, bool strict) const +{ + m_error = true; + m_errorQueue.push(ValueError(message,strict)); +} + +/// return a reference to the last error or creates a new one. +PyTypeInterface::ValueError& +PyTypeInterface::_lastError() const +{ + m_error = false; + if (!m_errorQueue.empty()) return m_errorQueue.back(); + else { + m_errorQueue.push(ValueError("Type conversion error.",m_strict)); + return m_errorQueue.back(); + } +} + +/// return the last error message and clear the error flag +const PyTypeInterface::ValueError& +PyTypeInterface::lastError() const +{ + // PyTypeInterface *self = const_cast<PyTypeInterface*> (this); + m_error = false; + if (!m_errorQueue.empty()) return m_errorQueue.back(); + else return m_noError; +} + +/// iterate over the error message queue and pop the oldest item +PyTypeInterface::ValueError +PyTypeInterface::getError() const +{ + if (!m_errorQueue.empty()) { + PyTypeInterface::ValueError e = m_errorQueue.front(); + m_errorQueue.pop(); + if (m_errorQueue.empty()) m_error = false; + return e; + } + else { + m_error = false; + return PyTypeInterface::ValueError(); + } +} + +/* Utilities */ + +//return a pointer to the data in the numPy array +float* +PyTypeInterface::getNumPyObjectData(PyObject *object, int &length) const +{ + + char attr_name[]="__array_struct__"; + + //check if we passed in a NumPy array object + if (!PyObject_HasAttrString(object,attr_name)) { + // PyErr_SetString(PyExc_TypeError, + // "Input object has no __array_struct__ attribute. NumPy array required."); + return NULL; + } + + //retrieve __array_struct__ interface + object = PyObject_GetAttrString(object,attr_name); + + //check whether we found CObjects + if (!PyCObject_Check(object)) { + PyErr_SetString(PyExc_TypeError, + "The passed __array_struct__ interface is not a valid C Object."); + return NULL; + } + + + //check if the pointers directed to the integer '2' + int *check = (int *) PyCObject_AsVoidPtr (object); + + if (*check != 2 ) { + PyErr_SetString(PyExc_TypeError, + "A C Object __array_struct__ required as inputs"); + return NULL; + } + + //convert CObjects to Array interfaces + PyArrayInterface *arrayInterface = + (PyArrayInterface *) PyCObject_AsVoidPtr (object); + + //check array dimension: should be 1 + int inputDim = arrayInterface->nd; + + if (inputDim > 1 ) { + PyErr_SetString(PyExc_TypeError, + "Array dimensions must not exceed one."); + return NULL; + } + + // check if vector size is sane + Py_intptr_t arrayLength = arrayInterface->shape[0]; + length = (int) arrayLength; + + // if (arrayLength < 8 || arrayLength > 65536 ) { + // PyErr_SetString(PyExc_TypeError, + // "Array length is out of bounds."); + // return NULL; + // } + + //check type; must be float32 + char arrayType = arrayInterface->typekind; + + if (arrayType != 'f' ) { + PyErr_SetString(PyExc_TypeError, + "Floating point arrays required."); + return NULL; + } + + //return data vector address + return (float*) arrayInterface->data; + +} + +/// get the type name of an object +std::string +PyTypeInterface::PyValue_Get_TypeName(PyObject* pyValue) const +{ + PyObject *pyType = PyObject_Type(pyValue); + if (!pyType) return std::string ("< unknown type >"); + PyObject *pyString = PyObject_Str(pyType); + if (!pyString) + { + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + Py_CLEAR(pyType); + return std::string ("< unknown type >"); + } + char *cstr = PyString_AS_STRING(pyString); + if (!cstr) + { + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + Py_DECREF(pyType); + Py_CLEAR(pyString); + cerr << "Warning: Object type name could not be found." << endl; + return std::string("< unknown type >"); + } + Py_DECREF(pyType); + Py_DECREF(pyString); + return std::string(cstr); +} + +bool +PyTypeInterface::initMaps() const +{ + + if (isMapInitialised) return true; + + outKeys["identifier"] = o::identifier; + outKeys["name"] = o::name; + outKeys["description"] = o::description; + outKeys["unit"] = o::unit; + outKeys["hasFixedBinCount"] = o::hasFixedBinCount; + outKeys["binCount"] = o::binCount; + outKeys["binNames"] = o::binNames; + outKeys["hasKnownExtents"] = o::hasKnownExtents; + outKeys["minValue"] = o::minValue; + outKeys["maxValue"] = o::maxValue; + outKeys["isQuantized"] = o::isQuantized; + outKeys["quantizeStep"] = o::quantizeStep; + outKeys["sampleType"] = o::sampleType; + outKeys["sampleRate"] = o::sampleRate; + outKeys["hasDuration"] = o::hasDuration; + + sampleKeys["OneSamplePerStep"] = OneSamplePerStep; + sampleKeys["FixedSampleRate"] = FixedSampleRate; + sampleKeys["VariableSampleRate"] = VariableSampleRate; + + ffKeys["hasTimestamp"] = hasTimestamp; + ffKeys["timeStamp"] = timeStamp; + ffKeys["hasDuration"] = hasDuration; + ffKeys["duration"] = duration; + ffKeys["values"] = values; + ffKeys["label"] = label; + + parmKeys["identifier"] = p::identifier; + parmKeys["name"] = p::name; + parmKeys["description"] = p::description; + parmKeys["unit"] = p::unit; + parmKeys["minValue"] = p::minValue; + parmKeys["maxValue"] = p::maxValue; + parmKeys["defaultValue"] = p::defaultValue; + parmKeys["isQuantized"] = p::isQuantized; + parmKeys["quantizeStep"] = p::quantizeStep; + + isMapInitialised = true; + return true; +}