cannam@18
|
1 /* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */
|
fazekasgy@0
|
2 /*
|
fazekasgy@0
|
3 Vamp
|
fazekasgy@0
|
4
|
fazekasgy@0
|
5 An API for audio analysis and feature extraction plugins.
|
fazekasgy@0
|
6
|
fazekasgy@0
|
7 Centre for Digital Music, Queen Mary, University of London.
|
fazekasgy@0
|
8 Copyright 2006 Chris Cannam.
|
fazekasgy@0
|
9
|
fazekasgy@0
|
10 Permission is hereby granted, free of charge, to any person
|
fazekasgy@0
|
11 obtaining a copy of this software and associated documentation
|
fazekasgy@0
|
12 files (the "Software"), to deal in the Software without
|
fazekasgy@0
|
13 restriction, including without limitation the rights to use, copy,
|
fazekasgy@0
|
14 modify, merge, publish, distribute, sublicense, and/or sell copies
|
fazekasgy@0
|
15 of the Software, and to permit persons to whom the Software is
|
fazekasgy@0
|
16 furnished to do so, subject to the following conditions:
|
fazekasgy@0
|
17
|
fazekasgy@0
|
18 The above copyright notice and this permission notice shall be
|
fazekasgy@0
|
19 included in all copies or substantial portions of the Software.
|
fazekasgy@0
|
20
|
fazekasgy@0
|
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
fazekasgy@0
|
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
fazekasgy@0
|
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
fazekasgy@0
|
24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
fazekasgy@0
|
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
fazekasgy@0
|
26 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
fazekasgy@0
|
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
fazekasgy@0
|
28
|
fazekasgy@0
|
29 Except as contained in this notice, the names of the Centre for
|
fazekasgy@0
|
30 Digital Music; Queen Mary, University of London; and Chris Cannam
|
fazekasgy@0
|
31 shall not be used in advertising or otherwise to promote the sale,
|
fazekasgy@0
|
32 use or other dealings in this Software without prior written
|
fazekasgy@0
|
33 authorization.
|
fazekasgy@0
|
34 */
|
fazekasgy@0
|
35
|
fazekasgy@0
|
36
|
fazekasgy@0
|
37
|
fazekasgy@0
|
38 /**
|
fazekasgy@8
|
39 * This Vamp plugin is a wrapper for Python Scripts. (VamPy)
|
fazekasgy@0
|
40 * Centre for Digital Music, Queen Mary, University of London.
|
fazekasgy@0
|
41 * Copyright 2008, George Fazekas.
|
fazekasgy@0
|
42
|
fazekasgy@0
|
43 TODO: needs more complete error checking
|
fazekasgy@0
|
44 needs correct implementation of Python threading
|
fazekasgy@0
|
45 more efficient data conversion using the buffering interface or ctypes
|
cannam@7
|
46 Vamp programs not implemented
|
fazekasgy@0
|
47 support multiple plugins per script in scanner
|
fazekasgy@0
|
48 ensure proper cleanup, host do a good job though
|
fazekasgy@0
|
49
|
fazekasgy@0
|
50 */
|
fazekasgy@0
|
51
|
cannam@3
|
52 #include <Python.h>
|
fazekasgy@0
|
53 #include "PyPlugin.h"
|
fazekasgy@0
|
54
|
fazekasgy@0
|
55 #ifdef _WIN32
|
fazekasgy@0
|
56 #define pathsep ('\\')
|
fazekasgy@0
|
57 #else
|
fazekasgy@0
|
58 #define pathsep ('/')
|
fazekasgy@0
|
59 #endif
|
fazekasgy@0
|
60
|
fazekasgy@6
|
61 //#define _DEBUG
|
fazekasgy@0
|
62
|
fazekasgy@0
|
63 using std::string;
|
fazekasgy@0
|
64 using std::vector;
|
fazekasgy@0
|
65 using std::cerr;
|
fazekasgy@0
|
66 using std::endl;
|
fazekasgy@0
|
67 using std::map;
|
fazekasgy@0
|
68
|
fazekasgy@0
|
69 // Maps to associate strings with enum values
|
cannam@18
|
70 static std::map<std::string, o::eOutDescriptors> outKeys;
|
fazekasgy@0
|
71 static std::map<std::string, eSampleTypes> sampleKeys;
|
fazekasgy@0
|
72 static std::map<std::string, eFeatureFields> ffKeys;
|
fazekasgy@0
|
73 static std::map<std::string, p::eParmDescriptors> parmKeys;
|
fazekasgy@0
|
74
|
cannam@3
|
75 Mutex PyPlugin::m_pythonInterpreterMutex;
|
fazekasgy@6
|
76 static bool isMapInitialised = false;
|
fazekasgy@0
|
77
|
cannam@24
|
78 PyPlugin::PyPlugin(std::string pluginKey, float inputSampleRate, PyObject *pyClass) :
|
cannam@24
|
79 Plugin(inputSampleRate),
|
cannam@24
|
80 m_pyClass(pyClass),
|
fazekasgy@0
|
81 m_stepSize(0),
|
fazekasgy@6
|
82 m_blockSize(0),
|
cannam@24
|
83 m_channels(0),
|
fazekasgy@0
|
84 m_plugin(pluginKey),
|
fazekasgy@0
|
85 m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)),
|
fazekasgy@6
|
86 m_path((pluginKey.substr(0,pluginKey.rfind(pathsep)))),
|
fazekasgy@6
|
87 m_processType(0),
|
fazekasgy@6
|
88 m_pyProcess(NULL),
|
fazekasgy@6
|
89 m_inputDomain(TimeDomain)
|
fazekasgy@0
|
90 {
|
cannam@24
|
91 // Create an instance
|
fazekasgy@27
|
92 MutexLocker locker(&m_pythonInterpreterMutex);
|
fazekasgy@27
|
93 Py_INCREF(m_pyClass);
|
cannam@24
|
94 PyObject *pyInputSampleRate = PyFloat_FromDouble(inputSampleRate);
|
cannam@24
|
95 PyObject *args = PyTuple_Pack(1, pyInputSampleRate);
|
fazekasgy@27
|
96 m_pyInstance = PyObject_Call(m_pyClass, args, NULL);
|
fazekasgy@27
|
97
|
fazekasgy@27
|
98 if (!m_pyInstance || PyErr_Occurred()) {
|
fazekasgy@27
|
99 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@27
|
100 Py_CLEAR(args);
|
fazekasgy@27
|
101 Py_CLEAR(pyInputSampleRate);
|
cannam@24
|
102 cerr << "PyPlugin::PyPlugin: Failed to create Python plugin instance for key \"" << pluginKey << "\" (is the 1-arg class constructor from sample rate correctly provided?)" << endl;
|
cannam@24
|
103 throw std::string("Constructor failed");
|
cannam@24
|
104 }
|
fazekasgy@27
|
105 Py_INCREF(m_pyInstance);
|
cannam@24
|
106 Py_DECREF(args);
|
cannam@24
|
107 Py_DECREF(pyInputSampleRate);
|
fazekasgy@27
|
108
|
fazekasgy@0
|
109 }
|
fazekasgy@0
|
110
|
fazekasgy@0
|
111 PyPlugin::~PyPlugin()
|
fazekasgy@0
|
112 {
|
cannam@24
|
113 if (m_pyInstance) Py_DECREF(m_pyInstance);
|
fazekasgy@27
|
114 if (m_pyClass) Py_DECREF(m_pyClass);
|
fazekasgy@27
|
115 if (m_pyProcess) Py_CLEAR(m_pyProcess);
|
cannam@24
|
116
|
fazekasgy@6
|
117 #ifdef _DEBUG
|
fazekasgy@0
|
118 cerr << "PyPlugin::PyPlugin:" << m_class
|
cannam@24
|
119 << " Instance deleted." << endl;
|
fazekasgy@6
|
120 #endif
|
fazekasgy@0
|
121 }
|
fazekasgy@0
|
122
|
fazekasgy@0
|
123
|
fazekasgy@0
|
124 string
|
fazekasgy@0
|
125 PyPlugin::getIdentifier() const
|
fazekasgy@0
|
126 {
|
cannam@3
|
127 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
128
|
fazekasgy@0
|
129 char method[]="getIdentifier";
|
fazekasgy@0
|
130 cerr << "[call] " << method << endl;
|
fazekasgy@6
|
131 string rString="vampy-x";
|
fazekasgy@0
|
132
|
fazekasgy@0
|
133 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@0
|
134
|
fazekasgy@0
|
135 //Call the method
|
fazekasgy@0
|
136 PyObject *pyString =
|
fazekasgy@0
|
137 PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@0
|
138
|
fazekasgy@0
|
139 //Check return value
|
fazekasgy@0
|
140 if (!PyString_Check(pyString)) {
|
fazekasgy@0
|
141 Py_CLEAR(pyString);
|
fazekasgy@0
|
142 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
143 << "] Expected String return value." << endl;
|
fazekasgy@0
|
144 return rString;
|
fazekasgy@0
|
145 }
|
fazekasgy@0
|
146
|
fazekasgy@0
|
147 rString=PyString_AsString(pyString);
|
fazekasgy@0
|
148 Py_CLEAR(pyString);
|
fazekasgy@6
|
149 return rString;
|
fazekasgy@0
|
150 }
|
fazekasgy@0
|
151 cerr << "Warning: Plugin must return a unique identifier." << endl;
|
fazekasgy@0
|
152 return rString;
|
fazekasgy@0
|
153 }
|
fazekasgy@0
|
154
|
fazekasgy@0
|
155
|
fazekasgy@0
|
156 string
|
fazekasgy@0
|
157 PyPlugin::getName() const
|
fazekasgy@0
|
158 {
|
cannam@3
|
159 MutexLocker locker(&m_pythonInterpreterMutex);
|
fazekasgy@0
|
160
|
fazekasgy@0
|
161 char method[]="getName";
|
fazekasgy@0
|
162 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
163 string rString="VamPy Plugin (Noname)";
|
fazekasgy@0
|
164
|
fazekasgy@0
|
165 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@0
|
166
|
fazekasgy@0
|
167 //Call the method
|
fazekasgy@0
|
168 PyObject *pyString =
|
fazekasgy@0
|
169 PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@0
|
170
|
fazekasgy@0
|
171 //Check return value
|
fazekasgy@0
|
172 if (!PyString_Check(pyString)) {
|
fazekasgy@0
|
173 Py_CLEAR(pyString);
|
fazekasgy@0
|
174 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
175 << "] Expected String return value." << endl;
|
fazekasgy@0
|
176 return rString;
|
fazekasgy@0
|
177 }
|
fazekasgy@0
|
178
|
fazekasgy@0
|
179 rString=PyString_AsString(pyString);
|
fazekasgy@0
|
180 Py_CLEAR(pyString);
|
fazekasgy@0
|
181 }
|
fazekasgy@0
|
182 return rString;
|
fazekasgy@0
|
183 }
|
fazekasgy@0
|
184
|
fazekasgy@0
|
185 string
|
fazekasgy@0
|
186 PyPlugin::getDescription() const
|
fazekasgy@0
|
187 {
|
cannam@3
|
188 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
189
|
fazekasgy@0
|
190 char method[]="getDescription";
|
fazekasgy@0
|
191 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
192 string rString="Not given. (Hint: Implement getDescription method.)";
|
fazekasgy@0
|
193
|
fazekasgy@0
|
194 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@0
|
195
|
fazekasgy@0
|
196 //Call the method
|
fazekasgy@0
|
197 PyObject *pyString =
|
fazekasgy@0
|
198 PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@0
|
199
|
fazekasgy@0
|
200 //Check return value
|
fazekasgy@0
|
201 if (!PyString_Check(pyString)) {
|
fazekasgy@0
|
202 Py_CLEAR(pyString);
|
fazekasgy@0
|
203 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
204 << "] Expected String return value." << endl;
|
fazekasgy@0
|
205 return rString;
|
fazekasgy@0
|
206 }
|
fazekasgy@0
|
207
|
fazekasgy@0
|
208 rString=PyString_AsString(pyString);
|
fazekasgy@0
|
209 Py_CLEAR(pyString);
|
fazekasgy@0
|
210 }
|
fazekasgy@0
|
211 return rString;
|
fazekasgy@0
|
212 }
|
fazekasgy@0
|
213
|
fazekasgy@0
|
214 string
|
fazekasgy@0
|
215 PyPlugin::getMaker() const
|
fazekasgy@0
|
216 {
|
cannam@3
|
217 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
218
|
fazekasgy@0
|
219 char method[]="getMaker";
|
fazekasgy@0
|
220 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
221 string rString="Generic VamPy Plugin.";
|
fazekasgy@0
|
222
|
fazekasgy@0
|
223 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@0
|
224
|
fazekasgy@0
|
225 //Call the method
|
fazekasgy@0
|
226 PyObject *pyString =
|
fazekasgy@0
|
227 PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@0
|
228
|
fazekasgy@0
|
229 //Check return value
|
fazekasgy@0
|
230 if (!PyString_Check(pyString)) {
|
fazekasgy@0
|
231 Py_CLEAR(pyString);
|
fazekasgy@0
|
232 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
233 << "] Expected String return value." << endl;
|
fazekasgy@0
|
234 return rString;
|
fazekasgy@0
|
235 }
|
fazekasgy@0
|
236
|
fazekasgy@0
|
237 rString=PyString_AsString(pyString);
|
fazekasgy@0
|
238 Py_CLEAR(pyString);
|
fazekasgy@0
|
239 }
|
fazekasgy@0
|
240 return rString;
|
fazekasgy@0
|
241 }
|
fazekasgy@0
|
242
|
fazekasgy@0
|
243 int
|
fazekasgy@0
|
244 PyPlugin::getPluginVersion() const
|
fazekasgy@0
|
245 {
|
cannam@24
|
246 //!!! implement
|
cannam@24
|
247
|
cannam@24
|
248 return 2;
|
fazekasgy@0
|
249 }
|
fazekasgy@0
|
250
|
fazekasgy@0
|
251 string
|
fazekasgy@0
|
252 PyPlugin::getCopyright() const
|
fazekasgy@0
|
253 {
|
cannam@3
|
254 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
255
|
fazekasgy@0
|
256 char method[]="getCopyright";
|
fazekasgy@0
|
257 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
258 string rString="BSD License";
|
fazekasgy@0
|
259
|
fazekasgy@0
|
260 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@0
|
261
|
fazekasgy@0
|
262 //Call the method
|
fazekasgy@0
|
263 PyObject *pyString =
|
fazekasgy@0
|
264 PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@0
|
265
|
fazekasgy@0
|
266 //Check return value
|
fazekasgy@0
|
267 if (!PyString_Check(pyString)) {
|
fazekasgy@0
|
268 Py_CLEAR(pyString);
|
fazekasgy@0
|
269 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
270 << "] Expected String return value." << endl;
|
fazekasgy@0
|
271 return rString;
|
fazekasgy@0
|
272 }
|
fazekasgy@0
|
273
|
fazekasgy@0
|
274
|
fazekasgy@0
|
275 rString=PyString_AsString(pyString);
|
fazekasgy@0
|
276 Py_CLEAR(pyString);
|
fazekasgy@0
|
277 }
|
cannam@24
|
278
|
cannam@24
|
279 return rString;
|
fazekasgy@0
|
280 }
|
fazekasgy@0
|
281
|
fazekasgy@0
|
282
|
fazekasgy@0
|
283 bool
|
fazekasgy@0
|
284 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
fazekasgy@0
|
285 {
|
fazekasgy@8
|
286 //useful for debugging Python plugins
|
fazekasgy@8
|
287 char method[]="initialise";
|
fazekasgy@8
|
288 cerr << "[call] " << method << endl;
|
fazekasgy@6
|
289
|
fazekasgy@6
|
290 //placing Mutex before these calls causes deadlock
|
cannam@24
|
291 if (channels < getMinChannelCount() ||
|
cannam@24
|
292 channels > getMaxChannelCount()) return false;
|
fazekasgy@6
|
293
|
fazekasgy@6
|
294 m_inputDomain = getInputDomain();
|
fazekasgy@6
|
295
|
cannam@3
|
296 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
297
|
fazekasgy@6
|
298 initMaps();
|
fazekasgy@6
|
299
|
fazekasgy@6
|
300 m_stepSize = stepSize;
|
fazekasgy@6
|
301 m_blockSize = blockSize;
|
fazekasgy@6
|
302 m_channels = channels;
|
fazekasgy@6
|
303
|
fazekasgy@6
|
304 //quering process implementation type
|
fazekasgy@6
|
305 char legacyMethod[]="process";
|
fazekasgy@6
|
306 char numpyMethod[]="processN";
|
fazekasgy@6
|
307
|
cannam@18
|
308 if (PyObject_HasAttrString(m_pyInstance,legacyMethod) &&
|
cannam@18
|
309 m_processType == 0)
|
fazekasgy@6
|
310 {
|
fazekasgy@6
|
311 m_processType = legacyProcess;
|
fazekasgy@6
|
312 m_pyProcess = PyString_FromString(legacyMethod);
|
fazekasgy@6
|
313 }
|
fazekasgy@6
|
314
|
cannam@18
|
315 if (PyObject_HasAttrString(m_pyInstance,numpyMethod) &&
|
cannam@18
|
316 m_processType == 0)
|
fazekasgy@6
|
317 {
|
fazekasgy@6
|
318 m_processType = numpyProcess;
|
fazekasgy@6
|
319 m_pyProcess = PyString_FromString(numpyMethod);
|
fazekasgy@6
|
320 }
|
fazekasgy@6
|
321
|
fazekasgy@6
|
322 if (!m_processType)
|
fazekasgy@6
|
323 {
|
fazekasgy@6
|
324 m_processType = not_implemented;
|
fazekasgy@6
|
325 m_pyProcess = NULL;
|
fazekasgy@6
|
326 cerr << "Warning: Python plugin [" << m_class << "::" << method
|
cannam@24
|
327 << "] No process implementation found. Plugin will do nothing." << endl;
|
fazekasgy@6
|
328 }
|
fazekasgy@6
|
329
|
cannam@24
|
330 //Check if the method is implemented in Python else return false
|
cannam@24
|
331 if (PyObject_HasAttrString(m_pyInstance,method)) {
|
fazekasgy@0
|
332
|
cannam@24
|
333 PyObject *pyMethod = PyString_FromString(method);
|
cannam@24
|
334 PyObject *pyChannels = PyInt_FromSsize_t((Py_ssize_t)channels);
|
cannam@24
|
335 PyObject *pyStepSize = PyInt_FromSsize_t((Py_ssize_t)m_stepSize);
|
cannam@24
|
336 PyObject *pyBlockSize = PyInt_FromSsize_t((Py_ssize_t)blockSize);
|
cannam@24
|
337 //Call the method
|
cannam@24
|
338 PyObject *pyBool =
|
cannam@24
|
339 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyChannels,pyStepSize,pyBlockSize,NULL);
|
fazekasgy@8
|
340
|
cannam@24
|
341 Py_DECREF(pyMethod);
|
cannam@24
|
342 Py_DECREF(pyChannels);
|
cannam@24
|
343 Py_DECREF(pyStepSize);
|
cannam@24
|
344 Py_DECREF(pyBlockSize);
|
fazekasgy@0
|
345
|
cannam@24
|
346 //Check return value
|
cannam@24
|
347 if (PyErr_Occurred() || !PyBool_Check(pyBool)) {
|
cannam@24
|
348 PyErr_Print(); PyErr_Clear();
|
cannam@24
|
349 Py_CLEAR(pyBool);
|
cannam@24
|
350 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
cannam@24
|
351 << "] Expected Bool return value." << endl;
|
cannam@24
|
352 return false;
|
cannam@24
|
353 }
|
cannam@24
|
354
|
cannam@24
|
355 if (pyBool == Py_True) {
|
cannam@24
|
356 Py_CLEAR(pyBool);
|
cannam@24
|
357 return true;
|
cannam@24
|
358 } else {
|
cannam@24
|
359 Py_CLEAR(pyBool);
|
cannam@24
|
360 return false;
|
cannam@24
|
361 }
|
cannam@24
|
362 }
|
fazekasgy@6
|
363 return false;
|
fazekasgy@0
|
364 }
|
fazekasgy@0
|
365
|
fazekasgy@0
|
366 void
|
fazekasgy@0
|
367 PyPlugin::reset()
|
fazekasgy@0
|
368 {
|
fazekasgy@6
|
369 MutexLocker locker(&m_pythonInterpreterMutex);
|
fazekasgy@6
|
370
|
fazekasgy@6
|
371 char method[]="reset";
|
fazekasgy@6
|
372 cerr << "[call] " << method << endl;
|
fazekasgy@6
|
373
|
fazekasgy@6
|
374 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@6
|
375
|
fazekasgy@6
|
376 PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@6
|
377 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@6
|
378
|
fazekasgy@6
|
379 }
|
fazekasgy@0
|
380 }
|
fazekasgy@0
|
381
|
fazekasgy@6
|
382 PyPlugin::InputDomain PyPlugin::getInputDomain() const
|
fazekasgy@0
|
383 {
|
cannam@3
|
384 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
385
|
fazekasgy@0
|
386 char method[]="getInputDomain";
|
fazekasgy@0
|
387 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
388 PyPlugin::InputDomain rValue = TimeDomain; // TimeDomain
|
fazekasgy@0
|
389
|
fazekasgy@0
|
390 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@0
|
391
|
fazekasgy@0
|
392 PyObject *pyString = PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@0
|
393
|
fazekasgy@0
|
394 //Check return value
|
fazekasgy@0
|
395 if (!PyString_Check(pyString)) {
|
fazekasgy@0
|
396 Py_CLEAR(pyString);
|
fazekasgy@0
|
397 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
398 << "] Expected String return value." << endl;
|
fazekasgy@0
|
399 return rValue;
|
fazekasgy@0
|
400 }
|
fazekasgy@0
|
401
|
fazekasgy@0
|
402 string domain = (string) PyString_AsString(pyString);
|
fazekasgy@0
|
403 if (domain == "FrequencyDomain") rValue = FrequencyDomain;
|
fazekasgy@0
|
404 Py_CLEAR(pyString);
|
fazekasgy@0
|
405 }
|
fazekasgy@0
|
406 return rValue;
|
fazekasgy@0
|
407 }
|
fazekasgy@0
|
408
|
fazekasgy@6
|
409
|
fazekasgy@0
|
410 size_t PyPlugin::getPreferredBlockSize() const
|
fazekasgy@0
|
411 {
|
cannam@3
|
412 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
413
|
fazekasgy@0
|
414 char method[]="getPreferredBlockSize";
|
fazekasgy@0
|
415 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
416 size_t rValue=0; //not set by default
|
fazekasgy@0
|
417 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@0
|
418 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@0
|
419
|
fazekasgy@0
|
420 //Check return value
|
fazekasgy@0
|
421 if (!PyInt_Check(pyInt)) {
|
fazekasgy@0
|
422 Py_CLEAR(pyInt);
|
fazekasgy@0
|
423 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
424 << "] Expected Integer return value." << endl;
|
fazekasgy@0
|
425 return rValue;
|
fazekasgy@0
|
426 }
|
fazekasgy@0
|
427
|
fazekasgy@0
|
428 rValue=(size_t)PyInt_AS_LONG(pyInt);
|
fazekasgy@0
|
429 Py_CLEAR(pyInt);
|
fazekasgy@0
|
430 }
|
fazekasgy@0
|
431 return rValue;
|
fazekasgy@0
|
432 }
|
fazekasgy@0
|
433
|
fazekasgy@0
|
434 //size_t PyPlugin::getPreferredStepSize() const { return 0; }
|
fazekasgy@0
|
435 size_t PyPlugin::getPreferredStepSize() const
|
fazekasgy@0
|
436 {
|
cannam@3
|
437 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
438
|
fazekasgy@0
|
439 char method[]="getPreferredStepSize";
|
fazekasgy@0
|
440 cerr << "[call] " << method << endl;
|
fazekasgy@8
|
441 size_t rValue=1024; //not set by default
|
fazekasgy@0
|
442 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@0
|
443 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@0
|
444
|
fazekasgy@0
|
445 //Check return value
|
fazekasgy@0
|
446 if (!PyInt_Check(pyInt)) {
|
fazekasgy@0
|
447 Py_CLEAR(pyInt);
|
fazekasgy@0
|
448 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
449 << "] Expected Integer return value." << endl;
|
fazekasgy@0
|
450 return rValue;
|
fazekasgy@0
|
451 }
|
fazekasgy@0
|
452
|
fazekasgy@0
|
453 rValue=(size_t)PyInt_AS_LONG(pyInt);
|
fazekasgy@0
|
454 Py_CLEAR(pyInt);
|
fazekasgy@0
|
455 }
|
fazekasgy@0
|
456 return rValue;
|
fazekasgy@0
|
457 }
|
fazekasgy@0
|
458
|
fazekasgy@0
|
459 size_t PyPlugin::getMinChannelCount() const
|
fazekasgy@0
|
460 {
|
cannam@3
|
461 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
462
|
fazekasgy@0
|
463 char method[]="getMinChannelCount";
|
fazekasgy@0
|
464 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
465 size_t rValue=1; //default value
|
fazekasgy@0
|
466 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@0
|
467 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@0
|
468
|
fazekasgy@0
|
469 //Check return value
|
fazekasgy@0
|
470 if (!PyInt_Check(pyInt)) {
|
fazekasgy@0
|
471 Py_CLEAR(pyInt);
|
fazekasgy@0
|
472 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
473 << "] Expected String return value." << endl;
|
fazekasgy@0
|
474 return rValue;
|
fazekasgy@0
|
475 }
|
fazekasgy@0
|
476
|
fazekasgy@0
|
477 rValue=(size_t)PyInt_AS_LONG(pyInt);
|
fazekasgy@0
|
478 Py_CLEAR(pyInt);
|
fazekasgy@0
|
479 }
|
fazekasgy@0
|
480 return rValue;
|
fazekasgy@0
|
481 }
|
fazekasgy@0
|
482
|
fazekasgy@0
|
483 size_t PyPlugin::getMaxChannelCount() const
|
fazekasgy@0
|
484 {
|
cannam@3
|
485 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
486
|
fazekasgy@0
|
487 char method[]="getMaxChannelCount";
|
fazekasgy@0
|
488 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
489 size_t rValue=1; //default value
|
fazekasgy@0
|
490 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@0
|
491 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@0
|
492
|
fazekasgy@0
|
493 //Check return value
|
fazekasgy@0
|
494 if (!PyInt_Check(pyInt)) {
|
fazekasgy@0
|
495 Py_CLEAR(pyInt);
|
fazekasgy@0
|
496 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
497 << "] Expected String return value." << endl;
|
fazekasgy@0
|
498 return rValue;
|
fazekasgy@0
|
499 }
|
fazekasgy@0
|
500
|
fazekasgy@0
|
501 rValue=(size_t)PyInt_AS_LONG(pyInt);
|
fazekasgy@0
|
502 Py_CLEAR(pyInt);
|
fazekasgy@0
|
503 }
|
fazekasgy@0
|
504 return rValue;
|
fazekasgy@0
|
505 }
|
fazekasgy@0
|
506
|
fazekasgy@0
|
507
|
fazekasgy@0
|
508 PyPlugin::OutputList
|
fazekasgy@0
|
509 PyPlugin::getOutputDescriptors() const
|
fazekasgy@0
|
510 {
|
fazekasgy@6
|
511
|
cannam@3
|
512 MutexLocker locker(&m_pythonInterpreterMutex);
|
fazekasgy@6
|
513
|
fazekasgy@0
|
514 //PyEval_AcquireThread(newThreadState);
|
fazekasgy@0
|
515 OutputList list;
|
fazekasgy@0
|
516 OutputDescriptor od;
|
fazekasgy@0
|
517 char method[]="getOutputDescriptors";
|
fazekasgy@0
|
518 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
519
|
fazekasgy@0
|
520 //Check if the method is implemented in Python
|
fazekasgy@6
|
521 if ( ! PyObject_HasAttrString(m_pyInstance,method) ) return list;
|
fazekasgy@0
|
522
|
fazekasgy@0
|
523 //Call the method: must return list object (new reference)
|
fazekasgy@0
|
524 PyObject *pyList =
|
fazekasgy@0
|
525 PyObject_CallMethod(m_pyInstance,method, NULL);
|
fazekasgy@0
|
526
|
fazekasgy@0
|
527 //Check return type
|
fazekasgy@0
|
528 if (! PyList_Check(pyList) ) {
|
fazekasgy@0
|
529 Py_CLEAR(pyList);
|
fazekasgy@0
|
530 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
531 << "] Expected List return type." << endl;
|
fazekasgy@0
|
532 return list;
|
fazekasgy@0
|
533 }
|
fazekasgy@0
|
534
|
fazekasgy@0
|
535 //These will all be borrowed references (no need to DECREF)
|
fazekasgy@0
|
536 PyObject *pyDict, *pyKey, *pyValue;
|
fazekasgy@0
|
537
|
fazekasgy@0
|
538 //Parse Output List
|
fazekasgy@0
|
539 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
|
fazekasgy@0
|
540
|
cannam@18
|
541 //Get i-th Vamp output descriptor (Borrowed Reference)
|
fazekasgy@0
|
542 pyDict = PyList_GET_ITEM(pyList,i);
|
fazekasgy@0
|
543
|
fazekasgy@0
|
544 //We only care about dictionaries holding output descriptors
|
fazekasgy@0
|
545 if ( !PyDict_Check(pyDict) ) continue;
|
fazekasgy@0
|
546
|
fazekasgy@0
|
547 Py_ssize_t pyPos = NULL;
|
fazekasgy@0
|
548 initMaps();
|
fazekasgy@0
|
549
|
fazekasgy@0
|
550 //Python Sequence Iterator
|
fazekasgy@0
|
551 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
|
fazekasgy@0
|
552 {
|
fazekasgy@0
|
553 switch (outKeys[PyString_AsString(pyKey)])
|
fazekasgy@0
|
554 {
|
cannam@18
|
555 case o::not_found :
|
cannam@18
|
556 cerr << "Unknown key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl;
|
fazekasgy@0
|
557 break;
|
cannam@18
|
558 case o::identifier:
|
fazekasgy@0
|
559 od.identifier = PyString_AsString(pyValue);
|
fazekasgy@0
|
560 break;
|
cannam@18
|
561 case o::name:
|
fazekasgy@0
|
562 od.name = PyString_AsString(pyValue);
|
fazekasgy@0
|
563 break;
|
cannam@18
|
564 case o::description:
|
fazekasgy@0
|
565 od.description = PyString_AsString(pyValue);
|
fazekasgy@0
|
566 break;
|
cannam@18
|
567 case o::unit:
|
fazekasgy@0
|
568 od.unit = PyString_AsString(pyValue);
|
fazekasgy@0
|
569 break;
|
cannam@18
|
570 case o::hasFixedBinCount:
|
fazekasgy@0
|
571 od.hasFixedBinCount = (bool) PyInt_AS_LONG(pyValue);
|
fazekasgy@0
|
572 break;
|
cannam@18
|
573 case o::binCount:
|
fazekasgy@0
|
574 od.binCount = (size_t) PyInt_AS_LONG(pyValue);
|
fazekasgy@0
|
575 break;
|
cannam@18
|
576 case o::binNames:
|
fazekasgy@0
|
577 od.binNames = PyList_To_StringVector(pyValue);
|
fazekasgy@0
|
578 break;
|
cannam@18
|
579 case o::hasKnownExtents:
|
fazekasgy@0
|
580 od.hasKnownExtents = (bool) PyInt_AS_LONG(pyValue);
|
fazekasgy@0
|
581 break;
|
cannam@18
|
582 case o::minValue:
|
fazekasgy@0
|
583 od.minValue = (float) PyFloat_AS_DOUBLE(pyValue);
|
fazekasgy@0
|
584 break;
|
cannam@18
|
585 case o::maxValue:
|
fazekasgy@0
|
586 od.maxValue = (float) PyFloat_AS_DOUBLE(pyValue);
|
fazekasgy@0
|
587 break;
|
cannam@18
|
588 case o::isQuantized:
|
fazekasgy@0
|
589 od.isQuantized = (bool) PyInt_AS_LONG(pyValue);
|
fazekasgy@0
|
590 break;
|
cannam@18
|
591 case o::quantizeStep:
|
fazekasgy@0
|
592 od.quantizeStep = (float) PyFloat_AS_DOUBLE(pyValue);
|
fazekasgy@0
|
593 break;
|
cannam@18
|
594 case o::sampleType:
|
fazekasgy@0
|
595 od.sampleType = (OutputDescriptor::SampleType) sampleKeys[PyString_AsString(pyValue)];
|
fazekasgy@0
|
596 break;
|
cannam@18
|
597 case o::sampleRate:
|
fazekasgy@0
|
598 od.sampleRate = (float) PyFloat_AS_DOUBLE(pyValue);
|
fazekasgy@8
|
599 // od.sampleRate = m_inputSampleRate / m_stepSize;
|
fazekasgy@8
|
600 cerr << od.sampleRate << endl;
|
fazekasgy@0
|
601 break;
|
cannam@18
|
602 case o::hasDuration:
|
cannam@18
|
603 od.hasDuration = (bool)PyInt_AS_LONG(pyValue);
|
cannam@18
|
604 break;
|
fazekasgy@0
|
605 default :
|
cannam@18
|
606 cerr << "Invalid key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl;
|
fazekasgy@6
|
607 }
|
fazekasgy@6
|
608 } // while dict
|
fazekasgy@0
|
609 list.push_back(od);
|
fazekasgy@6
|
610 } // for list
|
fazekasgy@0
|
611 Py_CLEAR(pyList);
|
fazekasgy@0
|
612 return list;
|
fazekasgy@0
|
613 }
|
fazekasgy@0
|
614
|
fazekasgy@0
|
615 PyPlugin::ParameterList
|
fazekasgy@0
|
616 PyPlugin::getParameterDescriptors() const
|
fazekasgy@0
|
617 {
|
cannam@3
|
618 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
619
|
fazekasgy@0
|
620 ParameterList list;
|
fazekasgy@0
|
621 ParameterDescriptor pd;
|
fazekasgy@0
|
622 char method[]="getParameterDescriptors";
|
fazekasgy@0
|
623 cerr << "[call] " << method << endl;
|
fazekasgy@27
|
624
|
fazekasgy@27
|
625 if (!m_pyInstance) {cerr << "Error: pyInstance is NULL" << endl; return list;}
|
fazekasgy@0
|
626
|
fazekasgy@0
|
627 //Check if the method is implemented in Python
|
fazekasgy@6
|
628 if ( ! PyObject_HasAttrString(m_pyInstance,method) ) return list;
|
fazekasgy@0
|
629
|
fazekasgy@0
|
630 //Call the method: must return list object (new reference)
|
fazekasgy@0
|
631 PyObject *pyList =
|
fazekasgy@0
|
632 PyObject_CallMethod(m_pyInstance,method, NULL);
|
fazekasgy@0
|
633
|
fazekasgy@0
|
634 //Check return type
|
fazekasgy@0
|
635 if (! PyList_Check(pyList) ) {
|
fazekasgy@0
|
636 Py_CLEAR(pyList);
|
fazekasgy@0
|
637 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
638 << "] Expected List return type." << endl;
|
fazekasgy@0
|
639 return list;
|
fazekasgy@0
|
640 }
|
fazekasgy@0
|
641
|
fazekasgy@0
|
642
|
fazekasgy@0
|
643 //These will all be borrowed references (no need to DECREF)
|
fazekasgy@0
|
644 PyObject *pyDict, *pyKey, *pyValue;
|
fazekasgy@0
|
645
|
fazekasgy@0
|
646 //Parse Output List
|
fazekasgy@0
|
647 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
|
fazekasgy@0
|
648
|
cannam@18
|
649 //Get i-th Vamp output descriptor (Borrowed Reference)
|
fazekasgy@0
|
650 pyDict = PyList_GET_ITEM(pyList,i);
|
fazekasgy@0
|
651
|
fazekasgy@0
|
652 //We only care about dictionaries holding output descriptors
|
fazekasgy@0
|
653 if ( !PyDict_Check(pyDict) ) continue;
|
fazekasgy@0
|
654
|
fazekasgy@0
|
655 Py_ssize_t pyPos = NULL;
|
fazekasgy@0
|
656 initMaps();
|
fazekasgy@0
|
657
|
fazekasgy@0
|
658 //Python Sequence Iterator
|
fazekasgy@0
|
659 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
|
fazekasgy@0
|
660 {
|
fazekasgy@0
|
661 switch (parmKeys[PyString_AsString(pyKey)])
|
fazekasgy@0
|
662 {
|
cannam@18
|
663 case p::not_found :
|
cannam@18
|
664 cerr << "Unknown key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl;
|
fazekasgy@0
|
665 break;
|
fazekasgy@0
|
666 case p::identifier:
|
fazekasgy@0
|
667 pd.identifier = PyString_AsString(pyValue);
|
fazekasgy@0
|
668 break;
|
fazekasgy@0
|
669 case p::name:
|
fazekasgy@0
|
670 pd.name = PyString_AsString(pyValue);
|
fazekasgy@0
|
671 break;
|
fazekasgy@0
|
672 case p::description:
|
fazekasgy@0
|
673 pd.description = PyString_AsString(pyValue);
|
fazekasgy@0
|
674 break;
|
fazekasgy@0
|
675 case p::unit:
|
fazekasgy@0
|
676 pd.unit = PyString_AsString(pyValue);
|
fazekasgy@0
|
677 break;
|
fazekasgy@0
|
678 case p::minValue:
|
fazekasgy@0
|
679 pd.minValue = (float) PyFloat_AS_DOUBLE(pyValue);
|
fazekasgy@0
|
680 break;
|
fazekasgy@0
|
681 case p::maxValue:
|
fazekasgy@0
|
682 pd.maxValue = (float) PyFloat_AS_DOUBLE(pyValue);
|
fazekasgy@0
|
683 break;
|
fazekasgy@0
|
684 case p::defaultValue:
|
fazekasgy@0
|
685 pd.defaultValue = (float) PyFloat_AS_DOUBLE(pyValue);
|
fazekasgy@0
|
686 break;
|
fazekasgy@0
|
687 case p::isQuantized:
|
fazekasgy@0
|
688 pd.isQuantized = (bool) PyInt_AS_LONG(pyValue);
|
fazekasgy@27
|
689 break;
|
fazekasgy@27
|
690 case p::quantizeStep:
|
cannam@22
|
691 pd.quantizeStep = (float) PyFloat_AS_DOUBLE(pyValue);
|
cannam@22
|
692 break;
|
fazekasgy@0
|
693 default :
|
cannam@18
|
694 cerr << "Invalid key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl;
|
fazekasgy@6
|
695 }
|
fazekasgy@6
|
696 } // while dict
|
fazekasgy@0
|
697 list.push_back(pd);
|
fazekasgy@6
|
698 } // for list
|
fazekasgy@0
|
699 Py_CLEAR(pyList);
|
fazekasgy@0
|
700 return list;
|
fazekasgy@0
|
701 }
|
fazekasgy@0
|
702
|
fazekasgy@0
|
703 void PyPlugin::setParameter(std::string paramid, float newval)
|
fazekasgy@0
|
704 {
|
cannam@3
|
705 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
706
|
fazekasgy@0
|
707 char method[]="setParameter";
|
fazekasgy@0
|
708 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
709
|
fazekasgy@0
|
710 //Check if the method is implemented in Python
|
fazekasgy@0
|
711 if (PyObject_HasAttrString(m_pyInstance,method)) {
|
fazekasgy@0
|
712
|
fazekasgy@0
|
713 PyObject *pyMethod = PyString_FromString(method);
|
fazekasgy@0
|
714 PyObject *pyParamid = PyString_FromString(paramid.c_str());
|
fazekasgy@0
|
715 PyObject *pyNewval = PyFloat_FromDouble((double)newval);
|
fazekasgy@0
|
716
|
fazekasgy@0
|
717 //Call the method
|
fazekasgy@0
|
718 PyObject *pyBool =
|
fazekasgy@0
|
719 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyParamid,pyNewval,NULL);
|
fazekasgy@0
|
720
|
fazekasgy@0
|
721 //This only happens if there is a syntax error or so
|
fazekasgy@0
|
722 if (pyBool == NULL) {
|
fazekasgy@0
|
723 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
724 << "] Error setting parameter: " << paramid << endl;
|
fazekasgy@0
|
725 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@0
|
726 }
|
fazekasgy@0
|
727
|
fazekasgy@0
|
728 Py_DECREF(pyMethod);
|
fazekasgy@0
|
729 Py_DECREF(pyParamid);
|
fazekasgy@0
|
730 Py_DECREF(pyNewval);
|
fazekasgy@0
|
731 }
|
fazekasgy@0
|
732 }
|
fazekasgy@0
|
733
|
fazekasgy@0
|
734 float PyPlugin::getParameter(std::string paramid) const
|
fazekasgy@0
|
735 {
|
cannam@3
|
736 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
737
|
fazekasgy@0
|
738 char method[]="getParameter";
|
fazekasgy@0
|
739 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
740 float rValue = 0.0f;
|
fazekasgy@0
|
741
|
fazekasgy@0
|
742 //Check if the method is implemented in Python
|
fazekasgy@0
|
743 if (PyObject_HasAttrString(m_pyInstance,method)) {
|
fazekasgy@0
|
744
|
fazekasgy@0
|
745 PyObject *pyMethod = PyString_FromString(method);
|
fazekasgy@0
|
746 PyObject *pyParamid = PyString_FromString(paramid.c_str());
|
fazekasgy@0
|
747
|
fazekasgy@0
|
748 //Call the method
|
fazekasgy@0
|
749 PyObject *pyFloat =
|
fazekasgy@0
|
750 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyParamid,NULL);
|
fazekasgy@0
|
751
|
fazekasgy@0
|
752 //Check return type
|
fazekasgy@0
|
753 if (! PyFloat_Check(pyFloat) ) {
|
fazekasgy@0
|
754 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
755 << "] Expected Float return type." << endl;
|
fazekasgy@0
|
756 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@0
|
757 Py_CLEAR(pyFloat);
|
fazekasgy@0
|
758 return rValue;
|
fazekasgy@0
|
759 }
|
fazekasgy@0
|
760
|
fazekasgy@0
|
761 rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
|
fazekasgy@0
|
762
|
fazekasgy@0
|
763 Py_DECREF(pyMethod);
|
fazekasgy@0
|
764 Py_DECREF(pyParamid);
|
fazekasgy@0
|
765 Py_DECREF(pyFloat);
|
fazekasgy@0
|
766 }
|
fazekasgy@0
|
767
|
fazekasgy@0
|
768 return rValue;
|
fazekasgy@0
|
769 }
|
fazekasgy@0
|
770
|
fazekasgy@0
|
771 #ifdef _DEBUG
|
fazekasgy@0
|
772 static int proccounter = 0;
|
fazekasgy@0
|
773 #endif
|
fazekasgy@0
|
774
|
fazekasgy@0
|
775 PyPlugin::FeatureSet
|
fazekasgy@0
|
776 PyPlugin::process(const float *const *inputBuffers,
|
fazekasgy@0
|
777 Vamp::RealTime timestamp)
|
fazekasgy@0
|
778 {
|
cannam@3
|
779 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
780
|
fazekasgy@6
|
781 #ifdef _DEBUG
|
fazekasgy@6
|
782 cerr << "[call] process, frame:" << proccounter << endl;
|
fazekasgy@6
|
783 proccounter++;
|
fazekasgy@6
|
784 #endif
|
fazekasgy@6
|
785
|
fazekasgy@8
|
786 if (m_blockSize == 0 || m_channels == 0) {
|
fazekasgy@0
|
787 cerr << "ERROR: PyPlugin::process: "
|
fazekasgy@0
|
788 << "Plugin has not been initialised" << endl;
|
fazekasgy@0
|
789 return FeatureSet();
|
fazekasgy@0
|
790 }
|
fazekasgy@0
|
791
|
fazekasgy@6
|
792 if (m_processType == not_implemented) {
|
fazekasgy@6
|
793 cerr << "ERROR: In Python plugin [" << m_class
|
fazekasgy@6
|
794 << "] No process implementation found. Returning empty feature set." << endl;
|
fazekasgy@6
|
795 return FeatureSet();
|
fazekasgy@6
|
796 }
|
fazekasgy@0
|
797
|
fazekasgy@6
|
798 string method=PyString_AsString(m_pyProcess);
|
fazekasgy@6
|
799
|
fazekasgy@6
|
800 PyObject *pyOutputList = NULL;
|
fazekasgy@0
|
801
|
fazekasgy@6
|
802 /*new numPy support*/
|
fazekasgy@6
|
803 if (m_processType == numpyProcess) {
|
fazekasgy@8
|
804
|
fazekasgy@8
|
805 //create a list of buffers
|
fazekasgy@8
|
806 PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels);
|
fazekasgy@8
|
807 for (size_t i=0; i < m_channels; ++i) {
|
fazekasgy@6
|
808
|
fazekasgy@8
|
809 //Expose memory using the Buffer Interface of C/API
|
fazekasgy@8
|
810 //This will virtually pass a pointer which can be
|
fazekasgy@8
|
811 //recasted in Python code as float or complex array
|
fazekasgy@8
|
812 PyObject *pyBuffer = PyBuffer_FromMemory
|
fazekasgy@8
|
813 ((void *) (float *) inputBuffers[i],
|
fazekasgy@8
|
814 (Py_ssize_t) sizeof(float) * m_blockSize);
|
fazekasgy@6
|
815
|
fazekasgy@8
|
816 PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyBuffer);
|
fazekasgy@8
|
817 }
|
fazekasgy@8
|
818
|
fazekasgy@8
|
819 //pass RealTime as frameCount
|
fazekasgy@8
|
820 PyObject *pyLongSample = PyLong_FromLong (
|
fazekasgy@8
|
821 Vamp::RealTime::realTime2Frame
|
fazekasgy@8
|
822 (timestamp, (unsigned int) m_inputSampleRate));
|
fazekasgy@6
|
823
|
fazekasgy@8
|
824 //Call python process (returns new reference)
|
fazekasgy@8
|
825 pyOutputList = PyObject_CallMethodObjArgs
|
fazekasgy@8
|
826 (m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL);
|
fazekasgy@8
|
827
|
fazekasgy@8
|
828 Py_DECREF(pyChannelList);
|
fazekasgy@8
|
829 Py_DECREF(pyLongSample);
|
fazekasgy@6
|
830
|
fazekasgy@6
|
831 }
|
fazekasgy@6
|
832
|
fazekasgy@6
|
833 if (m_processType == legacyProcess) {
|
fazekasgy@0
|
834
|
fazekasgy@8
|
835 //create a list of lists
|
fazekasgy@8
|
836 PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels);
|
fazekasgy@8
|
837 for (size_t i=0; i < m_channels; ++i) {
|
fazekasgy@0
|
838
|
fazekasgy@8
|
839 //Declare new list object
|
fazekasgy@8
|
840 PyObject *pyFloat, *pyList;
|
fazekasgy@8
|
841 pyList = PyList_New((Py_ssize_t) m_blockSize);
|
fazekasgy@8
|
842
|
fazekasgy@8
|
843 //Pack samples into a Python List Object
|
fazekasgy@8
|
844 //pyFloat types will always be new references,
|
fazekasgy@8
|
845 //these will be discarded when the list is deallocated
|
fazekasgy@8
|
846 for (size_t j = 0; j < m_blockSize; ++j) {
|
fazekasgy@8
|
847 pyFloat=PyFloat_FromDouble(
|
fazekasgy@8
|
848 (double) inputBuffers[i][j]);
|
fazekasgy@8
|
849 PyList_SET_ITEM(pyList, (Py_ssize_t) j, pyFloat);
|
fazekasgy@8
|
850 }
|
fazekasgy@8
|
851 PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyList);
|
fazekasgy@8
|
852 }
|
fazekasgy@8
|
853
|
fazekasgy@8
|
854 //pass RealTime as frameCount
|
fazekasgy@8
|
855 PyObject *pyLongSample = PyLong_FromLong (
|
fazekasgy@8
|
856 Vamp::RealTime::realTime2Frame
|
fazekasgy@8
|
857 (timestamp, (unsigned int) m_inputSampleRate));
|
fazekasgy@8
|
858
|
fazekasgy@8
|
859 //Call python process (returns new reference)
|
fazekasgy@8
|
860 pyOutputList = PyObject_CallMethodObjArgs
|
fazekasgy@8
|
861 (m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL);
|
fazekasgy@8
|
862
|
fazekasgy@8
|
863 Py_DECREF(pyChannelList);
|
fazekasgy@8
|
864 Py_DECREF(pyLongSample);
|
fazekasgy@8
|
865
|
fazekasgy@0
|
866 }
|
fazekasgy@6
|
867
|
fazekasgy@8
|
868 //return nothing
|
fazekasgy@8
|
869 //Py_CLEAR(pyOutputList);
|
fazekasgy@8
|
870 //return FeatureSet();
|
fazekasgy@0
|
871
|
fazekasgy@0
|
872 //Check return type
|
fazekasgy@0
|
873 if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) {
|
fazekasgy@0
|
874 if (pyOutputList == NULL) {
|
fazekasgy@0
|
875 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
876 << "] Unexpected result." << endl;
|
fazekasgy@0
|
877 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@0
|
878 } else {
|
fazekasgy@0
|
879 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
880 << "] Expected List return type." << endl;
|
fazekasgy@0
|
881 }
|
fazekasgy@0
|
882 Py_CLEAR(pyOutputList);
|
fazekasgy@0
|
883 return FeatureSet();
|
fazekasgy@0
|
884 }
|
fazekasgy@0
|
885
|
fazekasgy@0
|
886 // Py_DECREF(pyList);
|
fazekasgy@0
|
887 // This appears to be tracked by the cyclic garbage collector
|
fazekasgy@0
|
888 // hence decrefing produces GC error
|
fazekasgy@0
|
889 #ifdef _DEBUG
|
fazekasgy@0
|
890 cerr << "Process Returned Features" << endl;
|
fazekasgy@0
|
891 #endif
|
fazekasgy@0
|
892 // These will ALL be borrowed references
|
fazekasgy@0
|
893 PyObject *pyFeatureList, *pyDict, *pyKey, *pyValue;
|
fazekasgy@0
|
894
|
fazekasgy@0
|
895 FeatureSet returnFeatures;
|
fazekasgy@0
|
896
|
fazekasgy@0
|
897 //Parse Output List for each element (FeatureSet)
|
fazekasgy@0
|
898 for (Py_ssize_t i = 0;
|
fazekasgy@0
|
899 i < PyList_GET_SIZE(pyOutputList); ++i) {
|
fazekasgy@0
|
900 //cerr << "output (FeatureSet): " << i << endl;
|
fazekasgy@0
|
901
|
fazekasgy@0
|
902 //Get i-th FeatureList (Borrowed Reference)
|
fazekasgy@0
|
903 pyFeatureList = PyList_GET_ITEM(pyOutputList,i);
|
fazekasgy@0
|
904
|
fazekasgy@0
|
905 //Parse FeatureList for each element (Feature)
|
fazekasgy@0
|
906 for (Py_ssize_t j = 0; j < PyList_GET_SIZE(pyFeatureList); ++j) {
|
fazekasgy@0
|
907 //cerr << "element (FeatureList): " << j << endl;
|
fazekasgy@0
|
908
|
fazekasgy@0
|
909 //Get j-th Feature (Borrowed Reference)
|
fazekasgy@0
|
910 pyDict = PyList_GET_ITEM(pyFeatureList,j);
|
fazekasgy@0
|
911
|
fazekasgy@0
|
912 //We only care about dictionaries holding a Feature struct
|
fazekasgy@0
|
913 if ( !PyDict_Check(pyDict) ) continue;
|
fazekasgy@0
|
914
|
fazekasgy@0
|
915 Py_ssize_t pyPos = NULL;
|
fazekasgy@0
|
916 bool emptyFeature = true;
|
fazekasgy@0
|
917 Feature feature;
|
fazekasgy@0
|
918
|
fazekasgy@0
|
919 //process::Python Sequence Iterator for dictionary
|
fazekasgy@0
|
920 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
|
fazekasgy@0
|
921 {
|
fazekasgy@0
|
922 emptyFeature = false;
|
fazekasgy@0
|
923 switch (ffKeys[PyString_AsString(pyKey)])
|
fazekasgy@0
|
924 {
|
cannam@18
|
925 case unknown:
|
cannam@18
|
926 cerr << "Unknown key in Vamp FeatureSet: "
|
fazekasgy@0
|
927 << PyString_AsString(pyKey) << endl;
|
fazekasgy@0
|
928 break;
|
fazekasgy@0
|
929 case hasTimestamp:
|
fazekasgy@0
|
930 feature.hasTimestamp = (bool) PyInt_AS_LONG(pyValue);
|
fazekasgy@0
|
931 break;
|
fazekasgy@0
|
932 case timeStamp:
|
fazekasgy@8
|
933 feature.timestamp =
|
fazekasgy@8
|
934 Vamp::RealTime::frame2RealTime(
|
fazekasgy@8
|
935 PyLong_AsLong(pyValue),
|
fazekasgy@8
|
936 (unsigned int) m_inputSampleRate );
|
fazekasgy@8
|
937 #ifdef _DEBUG
|
fazekasgy@8
|
938 cerr << "Timestamp: "
|
fazekasgy@8
|
939 << (long)PyLong_AsLong(pyValue) << ", ->"
|
fazekasgy@8
|
940 << feature.timestamp.toString() << endl;
|
fazekasgy@8
|
941 #endif
|
fazekasgy@0
|
942 break;
|
cannam@18
|
943 case hasDuration:
|
cannam@18
|
944 feature.hasDuration = (bool) PyInt_AS_LONG(pyValue);
|
cannam@18
|
945 break;
|
cannam@18
|
946 case duration:
|
cannam@18
|
947 feature.duration =
|
cannam@18
|
948 Vamp::RealTime::frame2RealTime(
|
cannam@18
|
949 PyLong_AsLong(pyValue),
|
cannam@18
|
950 (unsigned int) m_inputSampleRate );
|
cannam@18
|
951 #ifdef _DEBUG
|
cannam@18
|
952 cerr << "Duration: "
|
cannam@18
|
953 << (long)PyLong_AsLong(pyValue) << ", ->"
|
cannam@18
|
954 << feature.duration.toString() << endl;
|
cannam@18
|
955 #endif
|
cannam@18
|
956 break;
|
fazekasgy@0
|
957 case values:
|
fazekasgy@0
|
958 feature.values = PyList_As_FloatVector(pyValue);
|
fazekasgy@0
|
959 break;
|
fazekasgy@0
|
960 case label:
|
fazekasgy@0
|
961 feature.label = PyString_AsString(pyValue);
|
fazekasgy@0
|
962 break;
|
fazekasgy@0
|
963 default :
|
cannam@18
|
964 cerr << "Invalid key in Vamp FeatureSet: "
|
fazekasgy@0
|
965 << PyString_AsString(pyKey) << endl;
|
fazekasgy@0
|
966 } // switch
|
fazekasgy@0
|
967
|
fazekasgy@0
|
968 } // while
|
fazekasgy@0
|
969 if (emptyFeature) cerr << "Warning: This feature is empty or badly formatted." << endl;
|
fazekasgy@0
|
970 else returnFeatures[i].push_back(feature);
|
fazekasgy@0
|
971
|
fazekasgy@0
|
972 }// for j = FeatureList
|
fazekasgy@0
|
973
|
fazekasgy@0
|
974 }//for i = FeatureSet
|
fazekasgy@0
|
975 Py_CLEAR(pyOutputList);
|
fazekasgy@0
|
976 return returnFeatures;
|
fazekasgy@0
|
977 }
|
fazekasgy@0
|
978
|
fazekasgy@0
|
979
|
fazekasgy@0
|
980
|
fazekasgy@0
|
981 PyPlugin::FeatureSet
|
fazekasgy@0
|
982 PyPlugin::getRemainingFeatures()
|
fazekasgy@0
|
983 {
|
cannam@3
|
984 MutexLocker locker(&m_pythonInterpreterMutex);
|
cannam@3
|
985
|
fazekasgy@0
|
986 static char method[]="getRemainingFeatures";
|
fazekasgy@0
|
987 cerr << "[call] " << method << endl;
|
fazekasgy@0
|
988
|
fazekasgy@0
|
989 //check if the method is implemented
|
fazekasgy@0
|
990 if ( ! PyObject_HasAttrString(m_pyInstance,method) ) {
|
fazekasgy@0
|
991 return FeatureSet();
|
fazekasgy@0
|
992 }
|
fazekasgy@0
|
993
|
fazekasgy@0
|
994 PyObject *pyMethod = PyString_FromString(method);
|
fazekasgy@0
|
995
|
fazekasgy@0
|
996 PyObject *pyOutputList =
|
fazekasgy@0
|
997 PyObject_CallMethod(m_pyInstance,method, NULL);
|
fazekasgy@0
|
998
|
fazekasgy@0
|
999 //Check return type
|
fazekasgy@0
|
1000 if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) {
|
fazekasgy@0
|
1001 if (pyOutputList == NULL) {
|
fazekasgy@0
|
1002 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
1003 << "] Unexpected result." << endl;
|
fazekasgy@0
|
1004 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
fazekasgy@0
|
1005 } else {
|
fazekasgy@0
|
1006 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
|
fazekasgy@0
|
1007 << "] Expected List return type." << endl;
|
fazekasgy@0
|
1008 }
|
fazekasgy@0
|
1009 Py_CLEAR(pyMethod);
|
fazekasgy@0
|
1010 Py_CLEAR(pyOutputList);
|
fazekasgy@0
|
1011 return FeatureSet();
|
fazekasgy@0
|
1012 }
|
fazekasgy@0
|
1013 Py_DECREF(pyMethod);
|
fazekasgy@0
|
1014
|
fazekasgy@0
|
1015 PyObject *pyFeatureList, *pyDict, *pyKey, *pyValue;
|
fazekasgy@0
|
1016 FeatureSet returnFeatures;
|
fazekasgy@8
|
1017
|
fazekasgy@8
|
1018 //iterate through list of outputs
|
fazekasgy@0
|
1019 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyOutputList); ++i) {
|
fazekasgy@0
|
1020
|
fazekasgy@0
|
1021 pyFeatureList = PyList_GET_ITEM(pyOutputList,i);
|
fazekasgy@0
|
1022
|
fazekasgy@8
|
1023 //iterate list of Features
|
fazekasgy@0
|
1024 for (Py_ssize_t j = 0; j < PyList_GET_SIZE(pyFeatureList); ++j) {
|
fazekasgy@8
|
1025 #ifdef _DEBUG
|
fazekasgy@8
|
1026 cerr << "feature: " << j << endl;
|
fazekasgy@8
|
1027 #endif
|
fazekasgy@0
|
1028 pyDict = PyList_GET_ITEM(pyFeatureList,j);
|
fazekasgy@0
|
1029
|
fazekasgy@0
|
1030 if ( !PyDict_Check(pyDict) ) continue;
|
fazekasgy@0
|
1031
|
fazekasgy@0
|
1032 Py_ssize_t pyPos = NULL;
|
fazekasgy@0
|
1033 bool emptyFeature = true;
|
fazekasgy@0
|
1034 Feature feature;
|
fazekasgy@0
|
1035
|
fazekasgy@0
|
1036 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
|
fazekasgy@0
|
1037 {
|
fazekasgy@0
|
1038 emptyFeature = false;
|
fazekasgy@0
|
1039 switch (ffKeys[PyString_AsString(pyKey)])
|
fazekasgy@0
|
1040 {
|
cannam@18
|
1041 case unknown :
|
cannam@18
|
1042 cerr << "Unknown key in Vamp FeatureSet: "
|
fazekasgy@0
|
1043 << PyString_AsString(pyKey) << endl;
|
fazekasgy@0
|
1044 break;
|
fazekasgy@0
|
1045 case hasTimestamp:
|
fazekasgy@0
|
1046 feature.hasTimestamp = (bool) PyInt_AS_LONG(pyValue);
|
fazekasgy@0
|
1047 break;
|
fazekasgy@0
|
1048 case timeStamp:
|
fazekasgy@0
|
1049 feature.timestamp =
|
fazekasgy@8
|
1050 Vamp::RealTime::frame2RealTime(
|
fazekasgy@8
|
1051 PyLong_AsLong(pyValue),
|
fazekasgy@8
|
1052 (unsigned int) m_inputSampleRate );
|
fazekasgy@8
|
1053 #ifdef _DEBUG
|
fazekasgy@8
|
1054 cerr << "Timestamp: "
|
fazekasgy@8
|
1055 << (long)PyLong_AsLong(pyValue) << ", ->"
|
fazekasgy@8
|
1056 << feature.timestamp.toString() << endl;
|
fazekasgy@8
|
1057 #endif
|
fazekasgy@0
|
1058 break;
|
cannam@18
|
1059 case hasDuration:
|
cannam@18
|
1060 feature.hasDuration = (bool) PyInt_AS_LONG(pyValue);
|
cannam@18
|
1061 break;
|
cannam@18
|
1062 case duration:
|
cannam@18
|
1063 feature.duration =
|
cannam@18
|
1064 Vamp::RealTime::frame2RealTime(
|
cannam@18
|
1065 PyLong_AsLong(pyValue),
|
cannam@18
|
1066 (unsigned int) m_inputSampleRate );
|
cannam@18
|
1067 #ifdef _DEBUG
|
cannam@18
|
1068 cerr << "Duration: "
|
cannam@18
|
1069 << (long)PyLong_AsLong(pyValue) << ", ->"
|
cannam@18
|
1070 << feature.duration.toString() << endl;
|
cannam@18
|
1071 #endif
|
cannam@18
|
1072 break;
|
fazekasgy@0
|
1073 case values:
|
fazekasgy@0
|
1074 feature.values = PyList_As_FloatVector(pyValue);
|
fazekasgy@0
|
1075 break;
|
fazekasgy@0
|
1076 case label:
|
fazekasgy@0
|
1077 feature.label = PyString_AsString(pyValue);
|
fazekasgy@0
|
1078 break;
|
fazekasgy@0
|
1079 } // switch
|
fazekasgy@0
|
1080 } // while
|
fazekasgy@0
|
1081 if (emptyFeature) cerr << "Warning: This feature is empty or badly formatted." << endl;
|
fazekasgy@0
|
1082 else returnFeatures[i].push_back(feature);
|
fazekasgy@0
|
1083 }// for j
|
fazekasgy@0
|
1084 }//for i
|
fazekasgy@0
|
1085 Py_CLEAR(pyOutputList);
|
fazekasgy@0
|
1086 return returnFeatures;
|
fazekasgy@0
|
1087 }
|
fazekasgy@0
|
1088
|
fazekasgy@6
|
1089 bool
|
fazekasgy@6
|
1090 PyPlugin::initMaps() const
|
fazekasgy@6
|
1091 {
|
fazekasgy@6
|
1092
|
fazekasgy@6
|
1093 if (isMapInitialised) return true;
|
fazekasgy@6
|
1094
|
cannam@18
|
1095 outKeys["identifier"] = o::identifier;
|
cannam@18
|
1096 outKeys["name"] = o::name;
|
cannam@18
|
1097 outKeys["description"] = o::description;
|
cannam@18
|
1098 outKeys["unit"] = o::unit;
|
cannam@18
|
1099 outKeys["hasFixedBinCount"] = o::hasFixedBinCount;
|
cannam@18
|
1100 outKeys["binCount"] = o::binCount;
|
cannam@18
|
1101 outKeys["binNames"] = o::binNames;
|
cannam@18
|
1102 outKeys["hasKnownExtents"] = o::hasKnownExtents;
|
cannam@18
|
1103 outKeys["minValue"] = o::minValue;
|
cannam@18
|
1104 outKeys["maxValue"] = o::maxValue;
|
cannam@18
|
1105 outKeys["isQuantized"] = o::isQuantized;
|
cannam@18
|
1106 outKeys["quantizeStep"] = o::quantizeStep;
|
cannam@18
|
1107 outKeys["sampleType"] = o::sampleType;
|
cannam@18
|
1108 outKeys["sampleRate"] = o::sampleRate;
|
cannam@18
|
1109 outKeys["hasDuration"] = o::hasDuration;
|
fazekasgy@6
|
1110
|
fazekasgy@6
|
1111 sampleKeys["OneSamplePerStep"] = OneSamplePerStep;
|
fazekasgy@6
|
1112 sampleKeys["FixedSampleRate"] = FixedSampleRate;
|
fazekasgy@6
|
1113 sampleKeys["VariableSampleRate"] = VariableSampleRate;
|
fazekasgy@6
|
1114
|
fazekasgy@6
|
1115 ffKeys["hasTimestamp"] = hasTimestamp;
|
fazekasgy@6
|
1116 ffKeys["timeStamp"] = timeStamp;
|
cannam@18
|
1117 ffKeys["hasDuration"] = hasDuration;
|
cannam@18
|
1118 ffKeys["duration"] = duration;
|
fazekasgy@6
|
1119 ffKeys["values"] = values;
|
fazekasgy@6
|
1120 ffKeys["label"] = label;
|
fazekasgy@6
|
1121
|
fazekasgy@6
|
1122 parmKeys["identifier"] = p::identifier;
|
fazekasgy@6
|
1123 parmKeys["name"] = p::name;
|
fazekasgy@6
|
1124 parmKeys["description"] = p::description;
|
fazekasgy@6
|
1125 parmKeys["unit"] = p::unit;
|
fazekasgy@6
|
1126 parmKeys["minValue"] = p::minValue;
|
fazekasgy@6
|
1127 parmKeys["maxValue"] = p::maxValue;
|
fazekasgy@6
|
1128 parmKeys["defaultValue"] = p::defaultValue;
|
fazekasgy@6
|
1129 parmKeys["isQuantized"] = p::isQuantized;
|
cannam@22
|
1130 parmKeys["quantizeStep"] = p::quantizeStep;
|
fazekasgy@6
|
1131
|
fazekasgy@6
|
1132 isMapInitialised = true;
|
fazekasgy@6
|
1133 return true;
|
fazekasgy@6
|
1134 }
|
fazekasgy@6
|
1135
|
fazekasgy@6
|
1136
|
fazekasgy@6
|
1137 //missing API helper: convert Python list to C++ vector of strings
|
fazekasgy@6
|
1138 //TODO: these could be templates if we need more of this kind
|
fazekasgy@6
|
1139 std::vector<std::string>
|
fazekasgy@6
|
1140 PyPlugin::PyList_To_StringVector (PyObject *inputList) const {
|
fazekasgy@6
|
1141
|
fazekasgy@6
|
1142 std::vector<std::string> Output;
|
fazekasgy@6
|
1143 std::string ListElement;
|
fazekasgy@6
|
1144 PyObject *pyString = NULL;
|
fazekasgy@6
|
1145
|
fazekasgy@6
|
1146 if (!PyList_Check(inputList)) return Output;
|
fazekasgy@6
|
1147
|
fazekasgy@6
|
1148 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
|
fazekasgy@6
|
1149 //Get next list item (Borrowed Reference)
|
fazekasgy@6
|
1150 pyString = PyList_GET_ITEM(inputList,i);
|
fazekasgy@6
|
1151 ListElement = (string) PyString_AsString(PyObject_Str(pyString));
|
fazekasgy@6
|
1152 Output.push_back(ListElement);
|
fazekasgy@6
|
1153 }
|
fazekasgy@6
|
1154 return Output;
|
fazekasgy@6
|
1155 }
|
fazekasgy@6
|
1156
|
fazekasgy@6
|
1157 //missing API helper: convert Python list to C++ vector of floats
|
fazekasgy@6
|
1158 std::vector<float>
|
fazekasgy@6
|
1159 PyPlugin::PyList_As_FloatVector (PyObject *inputList) const {
|
fazekasgy@6
|
1160
|
fazekasgy@6
|
1161 std::vector<float> Output;
|
fazekasgy@6
|
1162 float ListElement;
|
fazekasgy@6
|
1163 PyObject *pyFloat = NULL;
|
fazekasgy@6
|
1164
|
fazekasgy@6
|
1165 if (!PyList_Check(inputList)) return Output;
|
fazekasgy@6
|
1166
|
fazekasgy@6
|
1167 for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) {
|
fazekasgy@6
|
1168 //Get next list item (Borrowed Reference)
|
fazekasgy@6
|
1169 pyFloat = PyList_GET_ITEM(inputList,k);
|
fazekasgy@6
|
1170 ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
|
fazekasgy@8
|
1171 #ifdef _DEBUG
|
fazekasgy@8
|
1172 cerr << "value: " << ListElement << endl;
|
fazekasgy@8
|
1173 #endif
|
fazekasgy@6
|
1174 Output.push_back(ListElement);
|
fazekasgy@6
|
1175 }
|
fazekasgy@6
|
1176
|
fazekasgy@6
|
1177 return Output;
|
fazekasgy@6
|
1178 }
|
fazekasgy@6
|
1179
|
fazekasgy@6
|
1180 /* TODO: find out why this produces error, also
|
fazekasgy@6
|
1181 do sg more clever about handling RealTime
|
fazekasgy@6
|
1182 Vamp::RealTime
|
fazekasgy@6
|
1183 PyFrame_As_RealTime (PyObject *frameNo,size_t inputSampleRate) {
|
fazekasgy@6
|
1184 Vamp::RealTime result =
|
fazekasgy@6
|
1185 Vamp::RealTime::frame2RealTime((size_t)PyInt_AS_LONG(frameNo), inputSampleRate);
|
fazekasgy@6
|
1186 return result;
|
fazekasgy@6
|
1187 }
|
fazekasgy@6
|
1188 */
|
fazekasgy@6
|
1189
|