Mercurial > hg > vampy-host
changeset 40:fa3f80d4e340
2D array conversion (incorrect, crashing)
author | Chris Cannam |
---|---|
date | Wed, 26 Nov 2014 15:58:46 +0000 |
parents | 13dcfe8c7ed7 |
children | 55fcd0e3e513 |
files | PyPluginObject.cpp VectorConversion.cpp VectorConversion.h test_process.py |
diffstat | 4 files changed, 146 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/PyPluginObject.cpp Wed Nov 26 15:23:56 2014 +0000 +++ b/PyPluginObject.cpp Wed Nov 26 15:58:46 2014 +0000 @@ -376,6 +376,52 @@ return pyFs; } +static vector<vector<float> > +convertPluginInput(PyObject *pyBuffer, int channels, int blockSize) +{ + vector<vector<float> > data; + + VectorConversion conv; + + if (PyArray_CheckExact(pyBuffer)) { + + data = conv.Py2DArray_To_FloatVector(pyBuffer); + + if (conv.error) { + PyErr_SetString(PyExc_TypeError, conv.getError().str().c_str()); + return data; + } + + } else { + + if (!PyList_Check(pyBuffer)) { + PyErr_SetString(PyExc_TypeError, "List of NumPy Array required for process input."); + return data; + } + + if (PyList_GET_SIZE(pyBuffer) != channels) { + cerr << "Wrong number of channels: got " << PyList_GET_SIZE(pyBuffer) << ", expected " << channels << endl; + PyErr_SetString(PyExc_TypeError, "Wrong number of channels"); + return data; + } + + for (int c = 0; c < channels; ++c) { + PyObject *cbuf = PyList_GET_ITEM(pyBuffer, c); + data.push_back(conv.PyValue_To_FloatVector(cbuf)); + } + + for (int c = 0; c < channels; ++c) { + if ((int)data[c].size() != blockSize) { + cerr << "Wrong number of samples on channel " << c << ": expected " << blockSize << " (plugin's block size), got " << data[c].size() << endl; + PyErr_SetString(PyExc_TypeError, "Wrong number of samples"); + return vector<vector<float> >(); + } + } + } + + return data; +} + static PyObject * process(PyObject *self, PyObject *args) { @@ -386,18 +432,13 @@ &pyBuffer, // Audio data &pyRealTime)) { // TimeStamp PyErr_SetString(PyExc_TypeError, - "process() takes plugin handle (object), buffer (2D array of channels * samples floats) and timestamp (RealTime) arguments"); + "process() takes plugin handle (object), buffer (list of arrays of floats, one array per channel) and timestamp (RealTime) arguments"); return 0; } if (!PyRealTime_Check(pyRealTime)) { - PyErr_SetString(PyExc_TypeError,"Valid timestamp required."); + PyErr_SetString(PyExc_TypeError, "Valid timestamp required."); return 0; } - if (!PyList_Check(pyBuffer)) { - PyErr_SetString(PyExc_TypeError, "List of NumPy Array required for process input."); - return 0; - } - PyPluginObject *pd = getPluginObject(self); if (!pd) return 0; @@ -407,37 +448,17 @@ return 0; } - int channels = pd->channels; - - if (PyList_GET_SIZE(pyBuffer) != channels) { - cerr << "Wrong number of channels: got " << PyList_GET_SIZE(pyBuffer) << ", expected " << channels << endl; - PyErr_SetString(PyExc_TypeError, "Wrong number of channels"); - return 0; - } + int channels = pd->channels; + vector<vector<float> > data = + convertPluginInput(pyBuffer, channels, pd->blockSize); + if (data.empty()) return 0; float **inbuf = new float *[channels]; - - VectorConversion typeConv; - - vector<vector<float> > data; for (int c = 0; c < channels; ++c) { - PyObject *cbuf = PyList_GET_ITEM(pyBuffer, c); - data.push_back(typeConv.PyValue_To_FloatVector(cbuf)); - } - - for (int c = 0; c < channels; ++c) { - if (data[c].size() != pd->blockSize) { - cerr << "Wrong number of samples on channel " << c << ": expected " << pd->blockSize << " (plugin's block size), got " << data[c].size() << endl; - PyErr_SetString(PyExc_TypeError, "Wrong number of samples"); - return 0; - } inbuf[c] = &data[c][0]; } - RealTime timeStamp = *PyRealTime_AsRealTime(pyRealTime); - Plugin::FeatureSet fs = pd->plugin->process(inbuf, timeStamp); - delete[] inbuf; return convertFeatureSet(fs); @@ -590,7 +611,7 @@ PyObject_GenericSetAttr, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Vamp plugin object.", /*tp_doc*/ + "Plugin object, providing a low-level API for running a Vamp plugin.", /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/
--- a/VectorConversion.cpp Wed Nov 26 15:23:56 2014 +0000 +++ b/VectorConversion.cpp Wed Nov 26 15:58:46 2014 +0000 @@ -136,7 +136,7 @@ } if (PyArray_NDIM(pyArray) != 1) { - string msg = "NumPy array must be a one dimensional vector."; + string msg = "NumPy array must be a one-dimensional vector."; setValueError(msg); return v; } @@ -165,6 +165,68 @@ } } +vector<vector<float> > +VectorConversion::Py2DArray_To_FloatVector (PyObject *pyValue) const +{ + vector<vector<float> > v; + + if (!PyArray_Check(pyValue)) { + setValueError("Value is not an array"); + return v; + } + + PyArrayObject* pyArray = (PyArrayObject*) pyValue; + PyArray_Descr* descr = PyArray_DESCR(pyArray); + + if (PyArray_DATA(pyArray) == 0 || descr == 0) { + string msg = "NumPy array with NULL data or descriptor pointer encountered."; + setValueError(msg); + return v; + } + + if (PyArray_NDIM(pyArray) != 2) { + string msg = "NumPy array must be a two-dimensional matrix."; + setValueError(msg); + return v; + } + + /// check strides (useful if array is not continuous) + size_t strides = *((size_t*) PyArray_STRIDES(pyArray)); + + cerr << "dims = " << PyArray_DIMS(pyArray)[0] << "x" << PyArray_DIMS(pyArray)[1] << ", strides = " << strides << endl; + + /// convert the array + for (int i = 0; i < PyArray_DIMS(pyArray)[0]; ++i) { + + vector<float> vv; + + switch (descr->type_num) { + + case NPY_FLOAT : // dtype='float32' + vv = PyArray_Convert<float,float>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strides); + break; + case NPY_DOUBLE : // dtype='float64' + vv = PyArray_Convert<float,double>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strides); + break; + case NPY_INT : // dtype='int' + vv = PyArray_Convert<float,int>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strides); + break; + case NPY_LONG : // dtype='long' + vv = PyArray_Convert<float,long>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strides); + break; + default : + string msg = "Unsupported value type in NumPy array object."; + cerr << "VectorConversion::PyArray_To_FloatVector failed (value type = " << descr->type_num << "). Error: " << msg << endl; + setValueError(msg); + return v; + } + + v.push_back(vv); + } + + return v; +} + PyObject * VectorConversion::PyArray_From_FloatVector(const vector<float> &v) const {
--- a/VectorConversion.h Wed Nov 26 15:23:56 2014 +0000 +++ b/VectorConversion.h Wed Nov 26 15:58:46 2014 +0000 @@ -87,7 +87,8 @@ std::vector<float> PyValue_To_FloatVector (PyObject*) const; std::vector<float> PyArray_To_FloatVector (PyObject *) const; std::vector<float> PyList_To_FloatVector (PyObject*) const; - + std::vector<std::vector<float> > Py2DArray_To_FloatVector (PyObject *) const; + PyObject *PyValue_From_StringVector(const std::vector<std::string> &) const; PyObject *PyArray_From_FloatVector(const std::vector<float> &) const; @@ -100,6 +101,8 @@ std::vector<RET> PyArray_Convert(void* raw_data_ptr, int length, size_t strides) const { + + std::cerr << "PyArray_Convert: raw pointer is " << (long long)(raw_data_ptr) << std::endl; std::vector<RET> v(length);
--- a/test_process.py Wed Nov 26 15:23:56 2014 +0000 +++ b/test_process.py Wed Nov 26 15:58:46 2014 +0000 @@ -1,5 +1,6 @@ import vampyhost as vh +import numpy as np testPluginKey = "vamp-test-plugin:vamp-test-plugin" @@ -26,12 +27,33 @@ plug = vh.loadPlugin(testPluginKey, rate) try: plug.process([[1,2,3,4]], vh.RealTime(0, 0)) - assert(False) + assert False except StandardError: pass -def test_process(): +def test_process_input_format(): plug = vh.loadPlugin(testPluginKey, rate) - plug.initialise(1, 4, 4) # channels, stepsize, blocksize - result = plug.process([[1,2,3,4]], vh.RealTime(0, 0)) + plug.initialise(2, 4, 4) # channels, stepsize, blocksize + result = plug.process([[1,2,3,4],[5,6,7,8]], vh.RealTime(0, 0)) + result = plug.process([np.array([1,2,3,4]),np.array([5,6,7,8])], vh.RealTime(0, 0)) + result = plug.process(np.array([[1,2,3,4],[5,6,7,8]]), vh.RealTime(0, 0)) + try: + # Wrong number of channels + result = plug.process(np.array([[1,2,3,4]]), vh.RealTime(0, 0)) + assert False + except TypeError: + pass + try: + # Wrong number of samples per channel + result = plug.process(np.array([[1,2,3],[4,5,6]]), vh.RealTime(0, 0)) + assert False + except TypeError: + pass + try: + # Differing numbers of samples per channel + result = plug.process(np.array([[1,2,3,4],[5,6,7]]), vh.RealTime(0, 0)) + assert False + except TypeError: + pass +