annotate native/VectorConversion.cpp @ 75:ad08a0fe6673

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