Mercurial > hg > vampy-host
changeset 12:d0d91312e5a2
Prepare attempt to build using VamPy structures
author | Chris Cannam |
---|---|
date | Thu, 20 Nov 2014 13:03:50 +0000 |
parents | d29c25695f5e |
children | 628c84ed0ef6 |
files | Makefile pyRealTime.cpp pyRealTime.h vampyhost.cpp |
diffstat | 4 files changed, 28 insertions(+), 580 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Tue Mar 12 18:20:06 2013 +0000 +++ b/Makefile Thu Nov 20 13:03:50 2014 +0000 @@ -2,26 +2,17 @@ PY_INCLUDE_PATH := /usr/include/python2.7 NUMPY_INCLUDE_PATH := /usr/lib/python2.7/site-packages/numpy/core/include -CFLAGS := -O2 -fPIC -Wall -I$(PY_INCLUDE_PATH) -I$(NUMPY_INCLUDE_PATH) -I. -CXXFLAGS := -O2 -fPIC -Wall -I$(PY_INCLUDE_PATH) -I$(NUMPY_INCLUDE_PATH) -I. +CFLAGS := -DHAVE_NUMPY -D_VAMP_PLUGIN_IN_HOST_NAMESPACE=1 -O2 -fPIC -Wall -Werror -Ivampy -I$(PY_INCLUDE_PATH) -I$(NUMPY_INCLUDE_PATH) -I. +CXXFLAGS := -DHAVE_NUMPY -D_VAMP_PLUGIN_IN_HOST_NAMESPACE=1 -O2 -fPIC -Wall -Werror -Ivampy -I$(PY_INCLUDE_PATH) -I$(NUMPY_INCLUDE_PATH) -I. -LDFLAGS := -shared -lpython2.7 -lvamp-hostsdk -#LDFLAGS := -dynamiclib -lpython2.5 /usr/lib/libvamp-hostsdk.a +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 -all: pyRealTime.so vampyhost.so +all: vampyhost.so -pyRealTime.a: pyRealTime.o - ar r $@ pyRealTime.o - -pyRealTime.so: pyRealTime.o - g++ -shared $^ -o $@ $(LDFLAGS) - -vampyhost.so: vampyhost.o pyRealTime.a +vampyhost.so: $(OBJECTS) g++ -o $@ -shared $^ $(LDFLAGS) - clean: - rm *.o - rm *.so - rm *.a + rm -f vampy/*.o *.o *.so *.a
--- a/pyRealTime.cpp Tue Mar 12 18:20:06 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,436 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ -/* - - This module exposes a Type Object wrapping Vamp::RealTime - together with module level functions to create - new pyRealTime objects from frame count, samplerate or sec,nsec tuples. - - A small API is provided for the C/C++ programmer and relevant - functions are exposed to Python. - - TODO: implement number protocol (i.e. wrap arithmetic operators) - partly done - -*/ - -#include <Python.h> -#include <pyRealTime.h> -#include "vamp-hostsdk/Plugin.h" -#include <string> - -using namespace std; -using namespace Vamp; - -using Vamp::Plugin; -using Vamp::RealTime; - -/* REAL-TIME TYPE OBJECT */ - - -/* Documentation for our new module */ -PyDoc_STRVAR(module_doc, - "This module is a thin wrapper around Vamp::RealTime."); - - -/* RealTime Object's Methods */ -//Note: 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_toText(RealTimeObject *self, PyObject *args) -{ - return Py_BuildValue("s", - self->rt->toText().c_str()); -} - -/* 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()); -} - - -/* 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, - "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); -} - -/* test */ -static PyObject * -RealTime_test(PyObject *self) -{ - - long frame = 100; - unsigned int sampleRate = 22050; - - const RealTime t = RealTime::frame2RealTime(frame,sampleRate); - long back = RealTime::realTime2Frame(t,sampleRate); - cerr << "Reverse Conversion: " << back << endl; - - return Py_BuildValue("s", - ((RealTimeObject*)self)->rt->toString().c_str()); -} - - -/* Type object's (RealTime) methods table */ -static PyMethodDef RealTime_methods[] = { - - {"toText", (PyCFunction)RealTime_toText, METH_NOARGS, - PyDoc_STR("toText() -> Return a user-readable string to the nearest millisecond in a form like HH:MM:SS.mmm")}, - - {"values", (PyCFunction)RealTime_values, METH_NOARGS, - PyDoc_STR("values() -> Tuple of sec,nsec representation.")}, - - {"toFrame", (PyCFunction)RealTime_toFrame, METH_VARARGS, - PyDoc_STR("toFrame(samplerate) -> Sample count for given sample rate.")}, - - {"toFloat", (PyCFunction)RealTime_float, METH_NOARGS, - PyDoc_STR("float() -> Floating point representation.")}, - - {"test", (PyCFunction)RealTime_test, METH_VARARGS, - PyDoc_STR("test() -> .")}, - - {NULL, NULL} /* sentinel */ -}; - - - -/* Function to set basic attributes */ -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; -} - -/* Function to get basic attributes */ -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); -} - - -/* DESTRUCTOR: delete type object */ -static void -RealTimeObject_dealloc(RealTimeObject *self) -{ - delete self->rt; //delete the C object - PyObject_Del(self); //delete the Python object -} - -/* Number Protocol */ - - -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*/ -}; - -/* pyRealTime TypeObject */ - - -/* Doc:: 10.3 Type Objects */ -/* static */ PyTypeObject RealTime_Type = { - /* The ob_type field must be initialized in the module init function - * to be portable to Windows without using C++. */ - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "pyRealTime.realtime", /*tp_name*/ - sizeof(RealTimeObject), /*tp_basicsize*/ - 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*/ - 0, /*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*/ - 0, /*tp_alloc*/ - 0, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ -}; - - -/* Remaining Functions Exposed by the MODULE */ - - -/* New RealTime object from Frame (with given samplerate) */ -/*static*/ PyObject * -RealTime_frame2RealTime(PyObject *ignored, PyObject *args) -{ - - long frame; - unsigned int sampleRate; - - if (!PyArg_ParseTuple(args, "lI:realtime.fame2RealTime ", - &frame, - &sampleRate)) - return NULL; - /*Doc:: 5.5 Parsing arguments and building values*/ - - RealTimeObject *self; - self = PyObject_New(RealTimeObject, &RealTime_Type); - if (self == NULL) - return NULL; - - self->rt = new RealTime( - RealTime::frame2RealTime(frame,sampleRate)); - - return (PyObject *) self; -} - -/* New RealTime object from sec and nsec */ -/*static*/ PyObject * -RealTime_new(PyObject *ignored, PyObject *args) -{ - - unsigned int sec = 0; - unsigned int nsec = 0; - double unary = 0; - const char *fmt = NULL; - - /*Doc:: 5.5 Parsing arguments and building values*/ - if ( - - !PyArg_ParseTuple(args, "|sd:realtime.new ", - (const char *) &fmt, - (double *) &unary) && - - !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); - 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 { - - 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; -} - - -/* pyRealTime Module's methods table */ -static PyMethodDef Module_methods[] = { - - {"frame2RealTime", (PyCFunction)RealTime_frame2RealTime, METH_VARARGS, - PyDoc_STR("frame2RealTime((int64)frame, (uint32)sampleRate ) -> returns new RealTime object from frame.")}, - - {"realtime", RealTime_new, METH_VARARGS, - PyDoc_STR("realtime() -> returns new RealTime object")}, - - {NULL, NULL} /* sentinel */ -}; - - -/* PyRealTime C API functions */ - - - -/*RealTime from PyRealTime*/ -RealTime* -PyRealTime_AsPointer (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; }; - -/*PyRealTime from RealTime*/ -PyObject* -PyRealTime_FromRealTime(Vamp::RealTime *rt) { - - RealTimeObject *self = - PyObject_New(RealTimeObject, &RealTime_Type); - if (self == NULL) return NULL; - - self->rt = new RealTime(*rt); - return (PyObject*) self; - //TODO: check if we need to INCREF here -} - - -/* Module initialization (includes extern "C" {...}) */ -PyMODINIT_FUNC -initpyRealTime(void) -{ - PyObject *m; - - /* Finalize the type object including setting type of the new type - * object; doing it here is required for portability to Windows - * without requiring C++. */ - if (PyType_Ready(&RealTime_Type) < 0) - return; - - /* Create the module and add the functions */ - m = Py_InitModule3("pyRealTime", Module_methods, module_doc); - if (m == NULL) - return; - -// PyModule_AddObject(m, "realtime", (PyObject *)&RealTime_Type); - -}
--- a/pyRealTime.h Tue Mar 12 18:20:06 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ -#ifndef _PYREALTIME_H_ -#define _PYREALTIME_H_ - -#include "vamp-hostsdk/Plugin.h" - -/* RealTime Type Object's structure */ -/* Doc:: 10.2 Common Object Structures */ -typedef struct { - PyObject_HEAD - /*PyObject *rt_attrs;*/ - Vamp::RealTime *rt; -} RealTimeObject; - -PyAPI_DATA(PyTypeObject) RealTime_Type; - -#define PyRealTime_CheckExact(v) ((v)->ob_type == &RealTime_Type) -#define PyRealTime_Check(v) PyObject_TypeCheck(v, &RealTime_Type) - -/* pyRealTime C API functions */ -// Example from Python's stringobject.h -// PyAPI_FUNC(PyObject *) PyString_FromString(const char *); - -#ifdef __cplusplus -extern "C" { -#endif - -/* PyRealTime C API functions */ - -PyAPI_FUNC(PyObject *) -PyRealTime_FromRealTime(Vamp::RealTime *rt); - -PyAPI_FUNC(Vamp::RealTime *) -PyRealTime_AsPointer(PyObject *self); - -/* PyRealTime Module functions */ - -PyAPI_FUNC(PyObject *) -RealTime_new(PyObject *ignored, PyObject *args); - -PyAPI_FUNC(PyObject *) -RealTime_frame2RealTime(PyObject *ignored, PyObject *args); - -#ifdef __cplusplus -} -#endif -#endif /* _PYREALTIME_H_ */
--- a/vampyhost.cpp Tue Mar 12 18:20:06 2013 +0000 +++ b/vampyhost.cpp Thu Nov 20 13:03:50 2014 +0000 @@ -3,11 +3,16 @@ //include for python extension module: must be first #include <Python.h> #include <vampyhost.h> -#include <pyRealTime.h> + +#include <PyRealTime.h> //!!! NB all our NumPy stuff is currently using the deprecated API -- //!!! need to work out how to update this -#include "numpy/arrayobject.h" +//#include "numpy/arrayobject.h" + +#define HAVE_NUMPY 1 // Required + +#include "PyTypeConversions.h" //includes for vamp host #include "vamp-hostsdk/Plugin.h" @@ -412,71 +417,6 @@ return Py_True; } -// These conversion functions are borrowed from PyTypeInterface in VamPy - -template<typename RET, typename DTYPE> -static -RET *pyArrayConvert(char* raw_data_ptr, long length, size_t strides) -{ - RET *rValue = new RET[length]; - - /// check if the array is continuous, if not use strides info - if (sizeof(DTYPE)!=strides) { - char* data = (char*) raw_data_ptr; - for (long i = 0; i<length; ++i){ - rValue[i] = (RET)(*((DTYPE*)data)); - data += strides; - } - return rValue; - } - - DTYPE* data = (DTYPE*) raw_data_ptr; - for (long i = 0; i<length; ++i){ - rValue[i] = (RET)data[i]; - } - - return rValue; -} - -static float * -pyArrayToFloatArray(PyObject *pyValue) -{ - if (!PyArray_Check(pyValue)) { - cerr << "pyArrayToFloatArray: Failed, object has no array interface" << endl; - return 0; - } - - PyArrayObject* pyArray = (PyArrayObject*) pyValue; - PyArray_Descr* descr = pyArray->descr; - - /// check raw data and descriptor pointers - if (pyArray->data == 0 || descr == 0) { - cerr << "pyArrayToFloatArray: Failed, NumPy array has NULL data or descriptor" << endl; - return 0; - } - - /// check dimensions - if (pyArray->nd != 1) { - cerr << "pyArrayToFloatArray: Failed, NumPy array is multi-dimensional" << endl; - return 0; - } - - /// check strides (useful if array is not continuous) - size_t strides = *((size_t*) pyArray->strides); - - /// convert the array - switch (descr->type_num) { - case NPY_FLOAT : // dtype='float32' - return pyArrayConvert<float,float>(pyArray->data,pyArray->dimensions[0],strides); - case NPY_DOUBLE : // dtype='float64' - return pyArrayConvert<float,double>(pyArray->data,pyArray->dimensions[0],strides); - default: - cerr << "pyArrayToFloatArray: Failed: Unsupported value type " << descr->type_num << " in NumPy array object (only float32, float64 supported)" << endl; - return 0; - } -} - - /* RUN PROCESS */ static PyObject * @@ -514,8 +454,8 @@ "Plugin has not been initialised."); return NULL; } - size_t channels = pd->channels; - size_t blockSize = pd->blockSize; + int channels = pd->channels; +// int blockSize = pd->blockSize; if (!PyList_Check(pyBuffer)) { PyErr_SetString(PyExc_TypeError, "List of NumPy Array required for process input."); @@ -530,16 +470,20 @@ float **inbuf = new float *[channels]; + PyTypeConversions typeConv; + typeConv.setNumpyInstalled(true); + + vector<vector<float> > data; for (int c = 0; c < channels; ++c) { PyObject *cbuf = PyList_GET_ITEM(pyBuffer, c); - inbuf[c] = pyArrayToFloatArray(cbuf); - if (!inbuf[c]) { - PyErr_SetString(PyExc_TypeError,"NumPy Array required for each channel in process input."); - return NULL; - } + data.push_back(typeConv.PyArray_To_FloatVector(cbuf)); + } + + for (int c = 0; c < channels; ++c) { + inbuf[c] = &data[c][0]; } - RealTime timeStamp = *PyRealTime_AsPointer(pyRealTime); + RealTime timeStamp = *PyRealTime_AsRealTime(pyRealTime); //Call process and store the output pd->output = plugin->process(inbuf, timeStamp); @@ -547,10 +491,6 @@ /* TODO: DO SOMETHONG WITH THE FEATURE SET HERE */ /// convert to appropriate python objects, reuse types and conversion utilities from Vampy ... - - for (int c = 0; c < channels; ++c){ - delete[] inbuf[c]; - } delete[] inbuf; return NULL; //!!! Need to return actual features! @@ -673,13 +613,13 @@ xx_foo_doc}, /* Add RealTime Module Methods */ - +/* {"frame2RealTime", (PyCFunction)RealTime_frame2RealTime, METH_VARARGS, PyDoc_STR("frame2RealTime((int64)frame, (uint32)sampleRate ) -> returns new RealTime object from frame.")}, {"realtime", (PyCFunction)RealTime_new, METH_VARARGS, PyDoc_STR("realtime() -> returns new RealTime object")}, - +*/ {NULL, NULL} /* sentinel */ };