From 92a880038648589865c7bd3fac15647a7b792788 Mon Sep 17 00:00:00 2001 From: Paul Brossier Date: Thu, 28 Apr 2016 18:59:55 +0200 Subject: [PATCH] python/ext/py-cvec.c: rewrite and simplify aubio.cvec, safer and better memory usage (see #49) --- python/ext/aubio-types.h | 11 +--- python/ext/aubioproxy.c | 23 --------- python/ext/py-cvec.c | 126 ++++++++++++++++++++++++++++----------------- python/ext/py-fft.c | 17 ++---- python/ext/py-filterbank.c | 2 +- python/ext/py-phasevoc.c | 14 ++--- python/lib/gen_code.py | 2 +- 7 files changed, 90 insertions(+), 105 deletions(-) diff --git a/python/ext/aubio-types.h b/python/ext/aubio-types.h index edcf1752..9bf92d3b 100644 --- a/python/ext/aubio-types.h +++ b/python/ext/aubio-types.h @@ -50,21 +50,14 @@ #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #endif -// special python type for cvec -typedef struct -{ - PyObject_HEAD - cvec_t * o; - uint_t length; -} Py_cvec; extern PyTypeObject Py_cvecType; // defined in aubio-proxy.c extern PyObject *PyAubio_CFvecToArray (fvec_t * self); extern int PyAubio_ArrayToCFvec (PyObject * self, fvec_t *out); -extern PyObject * PyAubio_CCvecToPyCvec (cvec_t * self, Py_cvec *out); -extern int PyAubio_ArrayToCCvec (PyObject *input, cvec_t *i); +extern PyObject * PyAubio_CCvecToPyCvec (cvec_t * self); +extern int PyAubio_PyCvecToCCvec (PyObject *input, cvec_t *i); extern PyObject *PyAubio_CFmatToArray (fmat_t * self); extern int PyAubio_ArrayToCFmat (PyObject *input, fmat_t *out); diff --git a/python/ext/aubioproxy.c b/python/ext/aubioproxy.c index 6ee61e9a..7abd24ec 100644 --- a/python/ext/aubioproxy.c +++ b/python/ext/aubioproxy.c @@ -56,29 +56,6 @@ PyAubio_ArrayToCFvec (PyObject *input, fvec_t *out) { } PyObject * -PyAubio_CCvecToPyCvec (cvec_t * input, Py_cvec *vec) { - vec->length = input->length; - vec->o = input; - // keep a reference to re-use after returning it - Py_INCREF(vec); - return (PyObject *)vec; -} - -int -PyAubio_ArrayToCCvec (PyObject *input, cvec_t *i) { - if (PyObject_TypeCheck (input, &Py_cvecType)) { - //*i = *(((Py_cvec*)input)->o); - i->norm = ((Py_cvec*)input)->o->norm; - i->phas = ((Py_cvec*)input)->o->phas; - i->length = ((Py_cvec*)input)->o->length; - return 1; - } else { - PyErr_SetString (PyExc_ValueError, "input array should be aubio.cvec"); - return 0; - } -} - -PyObject * PyAubio_CFmatToArray (fmat_t * input) { PyObject *array = NULL; diff --git a/python/ext/py-cvec.c b/python/ext/py-cvec.c index dc7e71c5..f81e1c8a 100644 --- a/python/ext/py-cvec.c +++ b/python/ext/py-cvec.c @@ -1,17 +1,62 @@ #include "aubio-types.h" -/* cvec type definition +/* cvec type definition class cvec(): - def __init__(self, length = 1024): - self.length = length - self.norm = array(length) - self.phas = array(length) + def __new__(self, length = 1024): + self.length = length / 2 + 1 + self.norm = np.zeros(length / 2 + 1) + self.phas = np.zeros(length / 2 + 1) */ +// special python type for cvec +typedef struct +{ + PyObject_HEAD + PyObject *norm; + PyObject *phas; + uint_t length; +} Py_cvec; + static char Py_cvec_doc[] = "cvec object"; +PyObject * +PyAubio_CCvecToPyCvec (cvec_t * input) { + if (input == NULL) { + PyErr_SetString (PyExc_ValueError, "PyAubio_CCvecToPyCvec got a null cvec!"); + return NULL; + } + Py_cvec* vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType); + npy_intp dims[] = { input->length, 1 }; + vec->norm = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, input->norm); + vec->phas = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, input->phas); + vec->length = input->length; + return (PyObject *)vec; +} + +int +PyAubio_PyCvecToCCvec (PyObject *input, cvec_t *i) { + if (PyObject_TypeCheck (input, &Py_cvecType)) { + Py_cvec * in = (Py_cvec *)input; + if (in->norm == NULL) { + npy_intp dims[] = { in->length, 1 }; + in->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0); + } + if (in->phas == NULL) { + npy_intp dims[] = { in->length, 1 }; + in->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0); + } + i->norm = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->norm), 0); + i->phas = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->phas), 0); + i->length = ((Py_cvec*)input)->length; + return 1; + } else { + PyErr_SetString (PyExc_ValueError, "input array should be aubio.cvec"); + return 0; + } +} + static PyObject * Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds) { @@ -24,7 +69,6 @@ Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds) return NULL; } - self = (Py_cvec *) type->tp_alloc (type, 0); self->length = Py_default_vector_length / 2 + 1; @@ -47,18 +91,16 @@ Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds) static int Py_cvec_init (Py_cvec * self, PyObject * args, PyObject * kwds) { - self->o = new_cvec ((self->length - 1) * 2); - if (self->o == NULL) { - return -1; - } - + self->norm = NULL; + self->phas = NULL; return 0; } static void Py_cvec_del (Py_cvec * self) { - del_cvec (self->o); + Py_XDECREF(self->norm); + Py_XDECREF(self->phas); Py_TYPE(self)->tp_free ((PyObject *) self); } @@ -78,7 +120,7 @@ Py_cvec_repr (Py_cvec * self, PyObject * unused) if (args == NULL) { goto fail; } - cvec_print ( self->o ); + // hide actual norm / phas content result = PyUnicode_Format (format, args); @@ -90,36 +132,27 @@ fail: } PyObject * -PyAubio_CvecNormToArray (Py_cvec * self) -{ - npy_intp dims[] = { self->o->length, 1 }; - return PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->o->norm); -} - - -PyObject * -PyAubio_CvecPhasToArray (Py_cvec * self) -{ - npy_intp dims[] = { self->o->length, 1 }; - return PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, self->o->phas); -} - -PyObject * -PyAubio_ArrayToCvecPhas (PyObject * self) -{ - return NULL; -} - -PyObject * Py_cvec_get_norm (Py_cvec * self, void *closure) { - return PyAubio_CvecNormToArray(self); + // if it norm hasn't been created, create it now + if (self->norm == NULL) { + npy_intp dims[] = { self->length, 1 }; + self->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0); + } + Py_INCREF(self->norm); + return (PyObject*)(self->norm); } PyObject * Py_cvec_get_phas (Py_cvec * self, void *closure) { - return PyAubio_CvecPhasToArray(self); + // if it phas hasn't been created, create it now + if (self->phas == NULL) { + npy_intp dims[] = { self->length, 1 }; + self->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0); + } + Py_INCREF(self->phas); + return (PyObject *)(self->phas); } static int @@ -131,8 +164,7 @@ Py_cvec_set_norm (Py_cvec * vec, PyObject *input, void * closure) goto fail; } if (PyArray_Check(input)) { - - // we got an array, convert it to a cvec.norm + // we got an array, convert it to a cvec.norm if (PyArray_NDIM ((PyArrayObject *)input) == 0) { PyErr_SetString (PyExc_ValueError, "input array is a scalar"); goto fail; @@ -158,22 +190,23 @@ Py_cvec_set_norm (Py_cvec * vec, PyObject *input, void * closure) PyArray_NDIM (array)); goto fail; } else { - if (vec->o->length != PyArray_SIZE (array)) { + if (vec->length != PyArray_SIZE (array)) { PyErr_Format (PyExc_ValueError, "input array has length %d, but cvec has length %d", - (int)PyArray_SIZE (array), vec->o->length); + (int)PyArray_SIZE (array), vec->length); goto fail; } } - vec->o->norm = (smpl_t *) PyArray_GETPTR1 (array, 0); + Py_XDECREF(vec->norm); + vec->norm = input; + Py_INCREF(vec->norm); } else { PyErr_SetString (PyExc_ValueError, "can only accept array as input"); return 1; } - Py_INCREF(array); return 0; fail: @@ -216,22 +249,23 @@ Py_cvec_set_phas (Py_cvec * vec, PyObject *input, void * closure) PyArray_NDIM (array)); goto fail; } else { - if (vec->o->length != PyArray_SIZE (array)) { + if (vec->length != PyArray_SIZE (array)) { PyErr_Format (PyExc_ValueError, "input array has length %d, but cvec has length %d", - (int)PyArray_SIZE (array), vec->o->length); + (int)PyArray_SIZE (array), vec->length); goto fail; } } - vec->o->phas = (smpl_t *) PyArray_GETPTR1 (array, 0); + Py_XDECREF(vec->phas); + vec->phas = input; + Py_INCREF(vec->phas); } else { PyErr_SetString (PyExc_ValueError, "can only accept array as input"); return 1; } - Py_INCREF(array); return 0; fail: diff --git a/python/ext/py-fft.c b/python/ext/py-fft.c index f13c820b..61595b95 100644 --- a/python/ext/py-fft.c +++ b/python/ext/py-fft.c @@ -13,8 +13,6 @@ typedef struct // do / rdo output results cvec_t *out; fvec_t *rout; - // bridge for cvec output - Py_cvec *py_out; } Py_fft; static PyObject * @@ -60,8 +58,6 @@ Py_fft_init (Py_fft * self, PyObject * args, PyObject * kwds) } self->out = new_cvec(self->win_s); - self->py_out = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType); - Py_XINCREF(self->py_out); self->rout = new_fvec(self->win_s); return 0; @@ -70,7 +66,6 @@ Py_fft_init (Py_fft * self, PyObject * args, PyObject * kwds) static void Py_fft_del (Py_fft *self, PyObject *unused) { - Py_XDECREF((PyObject*)(self->py_out)); del_aubio_fft(self->o); del_cvec(self->out); del_fvec(self->rout); @@ -92,14 +87,8 @@ Py_fft_do(Py_fft * self, PyObject * args) // compute the function aubio_fft_do (((Py_fft *)self)->o, &(self->vecin), self->out); -#if 0 - Py_cvec * py_out = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType); - PyObject* output = PyAubio_CCvecToPyCvec(self->out, py_out); - return output; -#else - // convert cvec to py_cvec, incrementing refcount to keep a copy - return PyAubio_CCvecToPyCvec(self->out, self->py_out); -#endif + // convert cvec to py_cvec + return PyAubio_CCvecToPyCvec(self->out); } static PyMemberDef Py_fft_members[] = { @@ -117,7 +106,7 @@ Py_fft_rdo(Py_fft * self, PyObject * args) return NULL; } - if (!PyAubio_ArrayToCCvec (input, &(self->cvecin)) ) { + if (!PyAubio_PyCvecToCCvec (input, &(self->cvecin)) ) { return NULL; } diff --git a/python/ext/py-filterbank.c b/python/ext/py-filterbank.c index f807de55..ed1d630e 100644 --- a/python/ext/py-filterbank.c +++ b/python/ext/py-filterbank.c @@ -87,7 +87,7 @@ Py_filterbank_do(Py_filterbank * self, PyObject * args) return NULL; } - if (!PyAubio_ArrayToCCvec(input, &(self->vec) )) { + if (!PyAubio_PyCvecToCCvec(input, &(self->vec) )) { return NULL; } diff --git a/python/ext/py-phasevoc.c b/python/ext/py-phasevoc.c index 0d153b4d..3de4ff4c 100644 --- a/python/ext/py-phasevoc.c +++ b/python/ext/py-phasevoc.c @@ -10,7 +10,6 @@ typedef struct uint_t hop_s; fvec_t vecin; cvec_t *output; - Py_cvec *py_out; cvec_t cvecin; fvec_t *routput; } Py_pvoc; @@ -72,7 +71,6 @@ Py_pvoc_init (Py_pvoc * self, PyObject * args, PyObject * kwds) } self->output = new_cvec(self->win_s); - self->py_out = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType); self->routput = new_fvec(self->hop_s); return 0; @@ -104,14 +102,8 @@ Py_pvoc_do(Py_pvoc * self, PyObject * args) // compute the function aubio_pvoc_do (self->o, &(self->vecin), self->output); -#if 0 - Py_cvec * py_out = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType); - PyObject* output = PyAubio_CCvecToPyCvec(self->output, py_out); - return output; -#else - // convert cvec to py_cvec, incrementing refcount to keep a copy - return PyAubio_CCvecToPyCvec(self->output, self->py_out); -#endif + // convert cvec to py_cvec + return PyAubio_CCvecToPyCvec(self->output); } static PyMemberDef Py_pvoc_members[] = { @@ -130,7 +122,7 @@ Py_pvoc_rdo(Py_pvoc * self, PyObject * args) return NULL; } - if (!PyAubio_ArrayToCCvec (input, &(self->cvecin) )) { + if (!PyAubio_PyCvecToCCvec (input, &(self->cvecin) )) { return NULL; } diff --git a/python/lib/gen_code.py b/python/lib/gen_code.py index d2107a93..2ef3bc21 100644 --- a/python/lib/gen_code.py +++ b/python/lib/gen_code.py @@ -37,7 +37,7 @@ pyfromtype_fn = { pytoaubio_fn = { 'fvec_t*': 'PyAubio_ArrayToCFvec', - 'cvec_t*': 'PyAubio_ArrayToCCvec', + 'cvec_t*': 'PyAubio_PyCvecToCCvec', #'fmat_t*': 'PyAubio_ArrayToCFmat', } -- 2.11.0