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