annotate PyPlugin.h @ 92:a6718f9fe942

If a module appears to redefine one of our own types, refuse to load it. Also clear out the class dict for all refused modules now, so that we don't get stale names on the next scan due to not having cleared the module on unload
author Chris Cannam
date Mon, 14 Jan 2019 16:19:44 +0000
parents f5c028376bf9
children
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 #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