comparison PyPlugin.cpp @ 6:e1b508f2f914

Added support to memory buffers to be used with NumPy (and some rationalisation of code)
author fazekasgy
date Wed, 19 Mar 2008 16:02:29 +0000
parents 134313c59d82
children a4c955e9a70b
comparison
equal deleted inserted replaced
5:6ed5ebd38fde 6:e1b508f2f914
55 #define pathsep ('\\') 55 #define pathsep ('\\')
56 #else 56 #else
57 #define pathsep ('/') 57 #define pathsep ('/')
58 #endif 58 #endif
59 59
60 #define _DEBUG 60 //#define _DEBUG
61 61
62 using std::string; 62 using std::string;
63 using std::vector; 63 using std::vector;
64 using std::cerr; 64 using std::cerr;
65 using std::endl; 65 using std::endl;
70 static std::map<std::string, eSampleTypes> sampleKeys; 70 static std::map<std::string, eSampleTypes> sampleKeys;
71 static std::map<std::string, eFeatureFields> ffKeys; 71 static std::map<std::string, eFeatureFields> ffKeys;
72 static std::map<std::string, p::eParmDescriptors> parmKeys; 72 static std::map<std::string, p::eParmDescriptors> parmKeys;
73 73
74 Mutex PyPlugin::m_pythonInterpreterMutex; 74 Mutex PyPlugin::m_pythonInterpreterMutex;
75 75 static bool isMapInitialised = false;
76 void initMaps()
77 {
78 outKeys["identifier"] = identifier;
79 outKeys["name"] = name;
80 outKeys["description"] = description;
81 outKeys["unit"] = unit;
82 outKeys["hasFixedBinCount"] = hasFixedBinCount;
83 outKeys["binCount"] = binCount;
84 outKeys["binNames"] = binNames;
85 outKeys["hasKnownExtents"] = hasKnownExtents;
86 outKeys["minValue"] = minValue;
87 outKeys["maxValue"] = maxValue;
88 outKeys["isQuantized"] = isQuantized;
89 outKeys["quantizeStep"] = quantizeStep;
90 outKeys["sampleType"] = sampleType;
91 outKeys["sampleRate"] = sampleRate;
92
93 sampleKeys["OneSamplePerStep"] = OneSamplePerStep;
94 sampleKeys["FixedSampleRate"] = FixedSampleRate;
95 sampleKeys["VariableSampleRate"] = VariableSampleRate;
96
97 ffKeys["hasTimestamp"] = hasTimestamp;
98 ffKeys["timeStamp"] = timeStamp;
99 ffKeys["values"] = values;
100 ffKeys["label"] = label;
101
102 parmKeys["identifier"] = p::identifier;
103 parmKeys["name"] = p::name;
104 parmKeys["description"] = p::description;
105 parmKeys["unit"] = p::unit;
106 parmKeys["minValue"] = p::minValue;
107 parmKeys["maxValue"] = p::maxValue;
108 parmKeys["defaultValue"] = p::defaultValue;
109 parmKeys["isQuantized"] = p::isQuantized;
110
111 }
112
113
114 //missing API helper: convert Python list to C++ vector of strings
115 //TODO: these could be templates if we need more of this kind
116 std::vector<std::string> PyList_To_StringVector (PyObject *inputList) {
117
118 std::vector<std::string> Output;
119 std::string ListElement;
120 PyObject *pyString = NULL;
121
122 if (!PyList_Check(inputList)) return Output;
123
124 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
125 //Get next list item (Borrowed Reference)
126 pyString = PyList_GET_ITEM(inputList,i);
127 ListElement = (string) PyString_AsString(PyObject_Str(pyString));
128 Output.push_back(ListElement);
129 }
130 return Output;
131 }
132
133 //missing API helper: convert Python list to C++ vector of floats
134 std::vector<float> PyList_As_FloatVector (PyObject *inputList) {
135
136 std::vector<float> Output;
137 float ListElement;
138 PyObject *pyFloat = NULL;
139
140 if (!PyList_Check(inputList)) return Output;
141
142 for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) {
143 //Get next list item (Borrowed Reference)
144 pyFloat = PyList_GET_ITEM(inputList,k);
145 ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
146 Output.push_back(ListElement);
147 }
148
149 return Output;
150 }
151
152 /* TODO: find out why this produces error, also
153 do sg more clever about handling RealTime
154 Vamp::RealTime
155 PyFrame_As_RealTime (PyObject *frameNo,size_t inputSampleRate) {
156 Vamp::RealTime result =
157 Vamp::RealTime::frame2RealTime((size_t)PyInt_AS_LONG(frameNo), inputSampleRate);
158 return result;
159 }
160 */
161
162 76
163 PyPlugin::PyPlugin(std::string pluginKey,float inputSampleRate, PyObject *pyInstance) : 77 PyPlugin::PyPlugin(std::string pluginKey,float inputSampleRate, PyObject *pyInstance) :
164 Plugin(inputSampleRate), 78 Plugin(inputSampleRate),
165 m_pyInstance(pyInstance), 79 m_pyInstance(pyInstance),
166 m_stepSize(0), 80 m_stepSize(0),
167 m_previousSample(0.0f), 81 m_blockSize(0),
82 m_channels(0),
168 m_plugin(pluginKey), 83 m_plugin(pluginKey),
169 m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)), 84 m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)),
170 m_path((pluginKey.substr(0,pluginKey.rfind(pathsep)))) 85 m_path((pluginKey.substr(0,pluginKey.rfind(pathsep)))),
86 m_processType(0),
87 m_pyProcess(NULL),
88 m_inputDomain(TimeDomain)
171 { 89 {
172 } 90 }
173 91
174 PyPlugin::~PyPlugin() 92 PyPlugin::~PyPlugin()
175 { 93 {
94 Py_CLEAR(m_pyProcess);
95 #ifdef _DEBUG
176 cerr << "PyPlugin::PyPlugin:" << m_class 96 cerr << "PyPlugin::PyPlugin:" << m_class
177 << " Instance deleted." << endl; 97 << " Instance deleted." << endl;
98 #endif
178 } 99 }
179 100
180 101
181 string 102 string
182 PyPlugin::getIdentifier() const 103 PyPlugin::getIdentifier() const
183 { 104 {
184 MutexLocker locker(&m_pythonInterpreterMutex); 105 MutexLocker locker(&m_pythonInterpreterMutex);
185 106
186 char method[]="getIdentifier"; 107 char method[]="getIdentifier";
187 cerr << "[call] " << method << endl; 108 cerr << "[call] " << method << endl;
188 string rString="VampPy-x"; 109 string rString="vampy-x";
189 110
190 if ( PyObject_HasAttrString(m_pyInstance,method) ) { 111 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
191 112
192 //Call the method 113 //Call the method
193 PyObject *pyString = 114 PyObject *pyString =
201 return rString; 122 return rString;
202 } 123 }
203 124
204 rString=PyString_AsString(pyString); 125 rString=PyString_AsString(pyString);
205 Py_CLEAR(pyString); 126 Py_CLEAR(pyString);
127 return rString;
206 } 128 }
207 cerr << "Warning: Plugin must return a unique identifier." << endl; 129 cerr << "Warning: Plugin must return a unique identifier." << endl;
208 return rString; 130 return rString;
209 } 131 }
210 132
334 256
335 257
336 bool 258 bool
337 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) 259 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
338 { 260 {
339 MutexLocker locker(&m_pythonInterpreterMutex); 261
340 262 //placing Mutex before these calls causes deadlock
341 if (channels < getMinChannelCount() || 263 if (channels < getMinChannelCount() ||
342 channels > getMaxChannelCount()) return false; 264 channels > getMaxChannelCount()) return false;
343 265
344 m_stepSize = std::min(stepSize, blockSize); 266 m_inputDomain = getInputDomain();
267
268 MutexLocker locker(&m_pythonInterpreterMutex);
269
270 //useful for debugging Python plugins
345 char method[]="initialise"; 271 char method[]="initialise";
346 cerr << "[call] " << method << endl; 272 cerr << "[call] " << method << endl;
347 273
274 initMaps();
275
276 m_stepSize = stepSize;
277 m_blockSize = blockSize;
278 m_channels = channels;
279
280 //quering process implementation type
281 char legacyMethod[]="process";
282 char numpyMethod[]="processN";
283 m_processType = 0;
284
285 if (PyObject_HasAttrString(m_pyInstance,legacyMethod))
286 {
287 m_processType = legacyProcess;
288 m_pyProcess = PyString_FromString(legacyMethod);
289 }
290
291 if (PyObject_HasAttrString(m_pyInstance,numpyMethod))
292 {
293 m_processType = numpyProcess;
294 m_pyProcess = PyString_FromString(numpyMethod);
295 }
296
297 if (!m_processType)
298 {
299 m_processType = not_implemented;
300 m_pyProcess = NULL;
301 cerr << "Warning: Python plugin [" << m_class << "::" << method
302 << "] No process implementation found. Plugin will do nothing." << endl;
303 }
304
305
348 //Check if the method is implemented in Python else return false 306 //Check if the method is implemented in Python else return false
349 if (PyObject_HasAttrString(m_pyInstance,method)) { 307 if (PyObject_HasAttrString(m_pyInstance,method)) {
350 308
351 PyObject *pyMethod = PyString_FromString(method); 309 PyObject *pyMethod = PyString_FromString(method);
352 PyObject *pyChannels = PyInt_FromSsize_t((Py_ssize_t)channels); 310 PyObject *pyChannels = PyInt_FromSsize_t((Py_ssize_t)channels);
377 return true; 335 return true;
378 } else { 336 } else {
379 Py_CLEAR(pyBool); 337 Py_CLEAR(pyBool);
380 return false;} 338 return false;}
381 } 339 }
382 return true; 340 return false;
383 } 341 }
384 342
385 void 343 void
386 PyPlugin::reset() 344 PyPlugin::reset()
387 { 345 {
388 //!!! implement this! 346 MutexLocker locker(&m_pythonInterpreterMutex);
389 m_previousSample = 0.0f; 347
390 } 348 char method[]="reset";
391 349 cerr << "[call] " << method << endl;
392 PyPlugin::InputDomain PyPlugin::getInputDomain() const 350
351 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
352
353 PyObject_CallMethod(m_pyInstance, method, NULL);
354 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
355
356 }
357 }
358
359 PyPlugin::InputDomain PyPlugin::getInputDomain() const
393 { 360 {
394 MutexLocker locker(&m_pythonInterpreterMutex); 361 MutexLocker locker(&m_pythonInterpreterMutex);
395 362
396 char method[]="getInputDomain"; 363 char method[]="getInputDomain";
397 cerr << "[call] " << method << endl; 364 cerr << "[call] " << method << endl;
414 Py_CLEAR(pyString); 381 Py_CLEAR(pyString);
415 } 382 }
416 return rValue; 383 return rValue;
417 } 384 }
418 385
386
419 size_t PyPlugin::getPreferredBlockSize() const 387 size_t PyPlugin::getPreferredBlockSize() const
420 { 388 {
421 MutexLocker locker(&m_pythonInterpreterMutex); 389 MutexLocker locker(&m_pythonInterpreterMutex);
422 390
423 char method[]="getPreferredBlockSize"; 391 char method[]="getPreferredBlockSize";
515 483
516 484
517 PyPlugin::OutputList 485 PyPlugin::OutputList
518 PyPlugin::getOutputDescriptors() const 486 PyPlugin::getOutputDescriptors() const
519 { 487 {
520 MutexLocker locker(&m_pythonInterpreterMutex); 488
521 489 MutexLocker locker(&m_pythonInterpreterMutex);
490
522 //PyEval_AcquireThread(newThreadState); 491 //PyEval_AcquireThread(newThreadState);
523 OutputList list; 492 OutputList list;
524 OutputDescriptor od; 493 OutputDescriptor od;
525 char method[]="getOutputDescriptors"; 494 char method[]="getOutputDescriptors";
526 cerr << "[call] " << method << endl; 495 cerr << "[call] " << method << endl;
527 496
528 //Check if the method is implemented in Python 497 //Check if the method is implemented in Python
529 if ( PyObject_HasAttrString(m_pyInstance,method) ) { 498 if ( ! PyObject_HasAttrString(m_pyInstance,method) ) return list;
530 499
531 //Call the method: must return list object (new reference) 500 //Call the method: must return list object (new reference)
532 PyObject *pyList = 501 PyObject *pyList =
533 PyObject_CallMethod(m_pyInstance,method, NULL); 502 PyObject_CallMethod(m_pyInstance,method, NULL);
534 503
605 case sampleRate: 574 case sampleRate:
606 od.sampleRate = (float) PyFloat_AS_DOUBLE(pyValue); 575 od.sampleRate = (float) PyFloat_AS_DOUBLE(pyValue);
607 break; 576 break;
608 default : 577 default :
609 cerr << "Invalid key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl; 578 cerr << "Invalid key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl;
610 } // switch 579 }
611 } // while dict keys 580 } // while dict
612 list.push_back(od); 581 list.push_back(od);
613 } // for each memeber in outputlist 582 } // for list
614 Py_CLEAR(pyList); 583 Py_CLEAR(pyList);
615 } // if method is implemented
616 //PyEval_ReleaseThread(newThreadState);
617 return list; 584 return list;
618 } 585 }
619 586
620 PyPlugin::ParameterList 587 PyPlugin::ParameterList
621 PyPlugin::getParameterDescriptors() const 588 PyPlugin::getParameterDescriptors() const
626 ParameterDescriptor pd; 593 ParameterDescriptor pd;
627 char method[]="getParameterDescriptors"; 594 char method[]="getParameterDescriptors";
628 cerr << "[call] " << method << endl; 595 cerr << "[call] " << method << endl;
629 596
630 //Check if the method is implemented in Python 597 //Check if the method is implemented in Python
631 if ( PyObject_HasAttrString(m_pyInstance,method) ) { 598 if ( ! PyObject_HasAttrString(m_pyInstance,method) ) return list;
632 599
633 //Call the method: must return list object (new reference) 600 //Call the method: must return list object (new reference)
634 PyObject *pyList = 601 PyObject *pyList =
635 PyObject_CallMethod(m_pyInstance,method, NULL); 602 PyObject_CallMethod(m_pyInstance,method, NULL);
636 603
690 case p::isQuantized: 657 case p::isQuantized:
691 pd.isQuantized = (bool) PyInt_AS_LONG(pyValue); 658 pd.isQuantized = (bool) PyInt_AS_LONG(pyValue);
692 break; 659 break;
693 default : 660 default :
694 cerr << "Invalid key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl; 661 cerr << "Invalid key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl;
695 } // switch 662 }
696 } // while dict keys 663 } // while dict
697 list.push_back(pd); 664 list.push_back(pd);
698 } // for each memeber in outputlist 665 } // for list
699 Py_CLEAR(pyList); 666 Py_CLEAR(pyList);
700 } // if
701 return list; 667 return list;
702 } 668 }
703 669
704 void PyPlugin::setParameter(std::string paramid, float newval) 670 void PyPlugin::setParameter(std::string paramid, float newval)
705 { 671 {
777 PyPlugin::process(const float *const *inputBuffers, 743 PyPlugin::process(const float *const *inputBuffers,
778 Vamp::RealTime timestamp) 744 Vamp::RealTime timestamp)
779 { 745 {
780 MutexLocker locker(&m_pythonInterpreterMutex); 746 MutexLocker locker(&m_pythonInterpreterMutex);
781 747
782 if (m_stepSize == 0) { 748 #ifdef _DEBUG
749 cerr << "[call] process, frame:" << proccounter << endl;
750 proccounter++;
751 #endif
752
753 if (m_blockSize == 0) {
783 cerr << "ERROR: PyPlugin::process: " 754 cerr << "ERROR: PyPlugin::process: "
784 << "Plugin has not been initialised" << endl; 755 << "Plugin has not been initialised" << endl;
785 return FeatureSet(); 756 return FeatureSet();
786 } 757 }
787 static char method[]="process"; 758
788 759 if (m_processType == not_implemented) {
789 #ifdef _DEBUG 760 cerr << "ERROR: In Python plugin [" << m_class
790 cerr << "[call] " << method << " frame:" << proccounter << endl; 761 << "] No process implementation found. Returning empty feature set." << endl;
791 proccounter++; 762 return FeatureSet();
792 //cerr << "C: proc..." << proccounter << " " << endl; 763 }
793 #endif 764
794 765 string method=PyString_AsString(m_pyProcess);
795 //proces::Check if the method is implemented in Python 766
796 if ( PyObject_HasAttrString(m_pyInstance,method) ) 767
797 { 768
798 769 PyObject *pyOutputList = NULL;
799 //Pack method name into Python Object 770
800 PyObject *pyMethod = PyString_FromString(method); 771 /*new numPy support*/
772 if (m_processType == numpyProcess) {
773
774 //declare buffer object
775 PyObject *pyBuffer;
776
777 //Expose memory using the Buffer Interface of C/API
778 //This will virtually pass a pointer only that can be
779 //recasted in Python code
780 pyBuffer =
781 PyBuffer_FromMemory((void *) (float *) inputBuffers[0],
782 (Py_ssize_t) sizeof(float) * m_blockSize);
783
784 //Call python process (returns new reference)
785 pyOutputList =
786 PyObject_CallMethodObjArgs(m_pyInstance,m_pyProcess,pyBuffer,NULL);
787
788 }
789
790 if (m_processType == legacyProcess) {
801 791
802 //Declare new list object 792 //Declare new list object
803 PyObject *pyFloat, *pyList; 793 PyObject *pyFloat, *pyList;
804 pyList = PyList_New((Py_ssize_t) m_stepSize); 794 pyList = PyList_New((Py_ssize_t) m_blockSize);
805 795
806 //Pack samples into a Python List Object 796 //Pack samples into a Python List Object
807 //pyFloat will always be new references, 797 //pyFloat types will always be new references,
808 //these will be discarded when the list is deallocated 798 //these will be discarded when the list is deallocated
809 for (size_t i = 0; i < m_stepSize; ++i) { 799 for (size_t i = 0; i < m_blockSize; ++i) {
810 pyFloat=PyFloat_FromDouble((double) inputBuffers[0][i]); 800 pyFloat=PyFloat_FromDouble((double) inputBuffers[0][i]);
811 PyList_SET_ITEM(pyList, (Py_ssize_t) i, pyFloat); 801 PyList_SET_ITEM(pyList, (Py_ssize_t) i, pyFloat);
812 } 802 }
813 803
814 //Call python process (returns new reference) 804 //Call python process (returns new reference)
815 PyObject *pyOutputList = 805 pyOutputList =
816 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyList,NULL); 806 PyObject_CallMethodObjArgs(m_pyInstance,m_pyProcess,pyList,NULL);
807
808 }
809
817 810
818 //Check return type 811 //Check return type
819 if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) { 812 if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) {
820 if (pyOutputList == NULL) { 813 if (pyOutputList == NULL) {
821 cerr << "ERROR: In Python plugin [" << m_class << "::" << method 814 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
823 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } 816 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
824 } else { 817 } else {
825 cerr << "ERROR: In Python plugin [" << m_class << "::" << method 818 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
826 << "] Expected List return type." << endl; 819 << "] Expected List return type." << endl;
827 } 820 }
828 Py_CLEAR(pyMethod); 821 //Py_CLEAR(pyMethod);
829 Py_CLEAR(pyOutputList); 822 Py_CLEAR(pyOutputList);
830 return FeatureSet(); 823 return FeatureSet();
831 } 824 }
832 825
833 Py_DECREF(pyMethod); 826 //Py_DECREF(pyMethod);
834 // Py_DECREF(pyList); 827 // Py_DECREF(pyList);
835 // This appears to be tracked by the cyclic garbage collector 828 // This appears to be tracked by the cyclic garbage collector
836 // hence decrefing produces GC error 829 // hence decrefing produces GC error
837 #ifdef _DEBUG 830 #ifdef _DEBUG
838 cerr << "Process Returned Features" << endl; 831 cerr << "Process Returned Features" << endl;
900 }// for j = FeatureList 893 }// for j = FeatureList
901 894
902 }//for i = FeatureSet 895 }//for i = FeatureSet
903 Py_CLEAR(pyOutputList); 896 Py_CLEAR(pyOutputList);
904 return returnFeatures; 897 return returnFeatures;
905
906 }//if (has_attribute)
907 return FeatureSet();
908 } 898 }
909 899
910 900
911 901
912 PyPlugin::FeatureSet 902 PyPlugin::FeatureSet
992 }//for i 982 }//for i
993 Py_CLEAR(pyOutputList); 983 Py_CLEAR(pyOutputList);
994 return returnFeatures; 984 return returnFeatures;
995 } 985 }
996 986
987 bool
988 PyPlugin::initMaps() const
989 {
990
991 if (isMapInitialised) return true;
992
993 outKeys["identifier"] = identifier;
994 outKeys["name"] = name;
995 outKeys["description"] = description;
996 outKeys["unit"] = unit;
997 outKeys["hasFixedBinCount"] = hasFixedBinCount;
998 outKeys["binCount"] = binCount;
999 outKeys["binNames"] = binNames;
1000 outKeys["hasKnownExtents"] = hasKnownExtents;
1001 outKeys["minValue"] = minValue;
1002 outKeys["maxValue"] = maxValue;
1003 outKeys["isQuantized"] = isQuantized;
1004 outKeys["quantizeStep"] = quantizeStep;
1005 outKeys["sampleType"] = sampleType;
1006 outKeys["sampleRate"] = sampleRate;
1007
1008 sampleKeys["OneSamplePerStep"] = OneSamplePerStep;
1009 sampleKeys["FixedSampleRate"] = FixedSampleRate;
1010 sampleKeys["VariableSampleRate"] = VariableSampleRate;
1011
1012 ffKeys["hasTimestamp"] = hasTimestamp;
1013 ffKeys["timeStamp"] = timeStamp;
1014 ffKeys["values"] = values;
1015 ffKeys["label"] = label;
1016
1017 parmKeys["identifier"] = p::identifier;
1018 parmKeys["name"] = p::name;
1019 parmKeys["description"] = p::description;
1020 parmKeys["unit"] = p::unit;
1021 parmKeys["minValue"] = p::minValue;
1022 parmKeys["maxValue"] = p::maxValue;
1023 parmKeys["defaultValue"] = p::defaultValue;
1024 parmKeys["isQuantized"] = p::isQuantized;
1025
1026 isMapInitialised = true;
1027 return true;
1028 }
1029
1030
1031 //missing API helper: convert Python list to C++ vector of strings
1032 //TODO: these could be templates if we need more of this kind
1033 std::vector<std::string>
1034 PyPlugin::PyList_To_StringVector (PyObject *inputList) const {
1035
1036 std::vector<std::string> Output;
1037 std::string ListElement;
1038 PyObject *pyString = NULL;
1039
1040 if (!PyList_Check(inputList)) return Output;
1041
1042 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
1043 //Get next list item (Borrowed Reference)
1044 pyString = PyList_GET_ITEM(inputList,i);
1045 ListElement = (string) PyString_AsString(PyObject_Str(pyString));
1046 Output.push_back(ListElement);
1047 }
1048 return Output;
1049 }
1050
1051 //missing API helper: convert Python list to C++ vector of floats
1052 std::vector<float>
1053 PyPlugin::PyList_As_FloatVector (PyObject *inputList) const {
1054
1055 std::vector<float> Output;
1056 float ListElement;
1057 PyObject *pyFloat = NULL;
1058
1059 if (!PyList_Check(inputList)) return Output;
1060
1061 for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) {
1062 //Get next list item (Borrowed Reference)
1063 pyFloat = PyList_GET_ITEM(inputList,k);
1064 ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
1065 Output.push_back(ListElement);
1066 }
1067
1068 return Output;
1069 }
1070
1071 /* TODO: find out why this produces error, also
1072 do sg more clever about handling RealTime
1073 Vamp::RealTime
1074 PyFrame_As_RealTime (PyObject *frameNo,size_t inputSampleRate) {
1075 Vamp::RealTime result =
1076 Vamp::RealTime::frame2RealTime((size_t)PyInt_AS_LONG(frameNo), inputSampleRate);
1077 return result;
1078 }
1079 */
1080