shithub: aubio

ref: bcf47ea4a19444e2af92cfd25994e169a5b80a63
dir: /python/ext/py-cvec.c/

View raw version
#include "aubio-types.h"

/* cvec type definition

class cvec():
    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 *
new_py_cvec(uint_t length) {
  Py_cvec* vec = (Py_cvec*) PyObject_New (Py_cvec, &Py_cvecType);
  npy_intp dims[] = { length / 2 + 1, 1 };
  vec->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
  vec->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
  vec->length = length / 2 + 1;
  return (PyObject*)vec;
}

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;
      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)
{
  int length= 0;
  Py_cvec *self;
  static char *kwlist[] = { "length", NULL };

  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|I", kwlist,
          &length)) {
    return NULL;
  }

  self = (Py_cvec *) type->tp_alloc (type, 0);

  self->length = Py_default_vector_length / 2 + 1;

  if (self == NULL) {
    return NULL;
  }

  if (length > 0) {
    self->length = length / 2 + 1;
  } else if (length < 0) {
    PyErr_SetString (PyExc_ValueError,
        "can not use negative number of elements");
    return NULL;
  }

  return (PyObject *) self;
}

static int
Py_cvec_init (Py_cvec * self, PyObject * args, PyObject * kwds)
{
  npy_intp dims[] = { self->length, 1 };
  self->phas = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
  self->norm = PyArray_ZEROS(1, dims, AUBIO_NPY_SMPL, 0);
  return 0;
}

static void
Py_cvec_del (Py_cvec * self)
{
  Py_DECREF(self->norm);
  Py_DECREF(self->phas);
  Py_TYPE(self)->tp_free ((PyObject *) self);
}

static PyObject *
Py_cvec_repr (Py_cvec * self, PyObject * unused)
{
  PyObject *format = NULL;
  PyObject *args = NULL;
  PyObject *result = NULL;

  format = PyUnicode_FromString ("aubio cvec of %d elements");
  if (format == NULL) {
    goto fail;
  }

  args = Py_BuildValue ("I", self->length);
  if (args == NULL) {
    goto fail;
  }
  // hide actual norm / phas content

  result = PyUnicode_Format (format, args);

fail:
  Py_XDECREF (format);
  Py_XDECREF (args);

  return result;
}

PyObject *
Py_cvec_get_norm (Py_cvec * self, void *closure)
{
  // we want self->norm to still exist after our caller return it
  Py_INCREF(self->norm);
  return (PyObject*)(self->norm);
}

PyObject *
Py_cvec_get_phas (Py_cvec * self, void *closure)
{
  // we want self->phas to still exist after our caller return it
  Py_INCREF(self->phas);
  return (PyObject *)(self->phas);
}

static int
Py_cvec_set_norm (Py_cvec * vec, PyObject *input, void * closure)
{
  PyArrayObject * array;
  if (input == NULL) {
    PyErr_SetString (PyExc_ValueError, "input array is not a python object");
    goto fail;
  }
  if (PyArray_Check(input)) {
    // 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;
    } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
      PyErr_SetString (PyExc_ValueError,
          "input array has more than two dimensions");
      goto fail;
    }

    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
      PyErr_SetString (PyExc_ValueError, "input array should be float");
      goto fail;
    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
      PyErr_SetString (PyExc_ValueError, "input array should be float32");
      goto fail;
    }
    array = (PyArrayObject *)input;

    // check input array dimensions
    if (PyArray_NDIM (array) != 1) {
      PyErr_Format (PyExc_ValueError,
          "input array has %d dimensions, not 1",
          PyArray_NDIM (array));
      goto fail;
    } else {
      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->length);
          goto fail;
      }
    }

    Py_XDECREF(vec->norm);
    vec->norm = input;
    Py_INCREF(vec->norm);

  } else {
    PyErr_SetString (PyExc_ValueError, "can only accept array as input");
    return 1;
  }

  return 0;

fail:
  return 1;
}

static int
Py_cvec_set_phas (Py_cvec * vec, PyObject *input, void * closure)
{
  PyArrayObject * array;
  if (input == NULL) {
    PyErr_SetString (PyExc_ValueError, "input array is not a python object");
    goto fail;
  }
  if (PyArray_Check(input)) {

    // we got an array, convert it to a cvec.phas
    if (PyArray_NDIM ((PyArrayObject *)input) == 0) {
      PyErr_SetString (PyExc_ValueError, "input array is a scalar");
      goto fail;
    } else if (PyArray_NDIM ((PyArrayObject *)input) > 2) {
      PyErr_SetString (PyExc_ValueError,
          "input array has more than two dimensions");
      goto fail;
    }

    if (!PyArray_ISFLOAT ((PyArrayObject *)input)) {
      PyErr_SetString (PyExc_ValueError, "input array should be float");
      goto fail;
    } else if (PyArray_TYPE ((PyArrayObject *)input) != AUBIO_NPY_SMPL) {
      PyErr_SetString (PyExc_ValueError, "input array should be float32");
      goto fail;
    }
    array = (PyArrayObject *)input;

    // check input array dimensions
    if (PyArray_NDIM (array) != 1) {
      PyErr_Format (PyExc_ValueError,
          "input array has %d dimensions, not 1",
          PyArray_NDIM (array));
      goto fail;
    } else {
      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->length);
          goto fail;
      }
    }

    Py_XDECREF(vec->phas);
    vec->phas = input;
    Py_INCREF(vec->phas);

  } else {
    PyErr_SetString (PyExc_ValueError, "can only accept array as input");
    return 1;
  }

  return 0;

fail:
  return 1;
}

static PyMemberDef Py_cvec_members[] = {
  // TODO remove READONLY flag and define getter/setter
  {"length", T_INT, offsetof (Py_cvec, length), READONLY,
      "length attribute"},
  {NULL}                        /* Sentinel */
};

