ref: 92a880038648589865c7bd3fac15647a7b792788
parent: 1f4d932e233b44476f39d699a19e6c023e058626
author: Paul Brossier <piem@piem.org>
date: Thu Apr 28 14:59:55 EDT 2016
python/ext/py-cvec.c: rewrite and simplify aubio.cvec, safer and better memory usage (see #49)
--- a/python/ext/aubio-types.h
+++ b/python/ext/aubio-types.h
@@ -50,13 +50,6 @@
#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
@@ -63,8 +56,8 @@
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);
--- a/python/ext/aubioproxy.c
+++ b/python/ext/aubioproxy.c
@@ -56,29 +56,6 @@
}
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;
--- 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 @@
return NULL;
}
-
self = (Py_cvec *) type->tp_alloc (type, 0);
self->length = Py_default_vector_length / 2 + 1;
@@ -47,11 +91,8 @@
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;
}
@@ -58,7 +99,8 @@
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 @@
if (args == NULL) {
goto fail;
}
- cvec_print ( self->o );
+ // hide actual norm / phas content
result = PyUnicode_Format (format, args);
@@ -90,36 +132,27 @@
}
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 @@
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,15 +190,17 @@
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");
@@ -173,7 +207,6 @@
return 1;
}
- Py_INCREF(array);
return 0;
fail:
@@ -216,15 +249,17 @@
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");
@@ -231,7 +266,6 @@
return 1;
}
- Py_INCREF(array);
return 0;
fail:
--- a/python/ext/py-fft.c
+++ b/python/ext/py-fft.c
@@ -13,8 +13,6 @@
// 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 @@
}
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 @@
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 @@
// 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 @@
return NULL;
}
- if (!PyAubio_ArrayToCCvec (input, &(self->cvecin)) ) {
+ if (!PyAubio_PyCvecToCCvec (input, &(self->cvecin)) ) {
return NULL;
}
--- a/python/ext/py-filterbank.c
+++ b/python/ext/py-filterbank.c
@@ -87,7 +87,7 @@
return NULL;
}
- if (!PyAubio_ArrayToCCvec(input, &(self->vec) )) {
+ if (!PyAubio_PyCvecToCCvec(input, &(self->vec) )) {
return NULL;
}
--- a/python/ext/py-phasevoc.c
+++ b/python/ext/py-phasevoc.c
@@ -10,7 +10,6 @@
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 @@
}
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 @@
// 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 @@
return NULL;
}
- if (!PyAubio_ArrayToCCvec (input, &(self->cvecin) )) {
+ if (!PyAubio_PyCvecToCCvec (input, &(self->cvecin) )) {
return NULL;
}
--- a/python/lib/gen_code.py
+++ b/python/lib/gen_code.py
@@ -37,7 +37,7 @@
pytoaubio_fn = {
'fvec_t*': 'PyAubio_ArrayToCFvec',
- 'cvec_t*': 'PyAubio_ArrayToCCvec',
+ 'cvec_t*': 'PyAubio_PyCvecToCCvec',
#'fmat_t*': 'PyAubio_ArrayToCFmat',
}