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@37
|
76 PyPlugin(std::string plugin,float inputSampleRate, PyObject *pyClass, int &instcount);
|
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@37
|
125
|
fazekasgy@37
|
126 void setProcessType();
|
fazekasgy@37
|
127
|
fazekasgy@37
|
128 FeatureSet processMethodCall(const float *const *inputBuffers,Vamp::RealTime timestamp);
|
fazekasgy@37
|
129
|
fazekasgy@37
|
130 bool getBooleanFlag(char flagName[],bool) const;
|
fazekasgy@37
|
131 int getBinaryFlags(char flagName[], eVampyFlags) const;
|
fazekasgy@37
|
132 void typeErrorHandler(char *method) const;
|
fazekasgy@37
|
133
|
fazekasgy@37
|
134 /// simple 'void return' call with no args
|
fazekasgy@37
|
135 void genericMethodCall(char *method) const
|
fazekasgy@37
|
136 {
|
fazekasgy@37
|
137 if (m_debugFlag) cerr << DEBUG_NAME << endl;
|
fazekasgy@37
|
138 if ( PyObject_HasAttrString(m_pyInstance,method) )
|
fazekasgy@37
|
139 {
|
fazekasgy@37
|
140 PyObject *pyValue = PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@37
|
141 if (!pyValue) {
|
fazekasgy@37
|
142 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
|
fazekasgy@37
|
143 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
144 }
|
fazekasgy@37
|
145 }
|
fazekasgy@37
|
146 }
|
fazekasgy@37
|
147
|
fazekasgy@37
|
148 /// 'no arg with default return value' call
|
fazekasgy@37
|
149 template<typename RET>
|
fazekasgy@37
|
150 RET &genericMethodCall(char *method, RET &rValue) const
|
fazekasgy@37
|
151 {
|
fazekasgy@37
|
152 if (m_debugFlag) cerr << DEBUG_NAME << endl;
|
fazekasgy@37
|
153 if ( PyObject_HasAttrString(m_pyInstance,method) )
|
fazekasgy@37
|
154 {
|
fazekasgy@37
|
155 PyObject *pyValue = PyObject_CallMethod(m_pyInstance, method, NULL);
|
fazekasgy@37
|
156 if (!pyValue) {
|
fazekasgy@37
|
157 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
|
fazekasgy@37
|
158 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
159 return rValue;
|
fazekasgy@37
|
160 }
|
fazekasgy@37
|
161
|
fazekasgy@37
|
162 /// convert the returned value
|
fazekasgy@37
|
163 m_ti.PyValue_To_rValue(pyValue,rValue);
|
fazekasgy@37
|
164 if (!m_ti.error) {
|
fazekasgy@37
|
165 Py_DECREF(pyValue);
|
fazekasgy@37
|
166 } else {
|
fazekasgy@37
|
167 Py_CLEAR(pyValue);
|
fazekasgy@37
|
168 typeErrorHandler(method);
|
fazekasgy@37
|
169 }
|
fazekasgy@37
|
170 return rValue;
|
fazekasgy@37
|
171 }
|
fazekasgy@37
|
172 if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
|
fazekasgy@37
|
173 return rValue;
|
fazekasgy@37
|
174 }
|
fazekasgy@37
|
175
|
fazekasgy@37
|
176 /// unary call
|
fazekasgy@37
|
177 template<typename RET,typename A1>
|
fazekasgy@37
|
178 RET genericMethodCallArgs(char *method, A1 arg1) const
|
fazekasgy@37
|
179 {
|
fazekasgy@37
|
180 RET rValue = RET();
|
fazekasgy@37
|
181 if (m_debugFlag) cerr << DEBUG_NAME << endl;
|
fazekasgy@37
|
182 if (!PyObject_HasAttrString(m_pyInstance,method)) {
|
fazekasgy@37
|
183 if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
|
fazekasgy@37
|
184 return rValue;
|
fazekasgy@37
|
185 }
|
fazekasgy@37
|
186
|
fazekasgy@37
|
187 /// prepare arguments for fast method call
|
fazekasgy@37
|
188 PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
|
fazekasgy@37
|
189 PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
|
fazekasgy@37
|
190 PyObject* pyArgs = PyTuple_New(1);
|
fazekasgy@37
|
191 if (!(pyArgs && pyCallable && pyMethod)) {
|
fazekasgy@37
|
192 cerr << PLUGIN_ERROR << "Failed to prepare argument for calling method." << endl;
|
fazekasgy@37
|
193 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
194 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
195 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
196 return rValue;
|
fazekasgy@37
|
197 }
|
fazekasgy@37
|
198
|
fazekasgy@37
|
199 PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
|
fazekasgy@37
|
200 if (m_ti.error) {
|
fazekasgy@37
|
201 cerr << PLUGIN_ERROR << "Failed to convert argument for calling method." << endl;
|
fazekasgy@37
|
202 typeErrorHandler(method);
|
fazekasgy@37
|
203 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
204 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
205 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
206 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
207 return rValue;
|
fazekasgy@37
|
208 }
|
fazekasgy@37
|
209
|
fazekasgy@37
|
210 PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
|
fazekasgy@37
|
211 Py_INCREF(pyArg1);
|
fazekasgy@37
|
212
|
fazekasgy@37
|
213 /// call the method
|
fazekasgy@37
|
214 PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
|
fazekasgy@37
|
215 if (!pyValue)
|
fazekasgy@37
|
216 {
|
fazekasgy@37
|
217 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
|
fazekasgy@37
|
218 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
219 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
220 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
221 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
222 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
223 return rValue;
|
fazekasgy@37
|
224 }
|
fazekasgy@37
|
225
|
fazekasgy@37
|
226 Py_DECREF(pyMethod);
|
fazekasgy@37
|
227 Py_DECREF(pyCallable);
|
fazekasgy@37
|
228 Py_DECREF(pyArg1);
|
fazekasgy@37
|
229 Py_DECREF(pyArgs);
|
fazekasgy@37
|
230
|
fazekasgy@37
|
231 /// convert the returned value
|
fazekasgy@37
|
232 m_ti.PyValue_To_rValue(pyValue,rValue);
|
fazekasgy@37
|
233 if (!m_ti.error) {
|
fazekasgy@37
|
234 Py_DECREF(pyValue);
|
fazekasgy@37
|
235 } else {
|
fazekasgy@37
|
236 Py_CLEAR(pyValue);
|
fazekasgy@37
|
237 typeErrorHandler(method);
|
fazekasgy@37
|
238 }
|
fazekasgy@37
|
239 return rValue;
|
fazekasgy@37
|
240 }
|
fazekasgy@37
|
241
|
fazekasgy@37
|
242 /// binary call
|
fazekasgy@37
|
243 template<typename RET,typename A1,typename A2>
|
fazekasgy@37
|
244 RET genericMethodCallArgs(char *method, A1 arg1, A2 arg2) const
|
fazekasgy@37
|
245 {
|
fazekasgy@37
|
246 RET rValue = RET();
|
fazekasgy@37
|
247 if (m_debugFlag) cerr << DEBUG_NAME << endl;
|
fazekasgy@37
|
248 if (!PyObject_HasAttrString(m_pyInstance,method)) {
|
fazekasgy@37
|
249 if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
|
fazekasgy@37
|
250 return rValue;
|
fazekasgy@37
|
251 }
|
fazekasgy@37
|
252
|
fazekasgy@37
|
253 /// prepare arguments for fast method call
|
fazekasgy@37
|
254 PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
|
fazekasgy@37
|
255 PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
|
fazekasgy@37
|
256 PyObject* pyArgs = PyTuple_New(2);
|
fazekasgy@37
|
257 if (!(pyArgs && pyCallable && pyMethod)) {
|
fazekasgy@37
|
258 cerr << PLUGIN_ERROR << "Failed to prepare arguments for calling method." << endl;
|
fazekasgy@37
|
259 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
260 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
261 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
262 return rValue;
|
fazekasgy@37
|
263 }
|
fazekasgy@37
|
264
|
fazekasgy@37
|
265 PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
|
fazekasgy@37
|
266 PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
|
fazekasgy@37
|
267 if (m_ti.error) {
|
fazekasgy@37
|
268 cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl;
|
fazekasgy@37
|
269 typeErrorHandler(method);
|
fazekasgy@37
|
270 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
271 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
272 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
273 Py_CLEAR(pyArg2);
|
fazekasgy@37
|
274 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
275 return rValue;
|
fazekasgy@37
|
276 }
|
fazekasgy@37
|
277
|
fazekasgy@37
|
278 PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
|
fazekasgy@37
|
279 Py_INCREF(pyArg1);
|
fazekasgy@37
|
280 PyTuple_SET_ITEM(pyArgs, 1, pyArg2);
|
fazekasgy@37
|
281 Py_INCREF(pyArg2);
|
fazekasgy@37
|
282
|
fazekasgy@37
|
283 // calls the method
|
fazekasgy@37
|
284 PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
|
fazekasgy@37
|
285 if (!pyValue)
|
fazekasgy@37
|
286 {
|
fazekasgy@37
|
287 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
|
fazekasgy@37
|
288 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
289 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
290 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
291 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
292 Py_CLEAR(pyArg2);
|
fazekasgy@37
|
293 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
294 return rValue;
|
fazekasgy@37
|
295 }
|
fazekasgy@37
|
296
|
fazekasgy@37
|
297 Py_DECREF(pyMethod);
|
fazekasgy@37
|
298 Py_DECREF(pyCallable);
|
fazekasgy@37
|
299 Py_DECREF(pyArg1);
|
fazekasgy@37
|
300 Py_DECREF(pyArg2);
|
fazekasgy@37
|
301 Py_DECREF(pyArgs);
|
fazekasgy@37
|
302
|
fazekasgy@37
|
303 /// convert the returned value
|
fazekasgy@37
|
304 m_ti.PyValue_To_rValue(pyValue,rValue);
|
fazekasgy@37
|
305 if (!m_ti.error) {
|
fazekasgy@37
|
306 Py_DECREF(pyValue);
|
fazekasgy@37
|
307 } else {
|
fazekasgy@37
|
308 Py_CLEAR(pyValue);
|
fazekasgy@37
|
309 typeErrorHandler(method);
|
fazekasgy@37
|
310 }
|
fazekasgy@37
|
311 return rValue;
|
fazekasgy@37
|
312 }
|
fazekasgy@37
|
313
|
fazekasgy@37
|
314 /// trenary call
|
fazekasgy@37
|
315 template<typename RET,typename A1,typename A2,typename A3>
|
fazekasgy@37
|
316 RET genericMethodCallArgs(char *method, A1 arg1, A2 arg2, A3 arg3) const
|
fazekasgy@37
|
317 {
|
fazekasgy@37
|
318 RET rValue = RET();
|
fazekasgy@37
|
319 if (m_debugFlag) cerr << DEBUG_NAME << endl;
|
fazekasgy@37
|
320 if (!PyObject_HasAttrString(m_pyInstance,method)) {
|
fazekasgy@37
|
321 if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
|
fazekasgy@37
|
322 return rValue;
|
fazekasgy@37
|
323 }
|
fazekasgy@37
|
324
|
fazekasgy@37
|
325 /// prepare arguments for fast method call
|
fazekasgy@37
|
326 PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
|
fazekasgy@37
|
327 PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
|
fazekasgy@37
|
328 PyObject* pyArgs = PyTuple_New(3);
|
fazekasgy@37
|
329 if (!(pyArgs && pyCallable && pyMethod)) {
|
fazekasgy@37
|
330 cerr << PLUGIN_ERROR << "Failed to prepare arguments for calling method." << endl;
|
fazekasgy@37
|
331 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
332 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
333 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
334 return rValue;
|
fazekasgy@37
|
335 }
|
fazekasgy@37
|
336
|
fazekasgy@37
|
337 PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
|
fazekasgy@37
|
338 PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
|
fazekasgy@37
|
339 PyObject *pyArg3 = m_ti.PyValue_From_CValue(arg3);
|
fazekasgy@37
|
340 if (m_ti.error) {
|
fazekasgy@37
|
341 cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl;
|
fazekasgy@37
|
342 typeErrorHandler(method);
|
fazekasgy@37
|
343 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
344 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
345 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
346 Py_CLEAR(pyArg2);
|
fazekasgy@37
|
347 Py_CLEAR(pyArg3);
|
fazekasgy@37
|
348 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
349 return rValue;
|
fazekasgy@37
|
350 }
|
fazekasgy@37
|
351
|
fazekasgy@37
|
352 /// Optimization: Pack args in a tuple to avoid va_list parsing.
|
fazekasgy@37
|
353 PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
|
fazekasgy@37
|
354 Py_INCREF(pyArg1);
|
fazekasgy@37
|
355 PyTuple_SET_ITEM(pyArgs, 1, pyArg2);
|
fazekasgy@37
|
356 Py_INCREF(pyArg2);
|
fazekasgy@37
|
357 PyTuple_SET_ITEM(pyArgs, 2, pyArg3);
|
fazekasgy@37
|
358 Py_INCREF(pyArg3);
|
fazekasgy@37
|
359
|
fazekasgy@37
|
360 // PyObject *pyValue = PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyArg1,pyArg2,pyArg3,NULL);
|
fazekasgy@37
|
361 /// fast method call
|
fazekasgy@37
|
362 PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
|
fazekasgy@37
|
363 if (!pyValue)
|
fazekasgy@37
|
364 {
|
fazekasgy@37
|
365 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
|
fazekasgy@37
|
366 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
367 Py_CLEAR(pyMethod);
|
fazekasgy@37
|
368 Py_CLEAR(pyCallable);
|
fazekasgy@37
|
369 Py_CLEAR(pyArg1);
|
fazekasgy@37
|
370 Py_CLEAR(pyArg2);
|
fazekasgy@37
|
371 Py_CLEAR(pyArg3);
|
fazekasgy@37
|
372 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
373 return rValue;
|
fazekasgy@37
|
374 }
|
fazekasgy@37
|
375
|
fazekasgy@37
|
376 Py_DECREF(pyMethod);
|
fazekasgy@37
|
377 Py_DECREF(pyCallable);
|
fazekasgy@37
|
378 Py_DECREF(pyArg1);
|
fazekasgy@37
|
379 Py_DECREF(pyArg2);
|
fazekasgy@37
|
380 Py_DECREF(pyArg3);
|
fazekasgy@37
|
381 Py_DECREF(pyArgs);
|
fazekasgy@37
|
382
|
fazekasgy@37
|
383 /// convert the returned value
|
fazekasgy@37
|
384 m_ti.PyValue_To_rValue(pyValue,rValue);
|
fazekasgy@37
|
385 if (!m_ti.error) {
|
fazekasgy@37
|
386 Py_DECREF(pyValue);
|
fazekasgy@37
|
387 } else {
|
fazekasgy@37
|
388 Py_CLEAR(pyValue);
|
fazekasgy@37
|
389 typeErrorHandler(method);
|
fazekasgy@37
|
390 }
|
fazekasgy@37
|
391 return rValue;
|
fazekasgy@37
|
392 }
|
fazekasgy@37
|
393
|
fazekasgy@37
|
394 };
|
fazekasgy@37
|
395
|
fazekasgy@37
|
396 /// optimised process call
|
fazekasgy@37
|
397 inline PyPlugin::FeatureSet
|
fazekasgy@37
|
398 PyPlugin::processMethodCall(const float *const *inputBuffers,Vamp::RealTime timestamp)
|
fazekasgy@37
|
399 {
|
fazekasgy@37
|
400
|
fazekasgy@37
|
401 /// Optimizations: 1) we avoid ...ObjArg functions since we know
|
fazekasgy@37
|
402 /// the number of arguments, and we don't like va_list parsing
|
fazekasgy@37
|
403 /// in the process. 2) Also: we're supposed to incref args,
|
fazekasgy@37
|
404 /// but instead, we let the arguments tuple steal the references
|
fazekasgy@37
|
405 /// and decref them when it is deallocated.
|
fazekasgy@37
|
406 /// 3) all conversions are now using the fast sequence protocol
|
fazekasgy@37
|
407 /// (indexing the underlying object array).
|
fazekasgy@37
|
408
|
fazekasgy@37
|
409 FeatureSet rFeatureSet;
|
fazekasgy@37
|
410 PyObject *pyChannelList = NULL;
|
fazekasgy@37
|
411
|
fazekasgy@37
|
412 if (m_processType == numpy_bufferProcess) {
|
fazekasgy@47
|
413 pyChannelList = m_ti.InputBuffers_As_SharedMemoryList(inputBuffers,m_channels,m_blockSize,m_inputDomain);
|
fazekasgy@37
|
414 }
|
fazekasgy@37
|
415
|
fazekasgy@37
|
416 if (m_processType == legacyProcess) {
|
fazekasgy@37
|
417 pyChannelList = m_ti.InputBuffers_As_PythonLists(inputBuffers,m_channels,m_blockSize,m_inputDomain);
|
fazekasgy@37
|
418 }
|
fazekasgy@37
|
419
|
fazekasgy@37
|
420 #ifdef HAVE_NUMPY
|
fazekasgy@37
|
421 if (m_processType == numpy_arrayProcess) {
|
fazekasgy@37
|
422 pyChannelList = m_ti.InputBuffers_As_NumpyArray(inputBuffers,m_channels,m_blockSize,m_inputDomain);
|
fazekasgy@37
|
423 }
|
fazekasgy@37
|
424 #endif
|
fazekasgy@37
|
425
|
fazekasgy@37
|
426 /// we don't expect these to fail unless out of memory (which is very unlikely on modern systems)
|
fazekasgy@37
|
427 #ifdef _DEBUG
|
fazekasgy@37
|
428 if (!pyChannelList) {
|
fazekasgy@37
|
429 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
430 std::string method = PyString_AsString(m_pyProcess);
|
fazekasgy@37
|
431 cerr << PLUGIN_ERROR << "Failed to create channel list." << endl;
|
fazekasgy@37
|
432 return rFeatureSet;
|
fazekasgy@37
|
433 }
|
fazekasgy@37
|
434 #endif
|
fazekasgy@37
|
435
|
fazekasgy@37
|
436 PyObject *pyTimeStamp = NULL;
|
fazekasgy@37
|
437
|
fazekasgy@37
|
438 if (m_useRealTimeFlag) {
|
fazekasgy@37
|
439 //(1) pass TimeStamp as PyRealTime object
|
fazekasgy@37
|
440 pyTimeStamp = PyRealTime_FromRealTime(timestamp);
|
fazekasgy@37
|
441
|
fazekasgy@37
|
442 } else {
|
fazekasgy@37
|
443 //(2) pass TimeStamp as frame count (long Sample Count)
|
fazekasgy@37
|
444 pyTimeStamp = PyLong_FromLong(Vamp::RealTime::realTime2Frame
|
fazekasgy@37
|
445 (timestamp, (unsigned int) m_inputSampleRate));
|
fazekasgy@37
|
446 }
|
fazekasgy@37
|
447
|
fazekasgy@37
|
448
|
fazekasgy@37
|
449 #ifdef _DEBUG
|
fazekasgy@37
|
450 if (!pyTimeStamp) {
|
fazekasgy@37
|
451 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
452 std::string method = PyString_AsString(m_pyProcess);
|
fazekasgy@37
|
453 cerr << PLUGIN_ERROR << "Failed to create RealTime time stamp." << endl;
|
fazekasgy@37
|
454 Py_DECREF(pyChannelList);
|
fazekasgy@37
|
455 return rFeatureSet;
|
fazekasgy@37
|
456 }
|
fazekasgy@37
|
457 #endif
|
fazekasgy@37
|
458
|
fazekasgy@37
|
459 /// Old method: Call python process (returns new reference)
|
fazekasgy@37
|
460 /// PyObject *pyValue = PyObject_CallMethodObjArgs
|
fazekasgy@37
|
461 /// (m_pyInstance,m_pyProcess,pyChannelList,pyTimeStamp,NULL);
|
fazekasgy@37
|
462
|
fazekasgy@37
|
463 PyObject *pyArgs = PyTuple_New(2);
|
fazekasgy@37
|
464 PyTuple_SET_ITEM(pyArgs, 0, pyChannelList);
|
fazekasgy@37
|
465 PyTuple_SET_ITEM(pyArgs, 1, pyTimeStamp);
|
fazekasgy@37
|
466
|
fazekasgy@37
|
467 /// Call python process (returns new reference) {kwArgs = NULL}
|
fazekasgy@37
|
468 PyObject *pyValue = PyObject_Call(m_pyProcessCallable,pyArgs,NULL);
|
fazekasgy@37
|
469
|
fazekasgy@37
|
470 if (!pyValue) {
|
fazekasgy@37
|
471 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
472 std::string method = PyString_AsString(m_pyProcess);
|
fazekasgy@37
|
473 cerr << PLUGIN_ERROR << "An error occurred while evaluating Python process." << endl;
|
fazekasgy@37
|
474 Py_CLEAR(pyValue);
|
fazekasgy@37
|
475 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
476 return rFeatureSet;
|
fazekasgy@37
|
477 }
|
fazekasgy@37
|
478
|
fazekasgy@37
|
479 rFeatureSet = m_ti.PyValue_To_FeatureSet(pyValue);
|
fazekasgy@37
|
480 if (!m_ti.error) {
|
fazekasgy@37
|
481 Py_DECREF(pyValue);
|
fazekasgy@37
|
482 Py_DECREF(pyArgs);
|
fazekasgy@37
|
483 } else {
|
fazekasgy@37
|
484 typeErrorHandler(PyString_AsString(m_pyProcess));
|
fazekasgy@37
|
485 Py_CLEAR(pyValue);
|
fazekasgy@37
|
486 Py_CLEAR(pyArgs);
|
fazekasgy@37
|
487 }
|
fazekasgy@37
|
488 return rFeatureSet;
|
fazekasgy@37
|
489 }
|
fazekasgy@37
|
490
|
fazekasgy@37
|
491 #endif
|