# HG changeset patch # User Chris Cannam # Date 1416995315 0 # Node ID 014c48d6f360337716646df1194baa1dee4243bb # Parent 5379af6bef00a28d4db9a0daa11976cbb796230f Now we know what we want from Vampy source, bring it in here again and lose the subrepo diff -r 5379af6bef00 -r 014c48d6f360 .hgsub --- a/.hgsub Wed Nov 26 09:38:56 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -vampy = https://code.soundsoftware.ac.uk/hg/vampy diff -r 5379af6bef00 -r 014c48d6f360 .hgsubstate --- a/.hgsubstate Wed Nov 26 09:38:56 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -2a9fb03458d74565845654aff6a0f2b8dc677248 vampy diff -r 5379af6bef00 -r 014c48d6f360 Makefile --- a/Makefile Wed Nov 26 09:38:56 2014 +0000 +++ b/Makefile Wed Nov 26 09:48:35 2014 +0000 @@ -2,12 +2,12 @@ PY_INCLUDE_PATH := /usr/include/python2.7 NUMPY_INCLUDE_PATH := /usr/lib/python2.7/site-packages/numpy/core/include -CFLAGS := -DHAVE_NUMPY -D_VAMP_PLUGIN_IN_HOST_NAMESPACE=1 -g -fPIC -Wall -Werror -Ivampy -I$(PY_INCLUDE_PATH) -I$(NUMPY_INCLUDE_PATH) -I. -CXXFLAGS := -DHAVE_NUMPY -D_VAMP_PLUGIN_IN_HOST_NAMESPACE=1 -g -fPIC -Wall -Werror -Ivampy -I$(PY_INCLUDE_PATH) -I$(NUMPY_INCLUDE_PATH) -I. +CFLAGS := -DHAVE_NUMPY -g -fPIC -Wall -Werror -I$(PY_INCLUDE_PATH) -I$(NUMPY_INCLUDE_PATH) -I. +CXXFLAGS := -DHAVE_NUMPY -g -fPIC -Wall -Werror -I$(PY_INCLUDE_PATH) -I$(NUMPY_INCLUDE_PATH) -I. LDFLAGS := -shared -Wl,-Bstatic -lvamp-hostsdk -Wl,-Bdynamic -Wl,-z,defs -lpython2.7 -ldl -OBJECTS := vampy/PyRealTime.o vampy/PyFeature.o vampy/PyFeatureSet.o vampy/PyTypeConversions.o vampyhost.o +OBJECTS := PyRealTime.o PyTypeConversions.o vampyhost.o all: vampyhost.so @@ -15,4 +15,4 @@ g++ -o $@ -shared $^ $(LDFLAGS) clean: - rm -f vampy/*.o *.o *.so *.a + rm -f *.o *.so *.a diff -r 5379af6bef00 -r 014c48d6f360 PyRealTime.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PyRealTime.cpp Wed Nov 26 09:48:35 2014 +0000 @@ -0,0 +1,366 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + VampyHost + + Use Vamp audio analysis plugins in Python + + Gyorgy Fazekas and Chris Cannam + Centre for Digital Music, Queen Mary, University of London + Copyright 2008-2014 Queen Mary, University of London + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and the authors + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include +#include "PyRealTime.h" +#include "vamp-sdk/Plugin.h" +#include + +using namespace std; +using namespace Vamp; +using Vamp::Plugin; +using Vamp::RealTime; + +/* CONSTRUCTOR: New RealTime object from sec and nsec */ +static PyObject* +RealTime_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + unsigned int sec = 0; + unsigned int nsec = 0; + double unary = 0; + const char *fmt = NULL; + + if ( + /// new RealTime from ('format',float) e.g. ('seconds',2.34123) + !PyArg_ParseTuple(args, "|sd:RealTime.new ", + (const char *) &fmt, + (double *) &unary) && + + /// new RealTime from (sec{int},nsec{int}) e.g. (2,34) + !PyArg_ParseTuple(args, "|II:RealTime.new ", + (unsigned int*) &sec, + (unsigned int*) &nsec) + + ) { + PyErr_SetString(PyExc_TypeError, + "RealTime initialised with wrong arguments."); + return NULL; + } + + // PyErr_Clear(); + + // RealTimeObject *self = PyObject_New(RealTimeObject, &RealTime_Type); + RealTimeObject *self = (RealTimeObject*)type->tp_alloc(type, 0); + + if (self == NULL) return NULL; + + self->rt = NULL; + + if (sec == 0 && nsec == 0 && fmt == 0) + self->rt = new RealTime(); + else if (fmt == 0) + self->rt = new RealTime(sec,nsec); + else { + /// new RealTime from seconds or milliseconds: i.e. >>>RealTime('seconds',12.3) + if (!string(fmt).compare("float") || + !string(fmt).compare("seconds")) + self->rt = new RealTime( + RealTime::fromSeconds((double) unary)); + + if (!string(fmt).compare("milliseconds")) { + self->rt = new RealTime( + RealTime::fromSeconds((double) unary / 1000.0)); } + } + + if (!self->rt) { + PyErr_SetString(PyExc_TypeError, + "RealTime initialised with wrong arguments."); + return NULL; + } + + return (PyObject *) self; +} + +/* DESTRUCTOR: delete type object */ +static void +RealTimeObject_dealloc(RealTimeObject *self) +{ + if (self->rt) delete self->rt; //delete the C object + PyObject_Del(self); //delete the Python object (original) + /// this requires PyType_Ready() which fills ob_type + // self->ob_type->tp_free((PyObject*)self); +} + +/* RealTime Object's Methods */ +//these are internals not exposed by the module but the object + +/* Returns a Tuple containing sec and nsec values */ +static PyObject * +RealTime_values(RealTimeObject *self) +{ + return Py_BuildValue("(ii)",self->rt->sec,self->rt->nsec); +} + +/* Returns a Text representation */ +static PyObject * +RealTime_toString(RealTimeObject *self, PyObject *args) +{ + return Py_BuildValue("s",self->rt->toText().c_str()); +} + +/* Frame representation */ +static PyObject * +RealTime_toFrame(PyObject *self, PyObject *args) +{ + unsigned int samplerate; + + if ( !PyArg_ParseTuple(args, "I:realtime.toFrame object ", + (unsigned int *) &samplerate )) { + PyErr_SetString(PyExc_ValueError,"Integer Sample Rate Required."); + return NULL; + } + + return Py_BuildValue("k", + RealTime::realTime2Frame( + *(const RealTime*) ((RealTimeObject*)self)->rt, + (unsigned int) samplerate)); +} + +/* Conversion of realtime to a double precision floating point value */ +/* ...in Python called by e.g. float(realtime) */ +static PyObject * +RealTime_float(PyObject *s) +{ + double drt = ((double) ((RealTimeObject*)s)->rt->sec + + (double)((double) ((RealTimeObject*)s)->rt->nsec)/1000000000); + return PyFloat_FromDouble(drt); +} + + +/* Type object's (RealTime) methods table */ +static PyMethodDef RealTime_methods[] = +{ + {"values", (PyCFunction)RealTime_values, METH_NOARGS, + PyDoc_STR("values() -> Tuple of sec,nsec representation.")}, + + {"toString", (PyCFunction)RealTime_toString, METH_NOARGS, + PyDoc_STR("toString() -> Return a user-readable string to the nearest millisecond in a form like HH:MM:SS.mmm")}, + + {"toFrame", (PyCFunction)RealTime_toFrame, METH_VARARGS, + PyDoc_STR("toFrame(samplerate) -> Sample count for given sample rate.")}, + + {"toFloat", (PyCFunction)RealTime_float, METH_NOARGS, + PyDoc_STR("toFloat() -> Floating point representation.")}, + + {NULL, NULL} /* sentinel */ +}; + + +/* Methods implementing protocols */ +// these functions are called by the interpreter + +/* Object Protocol */ + +static int +RealTime_setattr(RealTimeObject *self, char *name, PyObject *value) +{ + + if ( !string(name).compare("sec")) { + self->rt->sec= (int) PyInt_AS_LONG(value); + return 0; + } + + if ( !string(name).compare("nsec")) { + self->rt->nsec= (int) PyInt_AS_LONG(value); + return 0; + } + + return -1; +} + +static PyObject * +RealTime_getattr(RealTimeObject *self, char *name) +{ + + if ( !string(name).compare("sec") ) { + return PyInt_FromSsize_t( + (Py_ssize_t) self->rt->sec); + } + + if ( !string(name).compare("nsec") ) { + return PyInt_FromSsize_t( + (Py_ssize_t) self->rt->nsec); + } + + return Py_FindMethod(RealTime_methods, + (PyObject *)self, name); +} + +/* String representation called by e.g. str(realtime), print realtime*/ +static PyObject * +RealTime_repr(PyObject *self) +{ + return Py_BuildValue("s", + ((RealTimeObject*)self)->rt->toString().c_str()); +} + + +/* Number Protocol */ +/// TODO: implement all methods available in Vamp::RealTime() objects + +static PyObject * +RealTime_add(PyObject *s, PyObject *w) +{ + RealTimeObject *result = + PyObject_New(RealTimeObject, &RealTime_Type); + if (result == NULL) return NULL; + + result->rt = new RealTime( + *((RealTimeObject*)s)->rt + *((RealTimeObject*)w)->rt); + return (PyObject*)result; +} + +static PyObject * +RealTime_subtract(PyObject *s, PyObject *w) +{ + RealTimeObject *result = + PyObject_New(RealTimeObject, &RealTime_Type); + if (result == NULL) return NULL; + + result->rt = new RealTime( + *((RealTimeObject*)s)->rt - *((RealTimeObject*)w)->rt); + return (PyObject*)result; +} + +static PyNumberMethods realtime_as_number = +{ + RealTime_add, /*nb_add*/ + RealTime_subtract, /*nb_subtract*/ + 0, /*nb_multiply*/ + 0, /*nb_divide*/ + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + 0, /*nb_neg*/ + 0, /*nb_pos*/ + 0, /*(unaryfunc)array_abs,*/ + 0, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + 0, /*nb_coerce*/ + 0, /*nb_int*/ + 0, /*nb_long*/ + (unaryfunc)RealTime_float,/*nb_float*/ + 0, /*nb_oct*/ + 0, /*nb_hex*/ +}; + +/* REAL-TIME TYPE OBJECT */ + +#define RealTime_alloc PyType_GenericAlloc +#define RealTime_free PyObject_Del + +/* Doc:: 10.3 Type Objects */ /* static */ +PyTypeObject RealTime_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "vampy.RealTime", /*tp_name*/ + sizeof(RealTimeObject), /*tp_basicsize*/ + 0,//sizeof(RealTime), /*tp_itemsize*/ + /* methods */ + (destructor)RealTimeObject_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)RealTime_getattr, /*tp_getattr*/ + (setattrfunc)RealTime_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + RealTime_repr, /*tp_repr*/ + &realtime_as_number, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0,//(ternaryfunc)RealTime_new, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "RealTime Object", /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + RealTime_methods, /*tp_methods*/ //TypeObject Methods + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + RealTime_alloc, /*tp_alloc*/ + RealTime_new, /*tp_new*/ + RealTime_free, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + + + +/* PyRealTime C++ API */ + +/*PyRealTime from RealTime*/ +PyObject* +PyRealTime_FromRealTime(const Vamp::RealTime& rt) { + + RealTimeObject *self = + PyObject_New(RealTimeObject, &RealTime_Type); + if (self == NULL) return NULL; + + self->rt = new RealTime(rt); + return (PyObject*) self; +} + +/*RealTime* from PyRealTime*/ +const Vamp::RealTime* +PyRealTime_AsRealTime (PyObject *self) { + + RealTimeObject *s = (RealTimeObject*) self; + + if (!PyRealTime_Check(s)) { + PyErr_SetString(PyExc_TypeError, "RealTime Object Expected."); + cerr << "in call PyRealTime_AsPointer(): RealTime Object Expected. " << endl; + return NULL; } + return s->rt; +}; + diff -r 5379af6bef00 -r 014c48d6f360 PyRealTime.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PyRealTime.h Wed Nov 26 09:48:35 2014 +0000 @@ -0,0 +1,60 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + VampyHost + + Use Vamp audio analysis plugins in Python + + Gyorgy Fazekas and Chris Cannam + Centre for Digital Music, Queen Mary, University of London + Copyright 2008-2014 Queen Mary, University of London + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and the authors + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef PYREALTIME_H +#define PYREALTIME_H + +#include +#include + +typedef struct { + PyObject_HEAD + Vamp::RealTime *rt; +} RealTimeObject; + +PyAPI_DATA(PyTypeObject) RealTime_Type; + +#define PyRealTime_Check(v) PyObject_TypeCheck(v, &RealTime_Type) +#define PyRealTime_AS_REALTIME(v) ((const RealTimeObject* const) (v))->rt + +PyAPI_FUNC(PyObject *) +PyRealTime_FromRealTime(const Vamp::RealTime&); + +PyAPI_FUNC(const Vamp::RealTime*) +PyRealTime_AsRealTime (PyObject *self); + +#endif diff -r 5379af6bef00 -r 014c48d6f360 PyTypeConversions.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PyTypeConversions.cpp Wed Nov 26 09:48:35 2014 +0000 @@ -0,0 +1,866 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + VampyHost + + Use Vamp audio analysis plugins in Python + + Gyorgy Fazekas and Chris Cannam + Centre for Digital Music, Queen Mary, University of London + Copyright 2008-2014 Queen Mary, University of London + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and the authors + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include + +#include "PyTypeConversions.h" + +#include +#include +#include +#ifndef SIZE_T_MAX +#define SIZE_T_MAX ((size_t) -1) +#endif + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + +/* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS + (EXCEPT FOR TEMPORARY PYTHON OBJECTS)! */ + +PyTypeConversions::PyTypeConversions() : + m_strict(false), + m_error(false), + m_numpyInstalled(false), + error(m_error) // const public reference for easy access +{ +} + +PyTypeConversions::~PyTypeConversions() +{ +} + +/// floating point numbers (TODO: check numpy.float128) +float +PyTypeConversions::PyValue_To_Float(PyObject* pyValue) const +{ + // convert float + if (pyValue && PyFloat_Check(pyValue)) + //TODO: check for limits here (same on most systems) + return (float) PyFloat_AS_DOUBLE(pyValue); + + if (pyValue == NULL) + { + setValueError("Error while converting object " + PyValue_Get_TypeName(pyValue) + " to float. ",m_strict); + return 0.0; + } + + // in strict mode we will not try harder + if (m_strict) { + setValueError("Strict conversion error: object" + PyValue_Get_TypeName(pyValue) +" is not float.",m_strict); + return 0.0; + } + + // convert other objects supporting the number protocol + if (PyNumber_Check(pyValue)) + { + PyObject* pyFloat = PyNumber_Float(pyValue); // new ref + if (!pyFloat) + { + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + setValueError("Error while converting " + PyValue_Get_TypeName(pyValue) + " object to float.",m_strict); + return 0.0; + } + float rValue = (float) PyFloat_AS_DOUBLE(pyFloat); + Py_DECREF(pyFloat); + return rValue; + } +/* + // 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 > (Py_ssize_t)FLT_MAX || rValue < (Py_ssize_t)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) && 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 to float. "; + 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); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyValue_To_Float failed. " << msg << endl; +#endif + return 0.0; +} + +/// size_t (unsigned integer types) +size_t +PyTypeConversions::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 + // speed is not critical in the use of this type by Vamp + // 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; + } + // this test is nonsense -- neither part can occur + // owing to range of data types -- size_t is at least + // as big as long, and unsigned is always non-negative +/* + 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 ("Error converting string to size_t.",m_strict); + return 0; + } + } + + // convert the first element of iterable sequences + if (PySequence_Check(pyValue) && 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); + setValueError("Could not convert sequence element to size_t. ",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); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyValue_To_Size_t failed. " << msg << endl; +#endif + return 0; +} + +/// long and int +long +PyTypeConversions::PyValue_To_Long(PyObject* pyValue) const +{ + // most common case: convert int (faster) + if (pyValue && PyInt_Check(pyValue)) { + // if the object is not NULL and verified, this macro just extracts the value. + return PyInt_AS_LONG(pyValue); + } + + // long + if (PyLong_Check(pyValue)) { + long rValue = PyLong_AsLong(pyValue); + if (PyErr_Occurred()) { + PyErr_Print(); PyErr_Clear(); + setValueError("Error while converting long object.",m_strict); + return 0; + } + return rValue; + } + + if (m_strict) { + setValueError("Strict conversion error: object is not integer or long integer.",m_strict); + return 0; + } + + // convert all objects supporting the number protocol + if (PyNumber_Check(pyValue)) + { + // 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 (rValue > LONG_MAX || rValue < LONG_MIN) + { + setValueError("Overflow error. Object can not be converted to size_t.",m_strict); + return 0; + } + return (long) rValue; + } + + // 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 long.",m_strict); + return 0; + } + long rValue = this->PyValue_To_Long(pyLong); + if (!m_error) { + Py_DECREF(pyLong); + return rValue; + } else { + Py_CLEAR(pyLong); + setValueError ("Error converting string to long.",m_strict); + return 0; + } + } + + // convert the first element of iterable sequences + if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) + { + PyObject* item = PySequence_GetItem(pyValue,0); + if (item) + { + size_t rValue = this->PyValue_To_Long(item); + if (!m_error) { + Py_DECREF(item); + return rValue; + } else { + Py_CLEAR(item); + setValueError("Could not convert sequence element to long. ",m_strict); + return 0; + } + } + } + + // give up + if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } + std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to long is not possible."; + setValueError(msg,m_strict); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyValue_To_Long failed. " << msg << endl; +#endif + return 0; +} + + +bool +PyTypeConversions::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 in 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); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyValue_To_Bool failed. " << msg << endl; +#endif + return false; +} + +/// string and objects that support .__str__() +/// TODO: check unicode objects +std::string +PyTypeConversions::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(); + } + + // accept None as empty string + if (pyValue == Py_None) return std::string(); + + // convert list or tuple: empties are turned into empty strings conventionally + 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); + setValueError("Could not convert sequence element to string.",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. "; + 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); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyValue_To_String failed. " << msg << endl; +#endif + return std::string(); +} + +/* C Values to Py Values */ + + +PyObject* +PyTypeConversions::PyValue_From_CValue(const char* cValue) const +{ + // returns new reference +#ifdef _DEBUG + if (!cValue) { + std::string msg = "PyTypeConversions::PyValue_From_CValue: Null pointer encountered while converting from const char* ."; + cerr << msg << endl; + setValueError(msg,m_strict); + return NULL; + } +#endif + PyObject *pyValue = PyString_FromString(cValue); + if (!pyValue) + { + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + setValueError("Error while converting from char* or string.",m_strict); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from const char*" << endl; +#endif + return NULL; + } + return pyValue; +} + +PyObject* +PyTypeConversions::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); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from size_t" << endl; +#endif + return NULL; + } + return pyValue; +} + +PyObject* +PyTypeConversions::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); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from float or double" << endl; +#endif + return NULL; + } + return pyValue; +} + +PyObject* +PyTypeConversions::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); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyValue_From_CValue: Interpreter failed to convert from bool" << endl; +#endif + return NULL; + } + return pyValue; +} + + +/* Sequence Types to C++ Types */ + +//convert Python list to C++ vector of strings +std::vector +PyTypeConversions::PyValue_To_StringVector (PyObject *pyList) const +{ + + std::vector Output; + std::string ListElement; + PyObject *pyString = NULL; + + if (PyList_Check(pyList)) { + + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) { + //Get next list item (Borrowed Reference) + pyString = PyList_GET_ITEM(pyList,i); + ListElement = (string) PyString_AsString(PyObject_Str(pyString)); + Output.push_back(ListElement); + } + return Output; + } + +// #ifdef _DEBUG +// cerr << "PyTypeConversions::PyValue_To_StringVector: Warning: Value is not list of strings." << endl; +// #endif + + /// Assume a single value that can be casted as string + /// this allows to write e.g. Feature.label = 5.2 instead of ['5.2'] + Output.push_back(PyValue_To_String(pyList)); + if (m_error) { + std::string msg = "Value is not list of strings nor can be casted as string. "; + setValueError(msg,m_strict); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyValue_To_StringVector failed. " << msg << endl; +#endif + } + return Output; +} + +//convert PyFeature.value (typically a list or numpy array) to C++ vector of floats +std::vector +PyTypeConversions::PyValue_To_FloatVector (PyObject *pyValue) const +{ + +#ifdef HAVE_NUMPY +if (m_numpyInstalled) +{ + // there are four types of values we may receive from a numpy process: + // * a python scalar, + // * an array scalar, (e.g. numpy.float32) + // * an array with nd = 0 (0D array) + // * an array with nd > 0 + + /// check for scalars + if (PyArray_CheckScalar(pyValue) || PyFloat_Check(pyValue)) { + + std::vector Output; + + // we rely on the behaviour the scalars are either floats + // or support the number protocol + // TODO: a potential optimisation is to handle them directly + Output.push_back(PyValue_To_Float(pyValue)); + return Output; + } + + /// numpy array + if (PyArray_CheckExact(pyValue)) + return PyArray_To_FloatVector(pyValue); +} +#endif + + /// python list of floats (backward compatible) + if (PyList_Check(pyValue)) { + return PyList_To_FloatVector(pyValue); + } + + std::vector Output; + + /// finally assume a single value supporting the number protocol + /// this allows to write e.g. Feature.values = 5 instead of [5.00] + Output.push_back(PyValue_To_Float(pyValue)); + if (m_error) { + std::string msg = "Value is not list or array of floats nor can be casted as float. "; + setValueError(msg,m_strict); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyValue_To_FloatVector failed. " << msg << endl; +#endif + } + return Output; +} + +//convert a list of python floats +std::vector +PyTypeConversions::PyList_To_FloatVector (PyObject *inputList) const +{ + std::vector Output; + +#ifdef _DEBUG + // This is a low level function normally called from + // PyValue_To_FloatVector(). Checking for list is not required. + if (!PyList_Check(inputList)) { + std::string msg = "Value is not list."; + setValueError(msg,true); + cerr << "PyTypeConversions::PyList_To_FloatVector failed. " << msg << endl; + return Output; + } +#endif + + float ListElement; + PyObject *pyFloat = NULL; + PyObject **pyObjectArray = PySequence_Fast_ITEMS(inputList); + + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) { + + // pyFloat = PyList_GET_ITEM(inputList,i); + pyFloat = pyObjectArray[i]; + +#ifdef _DEBUG + if (!pyFloat) { + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + cerr << "PyTypeConversions::PyList_To_FloatVector: Could not obtain list element: " + << i << " PyList_GetItem returned NULL! Skipping value." << endl; + continue; + } +#endif + + // ListElement = (float) PyFloat_AS_DOUBLE(pyFloat); + ListElement = PyValue_To_Float(pyFloat); + + +#ifdef _DEBUG_VALUES + cerr << "value: " << ListElement << endl; +#endif + Output.push_back(ListElement); + } + return Output; +} + +// if numpy is not installed this will not be called, +// therefor we do not check again +#ifdef HAVE_NUMPY +std::vector +PyTypeConversions::PyArray_To_FloatVector (PyObject *pyValue) const +{ + std::vector Output; + +#ifdef _DEBUG + // This is a low level function, normally called from + // PyValue_To_FloatVector(). Checking the array here is not required. + if (!PyArray_Check(pyValue)) { + std::string msg = "Object has no array conversions."; + setValueError(msg,true); + cerr << "PyTypeConversions::PyArray_To_FloatVector failed. " << msg << endl; + return Output; + } +#endif + + PyArrayObject* pyArray = (PyArrayObject*) pyValue; + PyArray_Descr* descr = PyArray_DESCR(pyArray); + + /// check raw data and descriptor pointers + if (PyArray_DATA(pyArray) == 0 || descr == 0) { + std::string msg = "NumPy array with NULL data or descriptor pointer encountered."; + setValueError(msg,m_strict); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyArray_To_FloatVector failed. Error: " << msg << endl; +#endif + return Output; + } + + /// check dimensions + if (PyArray_NDIM(pyArray) != 1) { + std::string msg = "NumPy array must be a one dimensional vector."; + setValueError(msg,m_strict); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyArray_To_FloatVector failed. Error: " << msg << " Dims: " << (int) PyArray_NDIM(pyArray) << endl; +#endif + return Output; + } + +#ifdef _DEBUG_VALUES + cerr << "PyTypeConversions::PyArray_To_FloatVector: Numpy array verified." << endl; +#endif + + /// check strides (useful if array is not continuous) + size_t strides = *((size_t*) PyArray_STRIDES(pyArray)); + + /// convert the array + switch (descr->type_num) + { + case NPY_FLOAT : // dtype='float32' + return PyArray_Convert(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides); + case NPY_DOUBLE : // dtype='float64' + return PyArray_Convert(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides); + case NPY_INT : // dtype='int' + return PyArray_Convert(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides); + case NPY_LONG : // dtype='long' + return PyArray_Convert(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides); + default : + std::string msg = "Unsupported value type in NumPy array object."; + setValueError(msg,m_strict); +#ifdef _DEBUG + cerr << "PyTypeConversions::PyArray_To_FloatVector failed. Error: " << msg << endl; +#endif + return Output; + } +} + +PyObject * +PyTypeConversions::FloatVector_To_PyArray(const vector &v) const +{ + npy_intp ndims[1]; + ndims[0] = (int)v.size(); + PyObject *arr = PyArray_SimpleNew(1, ndims, dtype_float32); + float *data = (float *)PyArray_DATA((PyArrayObject *)arr); + for (int i = 0; i < ndims[0]; ++i) { + data[i] = v[i]; + } + return arr; +} +#endif + +PyObject * +PyTypeConversions::PyValue_From_StringVector(const std::vector &v) const +{ + PyObject *pyList = PyList_New(v.size()); + for (size_t i = 0; i < v.size(); ++i) { + PyObject *pyStr = PyString_FromString(v[i].c_str()); + PyList_SET_ITEM(pyList, i, pyStr); + } + return pyList; +} + + +/* Error handling */ + +void +PyTypeConversions::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. +ValueError& +PyTypeConversions::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(); + } +} + +/// helper function to iterate over the error message queue: +/// pops the oldest item +ValueError +PyTypeConversions::getError() const +{ + if (!m_errorQueue.empty()) { + ValueError e = m_errorQueue.front(); + m_errorQueue.pop(); + if (m_errorQueue.empty()) m_error = false; + return e; + } + else { + m_error = false; + return ValueError(); + } +} + +/* Utilities */ + +/// get the type name of an object +std::string +PyTypeConversions::PyValue_Get_TypeName(PyObject* pyValue) const +{ + PyObject *pyType = PyObject_Type(pyValue); + if (!pyType) + { + cerr << "Warning: Object type name could not be found." << endl; + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + return std::string ("< unknown type >"); + } + PyObject *pyString = PyObject_Str(pyType); + if (!pyString) + { + cerr << "Warning: Object type name could not be found." << endl; + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + Py_CLEAR(pyType); + return std::string ("< unknown type >"); + } + char *cstr = PyString_AS_STRING(pyString); + if (!cstr) + { + cerr << "Warning: Object type name could not be found." << endl; + if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} + Py_DECREF(pyType); + Py_CLEAR(pyString); + return std::string("< unknown type >"); + } + Py_DECREF(pyType); + Py_DECREF(pyString); + return std::string(cstr); + +} diff -r 5379af6bef00 -r 014c48d6f360 PyTypeConversions.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PyTypeConversions.h Wed Nov 26 09:48:35 2014 +0000 @@ -0,0 +1,198 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + VampyHost + + Use Vamp audio analysis plugins in Python + + Gyorgy Fazekas and Chris Cannam + Centre for Digital Music, Queen Mary, University of London + Copyright 2008-2014 Queen Mary, University of London + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and the authors + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +/* + PyTypeConversions: Type safe conversion utilities between Python + types and basic C/C++ types. +*/ + +#ifndef PY_TYPE_CONVERSIONS_H +#define PY_TYPE_CONVERSIONS_H + +#include + +#ifdef HAVE_NUMPY +#define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API +#define NO_IMPORT_ARRAY +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include "numpy/arrayobject.h" +#endif + +#include +#include +#include +#include +#include + +using std::cerr; +using std::endl; + +#ifdef HAVE_NUMPY +enum eArrayDataType { + dtype_float32 = (int) NPY_FLOAT, + dtype_complex64 = (int) NPY_CFLOAT + }; +#endif + +/* C++ mapping of PyNone Type */ +struct NoneType {}; + +// Data +class ValueError +{ +public: + ValueError() {} + ValueError(std::string m, bool s) : message(m),strict(s) {} + std::string location; + std::string message; + bool strict; + std::string str() const { + return (location.empty()) ? message : message + "\nLocation: " + location;} + void print() const { cerr << str() << endl; } + template ValueError &operator<< (const V& v) + { + std::ostringstream ss; + ss << v; + location += ss.str(); + return *this; + } +}; + +class PyTypeConversions +{ +public: + PyTypeConversions(); + ~PyTypeConversions(); + + // Utilities + void setStrictTypingFlag(bool b) {m_strict = b;} + void setNumpyInstalled(bool b) {m_numpyInstalled = b;} + ValueError getError() const; + std::string PyValue_Get_TypeName(PyObject*) const; + + // Basic type conversion: Python to C++ + float PyValue_To_Float(PyObject*) const; + size_t PyValue_To_Size_t(PyObject*) const; + bool PyValue_To_Bool(PyObject*) const; + std::string PyValue_To_String(PyObject*) const; + long PyValue_To_Long(PyObject*) const; + // int PyValue_To_Int(PyObject* pyValue) const; + + // C++ to Python + PyObject *PyValue_From_CValue(const char*) const; + PyObject *PyValue_From_CValue(const std::string& x) const { return PyValue_From_CValue(x.c_str()); } + PyObject *PyValue_From_CValue(size_t) const; + PyObject *PyValue_From_CValue(double) const; + PyObject *PyValue_From_CValue(float x) const { return PyValue_From_CValue((double)x); } + PyObject *PyValue_From_CValue(bool) const; + + // Sequence types + std::vector PyValue_To_StringVector (PyObject*) const; + std::vector PyValue_To_FloatVector (PyObject*) const; + std::vector PyList_To_FloatVector (PyObject*) const; + + PyObject *PyValue_From_StringVector(const std::vector &) const; + + // Numpy types +#ifdef HAVE_NUMPY + std::vector PyArray_To_FloatVector (PyObject *pyValue) const; + PyObject *FloatVector_To_PyArray(const std::vector &) const; // Copying the data +#endif + + /// Convert DTYPE type 1D NumpyArray to std::vector + template + std::vector PyArray_Convert(void* raw_data_ptr, long length, size_t strides) const + { + std::vector rValue; + + /// check if the array is continuous, if not use strides info + if (sizeof(DTYPE)!=strides) { +#ifdef _DEBUG_VALUES + cerr << "Warning: discontinuous numpy array. Strides: " << strides << " bytes. sizeof(dtype): " << sizeof(DTYPE) << endl; +#endif + char* data = (char*) raw_data_ptr; + for (long i = 0; i PyArray0D_Convert(PyArrayInterface *ai) const + { + std::vector rValue; + if ((ai->typekind) == *"f") + rValue.push_back((float)*(double*)(ai->data)); + else { + setValueError("Unsupported NumPy data type.",m_strict); + return rValue; + } +#ifdef _DEBUG_VALUES + cerr << "value: " << rValue[0] << endl; +#endif + return rValue; + } + +private: + bool m_strict; + mutable bool m_error; + mutable std::queue m_errorQueue; + bool m_numpyInstalled; + + void setValueError(std::string,bool) const; + ValueError& lastError() const; + +public: + const bool& error; + +}; + +#endif diff -r 5379af6bef00 -r 014c48d6f360 vampyhost.cpp --- a/vampyhost.cpp Wed Nov 26 09:38:56 2014 +0000 +++ b/vampyhost.cpp Wed Nov 26 09:48:35 2014 +0000 @@ -1,5 +1,42 @@ /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ +/* + VampyHost + + Use Vamp audio analysis plugins in Python + + Gyorgy Fazekas and Chris Cannam + Centre for Digital Music, Queen Mary, University of London + Copyright 2008-2014 Queen Mary, University of London + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and the authors + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "PyRealTime.h" + //include for python extension module: must be first #include diff -r 5379af6bef00 -r 014c48d6f360 vampyhost.h --- a/vampyhost.h Wed Nov 26 09:38:56 2014 +0000 +++ b/vampyhost.h Wed Nov 26 09:48:35 2014 +0000 @@ -1,6 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -#ifndef _VAMPYHOST_H_ -#define _VAMPYHOST_H_ - -#endif