annotate native/VectorConversion.cpp @ 151:5a6b8f4be9b9 tracks tip

Docs
author Chris Cannam
date Fri, 21 Apr 2017 14:33:57 +0100
parents 2370b942cd32
children
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@117 10 Copyright 2008-2015 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@112 40 #include "VectorConversion.h"
Chris@48 41 #include "FloatConversion.h"
Chris@112 42 #include "StringConversion.h"
Chris@26 43
Chris@26 44 #include <math.h>
Chris@26 45 #include <float.h>
Chris@26 46
Chris@28 47 using namespace std;
Chris@26 48
Chris@26 49 /* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS
Chris@28 50 (EXCEPT FOR TEMPORARY PYTHON OBJECTS)! */
Chris@26 51
Chris@29 52 VectorConversion::VectorConversion() :
Chris@28 53 m_error(false),
Chris@28 54 error(m_error) // const public reference for easy access
Chris@26 55 {
Chris@26 56 }
Chris@26 57
Chris@29 58 VectorConversion::~VectorConversion()
Chris@26 59 {
Chris@26 60 }
Chris@26 61
Chris@26 62 /// floating point numbers (TODO: check numpy.float128)
Chris@26 63 float
Chris@29 64 VectorConversion::PyValue_To_Float(PyObject* pyValue) const
Chris@26 65 {
Chris@48 66 if (FloatConversion::check(pyValue)) {
Chris@48 67 return FloatConversion::convert(pyValue);
Chris@43 68 }
Chris@43 69
Chris@43 70 setValueError("Conversion error: object" + PyValue_Get_TypeName(pyValue) +" is not float, int, or long.");
Chris@28 71 return 0.0;
Chris@26 72 }
Chris@26 73
Chris@28 74 vector<float>
Chris@29 75 VectorConversion::PyValue_To_FloatVector (PyObject *pyValue) const
Chris@26 76 {
Chris@28 77 /// numpy array
Chris@28 78 if (PyArray_CheckExact(pyValue))
Chris@28 79 return PyArray_To_FloatVector(pyValue);
Chris@26 80
Chris@28 81 /// python list of floats (backward compatible)
Chris@28 82 if (PyList_Check(pyValue)) {
Chris@28 83 return PyList_To_FloatVector(pyValue);
Chris@28 84 }
Chris@26 85
Chris@28 86 string msg = "Value is not list or array of floats";
Chris@28 87 setValueError(msg);
Chris@26 88 #ifdef _DEBUG
Chris@29 89 cerr << "VectorConversion::PyValue_To_FloatVector failed. " << msg << endl;
Chris@26 90 #endif
Chris@28 91 return vector<float>();
Chris@26 92 }
Chris@26 93
Chris@28 94 vector<float>
Chris@29 95 VectorConversion::PyList_To_FloatVector (PyObject *inputList) const
Chris@26 96 {
Chris@28 97 vector<float> v;
Chris@26 98
Chris@28 99 if (!PyList_Check(inputList)) {
Chris@28 100 setValueError("Value is not a list");
Chris@28 101 return v;
Chris@28 102 }
Chris@26 103
Chris@28 104 PyObject **pyObjectArray = PySequence_Fast_ITEMS(inputList);
Chris@28 105 int n = PyList_GET_SIZE(inputList);
Chris@26 106
Chris@28 107 for (int i = 0; i < n; ++i) {
Chris@28 108 v.push_back(PyValue_To_Float(pyObjectArray[i]));
Chris@28 109 }
Chris@28 110
Chris@28 111 return v;
Chris@26 112 }
Chris@26 113
Chris@28 114 vector<float>
Chris@29 115 VectorConversion::PyArray_To_FloatVector (PyObject *pyValue) const
Chris@26 116 {
Chris@28 117 vector<float> v;
Chris@26 118
Chris@28 119 if (!PyArray_Check(pyValue)) {
Chris@28 120 setValueError("Value is not an array");
Chris@28 121 return v;
Chris@28 122 }
Chris@28 123
Chris@28 124 PyArrayObject* pyArray = (PyArrayObject*) pyValue;
Chris@28 125 PyArray_Descr* descr = PyArray_DESCR(pyArray);
Chris@28 126
Chris@28 127 if (PyArray_DATA(pyArray) == 0 || descr == 0) {
Chris@28 128 string msg = "NumPy array with NULL data or descriptor pointer encountered.";
Chris@28 129 setValueError(msg);
Chris@28 130 return v;
Chris@28 131 }
Chris@28 132
Chris@28 133 if (PyArray_NDIM(pyArray) != 1) {
Chris@40 134 string msg = "NumPy array must be a one-dimensional vector.";
Chris@28 135 setValueError(msg);
Chris@28 136 return v;
Chris@28 137 }
Chris@28 138
Chris@28 139 /// check strides (useful if array is not continuous)
Chris@28 140 size_t strides = *((size_t*) PyArray_STRIDES(pyArray));
Chris@28 141
Chris@28 142 /// convert the array
Chris@28 143 switch (descr->type_num) {
Chris@28 144
Chris@28 145 case NPY_FLOAT : // dtype='float32'
Chris@28 146 return PyArray_Convert<float,float>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
Chris@28 147 case NPY_DOUBLE : // dtype='float64'
Chris@28 148 return PyArray_Convert<float,double>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
Chris@28 149 case NPY_INT : // dtype='int'
Chris@28 150 return PyArray_Convert<float,int>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
Chris@28 151 case NPY_LONG : // dtype='long'
Chris@28 152 return PyArray_Convert<float,long>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
Chris@28 153 default :
Chris@28 154 string msg = "Unsupported value type in NumPy array object.";
Chris@28 155 setValueError(msg);
Chris@26 156 #ifdef _DEBUG
Chris@29 157 cerr << "VectorConversion::PyArray_To_FloatVector failed. Error: " << msg << endl;
Chris@26 158 #endif
Chris@28 159 return v;
Chris@28 160 }
Chris@26 161 }
Chris@26 162
Chris@40 163 vector<vector<float> >
Chris@40 164 VectorConversion::Py2DArray_To_FloatVector (PyObject *pyValue) const
Chris@40 165 {
Chris@40 166 vector<vector<float> > v;
Chris@40 167
Chris@40 168 if (!PyArray_Check(pyValue)) {
Chris@40 169 setValueError("Value is not an array");
Chris@40 170 return v;
Chris@40 171 }
Chris@40 172
Chris@40 173 PyArrayObject* pyArray = (PyArrayObject*) pyValue;
Chris@40 174 PyArray_Descr* descr = PyArray_DESCR(pyArray);
Chris@40 175
Chris@40 176 if (PyArray_DATA(pyArray) == 0 || descr == 0) {
Chris@40 177 string msg = "NumPy array with NULL data or descriptor pointer encountered.";
Chris@40 178 setValueError(msg);
Chris@40 179 return v;
Chris@40 180 }
Chris@40 181
Chris@40 182 if (PyArray_NDIM(pyArray) != 2) {
Chris@40 183 string msg = "NumPy array must be a two-dimensional matrix.";
Chris@40 184 setValueError(msg);
Chris@40 185 return v;
Chris@40 186 }
Chris@40 187
Chris@40 188 /// check strides (useful if array is not continuous)
Chris@41 189 size_t *strideptr = (size_t*) PyArray_STRIDES(pyArray);
Chris@40 190
Chris@40 191 /// convert the array
Chris@40 192 for (int i = 0; i < PyArray_DIMS(pyArray)[0]; ++i) {
Chris@40 193
Chris@40 194 vector<float> vv;
Chris@40 195
Chris@40 196 switch (descr->type_num) {
Chris@40 197
Chris@40 198 case NPY_FLOAT : // dtype='float32'
Chris@41 199 vv = PyArray_Convert<float,float>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strideptr[1]);
Chris@40 200 break;
Chris@40 201 case NPY_DOUBLE : // dtype='float64'
Chris@41 202 vv = PyArray_Convert<float,double>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strideptr[1]);
Chris@40 203 break;
Chris@40 204 case NPY_INT : // dtype='int'
Chris@41 205 vv = PyArray_Convert<float,int>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strideptr[1]);
Chris@40 206 break;
Chris@40 207 case NPY_LONG : // dtype='long'
Chris@41 208 vv = PyArray_Convert<float,long>(PyArray_GETPTR2(pyArray, i, 0),PyArray_DIMS(pyArray)[1],strideptr[1]);
Chris@40 209 break;
Chris@40 210 default :
Chris@40 211 string msg = "Unsupported value type in NumPy array object.";
Chris@40 212 cerr << "VectorConversion::PyArray_To_FloatVector failed (value type = " << descr->type_num << "). Error: " << msg << endl;
Chris@40 213 setValueError(msg);
Chris@40 214 return v;
Chris@40 215 }
Chris@40 216
Chris@40 217 v.push_back(vv);
Chris@40 218 }
Chris@40 219
Chris@40 220 return v;
Chris@40 221 }
Chris@40 222
Chris@26 223 PyObject *
Chris@29 224 VectorConversion::PyArray_From_FloatVector(const vector<float> &v) const
Chris@26 225 {
Chris@28 226 npy_intp ndims[1];
Chris@28 227 ndims[0] = (int)v.size();
Chris@28 228 PyObject *arr = PyArray_SimpleNew(1, ndims, NPY_FLOAT);
Chris@28 229 float *data = (float *)PyArray_DATA((PyArrayObject *)arr);
Chris@28 230 for (int i = 0; i < ndims[0]; ++i) {
Chris@28 231 data[i] = v[i];
Chris@28 232 }
Chris@28 233 return arr;
Chris@26 234 }
Chris@26 235
Chris@26 236 PyObject *
Chris@29 237 VectorConversion::PyValue_From_StringVector(const vector<string> &v) const
Chris@26 238 {
Chris@28 239 PyObject *pyList = PyList_New(v.size());
Chris@28 240 for (size_t i = 0; i < v.size(); ++i) {
Chris@112 241 PyObject *pyStr = StringConversion().string2py(v[i].c_str());
Chris@28 242 PyList_SET_ITEM(pyList, i, pyStr);
Chris@28 243 }
Chris@28 244 return pyList;
Chris@26 245 }
Chris@26 246
Chris@26 247
Chris@28 248 /* Error handling */
Chris@26 249
Chris@26 250 void
Chris@29 251 VectorConversion::setValueError (string message) const
Chris@26 252 {
Chris@28 253 m_error = true;
Chris@28 254 m_errorQueue.push(ValueError(message));
Chris@26 255 }
Chris@26 256
Chris@26 257 /// return a reference to the last error or creates a new one.
Chris@26 258 ValueError&
Chris@29 259 VectorConversion::lastError() const
Chris@26 260 {
Chris@28 261 m_error = false;
Chris@28 262 if (!m_errorQueue.empty()) return m_errorQueue.back();
Chris@28 263 else {
Chris@28 264 m_errorQueue.push(ValueError("Type conversion error."));
Chris@28 265 return m_errorQueue.back();
Chris@28 266 }
Chris@26 267 }
Chris@26 268
Chris@26 269 /// helper function to iterate over the error message queue:
Chris@26 270 /// pops the oldest item
Chris@26 271 ValueError
Chris@29 272 VectorConversion::getError() const
Chris@26 273 {
Chris@28 274 if (!m_errorQueue.empty()) {
Chris@28 275 ValueError e = m_errorQueue.front();
Chris@28 276 m_errorQueue.pop();
Chris@28 277 if (m_errorQueue.empty()) m_error = false;
Chris@28 278 return e;
Chris@28 279 }
Chris@28 280 else {
Chris@28 281 m_error = false;
Chris@28 282 return ValueError();
Chris@28 283 }
Chris@26 284 }
Chris@26 285
Chris@28 286 /* Utilities */
Chris@26 287
Chris@26 288 /// get the type name of an object
Chris@28 289 string
Chris@29 290 VectorConversion::PyValue_Get_TypeName(PyObject* pyValue) const
Chris@26 291 {
Chris@28 292 PyObject *pyType = PyObject_Type(pyValue);
Chris@112 293 if (!pyType) {
Chris@28 294 cerr << "Warning: Object type name could not be found." << endl;
Chris@28 295 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
Chris@28 296 return string ("< unknown type >");
Chris@28 297 }
Chris@28 298 PyObject *pyString = PyObject_Str(pyType);
Chris@112 299 if (!pyString) {
Chris@28 300 cerr << "Warning: Object type name could not be found." << endl;
Chris@28 301 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
Chris@28 302 Py_CLEAR(pyType);
Chris@28 303 return string ("< unknown type >");
Chris@28 304 }
Chris@112 305 string str = StringConversion().py2string(pyString);
Chris@112 306 if (str == "") {
Chris@28 307 cerr << "Warning: Object type name could not be found." << endl;
Chris@28 308 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
Chris@28 309 Py_DECREF(pyType);
Chris@28 310 Py_CLEAR(pyString);
Chris@28 311 return string("< unknown type >");
Chris@28 312 }
Chris@28 313 Py_DECREF(pyType);
Chris@28 314 Py_DECREF(pyString);
Chris@112 315 return str;
Chris@26 316 }