Mercurial > hg > vampy
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 |