Mercurial > hg > vampy
comparison PyTypeInterface.cpp @ 71:40a01bb24209 vampyhost
Pull apart some type conversion classes for possible use in VamPy Host
author | Chris Cannam |
---|---|
date | Thu, 20 Nov 2014 13:02:50 +0000 |
parents | 6c755f3e1173 |
children | ffaa1fb3d7de |
comparison
equal
deleted
inserted
replaced
70:6c755f3e1173 | 71:40a01bb24209 |
---|---|
53 } | 53 } |
54 | 54 |
55 PyTypeInterface::~PyTypeInterface() | 55 PyTypeInterface::~PyTypeInterface() |
56 { | 56 { |
57 } | 57 } |
58 | |
59 /// floating point numbers (TODO: check numpy.float128) | |
60 float | |
61 PyTypeInterface::PyValue_To_Float(PyObject* pyValue) const | |
62 { | |
63 // convert float | |
64 if (pyValue && PyFloat_Check(pyValue)) | |
65 //TODO: check for limits here (same on most systems) | |
66 return (float) PyFloat_AS_DOUBLE(pyValue); | |
67 | |
68 if (pyValue == NULL) | |
69 { | |
70 setValueError("Error while converting object " + PyValue_Get_TypeName(pyValue) + " to float. ",m_strict); | |
71 return 0.0; | |
72 } | |
73 | |
74 // in strict mode we will not try harder | |
75 if (m_strict) { | |
76 setValueError("Strict conversion error: object" + PyValue_Get_TypeName(pyValue) +" is not float.",m_strict); | |
77 return 0.0; | |
78 } | |
79 | |
80 // convert other objects supporting the number protocol | |
81 if (PyNumber_Check(pyValue)) | |
82 { | |
83 PyObject* pyFloat = PyNumber_Float(pyValue); // new ref | |
84 if (!pyFloat) | |
85 { | |
86 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} | |
87 setValueError("Error while converting " + PyValue_Get_TypeName(pyValue) + " object to float.",m_strict); | |
88 return 0.0; | |
89 } | |
90 float rValue = (float) PyFloat_AS_DOUBLE(pyFloat); | |
91 Py_DECREF(pyFloat); | |
92 return rValue; | |
93 } | |
94 /* | |
95 // convert other objects supporting the number protocol | |
96 if (PyNumber_Check(pyValue)) | |
97 { | |
98 // PEP353: Py_ssize_t is size_t but signed ! | |
99 // This will work up to numpy.float64 | |
100 Py_ssize_t rValue = PyNumber_AsSsize_t(pyValue,NULL); | |
101 if (PyErr_Occurred()) | |
102 { | |
103 PyErr_Print(); PyErr_Clear(); | |
104 setValueError("Error while converting integer object.",m_strict); | |
105 return 0.0; | |
106 } | |
107 if (rValue > (Py_ssize_t)FLT_MAX || rValue < (Py_ssize_t)FLT_MIN) | |
108 { | |
109 setValueError("Overflow error. Object can not be converted to float.",m_strict); | |
110 return 0.0; | |
111 } | |
112 return (float) rValue; | |
113 } | |
114 */ | |
115 // convert string | |
116 if (PyString_Check(pyValue)) | |
117 { | |
118 PyObject* pyFloat = PyFloat_FromString(pyValue,NULL); | |
119 if (!pyFloat) | |
120 { | |
121 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } | |
122 setValueError("String value can not be converted to float.",m_strict); | |
123 return 0.0; | |
124 } | |
125 float rValue = (float) PyFloat_AS_DOUBLE(pyFloat); | |
126 if (PyErr_Occurred()) | |
127 { | |
128 PyErr_Print(); PyErr_Clear(); | |
129 Py_CLEAR(pyFloat); | |
130 setValueError("Error while converting float object.",m_strict); | |
131 return 0.0; | |
132 } | |
133 Py_DECREF(pyFloat); | |
134 return rValue; | |
135 } | |
136 | |
137 // convert the first element of any iterable sequence (for convenience and backwards compatibility) | |
138 if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) | |
139 { | |
140 PyObject* item = PySequence_GetItem(pyValue,0); | |
141 if (item) | |
142 { | |
143 float rValue = this->PyValue_To_Float(item); | |
144 if (!m_error) { | |
145 Py_DECREF(item); | |
146 return rValue; | |
147 } else { | |
148 Py_CLEAR(item); | |
149 std::string msg = "Could not convert sequence element to float. "; | |
150 setValueError(msg,m_strict); | |
151 return 0.0; | |
152 } | |
153 } | |
154 } | |
155 | |
156 // give up | |
157 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } | |
158 std::string msg = "Conversion from " + PyValue_Get_TypeName(pyValue) + " to float is not possible."; | |
159 setValueError(msg,m_strict); | |
160 #ifdef _DEBUG | |
161 cerr << "PyTypeInterface::PyValue_To_Float failed. " << msg << endl; | |
162 #endif | |
163 return 0.0; | |
164 } | |
165 | |
166 /// size_t (unsigned integer types) | |
167 size_t | |
168 PyTypeInterface::PyValue_To_Size_t(PyObject* pyValue) const | |
169 { | |
170 // convert objects supporting the number protocol | |
171 if (PyNumber_Check(pyValue)) | |
172 { | |
173 if (m_strict && !PyInt_Check(pyValue) && !PyLong_Check(pyValue)) | |
174 setValueError("Strict conversion error: object is not integer type.",m_strict); | |
175 // Note: this function handles Bool,Int,Long,Float | |
176 // speed is not critical in the use of this type by Vamp | |
177 // PEP353: Py_ssize_t is size_t but signed ! | |
178 Py_ssize_t rValue = PyInt_AsSsize_t(pyValue); | |
179 if (PyErr_Occurred()) | |
180 { | |
181 PyErr_Print(); PyErr_Clear(); | |
182 setValueError("Error while converting integer object.",m_strict); | |
183 return 0; | |
184 } | |
185 // this test is nonsense -- neither part can occur | |
186 // owing to range of data types -- size_t is at least | |
187 // as big as long, and unsigned is always non-negative | |
188 /* | |
189 if ((unsigned long)rValue > SIZE_T_MAX || (unsigned long)rValue < 0) | |
190 { | |
191 setValueError("Overflow error. Object can not be converted to size_t.",m_strict); | |
192 return 0; | |
193 } | |
194 */ | |
195 return (size_t) rValue; | |
196 } | |
197 | |
198 // in strict mode we will not try harder and throw an exception | |
199 // then the caller should decide what to do with it | |
200 if (m_strict) { | |
201 setValueError("Strict conversion error: object is not integer.",m_strict); | |
202 return 0; | |
203 } | |
204 | |
205 // convert string | |
206 if (PyString_Check(pyValue)) | |
207 { | |
208 PyObject* pyLong = PyNumber_Long(pyValue); | |
209 if (!pyLong) | |
210 { | |
211 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } | |
212 setValueError("String object can not be converted to size_t.",m_strict); | |
213 return 0; | |
214 } | |
215 size_t rValue = this->PyValue_To_Size_t(pyLong); | |
216 if (!m_error) { | |
217 Py_DECREF(pyLong); | |
218 return rValue; | |
219 } else { | |
220 Py_CLEAR(pyLong); | |
221 setValueError ("Error converting string to size_t.",m_strict); | |
222 return 0; | |
223 } | |
224 } | |
225 | |
226 // convert the first element of iterable sequences | |
227 if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) | |
228 { | |
229 PyObject* item = PySequence_GetItem(pyValue,0); | |
230 if (item) | |
231 { | |
232 size_t rValue = this->PyValue_To_Size_t(item); | |
233 if (!m_error) { | |
234 Py_DECREF(item); | |
235 return rValue; | |
236 } else { | |
237 Py_CLEAR(item); | |
238 setValueError("Could not convert sequence element to size_t. ",m_strict); | |
239 return 0; | |
240 } | |
241 } | |
242 } | |
243 | |
244 // give up | |
245 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } | |
246 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to size_t is not possible."; | |
247 setValueError(msg,m_strict); | |
248 #ifdef _DEBUG | |
249 cerr << "PyTypeInterface::PyValue_To_Size_t failed. " << msg << endl; | |
250 #endif | |
251 return 0; | |
252 } | |
253 | |
254 /// long and int | |
255 long | |
256 PyTypeInterface::PyValue_To_Long(PyObject* pyValue) const | |
257 { | |
258 // most common case: convert int (faster) | |
259 if (pyValue && PyInt_Check(pyValue)) { | |
260 // if the object is not NULL and verified, this macro just extracts the value. | |
261 return PyInt_AS_LONG(pyValue); | |
262 } | |
263 | |
264 // long | |
265 if (PyLong_Check(pyValue)) { | |
266 long rValue = PyLong_AsLong(pyValue); | |
267 if (PyErr_Occurred()) { | |
268 PyErr_Print(); PyErr_Clear(); | |
269 setValueError("Error while converting long object.",m_strict); | |
270 return 0; | |
271 } | |
272 return rValue; | |
273 } | |
274 | |
275 if (m_strict) { | |
276 setValueError("Strict conversion error: object is not integer or long integer.",m_strict); | |
277 return 0; | |
278 } | |
279 | |
280 // convert all objects supporting the number protocol | |
281 if (PyNumber_Check(pyValue)) | |
282 { | |
283 // Note: this function handles Bool,Int,Long,Float | |
284 // PEP353: Py_ssize_t is size_t but signed ! | |
285 Py_ssize_t rValue = PyInt_AsSsize_t(pyValue); | |
286 if (PyErr_Occurred()) | |
287 { | |
288 PyErr_Print(); PyErr_Clear(); | |
289 setValueError("Error while converting integer object.",m_strict); | |
290 return 0; | |
291 } | |
292 if (rValue > LONG_MAX || rValue < LONG_MIN) | |
293 { | |
294 setValueError("Overflow error. Object can not be converted to size_t.",m_strict); | |
295 return 0; | |
296 } | |
297 return (long) rValue; | |
298 } | |
299 | |
300 // convert string | |
301 if (PyString_Check(pyValue)) | |
302 { | |
303 PyObject* pyLong = PyNumber_Long(pyValue); | |
304 if (!pyLong) | |
305 { | |
306 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } | |
307 setValueError("String object can not be converted to long.",m_strict); | |
308 return 0; | |
309 } | |
310 long rValue = this->PyValue_To_Long(pyLong); | |
311 if (!m_error) { | |
312 Py_DECREF(pyLong); | |
313 return rValue; | |
314 } else { | |
315 Py_CLEAR(pyLong); | |
316 setValueError ("Error converting string to long.",m_strict); | |
317 return 0; | |
318 } | |
319 } | |
320 | |
321 // convert the first element of iterable sequences | |
322 if (PySequence_Check(pyValue) && PySequence_Size(pyValue) > 0) | |
323 { | |
324 PyObject* item = PySequence_GetItem(pyValue,0); | |
325 if (item) | |
326 { | |
327 size_t rValue = this->PyValue_To_Long(item); | |
328 if (!m_error) { | |
329 Py_DECREF(item); | |
330 return rValue; | |
331 } else { | |
332 Py_CLEAR(item); | |
333 setValueError("Could not convert sequence element to long. ",m_strict); | |
334 return 0; | |
335 } | |
336 } | |
337 } | |
338 | |
339 // give up | |
340 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } | |
341 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to long is not possible."; | |
342 setValueError(msg,m_strict); | |
343 #ifdef _DEBUG | |
344 cerr << "PyTypeInterface::PyValue_To_Long failed. " << msg << endl; | |
345 #endif | |
346 return 0; | |
347 } | |
348 | |
349 | |
350 bool | |
351 PyTypeInterface::PyValue_To_Bool(PyObject* pyValue) const | |
352 { | |
353 // convert objects supporting the number protocol | |
354 // Note: PyBool is a subclass of PyInt | |
355 if (PyNumber_Check(pyValue)) | |
356 { | |
357 if (m_strict && !PyBool_Check(pyValue)) | |
358 setValueError | |
359 ("Strict conversion error: object is not boolean type.",m_strict); | |
360 | |
361 // Note: this function handles Bool,Int,Long,Float | |
362 Py_ssize_t rValue = PyInt_AsSsize_t(pyValue); | |
363 if (PyErr_Occurred()) | |
364 { | |
365 PyErr_Print(); PyErr_Clear(); | |
366 setValueError ("Error while converting boolean object.",m_strict); | |
367 } | |
368 if (rValue != 1 && rValue != 0) | |
369 { | |
370 setValueError ("Overflow error. Object can not be converted to boolean.",m_strict); | |
371 } | |
372 return (bool) rValue; | |
373 } | |
374 | |
375 if (m_strict) { | |
376 setValueError ("Strict conversion error: object is not numerical type.",m_strict); | |
377 return false; | |
378 } | |
379 | |
380 // convert iterables: the rule is the same as in the interpreter: | |
381 // empty sequence evaluates to False, anything else is True | |
382 if (PySequence_Check(pyValue)) | |
383 { | |
384 return PySequence_Size(pyValue)?true:false; | |
385 } | |
386 | |
387 // give up | |
388 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } | |
389 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to boolean is not possible."; | |
390 setValueError(msg,m_strict); | |
391 #ifdef _DEBUG | |
392 cerr << "PyTypeInterface::PyValue_To_Bool failed. " << msg << endl; | |
393 #endif | |
394 return false; | |
395 } | |
396 | |
397 /// string and objects that support .__str__() | |
398 /// TODO: check unicode objects | |
399 std::string | |
400 PyTypeInterface::PyValue_To_String(PyObject* pyValue) const | |
401 { | |
402 // convert string | |
403 if (PyString_Check(pyValue)) | |
404 { | |
405 char *cstr = PyString_AS_STRING(pyValue); | |
406 if (!cstr) | |
407 { | |
408 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} | |
409 setValueError("Error while converting string object.",m_strict); | |
410 return std::string(); | |
411 } | |
412 return std::string(cstr); | |
413 } | |
414 // TODO: deal with unicode here (argh!) | |
415 | |
416 // in strict mode we will not try harder | |
417 if (m_strict) { | |
418 setValueError("Strict conversion error: object is not string.",m_strict); | |
419 return std::string(); | |
420 } | |
421 | |
422 // accept None as empty string | |
423 if (pyValue == Py_None) return std::string(); | |
424 | |
425 // convert list or tuple: empties are turned into empty strings conventionally | |
426 if (PyList_Check(pyValue) || PyTuple_Check(pyValue)) | |
427 { | |
428 if (!PySequence_Size(pyValue)) return std::string(); | |
429 PyObject* item = PySequence_GetItem(pyValue,0); | |
430 if (item) | |
431 { | |
432 std::string rValue = this->PyValue_To_String(item); | |
433 if (!m_error) { | |
434 Py_DECREF(item); | |
435 return rValue; | |
436 } else { | |
437 Py_CLEAR(item); | |
438 setValueError("Could not convert sequence element to string.",m_strict); | |
439 return std::string(); | |
440 } | |
441 } | |
442 } | |
443 | |
444 // convert any other object that has .__str__() or .__repr__() | |
445 PyObject* pyString = PyObject_Str(pyValue); | |
446 if (pyString && !PyErr_Occurred()) | |
447 { | |
448 std::string rValue = this->PyValue_To_String(pyString); | |
449 if (!m_error) { | |
450 Py_DECREF(pyString); | |
451 return rValue; | |
452 } else { | |
453 Py_CLEAR(pyString); | |
454 std::string msg = "Object " + this->PyValue_Get_TypeName(pyValue) +" can not be represented as string. "; | |
455 setValueError (msg,m_strict); | |
456 return std::string(); | |
457 } | |
458 } | |
459 | |
460 // give up | |
461 PyErr_Print(); PyErr_Clear(); | |
462 std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to string is not possible."; | |
463 setValueError(msg,m_strict); | |
464 #ifdef _DEBUG | |
465 cerr << "PyTypeInterface::PyValue_To_String failed. " << msg << endl; | |
466 #endif | |
467 return std::string(); | |
468 } | |
469 | |
470 /* C Values to Py Values */ | |
471 | |
472 | |
473 PyObject* | |
474 PyTypeInterface::PyValue_From_CValue(const char* cValue) const | |
475 { | |
476 // returns new reference | |
477 #ifdef _DEBUG | |
478 if (!cValue) { | |
479 std::string msg = "PyTypeInterface::PyValue_From_CValue: Null pointer encountered while converting from const char* ."; | |
480 cerr << msg << endl; | |
481 setValueError(msg,m_strict); | |
482 return NULL; | |
483 } | |
484 #endif | |
485 PyObject *pyValue = PyString_FromString(cValue); | |
486 if (!pyValue) | |
487 { | |
488 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} | |
489 setValueError("Error while converting from char* or string.",m_strict); | |
490 #ifdef _DEBUG | |
491 cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from const char*" << endl; | |
492 #endif | |
493 return NULL; | |
494 } | |
495 return pyValue; | |
496 } | |
497 | |
498 PyObject* | |
499 PyTypeInterface::PyValue_From_CValue(size_t cValue) const | |
500 { | |
501 // returns new reference | |
502 PyObject *pyValue = PyInt_FromSsize_t((Py_ssize_t)cValue); | |
503 if (!pyValue) | |
504 { | |
505 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} | |
506 setValueError("Error while converting from size_t.",m_strict); | |
507 #ifdef _DEBUG | |
508 cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from size_t" << endl; | |
509 #endif | |
510 return NULL; | |
511 } | |
512 return pyValue; | |
513 } | |
514 | |
515 PyObject* | |
516 PyTypeInterface::PyValue_From_CValue(double cValue) const | |
517 { | |
518 // returns new reference | |
519 PyObject *pyValue = PyFloat_FromDouble(cValue); | |
520 if (!pyValue) | |
521 { | |
522 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} | |
523 setValueError("Error while converting from float or double.",m_strict); | |
524 #ifdef _DEBUG | |
525 cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from float or double" << endl; | |
526 #endif | |
527 return NULL; | |
528 } | |
529 return pyValue; | |
530 } | |
531 | |
532 PyObject* | |
533 PyTypeInterface::PyValue_From_CValue(bool cValue) const | |
534 { | |
535 // returns new reference | |
536 PyObject *pyValue = PyBool_FromLong((long)cValue); | |
537 if (!pyValue) | |
538 { | |
539 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} | |
540 setValueError("Error while converting from bool.",m_strict); | |
541 #ifdef _DEBUG | |
542 cerr << "PyTypeInterface::PyValue_From_CValue: Interpreter failed to convert from bool" << endl; | |
543 #endif | |
544 return NULL; | |
545 } | |
546 return pyValue; | |
547 } | |
548 | |
549 | |
550 /* Sequence Types to C++ Types */ | |
551 | |
552 //convert Python list to C++ vector of strings | |
553 std::vector<std::string> | |
554 PyTypeInterface::PyValue_To_StringVector (PyObject *pyList) const | |
555 { | |
556 | |
557 std::vector<std::string> Output; | |
558 std::string ListElement; | |
559 PyObject *pyString = NULL; | |
560 | |
561 if (PyList_Check(pyList)) { | |
562 | |
563 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) { | |
564 //Get next list item (Borrowed Reference) | |
565 pyString = PyList_GET_ITEM(pyList,i); | |
566 ListElement = (string) PyString_AsString(PyObject_Str(pyString)); | |
567 Output.push_back(ListElement); | |
568 } | |
569 return Output; | |
570 } | |
571 | |
572 // #ifdef _DEBUG | |
573 // cerr << "PyTypeInterface::PyValue_To_StringVector: Warning: Value is not list of strings." << endl; | |
574 // #endif | |
575 | |
576 /// Assume a single value that can be casted as string | |
577 /// this allows to write e.g. Feature.label = 5.2 instead of ['5.2'] | |
578 Output.push_back(PyValue_To_String(pyList)); | |
579 if (m_error) { | |
580 std::string msg = "Value is not list of strings nor can be casted as string. "; | |
581 setValueError(msg,m_strict); | |
582 #ifdef _DEBUG | |
583 cerr << "PyTypeInterface::PyValue_To_StringVector failed. " << msg << endl; | |
584 #endif | |
585 } | |
586 return Output; | |
587 } | |
588 | |
589 //convert PyFeature.value (typically a list or numpy array) to C++ vector of floats | |
590 std::vector<float> | |
591 PyTypeInterface::PyValue_To_FloatVector (PyObject *pyValue) const | |
592 { | |
593 | |
594 #ifdef HAVE_NUMPY | |
595 if (m_numpyInstalled) | |
596 { | |
597 // there are four types of values we may receive from a numpy process: | |
598 // * a python scalar, | |
599 // * an array scalar, (e.g. numpy.float32) | |
600 // * an array with nd = 0 (0D array) | |
601 // * an array with nd > 0 | |
602 | |
603 /// check for scalars | |
604 if (PyArray_CheckScalar(pyValue) || PyFloat_Check(pyValue)) { | |
605 | |
606 std::vector<float> Output; | |
607 | |
608 // we rely on the behaviour the scalars are either floats | |
609 // or support the number protocol | |
610 // TODO: a potential optimisation is to handle them directly | |
611 Output.push_back(PyValue_To_Float(pyValue)); | |
612 return Output; | |
613 } | |
614 | |
615 /// numpy array | |
616 if (PyArray_CheckExact(pyValue)) | |
617 return PyArray_To_FloatVector(pyValue); | |
618 } | |
619 #endif | |
620 | |
621 /// python list of floats (backward compatible) | |
622 if (PyList_Check(pyValue)) { | |
623 return PyList_To_FloatVector(pyValue); | |
624 } | |
625 | |
626 std::vector<float> Output; | |
627 | |
628 /// finally assume a single value supporting the number protocol | |
629 /// this allows to write e.g. Feature.values = 5 instead of [5.00] | |
630 Output.push_back(PyValue_To_Float(pyValue)); | |
631 if (m_error) { | |
632 std::string msg = "Value is not list or array of floats nor can be casted as float. "; | |
633 setValueError(msg,m_strict); | |
634 #ifdef _DEBUG | |
635 cerr << "PyTypeInterface::PyValue_To_FloatVector failed. " << msg << endl; | |
636 #endif | |
637 } | |
638 return Output; | |
639 } | |
640 | |
641 //convert a list of python floats | |
642 std::vector<float> | |
643 PyTypeInterface::PyList_To_FloatVector (PyObject *inputList) const | |
644 { | |
645 std::vector<float> Output; | |
646 | |
647 #ifdef _DEBUG | |
648 // This is a low level function normally called from | |
649 // PyValue_To_FloatVector(). Checking for list is not required. | |
650 if (!PyList_Check(inputList)) { | |
651 std::string msg = "Value is not list."; | |
652 setValueError(msg,true); | |
653 cerr << "PyTypeInterface::PyList_To_FloatVector failed. " << msg << endl; | |
654 return Output; | |
655 } | |
656 #endif | |
657 | |
658 float ListElement; | |
659 PyObject *pyFloat = NULL; | |
660 PyObject **pyObjectArray = PySequence_Fast_ITEMS(inputList); | |
661 | |
662 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) { | |
663 | |
664 // pyFloat = PyList_GET_ITEM(inputList,i); | |
665 pyFloat = pyObjectArray[i]; | |
666 | |
667 #ifdef _DEBUG | |
668 if (!pyFloat) { | |
669 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} | |
670 cerr << "PyTypeInterface::PyList_To_FloatVector: Could not obtain list element: " | |
671 << i << " PyList_GetItem returned NULL! Skipping value." << endl; | |
672 continue; | |
673 } | |
674 #endif | |
675 | |
676 // ListElement = (float) PyFloat_AS_DOUBLE(pyFloat); | |
677 ListElement = PyValue_To_Float(pyFloat); | |
678 | |
679 | |
680 #ifdef _DEBUG_VALUES | |
681 cerr << "value: " << ListElement << endl; | |
682 #endif | |
683 Output.push_back(ListElement); | |
684 } | |
685 return Output; | |
686 } | |
687 | |
688 // if numpy is not installed this will not be called, | |
689 // therefor we do not check again | |
690 #ifdef HAVE_NUMPY | |
691 std::vector<float> | |
692 PyTypeInterface::PyArray_To_FloatVector (PyObject *pyValue) const | |
693 { | |
694 std::vector<float> Output; | |
695 | |
696 #ifdef _DEBUG | |
697 // This is a low level function, normally called from | |
698 // PyValue_To_FloatVector(). Checking the array here is not required. | |
699 if (!PyArray_Check(pyValue)) { | |
700 std::string msg = "Object has no array interface."; | |
701 setValueError(msg,true); | |
702 cerr << "PyTypeInterface::PyArray_To_FloatVector failed. " << msg << endl; | |
703 return Output; | |
704 } | |
705 #endif | |
706 | |
707 PyArrayObject* pyArray = (PyArrayObject*) pyValue; | |
708 PyArray_Descr* descr = PyArray_DESCR(pyArray); | |
709 | |
710 /// check raw data and descriptor pointers | |
711 if (PyArray_DATA(pyArray) == 0 || descr == 0) { | |
712 std::string msg = "NumPy array with NULL data or descriptor pointer encountered."; | |
713 setValueError(msg,m_strict); | |
714 #ifdef _DEBUG | |
715 cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << endl; | |
716 #endif | |
717 return Output; | |
718 } | |
719 | |
720 /// check dimensions | |
721 if (PyArray_NDIM(pyArray) != 1) { | |
722 std::string msg = "NumPy array must be a one dimensional vector."; | |
723 setValueError(msg,m_strict); | |
724 #ifdef _DEBUG | |
725 cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << " Dims: " << (int) PyArray_NDIM(pyArray) << endl; | |
726 #endif | |
727 return Output; | |
728 } | |
729 | |
730 #ifdef _DEBUG_VALUES | |
731 cerr << "PyTypeInterface::PyArray_To_FloatVector: Numpy array verified." << endl; | |
732 #endif | |
733 | |
734 /// check strides (useful if array is not continuous) | |
735 size_t strides = *((size_t*) PyArray_STRIDES(pyArray)); | |
736 | |
737 /// convert the array | |
738 switch (descr->type_num) | |
739 { | |
740 case NPY_FLOAT : // dtype='float32' | |
741 return PyArray_Convert<float,float>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides); | |
742 case NPY_DOUBLE : // dtype='float64' | |
743 return PyArray_Convert<float,double>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides); | |
744 case NPY_INT : // dtype='int' | |
745 return PyArray_Convert<float,int>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides); | |
746 case NPY_LONG : // dtype='long' | |
747 return PyArray_Convert<float,long>(PyArray_DATA(pyArray),PyArray_DIMS(pyArray)[0],strides); | |
748 default : | |
749 std::string msg = "Unsupported value type in NumPy array object."; | |
750 setValueError(msg,m_strict); | |
751 #ifdef _DEBUG | |
752 cerr << "PyTypeInterface::PyArray_To_FloatVector failed. Error: " << msg << endl; | |
753 #endif | |
754 return Output; | |
755 } | |
756 } | |
757 #endif | |
758 | |
759 | 58 |
760 /// FeatureSet (an integer map of FeatureLists) | 59 /// FeatureSet (an integer map of FeatureLists) |
761 Vamp::Plugin::FeatureSet | 60 Vamp::Plugin::FeatureSet |
762 PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const | 61 PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const |
763 { | 62 { |
834 /// just create a copy of the wrapped object | 133 /// just create a copy of the wrapped object |
835 return Vamp::RealTime(*PyRealTime_AS_REALTIME(pyValue)); | 134 return Vamp::RealTime(*PyRealTime_AS_REALTIME(pyValue)); |
836 } | 135 } |
837 | 136 |
838 // assume integer sample count | 137 // assume integer sample count |
839 long sampleCount = PyValue_To_Long(pyValue); | 138 long sampleCount = m_conv.PyValue_To_Long(pyValue); |
840 if (m_error) { | 139 if (m_conv.error) { |
841 std::string msg = "Unexpected value passed as RealTime.\nMust be vampy.RealTime type or integer sample count."; | 140 std::string msg = "Unexpected value passed as RealTime.\nMust be vampy.RealTime type or integer sample count."; |
842 setValueError(msg,m_strict); | 141 setValueError(msg,m_strict); |
843 #ifdef _DEBUG | 142 #ifdef _DEBUG |
844 cerr << "PyTypeInterface::PyValue_To_RealTime failed. " << msg << endl; | 143 cerr << "PyTypeInterface::PyValue_To_RealTime failed. " << msg << endl; |
845 #endif | 144 #endif |
872 } | 171 } |
873 | 172 |
874 /// convert string (backward compatible) | 173 /// convert string (backward compatible) |
875 if (PyString_CheckExact(pyValue)) { | 174 if (PyString_CheckExact(pyValue)) { |
876 Vamp::Plugin::OutputDescriptor::SampleType st; | 175 Vamp::Plugin::OutputDescriptor::SampleType st; |
877 st = (Vamp::Plugin::OutputDescriptor::SampleType) sampleKeys[PyValue_To_String(pyValue)]; | 176 st = (Vamp::Plugin::OutputDescriptor::SampleType) sampleKeys[m_conv.PyValue_To_String(pyValue)]; |
878 if (m_error) { | 177 if (m_conv.error) { |
879 std::string msg = "Unexpected value passed as SampleType. Must be one of { OneSamplePerStep,FixedSampleRate,VariableSampleRate }\n(an integer in the range of 0..2) or a string value naming the type."; | 178 std::string msg = "Unexpected value passed as SampleType. Must be one of { OneSamplePerStep,FixedSampleRate,VariableSampleRate }\n(an integer in the range of 0..2) or a string value naming the type."; |
880 setValueError(msg,m_strict); | 179 setValueError(msg,m_strict); |
881 return Vamp::Plugin::OutputDescriptor::SampleType(); | 180 return Vamp::Plugin::OutputDescriptor::SampleType(); |
882 } | 181 } |
883 return st; | 182 return st; |
906 } | 205 } |
907 | 206 |
908 /// convert string (backward compatible) | 207 /// convert string (backward compatible) |
909 if (PyString_CheckExact(pyValue)) { | 208 if (PyString_CheckExact(pyValue)) { |
910 Vamp::Plugin::InputDomain id; | 209 Vamp::Plugin::InputDomain id; |
911 id = (PyValue_To_String(pyValue) == "FrequencyDomain")?Vamp::Plugin::FrequencyDomain:Vamp::Plugin::TimeDomain; | 210 id = (m_conv.PyValue_To_String(pyValue) == "FrequencyDomain")?Vamp::Plugin::FrequencyDomain:Vamp::Plugin::TimeDomain; |
912 if (m_error) | 211 if (m_conv.error) |
913 { | 212 { |
914 std::string msg = "Unexpected value passed as SampleType. Must be one of { TimeDomain,FrequencyDomain }\n(an integer in the range of 0..1) or a string value naming the type."; | 213 std::string msg = "Unexpected value passed as SampleType. Must be one of { TimeDomain,FrequencyDomain }\n(an integer in the range of 0..1) or a string value naming the type."; |
915 setValueError(msg,m_strict); | 214 setValueError(msg,m_strict); |
916 return Vamp::Plugin::InputDomain(); | 215 return Vamp::Plugin::InputDomain(); |
917 } | 216 } |
925 cerr << "PyTypeInterface::PyValue_To_InputDomain failed. Error: " << msg << endl; | 224 cerr << "PyTypeInterface::PyValue_To_InputDomain failed. Error: " << msg << endl; |
926 #endif | 225 #endif |
927 return Vamp::Plugin::InputDomain(); | 226 return Vamp::Plugin::InputDomain(); |
928 } | 227 } |
929 | 228 |
229 /* Convert Sample Buffers to Python */ | |
230 | |
231 /// passing the sample buffers as builtin python lists | |
232 /// Optimization: using fast sequence protocol | |
233 inline PyObject* | |
234 PyTypeInterface::InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype) | |
235 { | |
236 //create a list of lists (new references) | |
237 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels); | |
238 | |
239 // Pack samples into a Python List Object | |
240 // pyFloat/pyComplex types will always be new references, | |
241 // they will be freed when the lists are deallocated. | |
242 | |
243 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList); | |
244 for (size_t i=0; i < channels; ++i) { | |
245 | |
246 size_t arraySize; | |
247 if (dtype==Vamp::Plugin::FrequencyDomain) | |
248 arraySize = (blockSize / 2) + 1; //blockSize + 2; if cplx list isn't used | |
249 else | |
250 arraySize = blockSize; | |
251 | |
252 PyObject *pySampleList = PyList_New((Py_ssize_t) arraySize); | |
253 PyObject **pySampleListArray = PySequence_Fast_ITEMS(pySampleList); | |
254 | |
255 // Note: passing a complex list crashes the C-style plugin | |
256 // when it tries to convert it to a numpy array directly. | |
257 // This plugin will be obsolete, but we have to find a way | |
258 // to prevent such crash: possibly a numpy bug, | |
259 // works fine above 1.0.4 | |
260 | |
261 switch (dtype) //(Vamp::Plugin::TimeDomain) | |
262 { | |
263 case Vamp::Plugin::TimeDomain : | |
264 | |
265 for (size_t j = 0; j < arraySize; ++j) { | |
266 PyObject *pyFloat=PyFloat_FromDouble( | |
267 (double) inputBuffers[i][j]); | |
268 pySampleListArray[j] = pyFloat; | |
269 } | |
270 break; | |
271 | |
272 case Vamp::Plugin::FrequencyDomain : | |
273 | |
274 size_t k = 0; | |
275 for (size_t j = 0; j < arraySize; ++j) { | |
276 PyObject *pyComplex=PyComplex_FromDoubles( | |
277 (double) inputBuffers[i][k], | |
278 (double) inputBuffers[i][k+1]); | |
279 pySampleListArray[j] = pyComplex; | |
280 k += 2; | |
281 } | |
282 break; | |
283 | |
284 } | |
285 pyChannelListArray[i] = pySampleList; | |
286 } | |
287 return pyChannelList; | |
288 } | |
289 | |
290 /// numpy buffer interface: passing the sample buffers as shared memory buffers | |
291 /// Optimization: using sequence protocol for creating the buffer list | |
292 inline PyObject* | |
293 PyTypeInterface::InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype) | |
294 { | |
295 //create a list of buffers (returns new references) | |
296 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels); | |
297 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList); | |
298 | |
299 // Expose memory using the Buffer Interface. | |
300 // This will pass a pointer which can be recasted in Python code | |
301 // as complex or float array using Numpy's frombuffer() method | |
302 // (this will not copy values just keep the starting adresses | |
303 // for each channel in a list) | |
304 Py_ssize_t bufferSize; | |
305 | |
306 if (dtype==Vamp::Plugin::FrequencyDomain) | |
307 bufferSize = (Py_ssize_t) sizeof(float) * (blockSize+2); | |
308 else | |
309 bufferSize = (Py_ssize_t) sizeof(float) * blockSize; | |
310 | |
311 for (size_t i=0; i < channels; ++i) { | |
312 PyObject *pyBuffer = PyBuffer_FromMemory | |
313 ((void *) (float *) inputBuffers[i],bufferSize); | |
314 pyChannelListArray[i] = pyBuffer; | |
315 } | |
316 return pyChannelList; | |
317 } | |
318 | |
319 | |
320 /// numpy array interface: passing the sample buffers as 2D numpy array | |
321 /// Optimization: using array API (needs numpy headers) | |
322 #ifdef HAVE_NUMPY | |
323 inline PyObject* | |
324 PyTypeInterface::InputBuffers_As_NumpyArray(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype) | |
325 { | |
326 /* | |
327 NOTE: We create a list of 1D Numpy arrays for each channel instead | |
328 of a matrix, because the address space of inputBuffers doesn't seem | |
329 to be continuous. Although the array strides could be calculated for | |
330 2 channels (i.e. inputBuffers[1] - inputBuffers[0]) i'm not sure | |
331 if this can be trusted, especially for more than 2 channels. | |
332 | |
333 cerr << "First channel: " << inputBuffers[0][0] << " address: " << inputBuffers[0] << endl; | |
334 if (channels == 2) | |
335 cerr << "Second channel: " << inputBuffers[1][0] << " address: " << inputBuffers[1] << endl; | |
336 | |
337 */ | |
338 | |
339 // create a list of arrays (returns new references) | |
340 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels); | |
341 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList); | |
342 | |
343 // Expose memory using the Numpy Array Interface. | |
344 // This will wrap an array objects around the data. | |
345 // (will not copy values just steal the starting adresses) | |
346 | |
347 int arraySize, typenum; | |
348 | |
349 switch (dtype) | |
350 { | |
351 case Vamp::Plugin::TimeDomain : | |
352 typenum = dtype_float32; //NPY_FLOAT; | |
353 arraySize = (int) blockSize; | |
354 break; | |
355 | |
356 case Vamp::Plugin::FrequencyDomain : | |
357 typenum = dtype_complex64; //NPY_CFLOAT; | |
358 arraySize = (int) (blockSize / 2) + 1; | |
359 break; | |
360 | |
361 default : | |
362 cerr << "PyTypeInterface::InputBuffers_As_NumpyArray: Error: Unsupported numpy array data type." << endl; | |
363 return pyChannelList; | |
364 } | |
365 | |
366 // size for each dimension | |
367 npy_intp ndims[1]={arraySize}; | |
368 | |
369 for (size_t i=0; i < channels; ++i) { | |
370 PyObject *pyChannelArray = | |
371 //args: (dimensions, size in each dim, type kind, pointer to continuous array) | |
372 PyArray_SimpleNewFromData(1, ndims, typenum, (void*) inputBuffers[i]); | |
373 // make it read-only: set all flags to false except NPY_C_CONTIGUOUS | |
374 //!!! what about NPY_ARRAY_OWNDATA? | |
375 PyArray_CLEARFLAGS((PyArrayObject *)pyChannelArray, 0xff); | |
376 PyArray_ENABLEFLAGS((PyArrayObject *)pyChannelArray, NPY_ARRAY_C_CONTIGUOUS); | |
377 pyChannelListArray[i] = pyChannelArray; | |
378 } | |
379 return pyChannelList; | |
380 } | |
381 #endif | |
930 | 382 |
931 /// OutputDescriptor | 383 /// OutputDescriptor |
932 void | 384 void |
933 PyTypeInterface::SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const | 385 PyTypeInterface::SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const |
934 { | 386 { |
1071 } | 523 } |
1072 return found; | 524 return found; |
1073 } | 525 } |
1074 | 526 |
1075 | 527 |
1076 /* Error handling */ | 528 /* Error handling */ |
1077 | 529 |
1078 void | 530 void |
1079 PyTypeInterface::setValueError (std::string message, bool strict) const | 531 PyTypeInterface::setValueError (std::string message, bool strict) const |
1080 { | 532 { |
1081 m_error = true; | 533 m_error = true; |
1082 m_errorQueue.push(ValueError(message,strict)); | 534 m_errorQueue.push(ValueError(message,strict)); |
1083 } | 535 } |
1084 | 536 |
1085 /// return a reference to the last error or creates a new one. | 537 /// return a reference to the last error or creates a new one. |
1086 PyTypeInterface::ValueError& | 538 ValueError& |
1087 PyTypeInterface::lastError() const | 539 PyTypeInterface::lastError() const |
1088 { | 540 { |
1089 m_error = false; | 541 m_error = false; |
1090 if (!m_errorQueue.empty()) return m_errorQueue.back(); | 542 if (!m_errorQueue.empty()) return m_errorQueue.back(); |
1091 else { | 543 else { |
1094 } | 546 } |
1095 } | 547 } |
1096 | 548 |
1097 /// helper function to iterate over the error message queue: | 549 /// helper function to iterate over the error message queue: |
1098 /// pops the oldest item | 550 /// pops the oldest item |
1099 PyTypeInterface::ValueError | 551 ValueError |
1100 PyTypeInterface::getError() const | 552 PyTypeInterface::getError() const |
1101 { | 553 { |
1102 if (!m_errorQueue.empty()) { | 554 if (!m_errorQueue.empty()) { |
1103 PyTypeInterface::ValueError e = m_errorQueue.front(); | 555 ValueError e = m_errorQueue.front(); |
1104 m_errorQueue.pop(); | 556 m_errorQueue.pop(); |
1105 if (m_errorQueue.empty()) m_error = false; | 557 if (m_errorQueue.empty()) m_error = false; |
1106 return e; | 558 return e; |
1107 } | 559 } |
1108 else { | 560 else { |
1109 m_error = false; | 561 m_error = false; |
1110 return PyTypeInterface::ValueError(); | 562 return ValueError(); |
1111 } | 563 } |
1112 } | 564 } |
1113 | 565 |
1114 /* Utilities */ | 566 /* Utilities */ |
1115 | |
1116 /// get the type name of an object | |
1117 std::string | |
1118 PyTypeInterface::PyValue_Get_TypeName(PyObject* pyValue) const | |
1119 { | |
1120 PyObject *pyType = PyObject_Type(pyValue); | |
1121 if (!pyType) | |
1122 { | |
1123 cerr << "Warning: Object type name could not be found." << endl; | |
1124 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} | |
1125 return std::string ("< unknown type >"); | |
1126 } | |
1127 PyObject *pyString = PyObject_Str(pyType); | |
1128 if (!pyString) | |
1129 { | |
1130 cerr << "Warning: Object type name could not be found." << endl; | |
1131 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} | |
1132 Py_CLEAR(pyType); | |
1133 return std::string ("< unknown type >"); | |
1134 } | |
1135 char *cstr = PyString_AS_STRING(pyString); | |
1136 if (!cstr) | |
1137 { | |
1138 cerr << "Warning: Object type name could not be found." << endl; | |
1139 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} | |
1140 Py_DECREF(pyType); | |
1141 Py_CLEAR(pyString); | |
1142 return std::string("< unknown type >"); | |
1143 } | |
1144 Py_DECREF(pyType); | |
1145 Py_DECREF(pyString); | |
1146 return std::string(cstr); | |
1147 | |
1148 } | |
1149 | 567 |
1150 bool | 568 bool |
1151 PyTypeInterface::initMaps() const | 569 PyTypeInterface::initMaps() const |
1152 { | 570 { |
1153 | 571 |