source: python/ext/py-cvec.c @ ee092a8

feature/autosinkfeature/cnnfeature/cnn_orgfeature/constantqfeature/crepefeature/crepe_orgfeature/pitchshiftfeature/pydocstringsfeature/timestretchfix/ffmpeg5pitchshiftsamplertimestretchyinfft+
Last change on this file since ee092a8 was 92a8800, checked in by Paul Brossier <piem@piem.org>, 8 years ago

python/ext/py-cvec.c: rewrite and simplify aubio.cvec, safer and better memory usage (see #49)

  • Property mode set to 100644
File size: 9.6 KB
RevLine 
[f826349]1#include "aubio-types.h"
2
[92a8800]3/* cvec type definition
[f826349]4
5class cvec():
[92a8800]6    def __new__(self, length = 1024):
7        self.length = length / 2 + 1
8        self.norm = np.zeros(length / 2 + 1)
9        self.phas = np.zeros(length / 2 + 1)
[f826349]10
[7a7b00f]11*/
[f826349]12
[92a8800]13// special python type for cvec
14typedef struct
15{
16  PyObject_HEAD
17  PyObject *norm;
18  PyObject *phas;
19  uint_t length;
20} Py_cvec;
21
[f826349]22static char Py_cvec_doc[] = "cvec object";
23
[92a8800]24PyObject *
25PyAubio_CCvecToPyCvec (cvec_t * input) {
26  if (input == NULL) {
27      PyErr_SetString (PyExc_ValueError, "PyAubio_CCvecToPyCvec got a null cvec!");
28      return NULL;
29  }
30  Py_cvec* vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
31  npy_intp dims[] = { input->length, 1 };
32  vec->norm = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, input->norm);
33  vec->phas = PyArray_SimpleNewFromData (1, dims, AUBIO_NPY_SMPL, input->phas);
34  vec->length = input->length;
35  return (PyObject *)vec;
36}
37
38int
39PyAubio_PyCvecToCCvec (PyObject *input, cvec_t *i) {
40  if (PyObject_TypeCheck (input, &Py_cvecType)) {
41      Py_cvec * in = (Py_cvec *)input;
42      if (in->norm == NULL) {
43        npy_intp dims[] = { in->length, 1 };
44        in->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
45      }
46      if (in->phas == NULL) {
47        npy_intp dims[] = { in->length, 1 };
48        in->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
49      }
50      i->norm = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->norm), 0);
51      i->phas = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->phas), 0);
52      i->length = ((Py_cvec*)input)->length;
53      return 1;
54  } else {
55      PyErr_SetString (PyExc_ValueError, "input array should be aubio.cvec");
56      return 0;
57  }
58}
59
[f826349]60static PyObject *
61Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
62{
[7a7b00f]63  int length= 0;
[f826349]64  Py_cvec *self;
[7a7b00f]65  static char *kwlist[] = { "length", NULL };
[f826349]66
[7a7b00f]67  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist,
68          &length)) {
[f826349]69    return NULL;
70  }
71
72  self = (Py_cvec *) type->tp_alloc (type, 0);
73
[eb93592]74  self->length = Py_default_vector_length / 2 + 1;
[f826349]75
76  if (self == NULL) {
77    return NULL;
78  }
79
80  if (length > 0) {
[eb93592]81    self->length = length / 2 + 1;
[f826349]82  } else if (length < 0) {
83    PyErr_SetString (PyExc_ValueError,
84        "can not use negative number of elements");
85    return NULL;
86  }
87
88  return (PyObject *) self;
89}
90
91static int
92Py_cvec_init (Py_cvec * self, PyObject * args, PyObject * kwds)
93{
[92a8800]94  self->norm = NULL;
95  self->phas = NULL;
[f826349]96  return 0;
97}
98
99static void
100Py_cvec_del (Py_cvec * self)
101{
[92a8800]102  Py_XDECREF(self->norm);
103  Py_XDECREF(self->phas);
[770b9e7]104  Py_TYPE(self)->tp_free ((PyObject *) self);
[f826349]105}
106
107static PyObject *
108Py_cvec_repr (Py_cvec * self, PyObject * unused)
109{
110  PyObject *format = NULL;
111  PyObject *args = NULL;
112  PyObject *result = NULL;
113
[5c1200a]114  format = PyUnicode_FromString ("aubio cvec of %d elements");
[f826349]115  if (format == NULL) {
116    goto fail;
117  }
118
[7a7b00f]119  args = Py_BuildValue ("I", self->length);
[f826349]120  if (args == NULL) {
121    goto fail;
122  }
[92a8800]123  // hide actual norm / phas content
[f826349]124
[5c1200a]125  result = PyUnicode_Format (format, args);
[f826349]126
127fail:
128  Py_XDECREF (format);
129  Py_XDECREF (args);
130
131  return result;
132}
133
[615ac7d]134PyObject *
135Py_cvec_get_norm (Py_cvec * self, void *closure)
136{
[92a8800]137  // if it norm hasn't been created, create it now
138  if (self->norm == NULL) {
139    npy_intp dims[] = { self->length, 1 };
140    self->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
141  }
142  Py_INCREF(self->norm);
143  return (PyObject*)(self->norm);
[615ac7d]144}
145
146PyObject *
147Py_cvec_get_phas (Py_cvec * self, void *closure)
148{
[92a8800]149  // if it phas hasn't been created, create it now
150  if (self->phas == NULL) {
151    npy_intp dims[] = { self->length, 1 };
152    self->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
153  }
154  Py_INCREF(self->phas);
155  return (PyObject *)(self->phas);
[615ac7d]156}
157
158static int
[a8aaef3]159Py_cvec_set_norm (Py_cvec * vec, PyObject *input, void * closure)
[615ac7d]160{
[1458de5]161  PyArrayObject * array;
[a8aaef3]162  if (input == NULL) {
163    PyErr_SetString (PyExc_ValueError, "input array is not a python object");
164    goto fail;
165  }
166  if (PyArray_Check(input)) {
[92a8800]167    // we got an array, convert it to a cvec.norm
[1458de5]168    if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
[a8aaef3]169      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
170      goto fail;
[1458de5]171    } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
[a8aaef3]172      PyErr_SetString (PyExc_ValueError,
173          "input array has more than two dimensions");
174      goto fail;
175    }
176
[1458de5]177    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
[a8aaef3]178      PyErr_SetString (PyExc_ValueError, "input array should be float");
179      goto fail;
[1458de5]180    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
[a8aaef3]181      PyErr_SetString (PyExc_ValueError, "input array should be float32");
182      goto fail;
183    }
[1458de5]184    array = (PyArrayObject *)input;
[a8aaef3]185
186    // check input array dimensions
[7a7b00f]187    if (PyArray_NDIM (array) != 1) {
188      PyErr_Format (PyExc_ValueError,
189          "input array has %d dimensions, not 1",
190          PyArray_NDIM (array));
191      goto fail;
192    } else {
[92a8800]193      if (vec->length != PyArray_SIZE (array)) {
[a8aaef3]194          PyErr_Format (PyExc_ValueError,
195                  "input array has length %d, but cvec has length %d",
[92a8800]196                  (int)PyArray_SIZE (array), vec->length);
[a8aaef3]197          goto fail;
198      }
199    }
200
[92a8800]201    Py_XDECREF(vec->norm);
202    vec->norm = input;
203    Py_INCREF(vec->norm);
[a8aaef3]204
205  } else {
206    PyErr_SetString (PyExc_ValueError, "can only accept array as input");
207    return 1;
208  }
209
[615ac7d]210  return 0;
[a8aaef3]211
212fail:
213  return 1;
[615ac7d]214}
215
216static int
[a8aaef3]217Py_cvec_set_phas (Py_cvec * vec, PyObject *input, void * closure)
[615ac7d]218{
[1458de5]219  PyArrayObject * array;
[a8aaef3]220  if (input == NULL) {
221    PyErr_SetString (PyExc_ValueError, "input array is not a python object");
222    goto fail;
223  }
224  if (PyArray_Check(input)) {
225
226    // we got an array, convert it to a cvec.phas
[1458de5]227    if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
[a8aaef3]228      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
229      goto fail;
[1458de5]230    } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
[a8aaef3]231      PyErr_SetString (PyExc_ValueError,
232          "input array has more than two dimensions");
233      goto fail;
234    }
235
[1458de5]236    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
[a8aaef3]237      PyErr_SetString (PyExc_ValueError, "input array should be float");
238      goto fail;
[1458de5]239    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
[a8aaef3]240      PyErr_SetString (PyExc_ValueError, "input array should be float32");
241      goto fail;
242    }
[1458de5]243    array = (PyArrayObject *)input;
[a8aaef3]244
245    // check input array dimensions
[7a7b00f]246    if (PyArray_NDIM (array) != 1) {
247      PyErr_Format (PyExc_ValueError,
248          "input array has %d dimensions, not 1",
249          PyArray_NDIM (array));
250      goto fail;
251    } else {
[92a8800]252      if (vec->length != PyArray_SIZE (array)) {
[a8aaef3]253          PyErr_Format (PyExc_ValueError,
254                  "input array has length %d, but cvec has length %d",
[92a8800]255                  (int)PyArray_SIZE (array), vec->length);
[a8aaef3]256          goto fail;
257      }
258    }
259
[92a8800]260    Py_XDECREF(vec->phas);
261    vec->phas = input;
262    Py_INCREF(vec->phas);
[a8aaef3]263
264  } else {
265    PyErr_SetString (PyExc_ValueError, "can only accept array as input");
266    return 1;
267  }
268
[615ac7d]269  return 0;
[a8aaef3]270
271fail:
272  return 1;
[615ac7d]273}
274
[f826349]275static PyMemberDef Py_cvec_members[] = {
276  // TODO remove READONLY flag and define getter/setter
277  {"length", T_INT, offsetof (Py_cvec, length), READONLY,
278      "length attribute"},
279  {NULL}                        /* Sentinel */
280};
281
282static PyMethodDef Py_cvec_methods[] = {
283  {NULL}
284};
285
[615ac7d]286static PyGetSetDef Py_cvec_getseters[] = {
287  {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm, 
[474f297]288      "Numpy vector of shape (length,) containing the magnitude",
[615ac7d]289      NULL},
290  {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas, 
[474f297]291      "Numpy vector of shape (length,) containing the phase",
[615ac7d]292      NULL},
293  {NULL} /* sentinel */
294};
295
[f826349]296PyTypeObject Py_cvecType = {
[5c1200a]297  PyVarObject_HEAD_INIT(NULL, 0)
[f826349]298  "aubio.cvec",                 /* tp_name           */
299  sizeof (Py_cvec),             /* tp_basicsize      */
300  0,                            /* tp_itemsize       */
301  (destructor) Py_cvec_del,     /* tp_dealloc        */
302  0,                            /* tp_print          */
303  0,                            /* tp_getattr        */
304  0,                            /* tp_setattr        */
305  0,                            /* tp_compare        */
306  (reprfunc) Py_cvec_repr,      /* tp_repr           */
307  0,                            /* tp_as_number      */
[f2ce0fc]308  0, //&Py_cvec_tp_as_sequence, /* tp_as_sequence    */
[f826349]309  0,                            /* tp_as_mapping     */
310  0,                            /* tp_hash           */
311  0,                            /* tp_call           */
312  0,                            /* tp_str            */
313  0,                            /* tp_getattro       */
314  0,                            /* tp_setattro       */
315  0,                            /* tp_as_buffer      */
316  Py_TPFLAGS_DEFAULT,           /* tp_flags          */
317  Py_cvec_doc,                  /* tp_doc            */
318  0,                            /* tp_traverse       */
319  0,                            /* tp_clear          */
320  0,                            /* tp_richcompare    */
321  0,                            /* tp_weaklistoffset */
322  0,                            /* tp_iter           */
323  0,                            /* tp_iternext       */
324  Py_cvec_methods,              /* tp_methods        */
325  Py_cvec_members,              /* tp_members        */
[615ac7d]326  Py_cvec_getseters,            /* tp_getset         */
[f826349]327  0,                            /* tp_base           */
328  0,                            /* tp_dict           */
329  0,                            /* tp_descr_get      */
330  0,                            /* tp_descr_set      */
331  0,                            /* tp_dictoffset     */
332  (initproc) Py_cvec_init,      /* tp_init           */
333  0,                            /* tp_alloc          */
334  Py_cvec_new,                  /* tp_new            */
335};
Note: See TracBrowser for help on using the repository browser.