9854b6d6e1ad39d99816cede25f7d2d747b81bbb
[aubio.git] / python / ext / py-cvec.c
1 #include "aubio-types.h"
2
3 /* cvec type definition
4
5 class 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
14 typedef struct
15 {
16   PyObject_HEAD
17   PyObject *norm;
18   PyObject *phas;
19   uint_t length;
20 } Py_cvec;
21
22 static char Py_cvec_doc[] = ""
23 "cvec(size)\n"
24 "\n"
25 "A container holding spectral data.\n"
26 "\n"
27 "Create one `cvec` to store the spectral information of a window\n"
28 "of `size` points. The data will be stored  in two vectors,\n"
29 ":attr:`phas` and :attr:`norm`, each of shape (:attr:`length`,),\n"
30 "with `length = size // 2 + 1`.\n"
31 "\n"
32 "Parameters\n"
33 "----------\n"
34 "size: int\n"
35 "   Size of spectrum to create.\n"
36 "\n"
37 "Examples\n"
38 "--------\n"
39 ">>> c = aubio.cvec(1024)\n"
40 ">>> c\n"
41 "aubio cvec of 513 elements\n"
42 ">>> c.length\n"
43 "513\n"
44 ">>> c.norm.dtype, c.phas.dtype\n"
45 "(dtype('float32'), dtype('float32'))\n"
46 ">>> c.norm.shape, c.phas.shape\n"
47 "((513,), (513,))\n"
48 "\n"
49 "See Also\n"
50 "--------\n"
51 "fvec, fft, pvoc\n"
52 "";
53
54
55 PyObject *
56 new_py_cvec(uint_t length) {
57   Py_cvec* vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
58   npy_intp dims[] = { length / 2 + 1, 1 };
59   vec->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
60   vec->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
61   vec->length = length / 2 + 1;
62   return (PyObject*)vec;
63 }
64
65 int
66 PyAubio_PyCvecToCCvec (PyObject *input, cvec_t *i) {
67   if (PyObject_TypeCheck (input, &Py_cvecType)) {
68       Py_cvec * in = (Py_cvec *)input;
69       i->norm = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->norm), 0);
70       i->phas = (smpl_t *) PyArray_GETPTR1 ((PyArrayObject *)(in->phas), 0);
71       i->length = ((Py_cvec*)input)->length;
72       return 1;
73   } else {
74       PyErr_SetString (PyExc_ValueError, "input array should be aubio.cvec");
75       return 0;
76   }
77 }
78
79 static PyObject *
80 Py_cvec_new (PyTypeObject * type, PyObject * args, PyObject * kwds)
81 {
82   int length= 0;
83   Py_cvec *self;
84   static char *kwlist[] = { "length", NULL };
85
86   if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist,
87           &length)) {
88     return NULL;
89   }
90
91   self = (Py_cvec *) type->tp_alloc (type, 0);
92
93   self->length = Py_default_vector_length / 2 + 1;
94
95   if (self == NULL) {
96     return NULL;
97   }
98
99   if (length > 0) {
100     self->length = length / 2 + 1;
101   } else if (length < 0) {
102     PyErr_SetString (PyExc_ValueError,
103         "can not use negative number of elements");
104     return NULL;
105   }
106
107   return (PyObject *) self;
108 }
109
110 static int
111 Py_cvec_init (Py_cvec * self, PyObject * args, PyObject * kwds)
112 {
113   npy_intp dims[] = { self->length, 1 };
114   self->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
115   self->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
116   return 0;
117 }
118
119 static void
120 Py_cvec_del (Py_cvec * self)
121 {
122   Py_DECREF(self->norm);
123   Py_DECREF(self->phas);
124   Py_TYPE(self)->tp_free ((PyObject *) self);
125 }
126
127 static PyObject *
128 Py_cvec_repr (Py_cvec * self, PyObject * unused)
129 {
130   PyObject *format = NULL;
131   PyObject *args = NULL;
132   PyObject *result = NULL;
133
134   format = PyUnicode_FromString ("aubio cvec of %d elements");
135   if (format == NULL) {
136     goto fail;
137   }
138
139   args = Py_BuildValue ("I", self->length);
140   if (args == NULL) {
141     goto fail;
142   }
143   // hide actual norm / phas content
144
145   result = PyUnicode_Format (format, args);
146
147 fail:
148   Py_XDECREF (format);
149   Py_XDECREF (args);
150
151   return result;
152 }
153
154 PyObject *
155 Py_cvec_get_norm (Py_cvec * self, void *closure)
156 {
157   // we want self->norm to still exist after our caller return it
158   Py_INCREF(self->norm);
159   return (PyObject*)(self->norm);
160 }
161
162 PyObject *
163 Py_cvec_get_phas (Py_cvec * self, void *closure)
164 {
165   // we want self->phas to still exist after our caller return it
166   Py_INCREF(self->phas);
167   return (PyObject *)(self->phas);
168 }
169
170 static int
171 Py_cvec_set_norm (Py_cvec * vec, PyObject *input, void * closure)
172 {
173   npy_intp length;
174   if (!PyAubio_IsValidVector(input)) {
175     return -1;
176   }
177   length = PyArray_SIZE ((PyArrayObject *)input);
178   if (length != vec->length) {
179     PyErr_Format (PyExc_ValueError,
180         "input array has length %" NPY_INTP_FMT ", but cvec has length %d", length,
181         vec->length);
182     return -1;
183   }
184
185   Py_XDECREF(vec->norm);
186   vec->norm = input;
187   Py_INCREF(vec->norm);
188   return 0;
189 }
190
191 static int
192 Py_cvec_set_phas (Py_cvec * vec, PyObject *input, void * closure)
193 {
194   npy_intp length;
195   if (!PyAubio_IsValidVector(input)) {
196     return -1;
197   }
198   length = PyArray_SIZE ((PyArrayObject *)input);
199   if (length != vec->length) {
200     PyErr_Format (PyExc_ValueError,
201         "input array has length %" NPY_INTP_FMT ", but cvec has length %d", length,
202         vec->length);
203     return -1;
204   }
205
206   Py_XDECREF(vec->phas);
207   vec->phas = input;
208   Py_INCREF(vec->phas);
209   return 0;
210 }
211
212 static PyMemberDef Py_cvec_members[] = {
213   // TODO remove READONLY flag and define getter/setter
214   {"length", T_INT, offsetof (Py_cvec, length), READONLY,
215       "int: Length of `norm` and `phas` vectors."},
216   {NULL}                        /* Sentinel */
217 };
218
219 static PyMethodDef Py_cvec_methods[] = {
220   {NULL}
221 };
222
223 static PyGetSetDef Py_cvec_getseters[] = {
224   {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm,
225       "numpy.ndarray: Vector of shape `(length,)` containing the magnitude.",
226       NULL},
227   {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas,
228       "numpy.ndarray: Vector of shape `(length,)` containing the phase.",
229       NULL},
230   {NULL} /* sentinel */
231 };
232
233 PyTypeObject Py_cvecType = {
234   PyVarObject_HEAD_INIT(NULL, 0)
235   "aubio.cvec",                 /* tp_name           */
236   sizeof (Py_cvec),             /* tp_basicsize      */
237   0,                            /* tp_itemsize       */
238   (destructor) Py_cvec_del,     /* tp_dealloc        */
239   0,                            /* tp_print          */
240   0,                            /* tp_getattr        */
241   0,                            /* tp_setattr        */
242   0,                            /* tp_compare        */
243   (reprfunc) Py_cvec_repr,      /* tp_repr           */
244   0,                            /* tp_as_number      */
245   0, //&Py_cvec_tp_as_sequence, /* tp_as_sequence    */
246   0,                            /* tp_as_mapping     */
247   0,                            /* tp_hash           */
248   0,                            /* tp_call           */
249   0,                            /* tp_str            */
250   0,                            /* tp_getattro       */
251   0,                            /* tp_setattro       */
252   0,                            /* tp_as_buffer      */
253   Py_TPFLAGS_DEFAULT,           /* tp_flags          */
254   Py_cvec_doc,                  /* tp_doc            */
255   0,                            /* tp_traverse       */
256   0,                            /* tp_clear          */
257   0,                            /* tp_richcompare    */
258   0,                            /* tp_weaklistoffset */
259   0,                            /* tp_iter           */
260   0,                            /* tp_iternext       */
261   Py_cvec_methods,              /* tp_methods        */
262   Py_cvec_members,              /* tp_members        */
263   Py_cvec_getseters,            /* tp_getset         */
264   0,                            /* tp_base           */
265   0,                            /* tp_dict           */
266   0,                            /* tp_descr_get      */
267   0,                            /* tp_descr_set      */
268   0,                            /* tp_dictoffset     */
269   (initproc) Py_cvec_init,      /* tp_init           */
270   0,                            /* tp_alloc          */
271   Py_cvec_new,                  /* tp_new            */
272   0,
273   0,
274   0,
275   0,
276   0,
277   0,
278   0,
279   0,
280   0,
281 };