annotate PyPlugin.h @ 69:f5b8646494d2

Metadata fixes
author Chris Cannam
date Mon, 17 Nov 2014 12:53:51 +0000
parents 146d14ab15e7
children 40a01bb24209 f5c028376bf9
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_ << " "
Chris@67 52 #define DEFAULT_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
Chris@66 132 bool getBooleanFlag(const char flagName[],bool) const;
Chris@66 133 int getBinaryFlags(const char flagName[], eVampyFlags) const;
Chris@66 134 void typeErrorHandler(const char *method, bool process = false) const;
fazekasgy@37 135
fazekasgy@37 136 /// simple 'void return' call with no args
Chris@66 137 void genericMethodCall(const 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 {
Chris@66 142 PyObject *pyValue = PyObject_CallMethod(m_pyInstance, (char *)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>
Chris@66 152 RET &genericMethodCall(const 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 {
Chris@66 157 PyObject *pyValue = PyObject_CallMethod(m_pyInstance, (char *)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 }
Chris@67 174 if (m_debugFlag) cerr << DEFAULT_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>
Chris@66 180 RET genericMethodCallArgs(const 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)) {
Chris@67 185 if (m_debugFlag) cerr << DEFAULT_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>
Chris@66 246 RET genericMethodCallArgs(const 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)) {
Chris@67 251 if (m_debugFlag) cerr << DEFAULT_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>
Chris@66 318 RET genericMethodCallArgs(const 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)) {
Chris@67 323 if (m_debugFlag) cerr << DEFAULT_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