fazekasgy@37
|
1 /*
|
fazekasgy@37
|
2
|
fazekasgy@37
|
3 * Vampy : This plugin is a wrapper around the Vamp plugin API.
|
fazekasgy@37
|
4 * It allows for writing Vamp plugins in Python.
|
fazekasgy@37
|
5
|
fazekasgy@37
|
6 * Centre for Digital Music, Queen Mary University of London.
|
fazekasgy@37
|
7 * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources
|
fazekasgy@37
|
8 * for licence information.)
|
fazekasgy@37
|
9
|
fazekasgy@37
|
10 */
|
fazekasgy@37
|
11
|
fazekasgy@37
|
12 #ifndef _PYTHON_WRAPPER_PLUGIN_H_
|
fazekasgy@37
|
13 #define _PYTHON_WRAPPER_PLUGIN_H_
|
fazekasgy@37
|
14
|
fazekasgy@37
|
15 #define _CLASS_METHOD_ m_class << "::" << method
|
fazekasgy@37
|
16 #define PLUGIN_ERROR "ERROR: In Vampy plugin [" << _CLASS_METHOD_ << "]" << endl << "Cause: "
|
fazekasgy@37
|
17 #define DEBUG_NAME "[Vampy::call] " << _CLASS_METHOD_ << " "
|
Chris@67
|
18 #define DEFAULT_RETURN "Method [" << _CLASS_METHOD_ << "] is not implemented. Returning default value."
|
fazekasgy@37
|
19 #define FLAG_VALUE "Flag: " << flagName << ": " << ((rValue==0)?"False":"True")
|
fazekasgy@37
|
20
|
fazekasgy@37
|
21 #include <Python.h>
|
fazekasgy@37
|
22 #include "PyExtensionModule.h"
|
fazekasgy@37
|
23 #include "PyTypeInterface.h"
|
fazekasgy@37
|
24 #include "vamp-sdk/Plugin.h"
|
fazekasgy@37
|
25 #include "Mutex.h"
|
fazekasgy@37
|
26
|
fazekasgy@37
|
27 using std::string;
|
fazekasgy@37
|
28 using std::cerr;
|
fazekasgy@37
|
29 using std::endl;
|
fazekasgy@37
|
30
|
fazekasgy@37
|
31 enum eProcessType {
|
fazekasgy@37
|
32 not_implemented,
|
fazekasgy@37
|
33 legacyProcess,
|
fazekasgy@37
|
34 numpyProcess,
|
fazekasgy@37
|
35 numpy_bufferProcess,
|
fazekasgy@37
|
36 numpy_arrayProcess
|
fazekasgy@37
|
37 };
|
fazekasgy@37
|
38
|
fazekasgy@37
|
39 class PyPlugin : public Vamp::Plugin
|
fazekasgy@37
|
40 {
|
fazekasgy@37
|
41 public:
|
fazekasgy@51
|
42 PyPlugin(std::string plugin,float inputSampleRate, PyObject *pyClass, int &instcount, bool &numpyInstalled);
|
fazekasgy@37
|
43 virtual ~PyPlugin();
|
fazekasgy@37
|
44
|
fazekasgy@37
|
45 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
fazekasgy@37
|
46 void reset();
|
fazekasgy@37
|
47
|
fazekasgy@37
|
48 InputDomain getInputDomain() const;
|
fazekasgy@37
|
49 size_t getPreferredBlockSize() const;
|
fazekasgy@37
|
50 size_t getPreferredStepSize() const;
|
fazekasgy@37
|
51 size_t getMinChannelCount() const;
|
fazekasgy@37
|
52 size_t getMaxChannelCount() const;
|
fazekasgy@37
|
53
|
fazekasgy@37
|
54 std::string getIdentifier() const;
|
fazekasgy@37
|
55 std::string getName() const;
|
fazekasgy@37
|
56 std::string getDescription() const;
|
fazekasgy@37
|
57 std::string getMaker() const;
|
fazekasgy@37
|
58 int getPluginVersion() const;
|
fazekasgy@37
|
59 std::string getCopyright() const;
|
fazekasgy@37
|
60
|
fazekasgy@37
|
61 OutputList getOutputDescriptors() const;
|
fazekasgy@37
|
62 ParameterList getParameterDescriptors() const;
|
fazekasgy@37
|
63 float getParameter(std::string paramid) const;
|
fazekasgy@37
|
64 void setParameter(std::string paramid, float newval);
|
fazekasgy@37
|
65
|
fazekasgy@37
|
66 FeatureSet process(const float *const *inputBuffers,
|
fazekasgy@37
|
67 Vamp::RealTime timestamp);
|
fazekasgy@37
|
68
|
fazekasgy@37
|
69 FeatureSet getRemainingFeatures();
|
fazekasgy@37
|
70
|
fazekasgy@37
|
71 protected:
|
fazekasgy@37
|
72 static Mutex m_pythonInterpreterMutex;
|
fazekasgy@37
|
73 PyObject *m_pyClass;
|
fazekasgy@37
|
74 PyObject *m_pyInstance;
|
fazekasgy@37
|
75 int &m_instcount;
|
fazekasgy@37
|
76 size_t m_stepSize;
|
fazekasgy@37
|
77 size_t m_blockSize;
|
fazekasgy@37
|
78 size_t m_channels;
|
fazekasgy@37
|
79 std::string m_plugin;
|
fazekasgy@37
|
80 std::string m_class;
|
fazekasgy@37
|
81 std::string m_path;
|
fazekasgy@37
|
82 eProcessType m_processType;
|
fazekasgy@37
|
83 PyObject *m_pyProcess;
|
fazekasgy@37
|
84 PyObject *m_pyProcessCallable;
|
fazekasgy@37
|
85 mutable InputDomain m_inputDomain;
|
fazekasgy@37
|
86 PyTypeInterface m_ti;
|
fazekasgy@37
|
87 int m_vampyFlags;
|
fazekasgy@37
|
88 bool m_quitOnErrorFlag;
|
fazekasgy@37
|
89 bool m_debugFlag;
|
fazekasgy@37
|
90 bool m_useRealTimeFlag;
|
fazekasgy@51
|
91 bool m_numpyInstalled;
|
fazekasgy@51
|
92 mutable bool m_processFailure;
|
fazekasgy@37
|
93
|
fazekasgy@37
|
94 void setProcessType();
|
fazekasgy@37
|
95
|
fazekasgy@37
|
96 FeatureSet processMethodCall(const float *const *inputBuffers,Vamp::RealTime timestamp);
|
fazekasgy@37
|
97
|
Chris@66
|
98 bool getBooleanFlag(const char flagName[],bool) const;
|
Chris@66
|
99 int getBinaryFlags(const char flagName[], eVampyFlags) const;
|
Chris@66
|
100 void typeErrorHandler(const char *method, bool process = false) const;
|
fazekasgy@37
|
101
|
fazekasgy@37
|
102 /// simple 'void return' call with no args
|
Chris@66
|
103 void genericMethodCall(const char *method) const
|
fazekasgy@37
|
104 {
|
fazekasgy@37
|
105 if (m_debugFlag) cerr << DEBUG_NAME << endl;
|
fazekasgy@37
|
106 if ( PyObject_HasAttrString(m_pyInstance,method) )
|
fazekasgy@37
|
107 {
|
Chris@66
|
108 PyObject *pyValue = PyObject_CallMethod(m_pyInstance, (char *)method, NULL);
|
fazekasgy@37
|
109 if (!pyValue) {
|
fazekasgy@37
|
110 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
|
fazekasgy@37
|
111 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
112 }
|
fazekasgy@37
|
113 }
|
fazekasgy@37
|
114 }
|
fazekasgy@37
|
115
|
fazekasgy@37
|
116 /// 'no arg with default return value' call
|
fazekasgy@37
|
117 template<typename RET>
|
Chris@66
|
118 RET &genericMethodCall(const char *method, RET &rValue) const
|
fazekasgy@37
|
119 {
|
fazekasgy@37
|
120 if (m_debugFlag) cerr << DEBUG_NAME << endl;
|
fazekasgy@37
|
121 if ( PyObject_HasAttrString(m_pyInstance,method) )
|
fazekasgy@37
|
122 {
|
Chris@66
|
123 PyObject *pyValue = PyObject_CallMethod(m_pyInstance, (char *)method, NULL);
|
fazekasgy@37
|
124 if (!pyValue) {
|
fazekasgy@37
|
125 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
|
fazekasgy@37
|
126 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
127 return rValue;
|
fazekasgy@37
|
128 }
|
fazekasgy@37
|
129
|
fazekasgy@37
|
130 /// convert the returned value
|
fazekasgy@37
|
131 m_ti.PyValue_To_rValue(pyValue,rValue);
|
fazekasgy@37
|
132 if (!m_ti.error) {
|
fazekasgy@37
|
133 Py_DECREF(pyValue);
|
fazekasgy@37
|
134 } else {
|
fazekasgy@37
|
135 Py_CLEAR(pyValue);
|
fazekasgy@37
|
136 typeErrorHandler(method);
|
fazekasgy@37
|
137 }
|
fazekasgy@37
|
138 return rValue;
|
fazekasgy@37
|
139 }
|
Chris@67
|
140 if (m_debugFlag) cerr << DEFAULT_RETURN << endl;
|
fazekasgy@37
|
141 return rValue;
|
fazekasgy@37
|
142 }
|
fazekasgy@37
|
143
|
fazekasgy@37
|
144 /// unary call
|
fazekasgy@37
|
145 template<typename RET,typename A1>
|
Chris@66
|
146 RET genericMethodCallArgs(const char *method, A1 arg1) const
|
fazekasgy@37
|
147 {
|
fazekasgy@37
|
148 RET rValue = RET();
|
fazekasgy@37
|
149 if (m_debugFlag) cerr << DEBUG_NAME << endl;
|
fazekasgy@37
|
150 if (!PyObject_HasAttrString(m_pyInstance,method)) {
|
Chris@67
|
151 if (m_debugFlag) cerr << DEFAULT_RETURN << endl;
|
fazekasgy@37
|
152 return rValue;
|
fazekasgy@37
|
153 }
|
fazekasgy@37
|
154
|
fazekasgy@37
|
155 /// prepare arguments for fast method call
|
fazekasgy@37
|
156 PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
|
fazekasgy@37
|
157 PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
|
fazekasgy@37
|
158 PyObject* pyArgs = PyTuple_New(1);
|
fazekasgy@37
|
159 if (!(pyArgs && pyCallable && pyMethod)) {
|
fazekasgy@37
|
160 cerr << PLUGIN_ERROR << "Failed to prepare argument for calling method." << endl;
|
fazekasgy@37
|
161 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
162 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
163 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
164 return rValue;
|
fazekasgy@37
|
165 }
|
fazekasgy@37
|
166
|
fazekasgy@37
|
167 PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
|
fazekasgy@37
|
168 if (m_ti.error) {
|
fazekasgy@37
|
169 cerr << PLUGIN_ERROR << "Failed to convert argument for calling method." << endl;
|
fazekasgy@37
|
170 typeErrorHandler(method);
|
fazekasgy@37
|
171 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
172 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
173 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
174 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
175 return rValue;
|
fazekasgy@37
|
176 }
|
fazekasgy@37
|
177
|
fazekasgy@37
|
178 PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
|
fazekasgy@37
|
179 Py_INCREF(pyArg1);
|
fazekasgy@37
|
180
|
fazekasgy@37
|
181 /// call the method
|
fazekasgy@37
|
182 PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
|
fazekasgy@37
|
183 if (!pyValue)
|
fazekasgy@37
|
184 {
|
fazekasgy@37
|
185 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
|
fazekasgy@37
|
186 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
187 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
188 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
189 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
190 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
191 return rValue;
|
fazekasgy@37
|
192 }
|
fazekasgy@37
|
193
|
fazekasgy@37
|
194 Py_DECREF(pyMethod);
|
fazekasgy@37
|
195 Py_DECREF(pyCallable);
|
fazekasgy@37
|
196 Py_DECREF(pyArg1);
|
fazekasgy@37
|
197 Py_DECREF(pyArgs);
|
fazekasgy@37
|
198
|
fazekasgy@37
|
199 /// convert the returned value
|
fazekasgy@37
|
200 m_ti.PyValue_To_rValue(pyValue,rValue);
|
fazekasgy@37
|
201 if (!m_ti.error) {
|
fazekasgy@37
|
202 Py_DECREF(pyValue);
|
fazekasgy@37
|
203 } else {
|
fazekasgy@37
|
204 Py_CLEAR(pyValue);
|
fazekasgy@37
|
205 typeErrorHandler(method);
|
fazekasgy@37
|
206 }
|
fazekasgy@37
|
207 return rValue;
|
fazekasgy@37
|
208 }
|
fazekasgy@37
|
209
|
fazekasgy@37
|
210 /// binary call
|
fazekasgy@37
|
211 template<typename RET,typename A1,typename A2>
|
Chris@66
|
212 RET genericMethodCallArgs(const char *method, A1 arg1, A2 arg2) const
|
fazekasgy@37
|
213 {
|
fazekasgy@37
|
214 RET rValue = RET();
|
fazekasgy@37
|
215 if (m_debugFlag) cerr << DEBUG_NAME << endl;
|
fazekasgy@37
|
216 if (!PyObject_HasAttrString(m_pyInstance,method)) {
|
Chris@67
|
217 if (m_debugFlag) cerr << DEFAULT_RETURN << endl;
|
fazekasgy@37
|
218 return rValue;
|
fazekasgy@37
|
219 }
|
fazekasgy@37
|
220
|
fazekasgy@37
|
221 /// prepare arguments for fast method call
|
fazekasgy@37
|
222 PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
|
fazekasgy@37
|
223 PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
|
fazekasgy@37
|
224 PyObject* pyArgs = PyTuple_New(2);
|
fazekasgy@37
|
225 if (!(pyArgs && pyCallable && pyMethod)) {
|
fazekasgy@37
|
226 cerr << PLUGIN_ERROR << "Failed to prepare arguments for calling method." << endl;
|
fazekasgy@37
|
227 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
228 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
229 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
230 return rValue;
|
fazekasgy@37
|
231 }
|
fazekasgy@37
|
232
|
fazekasgy@37
|
233 PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
|
fazekasgy@37
|
234 PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
|
fazekasgy@37
|
235 if (m_ti.error) {
|
fazekasgy@37
|
236 cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl;
|
fazekasgy@37
|
237 typeErrorHandler(method);
|
fazekasgy@37
|
238 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
239 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
240 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
241 Py_CLEAR(pyArg2);
|
fazekasgy@37
|
242 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
243 return rValue;
|
fazekasgy@37
|
244 }
|
fazekasgy@37
|
245
|
fazekasgy@37
|
246 PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
|
fazekasgy@37
|
247 Py_INCREF(pyArg1);
|
fazekasgy@37
|
248 PyTuple_SET_ITEM(pyArgs, 1, pyArg2);
|
fazekasgy@37
|
249 Py_INCREF(pyArg2);
|
fazekasgy@37
|
250
|
fazekasgy@37
|
251 // calls the method
|
fazekasgy@37
|
252 PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
|
fazekasgy@37
|
253 if (!pyValue)
|
fazekasgy@37
|
254 {
|
fazekasgy@37
|
255 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
|
fazekasgy@37
|
256 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
257 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
258 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
259 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
260 Py_CLEAR(pyArg2);
|
fazekasgy@37
|
261 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
262 return rValue;
|
fazekasgy@37
|
263 }
|
fazekasgy@37
|
264
|
fazekasgy@37
|
265 Py_DECREF(pyMethod);
|
fazekasgy@37
|
266 Py_DECREF(pyCallable);
|
fazekasgy@37
|
267 Py_DECREF(pyArg1);
|
fazekasgy@37
|
268 Py_DECREF(pyArg2);
|
fazekasgy@37
|
269 Py_DECREF(pyArgs);
|
fazekasgy@37
|
270
|
fazekasgy@37
|
271 /// convert the returned value
|
fazekasgy@37
|
272 m_ti.PyValue_To_rValue(pyValue,rValue);
|
fazekasgy@37
|
273 if (!m_ti.error) {
|
fazekasgy@37
|
274 Py_DECREF(pyValue);
|
fazekasgy@37
|
275 } else {
|
fazekasgy@37
|
276 Py_CLEAR(pyValue);
|
fazekasgy@37
|
277 typeErrorHandler(method);
|
fazekasgy@37
|
278 }
|
fazekasgy@37
|
279 return rValue;
|
fazekasgy@37
|
280 }
|
fazekasgy@37
|
281
|
fazekasgy@37
|
282 /// trenary call
|
fazekasgy@37
|
283 template<typename RET,typename A1,typename A2,typename A3>
|
Chris@66
|
284 RET genericMethodCallArgs(const char *method, A1 arg1, A2 arg2, A3 arg3) const
|
fazekasgy@37
|
285 {
|
fazekasgy@37
|
286 RET rValue = RET();
|
fazekasgy@37
|
287 if (m_debugFlag) cerr << DEBUG_NAME << endl;
|
fazekasgy@37
|
288 if (!PyObject_HasAttrString(m_pyInstance,method)) {
|
Chris@67
|
289 if (m_debugFlag) cerr << DEFAULT_RETURN << endl;
|
fazekasgy@37
|
290 return rValue;
|
fazekasgy@37
|
291 }
|
fazekasgy@37
|
292
|
fazekasgy@37
|
293 /// prepare arguments for fast method call
|
fazekasgy@37
|
294 PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
|
fazekasgy@37
|
295 PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
|
fazekasgy@37
|
296 PyObject* pyArgs = PyTuple_New(3);
|
fazekasgy@37
|
297 if (!(pyArgs && pyCallable && pyMethod)) {
|
fazekasgy@37
|
298 cerr << PLUGIN_ERROR << "Failed to prepare arguments for calling method." << endl;
|
fazekasgy@37
|
299 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
300 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
301 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
302 return rValue;
|
fazekasgy@37
|
303 }
|
fazekasgy@37
|
304
|
fazekasgy@37
|
305 PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
|
fazekasgy@37
|
306 PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
|
fazekasgy@37
|
307 PyObject *pyArg3 = m_ti.PyValue_From_CValue(arg3);
|
fazekasgy@37
|
308 if (m_ti.error) {
|
fazekasgy@37
|
309 cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl;
|
fazekasgy@37
|
310 typeErrorHandler(method);
|
fazekasgy@37
|
311 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
312 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
313 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
314 Py_CLEAR(pyArg2);
|
fazekasgy@37
|
315 Py_CLEAR(pyArg3);
|
fazekasgy@37
|
316 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
317 return rValue;
|
fazekasgy@37
|
318 }
|
fazekasgy@37
|
319
|
fazekasgy@37
|
320 /// Optimization: Pack args in a tuple to avoid va_list parsing.
|
fazekasgy@37
|
321 PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
|
fazekasgy@37
|
322 Py_INCREF(pyArg1);
|
fazekasgy@37
|
323 PyTuple_SET_ITEM(pyArgs, 1, pyArg2);
|
fazekasgy@37
|
324 Py_INCREF(pyArg2);
|
fazekasgy@37
|
325 PyTuple_SET_ITEM(pyArgs, 2, pyArg3);
|
fazekasgy@37
|
326 Py_INCREF(pyArg3);
|
fazekasgy@37
|
327
|
fazekasgy@37
|
328 // PyObject *pyValue = PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyArg1,pyArg2,pyArg3,NULL);
|
fazekasgy@37
|
329 /// fast method call
|
fazekasgy@37
|
330 PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
|
fazekasgy@37
|
331 if (!pyValue)
|
fazekasgy@37
|
332 {
|
fazekasgy@37
|
333 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
|
fazekasgy@37
|
334 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
335 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
336 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
337 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
338 Py_CLEAR(pyArg2);
|
fazekasgy@37
|
339 Py_CLEAR(pyArg3);
|
fazekasgy@37
|
340 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
341 return rValue;
|
fazekasgy@37
|
342 }
|
fazekasgy@37
|
343
|
fazekasgy@37
|
344 Py_DECREF(pyMethod);
|
fazekasgy@37
|
345 Py_DECREF(pyCallable);
|
fazekasgy@37
|
346 Py_DECREF(pyArg1);
|
fazekasgy@37
|
347 Py_DECREF(pyArg2);
|
fazekasgy@37
|
348 Py_DECREF(pyArg3);
|
fazekasgy@37
|
349 Py_DECREF(pyArgs);
|
fazekasgy@37
|
350
|
fazekasgy@37
|
351 /// convert the returned value
|
fazekasgy@37
|
352 m_ti.PyValue_To_rValue(pyValue,rValue);
|
fazekasgy@37
|
353 if (!m_ti.error) {
|
fazekasgy@37
|
354 Py_DECREF(pyValue);
|
fazekasgy@37
|
355 } else {
|
fazekasgy@37
|
356 Py_CLEAR(pyValue);
|
fazekasgy@37
|
357 typeErrorHandler(method);
|
fazekasgy@37
|
358 }
|
fazekasgy@37
|
359 return rValue;
|
fazekasgy@37
|
360 }
|
fazekasgy@37
|
361
|
fazekasgy@37
|
362 };
|
fazekasgy@37
|
363
|
fazekasgy@37
|
364 /// optimised process call
|
fazekasgy@37
|
365 inline PyPlugin::FeatureSet
|
fazekasgy@37
|
366 PyPlugin::processMethodCall(const float *const *inputBuffers,Vamp::RealTime timestamp)
|
fazekasgy@37
|
367 {
|
fazekasgy@51
|
368
|
fazekasgy@37
|
369 /// Optimizations: 1) we avoid ...ObjArg functions since we know
|
fazekasgy@37
|
370 /// the number of arguments, and we don't like va_list parsing
|
fazekasgy@37
|
371 /// in the process. 2) Also: we're supposed to incref args,
|
fazekasgy@37
|
372 /// but instead, we let the arguments tuple steal the references
|
fazekasgy@37
|
373 /// and decref them when it is deallocated.
|
fazekasgy@37
|
374 /// 3) all conversions are now using the fast sequence protocol
|
fazekasgy@37
|
375 /// (indexing the underlying object array).
|
fazekasgy@37
|
376
|
fazekasgy@37
|
377 FeatureSet rFeatureSet;
|
fazekasgy@37
|
378 PyObject *pyChannelList = NULL;
|
fazekasgy@37
|
379
|
fazekasgy@37
|
380 if (m_processType == numpy_bufferProcess) {
|
fazekasgy@51
|
381 pyChannelList = m_ti.InputBuffers_As_SharedMemoryList(
|
fazekasgy@51
|
382 inputBuffers,m_channels,m_blockSize,m_inputDomain);
|
fazekasgy@37
|
383 }
|
fazekasgy@37
|
384
|
fazekasgy@37
|
385 if (m_processType == legacyProcess) {
|
fazekasgy@51
|
386 pyChannelList = m_ti.InputBuffers_As_PythonLists(
|
fazekasgy@51
|
387 inputBuffers,m_channels,m_blockSize,m_inputDomain);
|
fazekasgy@37
|
388 }
|
fazekasgy@37
|
389
|
fazekasgy@37
|
390 #ifdef HAVE_NUMPY
|
fazekasgy@37
|
391 if (m_processType == numpy_arrayProcess) {
|
fazekasgy@51
|
392 pyChannelList = m_ti.InputBuffers_As_NumpyArray(
|
fazekasgy@51
|
393 inputBuffers,m_channels,m_blockSize,m_inputDomain);
|
fazekasgy@37
|
394 }
|
fazekasgy@37
|
395 #endif
|
fazekasgy@37
|
396
|
fazekasgy@37
|
397 /// we don't expect these to fail unless out of memory (which is very unlikely on modern systems)
|
fazekasgy@37
|
398 #ifdef _DEBUG
|
fazekasgy@37
|
399 if (!pyChannelList) {
|
fazekasgy@37
|
400 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
401 std::string method = PyString_AsString(m_pyProcess);
|
fazekasgy@37
|
402 cerr << PLUGIN_ERROR << "Failed to create channel list." << endl;
|
fazekasgy@37
|
403 return rFeatureSet;
|
fazekasgy@37
|
404 }
|
fazekasgy@37
|
405 #endif
|
fazekasgy@37
|
406
|
fazekasgy@37
|
407 PyObject *pyTimeStamp = NULL;
|
fazekasgy@37
|
408
|
fazekasgy@37
|
409 if (m_useRealTimeFlag) {
|
fazekasgy@37
|
410 //(1) pass TimeStamp as PyRealTime object
|
fazekasgy@37
|
411 pyTimeStamp = PyRealTime_FromRealTime(timestamp);
|
fazekasgy@37
|
412
|
fazekasgy@37
|
413 } else {
|
fazekasgy@37
|
414 //(2) pass TimeStamp as frame count (long Sample Count)
|
fazekasgy@37
|
415 pyTimeStamp = PyLong_FromLong(Vamp::RealTime::realTime2Frame
|
fazekasgy@37
|
416 (timestamp, (unsigned int) m_inputSampleRate));
|
fazekasgy@37
|
417 }
|
fazekasgy@37
|
418
|
fazekasgy@37
|
419
|
fazekasgy@37
|
420 #ifdef _DEBUG
|
fazekasgy@37
|
421 if (!pyTimeStamp) {
|
fazekasgy@37
|
422 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
423 std::string method = PyString_AsString(m_pyProcess);
|
fazekasgy@37
|
424 cerr << PLUGIN_ERROR << "Failed to create RealTime time stamp." << endl;
|
fazekasgy@37
|
425 Py_DECREF(pyChannelList);
|
fazekasgy@37
|
426 return rFeatureSet;
|
fazekasgy@37
|
427 }
|
fazekasgy@37
|
428 #endif
|
fazekasgy@37
|
429
|
fazekasgy@37
|
430 /// Old method: Call python process (returns new reference)
|
fazekasgy@37
|
431 /// PyObject *pyValue = PyObject_CallMethodObjArgs
|
fazekasgy@37
|
432 /// (m_pyInstance,m_pyProcess,pyChannelList,pyTimeStamp,NULL);
|
fazekasgy@37
|
433
|
fazekasgy@37
|
434 PyObject *pyArgs = PyTuple_New(2);
|
fazekasgy@37
|
435 PyTuple_SET_ITEM(pyArgs, 0, pyChannelList);
|
fazekasgy@37
|
436 PyTuple_SET_ITEM(pyArgs, 1, pyTimeStamp);
|
fazekasgy@37
|
437
|
fazekasgy@37
|
438 /// Call python process (returns new reference) {kwArgs = NULL}
|
fazekasgy@37
|
439 PyObject *pyValue = PyObject_Call(m_pyProcessCallable,pyArgs,NULL);
|
fazekasgy@37
|
440
|
fazekasgy@37
|
441 if (!pyValue) {
|
fazekasgy@37
|
442 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
443 std::string method = PyString_AsString(m_pyProcess);
|
fazekasgy@37
|
444 cerr << PLUGIN_ERROR << "An error occurred while evaluating Python process." << endl;
|
fazekasgy@37
|
445 Py_CLEAR(pyValue);
|
fazekasgy@37
|
446 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
447 return rFeatureSet;
|
fazekasgy@37
|
448 }
|
fazekasgy@37
|
449
|
fazekasgy@37
|
450 rFeatureSet = m_ti.PyValue_To_FeatureSet(pyValue);
|
fazekasgy@37
|
451 if (!m_ti.error) {
|
fazekasgy@37
|
452 Py_DECREF(pyValue);
|
fazekasgy@37
|
453 Py_DECREF(pyArgs);
|
fazekasgy@37
|
454 } else {
|
fazekasgy@51
|
455 typeErrorHandler(PyString_AsString(m_pyProcess),true);
|
fazekasgy@37
|
456 Py_CLEAR(pyValue);
|
fazekasgy@37
|
457 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
458 }
|
fazekasgy@37
|
459 return rFeatureSet;
|
fazekasgy@37
|
460 }
|
fazekasgy@37
|
461
|
fazekasgy@37
|
462 #endif
|