annotate PyPlugin.h @ 53:7e59caea821b

* Make a better job of preloading Python, especially when it's in a framework. Go for the Python file in the frameworks directory in preference to any libpythonX.Y.dylib. Particularly, don't try to preload any library without an absolute path until we've exhausted all our framework possibilities (so as to avoid picking up an ancient system library).
author cannam
date Fri, 09 Oct 2009 13:48:25 +0000
parents c1e4f706ca9a
children 5664fe298af2
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@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