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@28
|
65 if (pyValue && PyFloat_Check(pyValue))
|
Chris@28
|
66 //TODO: check for limits here (same on most systems)
|
Chris@28
|
67 return (float) PyFloat_AS_DOUBLE(pyValue);
|
Chris@26
|
68
|
Chris@28
|
69 if (pyValue == NULL)
|
Chris@28
|
70 {
|
Chris@28
|
71 setValueError("Error while converting object " + PyValue_Get_TypeName(pyValue) + " to float. ");
|
Chris@28
|
72 return 0.0;
|
Chris@28
|
73 }
|
Chris@26
|
74
|
Chris@28
|
75 setValueError("Conversion error: object" + PyValue_Get_TypeName(pyValue) +" is not float.");
|
Chris@28
|
76 return 0.0;
|
Chris@26
|
77 }
|
Chris@26
|
78
|
Chris@28
|
79 vector<float>
|
Chris@29
|
80 VectorConversion::PyValue_To_FloatVector (PyObject *pyValue) const
|
Chris@26
|
81 {
|
Chris@28
|
82 /// numpy array
|
Chris@28
|
83 if (PyArray_CheckExact(pyValue))
|
Chris@28
|
84 return PyArray_To_FloatVector(pyValue);
|
Chris@26
|
85
|
Chris@28
|
86 /// python list of floats (backward compatible)
|
Chris@28
|
87 if (PyList_Check(pyValue)) {
|
Chris@28
|
88 return PyList_To_FloatVector(pyValue);
|
Chris@28
|
89 }
|
Chris@26
|
90
|
Chris@28
|
91 string msg = "Value is not list or array of floats";
|
Chris@28
|
92 setValueError(msg);
|
Chris@26
|
93 #ifdef _DEBUG
|
Chris@29
|
94 cerr << "VectorConversion::PyValue_To_FloatVector failed. " << msg << endl;
|
Chris@26
|
95 #endif
|
Chris@28
|
96 return vector<float>();
|
Chris@26
|
97 }
|
Chris@26
|
98
|
Chris@28
|
99 vector<float>
|
Chris@29
|
100 VectorConversion::PyList_To_FloatVector (PyObject *inputList) const
|
Chris@26
|
101 {
|
Chris@28
|
102 vector<float> v;
|
Chris@26
|
103
|
Chris@28
|
104 if (!PyList_Check(inputList)) {
|
Chris@28
|
105 setValueError("Value is not a list");
|
Chris@28
|
106 return v;
|
Chris@28
|
107 }
|
Chris@26
|
108
|
Chris@28
|
109 PyObject **pyObjectArray = PySequence_Fast_ITEMS(inputList);
|
Chris@28
|
110 int n = PyList_GET_SIZE(inputList);
|
Chris@26
|
111
|
Chris@28
|
112 for (int i = 0; i < n; ++i) {
|
Chris@28
|
113 v.push_back(PyValue_To_Float(pyObjectArray[i]));
|
Chris@28
|
114 }
|
Chris@28
|
115
|
Chris@28
|
116 return v;
|
Chris@26
|
117 }
|
Chris@26
|
118
|
Chris@28
|
119 vector<float>
|
Chris@29
|
120 VectorConversion::PyArray_To_FloatVector (PyObject *pyValue) const
|
Chris@26
|
121 {
|
Chris@28
|
122 vector<float> v;
|
Chris@26
|
123
|
Chris@28
|
124 if (!PyArray_Check(pyValue)) {
|
Chris@28
|
125 setValueError("Value is not an array");
|
Chris@28
|
126 return v;
|
Chris@28
|
127 }
|
Chris@28
|
128
|
Chris@28
|
129 PyArrayObject* pyArray = (PyArrayObject*) pyValue;
|
Chris@28
|
130 PyArray_Descr* descr = PyArray_DESCR(pyArray);
|
Chris@28
|
131
|
Chris@28
|
132 if (PyArray_DATA(pyArray) == 0 || descr == 0) {
|
Chris@28
|
133 string msg = "NumPy array with NULL data or descriptor pointer encountered.";
|
Chris@28
|
134 setValueError(msg);
|
Chris@28
|
135 return v;
|
Chris@28
|
136 }
|
Chris@28
|
137
|
Chris@28
|
138 if (PyArray_NDIM(pyArray) != 1) {
|
Chris@28
|
139 string msg = "NumPy array must be a one dimensional vector.";
|
Chris@28
|
140 setValueError(msg);
|
Chris@28
|
141 return v;
|
Chris@28
|
142 }
|
Chris@28
|
143
|
Chris@28
|
144 /// check strides (useful if array is not continuous)
|
Chris@28
|
145 size_t strides = *((size_t*) PyArray_STRIDES(pyArray));
|
Chris@28
|
146
|
Chris@28
|
147 /// convert the array
|
Chris@28
|
148 switch (descr->type_num) {
|
Chris@28
|
149
|
Chris@28
|
150 case NPY_FLOAT : // dtype='float32'
|
Chris@28
|
151 return PyArray_Convert<float,float>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
|
Chris@28
|
152 case NPY_DOUBLE : // dtype='float64'
|
Chris@28
|
153 return PyArray_Convert<float,double>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
|
Chris@28
|
154 case NPY_INT : // dtype='int'
|
Chris@28
|
155 return PyArray_Convert<float,int>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
|
Chris@28
|
156 case NPY_LONG : // dtype='long'
|
Chris@28
|
157 return PyArray_Convert<float,long>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides);
|
Chris@28
|
158 default :
|
Chris@28
|
159 string msg = "Unsupported value type in NumPy array object.";
|
Chris@28
|
160 setValueError(msg);
|
Chris@26
|
161 #ifdef _DEBUG
|
Chris@29
|
162 cerr << "VectorConversion::PyArray_To_FloatVector failed. Error: " << msg << endl;
|
Chris@26
|
163 #endif
|
Chris@28
|
164 return v;
|
Chris@28
|
165 }
|
Chris@26
|
166 }
|
Chris@26
|
167
|
Chris@26
|
168 PyObject *
|
Chris@29
|
169 VectorConversion::PyArray_From_FloatVector(const vector<float> &v) const
|
Chris@26
|
170 {
|
Chris@28
|
171 npy_intp ndims[1];
|
Chris@28
|
172 ndims[0] = (int)v.size();
|
Chris@28
|
173 PyObject *arr = PyArray_SimpleNew(1, ndims, NPY_FLOAT);
|
Chris@28
|
174 float *data = (float *)PyArray_DATA((PyArrayObject *)arr);
|
Chris@28
|
175 for (int i = 0; i < ndims[0]; ++i) {
|
Chris@28
|
176 data[i] = v[i];
|
Chris@28
|
177 }
|
Chris@28
|
178 return arr;
|
Chris@26
|
179 }
|
Chris@26
|
180
|
Chris@26
|
181 PyObject *
|
Chris@29
|
182 VectorConversion::PyValue_From_StringVector(const vector<string> &v) const
|
Chris@26
|
183 {
|
Chris@28
|
184 PyObject *pyList = PyList_New(v.size());
|
Chris@28
|
185 for (size_t i = 0; i < v.size(); ++i) {
|
Chris@28
|
186 PyObject *pyStr = PyString_FromString(v[i].c_str());
|
Chris@28
|
187 PyList_SET_ITEM(pyList, i, pyStr);
|
Chris@28
|
188 }
|
Chris@28
|
189 return pyList;
|
Chris@26
|
190 }
|
Chris@26
|
191
|
Chris@26
|
192
|
Chris@28
|
193 /* Error handling */
|
Chris@26
|
194
|
Chris@26
|
195 void
|
Chris@29
|
196 VectorConversion::setValueError (string message) const
|
Chris@26
|
197 {
|
Chris@28
|
198 m_error = true;
|
Chris@28
|
199 m_errorQueue.push(ValueError(message));
|
Chris@26
|
200 }
|
Chris@26
|
201
|
Chris@26
|
202 /// return a reference to the last error or creates a new one.
|
Chris@26
|
203 ValueError&
|
Chris@29
|
204 VectorConversion::lastError() const
|
Chris@26
|
205 {
|
Chris@28
|
206 m_error = false;
|
Chris@28
|
207 if (!m_errorQueue.empty()) return m_errorQueue.back();
|
Chris@28
|
208 else {
|
Chris@28
|
209 m_errorQueue.push(ValueError("Type conversion error."));
|
Chris@28
|
210 return m_errorQueue.back();
|
Chris@28
|
211 }
|
Chris@26
|
212 }
|
Chris@26
|
213
|
Chris@26
|
214 /// helper function to iterate over the error message queue:
|
Chris@26
|
215 /// pops the oldest item
|
Chris@26
|
216 ValueError
|
Chris@29
|
217 VectorConversion::getError() const
|
Chris@26
|
218 {
|
Chris@28
|
219 if (!m_errorQueue.empty()) {
|
Chris@28
|
220 ValueError e = m_errorQueue.front();
|
Chris@28
|
221 m_errorQueue.pop();
|
Chris@28
|
222 if (m_errorQueue.empty()) m_error = false;
|
Chris@28
|
223 return e;
|
Chris@28
|
224 }
|
Chris@28
|
225 else {
|
Chris@28
|
226 m_error = false;
|
Chris@28
|
227 return ValueError();
|
Chris@28
|
228 }
|
Chris@26
|
229 }
|
Chris@26
|
230
|
Chris@28
|
231 /* Utilities */
|
Chris@26
|
232
|
Chris@26
|
233 /// get the type name of an object
|
Chris@28
|
234 string
|
Chris@29
|
235 VectorConversion::PyValue_Get_TypeName(PyObject* pyValue) const
|
Chris@26
|
236 {
|
Chris@28
|
237 PyObject *pyType = PyObject_Type(pyValue);
|
Chris@28
|
238 if (!pyType)
|
Chris@28
|
239 {
|
Chris@28
|
240 cerr << "Warning: Object type name could not be found." << endl;
|
Chris@28
|
241 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
Chris@28
|
242 return string ("< unknown type >");
|
Chris@28
|
243 }
|
Chris@28
|
244 PyObject *pyString = PyObject_Str(pyType);
|
Chris@28
|
245 if (!pyString)
|
Chris@28
|
246 {
|
Chris@28
|
247 cerr << "Warning: Object type name could not be found." << endl;
|
Chris@28
|
248 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
Chris@28
|
249 Py_CLEAR(pyType);
|
Chris@28
|
250 return string ("< unknown type >");
|
Chris@28
|
251 }
|
Chris@28
|
252 char *cstr = PyString_AS_STRING(pyString);
|
Chris@28
|
253 if (!cstr)
|
Chris@28
|
254 {
|
Chris@28
|
255 cerr << "Warning: Object type name could not be found." << endl;
|
Chris@28
|
256 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
Chris@28
|
257 Py_DECREF(pyType);
|
Chris@28
|
258 Py_CLEAR(pyString);
|
Chris@28
|
259 return string("< unknown type >");
|
Chris@28
|
260 }
|
Chris@28
|
261 Py_DECREF(pyType);
|
Chris@28
|
262 Py_DECREF(pyString);
|
Chris@28
|
263 return string(cstr);
|
Chris@26
|
264 }
|