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