annotate VectorConversion.cpp @ 43:36cc53aad853

Test output values a bit; fix input conversion from int
author Chris Cannam
date Wed, 03 Dec 2014 08:25:05 +0000
parents 55fcd0e3e513
children 0e0e18629917
rev   line source
Chris@26 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@26 2
Chris@26 3 /*
Chris@28 4 VampyHost
Chris@26 5
Chris@28 6 Use Vamp audio analysis plugins in Python
Chris@26 7
Chris@28 8 Gyorgy Fazekas and Chris Cannam
Chris@28 9 Centre for Digital Music, Queen Mary, University of London
Chris@28 10 Copyright 2008-2014 Queen Mary, University of London
Chris@26 11
Chris@28 12 Permission is hereby granted, free of charge, to any person
Chris@28 13 obtaining a copy of this software and associated documentation
Chris@28 14 files (the "Software"), to deal in the Software without
Chris@28 15 restriction, including without limitation the rights to use, copy,
Chris@28 16 modify, merge, publish, distribute, sublicense, and/or sell copies
Chris@28 17 of the Software, and to permit persons to whom the Software is
Chris@28 18 furnished to do so, subject to the following conditions:
Chris@26 19
Chris@28 20 The above copyright notice and this permission notice shall be
Chris@28 21 included in all copies or substantial portions of the Software.
Chris@26 22
Chris@28 23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@28 24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@28 25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@28 26 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
Chris@28 27 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@28 28 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@28 29 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@26 30
Chris@28 31 Except as contained in this notice, the names of the Centre for
Chris@28 32 Digital Music; Queen Mary, University of London; and the authors
Chris@28 33 shall not be used in advertising or otherwise to promote the sale,
Chris@28 34 use or other dealings in this Software without prior written
Chris@28 35 authorization.
Chris@26 36 */
Chris@26 37
Chris@26 38 #include <Python.h>
Chris@26 39
Chris@29 40 #include "VectorConversion.h"
Chris@26 41
Chris@26 42 #include <math.h>
Chris@26 43 #include <float.h>
Chris@26 44
Chris@28 45 using namespace std;
Chris@26 46
Chris@26 47 /* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS
Chris@28 48 (EXCEPT FOR TEMPORARY PYTHON OBJECTS)! */
Chris@26 49
Chris@29 50 VectorConversion::VectorConversion() :
Chris@28 51 m_error(false),
Chris@28 52 error(m_error) // const public reference for easy access
Chris@26 53 {
Chris@26 54 }
Chris@26 55
Chris@29 56 VectorConversion::~VectorConversion()
Chris@26 57 {
Chris@26 58 }
Chris@26 59
Chris@26 60 /// floating point numbers (TODO: check numpy.float128)
Chris@26 61 float
Chris@29 62 VectorConversion::PyValue_To_Float(PyObject* pyValue) const
Chris@26 63 {
Chris@28 64 // convert float
Chris@43 65 if (pyValue && PyFloat_Check(pyValue)) {
Chris@28 66 return (float) PyFloat_AS_DOUBLE(pyValue);
Chris@43 67 }
Chris@43 68
Chris@43 69 // convert long
Chris@43 70 if (pyValue && PyLong_Check(pyValue)) {
Chris@43 71 return (float) PyLong_AsDouble(pyValue);
Chris@43 72 }
Chris@43 73
Chris@43 74 // convert int
Chris@43 75 if (pyValue && PyInt_Check(pyValue)) {
Chris@43 76 return (float) PyInt_AsLong(pyValue);
Chris@43 77 }
Chris@43 78
Chris@43 79 if (pyValue == NULL) {
Chris@28 80 setValueError("Error while converting object " + PyValue_Get_TypeName(pyValue) + " to float. ");
Chris@28 81 return 0.0;
Chris@28 82 }
Chris@26 83
Chris@43 84 setValueError("Conversion error: object" + PyValue_Get_TypeName(pyValue) +" is not float, int, or long.");
Chris@28 85 return 0.0;
Chris@26 86 }
Chris@26 87
Chris@28 88 vector<float>
Chris@29 89 VectorConversion::PyValue_To_FloatVector (PyObject *pyValue) const
Chris@26 90 {
Chris@28 91 /// numpy array
Chris@28 92 if (PyArray_CheckExact(pyValue))
Chris@28 93 return PyArray_To_FloatVector(pyValue);
Chris@26 94
Chris@28 95 /// python list of floats (backward compatible)
Chris@28 96 if (PyList_Check(pyValue)) {
Chris@28 97 return PyList_To_FloatVector(pyValue);
Chris@28 98 }
Chris@26 99
Chris@28 100 string msg = "Value is not list or array of floats";
Chris@28 101 setValueError(msg);
Chris@26 102 #ifdef _DEBUG
Chris@29 103 cerr << "VectorConversion::PyValue_To_FloatVector failed. " << msg << endl;
Chris@26 104 #endif
Chris@28 105 return vector<float>();
Chris@26 106 }
Chris@26 107
Chris@28 108 vector<float>
Chris@29 109 VectorConversion::PyList_To_FloatVector (PyObject *inputList) const
Chris@26 110 {
Chris@28 111 vector<float> v;
Chris@26 112
Chris@28 113 if (!PyList_Check(inputList)) {
Chris@28 114 setValueError("Value is not a list");
Chris@28 115 return v;
Chris@28 116 }
Chris@26 117
Chris@28 118 PyObject **pyObjectArray = PySequence_Fast_ITEMS(inputList);
Chris@28 119 int n = PyList_GET_SIZE(inputList);
Chris@26 120
Chris@28 121 for (int i = 0; i < n; ++i) {
Chris@28 122 v.push_back(PyValue_To_Float(pyObjectArray[i]));
Chris@28 123 }
Chris@28 124
Chris@28 125 return v;
Chris@26 126 }
Chris@26 127
Chris@28 128 vector<float>
Chris@29 129 VectorConversion::PyArray_To_FloatVector (PyObject *pyValue) const
Chris@26 130 {
Chris@28 131 vector<float> v;
Chris@26 132
Chris@28 133 if (!PyArray_Check(pyValue)) {
Chris@28 134 setValueError("Value is not an array");
Chris@28 135 return v;
Chris@28 136 }
Chris@28 137
Chris@28 138 PyArrayObject* pyArray = (PyArrayObject*) pyValue;
Chris@28 139 PyArray_Descr* descr = PyArray_DESCR(pyArray);
Chris@28 140
Chris@28 141 if (PyArray_DATA(pyArray) == 0 || descr == 0) {
Chris@28 142 string msg = "NumPy array with NULL data or descriptor pointer encountered.";
Chris@28 143 setValueError(msg);
Chris@28 144 return v;
Chris@28 145 }
Chris@28 146
Chris@28 147 if (PyArray_NDIM(pyArray) != 1) {
Chris@40 148 string msg = "NumPy array must be a one-dimensional vector.";
Chris@28 149 setValueError(msg);
Chris@28 150 return v;
Chris@28 151 }
Chris@28 152
Chris@28 153 /// check strides (useful if array is not continuous)
Chris@28 154 size_t strides = *((size_t*) PyArray_STRIDES(pyArray));
Chris@28 155
Chris@28 156 /// convert the array
Chris@28 157 switch (descr->type_num) {
Chris@28 158
Chris@28 159 case NPY_FLOAT : // dtype='float32'
Chris@28 160 return PyArray_Convert<float,float>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
Chris@28 161 case NPY_DOUBLE : // dtype='float64'
Chris@28 162 return PyArray_Convert<float,double>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
Chris@28 163 case NPY_INT : // dtype='int'
Chris@28 164 return PyArray_Convert<float,int>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
Chris@28 165 case NPY_LONG : // dtype='long'
Chris@28 166 return PyArray_Convert<float,long>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
Chris@28 167 default :
Chris@28 168 string msg = "Unsupported value type in NumPy array object.";
Chris@28 169 setValueError(msg);
Chris@26 170 #ifdef _DEBUG
Chris@29 171 cerr << "VectorConversion::PyArray_To_FloatVector failed. Error: " << msg << endl;
Chris@26 172 #endif
Chris@28 173 return v;
Chris@28 174 }
Chris@26 175 }
Chris@26 176
Chris@40 177 vector<vector<float> >
Chris@40 178 VectorConversion::Py2DArray_To_FloatVector (PyObject *pyValue) const
Chris@40 179 {
Chris@40 180 vector<vector<float> > v;
Chris@40 181
Chris@40 182 if (!PyArray_Check(pyValue)) {
Chris@40 183 setValueError("Value is not an array");
Chris@40 184 return v;
Chris@40 185 }
Chris@40 186
Chris@40 187 PyArrayObject* pyArray = (PyArrayObject*) pyValue;
Chris@40 188 PyArray_Descr* descr = PyArray_DESCR(pyArray);
Chris@40 189
Chris@40 190 if (PyArray_DATA(pyArray) == 0 || descr == 0) {
Chris@40 191 string msg = "NumPy array with NULL data or descriptor pointer encountered.";
Chris@40 192 setValueError(msg);
Chris@40 193 return v;
Chris@40 194 }
Chris@40 195
Chris@40 196 if (PyArray_NDIM(pyArray) != 2) {
Chris@40 197 string msg = "NumPy array must be a two-dimensional matrix.";
Chris@40 198 setValueError(msg);
Chris@40 199 return v;
Chris@40 200 }
Chris@40 201
Chris@40 202 /// check strides (useful if array is not continuous)
Chris@41 203 size_t *strideptr = (size_t*) PyArray_STRIDES(pyArray);
Chris@40 204
Chris@40 205 /// convert the array
Chris@40 206 for (int i = 0; i < PyArray_DIMS(pyArray)[0]; ++i) {
Chris@40 207
Chris@40 208 vector<float> vv;
Chris@40 209
Chris@40 210 switch (descr->type_num) {
Chris@40 211
Chris@40 212 case NPY_FLOAT : // dtype='float32'
Chris@41 213 vv = PyArray_Convert<float,float>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strideptr[1]);
Chris@40 214 break;
Chris@40 215 case NPY_DOUBLE : // dtype='float64'
Chris@41 216 vv = PyArray_Convert<float,double>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strideptr[1]);
Chris@40 217 break;
Chris@40 218 case NPY_INT : // dtype='int'
Chris@41 219 vv = PyArray_Convert<float,int>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strideptr[1]);
Chris@40 220 break;
Chris@40 221 case NPY_LONG : // dtype='long'
Chris@41 222 vv = PyArray_Convert<float,long>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strideptr[1]);
Chris@40 223 break;
Chris@40 224 default :
Chris@40 225 string msg = "Unsupported value type in NumPy array object.";
Chris@40 226 cerr << "VectorConversion::PyArray_To_FloatVector failed (value type = " << descr->type_num << "). Error: " << msg << endl;
Chris@40 227 setValueError(msg);
Chris@40 228 return v;
Chris@40 229 }
Chris@40 230
Chris@40 231 v.push_back(vv);
Chris@40 232 }
Chris@40 233
Chris@40 234 return v;
Chris@40 235 }
Chris@40 236
Chris@26 237 PyObject *
Chris@29 238 VectorConversion::PyArray_From_FloatVector(const vector<float> &v) const
Chris@26 239 {
Chris@28 240 npy_intp ndims[1];
Chris@28 241 ndims[0] = (int)v.size();
Chris@28 242 PyObject *arr = PyArray_SimpleNew(1, ndims, NPY_FLOAT);
Chris@28 243 float *data = (float *)PyArray_DATA((PyArrayObject *)arr);
Chris@28 244 for (int i = 0; i < ndims[0]; ++i) {
Chris@28 245 data[i] = v[i];
Chris@28 246 }
Chris@28 247 return arr;
Chris@26 248 }
Chris@26 249
Chris@26 250 PyObject *
Chris@29 251 VectorConversion::PyValue_From_StringVector(const vector<string> &v) const
Chris@26 252 {
Chris@28 253 PyObject *pyList = PyList_New(v.size());
Chris@28 254 for (size_t i = 0; i < v.size(); ++i) {
Chris@28 255 PyObject *pyStr = PyString_FromString(v[i].c_str());
Chris@28 256 PyList_SET_ITEM(pyList, i, pyStr);
Chris@28 257 }
Chris@28 258 return pyList;
Chris@26 259 }
Chris@26 260
Chris@26 261
Chris@28 262 /* Error handling */
Chris@26 263
Chris@26 264 void
Chris@29 265 VectorConversion::setValueError (string message) const
Chris@26 266 {
Chris@28 267 m_error = true;
Chris@28 268 m_errorQueue.push(ValueError(message));
Chris@26 269 }
Chris@26 270
Chris@26 271 /// return a reference to the last error or creates a new one.
Chris@26 272 ValueError&
Chris@29 273 VectorConversion::lastError() const
Chris@26 274 {
Chris@28 275 m_error = false;
Chris@28 276 if (!m_errorQueue.empty()) return m_errorQueue.back();
Chris@28 277 else {
Chris@28 278 m_errorQueue.push(ValueError("Type conversion error."));
Chris@28 279 return m_errorQueue.back();
Chris@28 280 }
Chris@26 281 }
Chris@26 282
Chris@26 283 /// helper function to iterate over the error message queue:
Chris@26 284 /// pops the oldest item
Chris@26 285 ValueError
Chris@29 286 VectorConversion::getError() const
Chris@26 287 {
Chris@28 288 if (!m_errorQueue.empty()) {
Chris@28 289 ValueError e = m_errorQueue.front();
Chris@28 290 m_errorQueue.pop();
Chris@28 291 if (m_errorQueue.empty()) m_error = false;
Chris@28 292 return e;
Chris@28 293 }
Chris@28 294 else {
Chris@28 295 m_error = false;
Chris@28 296 return ValueError();
Chris@28 297 }
Chris@26 298 }
Chris@26 299
Chris@28 300 /* Utilities */
Chris@26 301
Chris@26 302 /// get the type name of an object
Chris@28 303 string
Chris@29 304 VectorConversion::PyValue_Get_TypeName(PyObject* pyValue) const
Chris@26 305 {
Chris@28 306 PyObject *pyType = PyObject_Type(pyValue);
Chris@28 307 if (!pyType)
Chris@28 308 {
Chris@28 309 cerr << "Warning: Object type name could not be found." << endl;
Chris@28 310 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
Chris@28 311 return string ("< unknown type >");
Chris@28 312 }
Chris@28 313 PyObject *pyString = PyObject_Str(pyType);
Chris@28 314 if (!pyString)
Chris@28 315 {
Chris@28 316 cerr << "Warning: Object type name could not be found." << endl;
Chris@28 317 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
Chris@28 318 Py_CLEAR(pyType);
Chris@28 319 return string ("< unknown type >");
Chris@28 320 }
Chris@28 321 char *cstr = PyString_AS_STRING(pyString);
Chris@28 322 if (!cstr)
Chris@28 323 {
Chris@28 324 cerr << "Warning: Object type name could not be found." << endl;
Chris@28 325 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
Chris@28 326 Py_DECREF(pyType);
Chris@28 327 Py_CLEAR(pyString);
Chris@28 328 return string("< unknown type >");
Chris@28 329 }
Chris@28 330 Py_DECREF(pyType);
Chris@28 331 Py_DECREF(pyString);
Chris@28 332 return string(cstr);
Chris@26 333 }