static PyMethodDef Py_cvec_methods[] = {
  {NULL}
};

static PyGetSetDef Py_cvec_getseters[] = {
  {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm, 
      "Numpy vector of shape (length,) containing the magnitude",
      NULL},
  {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas, 
      "Numpy vector of shape (length,) containing the phase",
      NULL},
  {NULL} /* sentinel */
};

PyTypeObject Py_cvecType = {
  PyVarObject_HEAD_INIT(NULL, 0)
  "aubio.cvec",                 /* tp_name           */
  sizeof (Py_cvec),             /* tp_basicsize      */
  0,                            /* tp_itemsize       */
  (destructor) Py_cvec_del,     /* tp_dealloc        */
  0,                            /* tp_print          */
  0,                            /* tp_getattr        */
  0,                            /* tp_setattr        */
  0,                            /* tp_compare        */
  (reprfunc) Py_cvec_repr,      /* tp_repr           */
  0,                            /* tp_as_number      */
  0, //&Py_cvec_tp_as_sequence, /* tp_as_sequence    */
  0,                            /* tp_as_mapping     */
  0,                            /* tp_hash           */
  0,                            /* tp_call           */
  0,                            /* tp_str            */
  0,                            /* tp_getattro       */
  0,                            /* tp_setattro       */
  0,                            /* tp_as_buffer      */
  Py_TPFLAGS_DEFAULT,           /* tp_flags          */
  Py_cvec_doc,                  /* tp_doc            */
  0,                            /* tp_traverse       */
  0,                            /* tp_clear          */
  0,                            /* tp_richcompare    */
  0,                            /* tp_weaklistoffset */
  0,                            /* tp_iter           */
  0,                            /* tp_iternext       */
  Py_cvec_methods,              /* tp_methods        */
  Py_cvec_members,              /* tp_members        */
  Py_cvec_getseters,            /* tp_getset         */
  0,                            /* tp_base           */
  0,                            /* tp_dict           */
  0,                            /* tp_descr_get      */
  0,                            /* tp_descr_set      */
  0,                            /* tp_dictoffset     */
  (initproc) Py_cvec_init,      /* tp_init           */
  0,                            /* tp_alloc          */
  Py_cvec_new,                  /* tp_new            */
};