source: python/ext/py-cvec.c @ 92a8800

feature/autosinkfeature/cnnfeature/cnn_orgfeature/constantqfeature/crepefeature/crepe_orgfeature/pitchshiftfeature/pydocstringsfeature/timestretchfix/ffmpeg5pitchshiftsamplertimestretchyinfft+
Last change on this file since 92a8800 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
Line 
1#include "aubio-types.h"
2
3/* cvec type definition
4
5class cvec():
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)
10
11*/
12
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
22static char Py_cvec_doc[] = "cvec object";
23
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
60static PyObject *
61Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
62{
63  int length= 0;
64  Py_cvec *self;
65  static char *kwlist[] = { "length", NULL };
66
67  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist,
68          &length)) {
69    return NULL;
70  }
71
72  self = (Py_cvec *) type->tp_alloc (type, 0);
73
74  self->length = Py_default_vector_length / 2 + 1;
75
76  if (self == NULL) {
77    return NULL;
78  }
79
80  if (length > 0) {
81    self->length = length / 2 + 1;
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{
94  self->norm = NULL;
95  self->phas = NULL;
96  return 0;
97}
98
99static void
100Py_cvec_del (Py_cvec * self)
101{
102  Py_XDECREF(self->norm);
103  Py_XDECREF(self->phas);
104  Py_TYPE(self)->tp_free ((PyObject *) self);
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
114  format = PyUnicode_FromString ("aubio cvec of %d elements");
115  if (format == NULL) {
116    goto fail;
117  }
118
119  args = Py_BuildValue ("I", self->length);
120  if (args == NULL) {
121    goto fail;
122  }
123  // hide actual norm / phas content
124
125  result = PyUnicode_Format (format, args);
126
127fail:
128  Py_XDECREF (format);
129  Py_XDECREF (args);
130
131  return result;
132}
133
134PyObject *
135Py_cvec_get_norm (Py_cvec * self, void *closure)
136{
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);
144}
145
146PyObject *
147Py_cvec_get_phas (Py_cvec * self, void *closure)
148{
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);
156}
157
158static int
159Py_cvec_set_norm (Py_cvec * vec, PyObject *input, void * closure)
160{
161  PyArrayObject * array;
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)) {
167    // we got an array, convert it to a cvec.norm
168    if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
169      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
170      goto fail;
171    } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
172      PyErr_SetString (PyExc_ValueError,
173          "input array has more than two dimensions");
174      goto fail;
175    }
176
177    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
178      PyErr_SetString (PyExc_ValueError, "input array should be float");
179      goto fail;
180    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
181      PyErr_SetString (PyExc_ValueError, "input array should be float32");
182      goto fail;
183    }
184    array = (PyArrayObject *)input;
185
186    // check input array dimensions
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 {
193      if (vec->length != PyArray_SIZE (array)) {
194          PyErr_Format (PyExc_ValueError,
195                  "input array has length %d, but cvec has length %d",
196                  (int)PyArray_SIZE (array), vec->length);
197          goto fail;
198      }
199    }
200
201    Py_XDECREF(vec->norm);
202    vec->norm = input;
203    Py_INCREF(vec->norm);
204
205  } else {
206    PyErr_SetString (PyExc_ValueError, "can only accept array as input");
207    return 1;
208  }
209
210  return 0;
211
212fail:
213  return 1;
214}
215
216static int
217Py_cvec_set_phas (Py_cvec * vec, PyObject *input, void * closure)
218{
219  PyArrayObject * array;
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
227    if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
228      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
229      goto fail;
230    } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
231      PyErr_SetString (PyExc_ValueError,
232          "input array has more than two dimensions");
233      goto fail;
234    }
235
236    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
237      PyErr_SetString (PyExc_ValueError, "input array should be float");
238      goto fail;
239    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
240      PyErr_SetString (PyExc_ValueError, "input array should be float32");
241      goto fail;
242    }
243    array = (PyArrayObject *)input;
244
245    // check input array dimensions
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 {
252      if (vec->length != PyArray_SIZE (array)) {
253          PyErr_Format (PyExc_ValueError,
254                  "input array has length %d, but cvec has length %d",
255                  (int)PyArray_SIZE (array), vec->length);
256          goto fail;
257      }
258    }
259
260    Py_XDECREF(vec->phas);
261    vec->phas = input;
262    Py_INCREF(vec->phas);
263
264  } else {
265    PyErr_SetString (PyExc_ValueError, "can only accept array as input");
266    return 1;
267  }
268
269  return 0;
270
271fail:
272  return 1;
273}
274
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
286static PyGetSetDef Py_cvec_getseters[] = {
287  {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm, 
288      "Numpy vector of shape (length,) containing the magnitude",
289      NULL},
290  {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas, 
291      "Numpy vector of shape (length,) containing the phase",
292      NULL},
293  {NULL} /* sentinel */
294};
295
296PyTypeObject Py_cvecType = {
297  PyVarObject_HEAD_INIT(NULL, 0)
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      */
308  0, //&Py_cvec_tp_as_sequence, /* tp_as_sequence    */
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        */
326  Py_cvec_getseters,            /* tp_getset         */
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.