annotate PyPlugin.h @ 45:91d6cfd22883

...
author cannam
date Mon, 05 Oct 2009 13:57:10 +0000
parents 27bab3a16c9a
children 8b2eddf686da
rev   line source
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@37 413 pyChannelList = m_ti.InputBuffers_As_SharedMemoryList(inputBuffers,m_channels,m_blockSize);
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