annotate PyPlugin.h @ 72:ffaa1fb3d7de vampyhost

inline is not a useful keyword with contemporary compilers
author Chris Cannam
date Mon, 24 Nov 2014 09:50:49 +0000
parents 40a01bb24209
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"
Chris@71 24 #include "PyTypeConversions.h"
fazekasgy@37 25 #include "vamp-sdk/Plugin.h"
fazekasgy@37 26 #include "Mutex.h"
fazekasgy@37 27
fazekasgy@37 28 using std::string;
fazekasgy@37 29 using std::cerr;
fazekasgy@37 30 using std::endl;
fazekasgy@37 31
fazekasgy@37 32 enum eProcessType {
fazekasgy@37 33 not_implemented,
fazekasgy@37 34 legacyProcess,
fazekasgy@37 35 numpyProcess,
fazekasgy@37 36 numpy_bufferProcess,
fazekasgy@37 37 numpy_arrayProcess
fazekasgy@37 38 };
fazekasgy@37 39
fazekasgy@37 40 class PyPlugin : public Vamp::Plugin
fazekasgy@37 41 {
fazekasgy@37 42 public:
fazekasgy@51 43 PyPlugin(std::string plugin,float inputSampleRate, PyObject *pyClass, int &instcount, bool &numpyInstalled);
fazekasgy@37 44 virtual ~PyPlugin();
fazekasgy@37 45
fazekasgy@37 46 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
fazekasgy@37 47 void reset();
fazekasgy@37 48
fazekasgy@37 49 InputDomain getInputDomain() const;
fazekasgy@37 50 size_t getPreferredBlockSize() const;
fazekasgy@37 51 size_t getPreferredStepSize() const;
fazekasgy@37 52 size_t getMinChannelCount() const;
fazekasgy@37 53 size_t getMaxChannelCount() const;
fazekasgy@37 54
fazekasgy@37 55 std::string getIdentifier() const;
fazekasgy@37 56 std::string getName() const;
fazekasgy@37 57 std::string getDescription() const;
fazekasgy@37 58 std::string getMaker() const;
fazekasgy@37 59 int getPluginVersion() const;
fazekasgy@37 60 std::string getCopyright() const;
fazekasgy@37 61
fazekasgy@37 62 OutputList getOutputDescriptors() const;
fazekasgy@37 63 ParameterList getParameterDescriptors() const;
fazekasgy@37 64 float getParameter(std::string paramid) const;
fazekasgy@37 65 void setParameter(std::string paramid, float newval);
fazekasgy@37 66
fazekasgy@37 67 FeatureSet process(const float *const *inputBuffers,
fazekasgy@37 68 Vamp::RealTime timestamp);
fazekasgy@37 69
fazekasgy@37 70 FeatureSet getRemainingFeatures();
fazekasgy@37 71
fazekasgy@37 72 protected:
fazekasgy@37 73 static Mutex m_pythonInterpreterMutex;
fazekasgy@37 74 PyObject *m_pyClass;
fazekasgy@37 75 PyObject *m_pyInstance;
fazekasgy@37 76 int &m_instcount;
fazekasgy@37 77 size_t m_stepSize;
fazekasgy@37 78 size_t m_blockSize;
fazekasgy@37 79 size_t m_channels;
fazekasgy@37 80 std::string m_plugin;
fazekasgy@37 81 std::string m_class;
fazekasgy@37 82 std::string m_path;
fazekasgy@37 83 eProcessType m_processType;
fazekasgy@37 84 PyObject *m_pyProcess;
fazekasgy@37 85 PyObject *m_pyProcessCallable;
fazekasgy@37 86 mutable InputDomain m_inputDomain;
Chris@71 87 PyTypeConversions m_tc;
fazekasgy@37 88 PyTypeInterface m_ti;
fazekasgy@37 89 int m_vampyFlags;
fazekasgy@37 90 bool m_quitOnErrorFlag;
fazekasgy@37 91 bool m_debugFlag;
fazekasgy@37 92 bool m_useRealTimeFlag;
fazekasgy@51 93 bool m_numpyInstalled;
fazekasgy@51 94 mutable bool m_processFailure;
fazekasgy@37 95
fazekasgy@37 96 void setProcessType();
fazekasgy@37 97
fazekasgy@37 98 FeatureSet processMethodCall(const float *const *inputBuffers,Vamp::RealTime timestamp);
fazekasgy@37 99
Chris@66 100 bool getBooleanFlag(const char flagName[],bool) const;
Chris@66 101 int getBinaryFlags(const char flagName[], eVampyFlags) const;
Chris@66 102 void typeErrorHandler(const char *method, bool process = false) const;
fazekasgy@37 103
fazekasgy@37 104 /// simple 'void return' call with no args
Chris@66 105 void genericMethodCall(const char *method) const
fazekasgy@37 106 {
fazekasgy@37 107 if (m_debugFlag) cerr << DEBUG_NAME << endl;
fazekasgy@37 108 if ( PyObject_HasAttrString(m_pyInstance,method) )
fazekasgy@37 109 {
Chris@66 110 PyObject *pyValue = PyObject_CallMethod(m_pyInstance, (char *)method, NULL);
fazekasgy@37 111 if (!pyValue) {
fazekasgy@37 112 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
fazekasgy@37 113 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 114 }
fazekasgy@37 115 }
fazekasgy@37 116 }
fazekasgy@37 117
fazekasgy@37 118 /// 'no arg with default return value' call
fazekasgy@37 119 template<typename RET>
Chris@66 120 RET &genericMethodCall(const char *method, RET &rValue) const
fazekasgy@37 121 {
fazekasgy@37 122 if (m_debugFlag) cerr << DEBUG_NAME << endl;
fazekasgy@37 123 if ( PyObject_HasAttrString(m_pyInstance,method) )
fazekasgy@37 124 {
Chris@66 125 PyObject *pyValue = PyObject_CallMethod(m_pyInstance, (char *)method, NULL);
fazekasgy@37 126 if (!pyValue) {
fazekasgy@37 127 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
fazekasgy@37 128 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 129 return rValue;
fazekasgy@37 130 }
fazekasgy@37 131
fazekasgy@37 132 /// convert the returned value
fazekasgy@37 133 m_ti.PyValue_To_rValue(pyValue,rValue);
fazekasgy@37 134 if (!m_ti.error) {
fazekasgy@37 135 Py_DECREF(pyValue);
fazekasgy@37 136 } else {
fazekasgy@37 137 Py_CLEAR(pyValue);
fazekasgy@37 138 typeErrorHandler(method);
fazekasgy@37 139 }
fazekasgy@37 140 return rValue;
fazekasgy@37 141 }
Chris@67 142 if (m_debugFlag) cerr << DEFAULT_RETURN << endl;
fazekasgy@37 143 return rValue;
fazekasgy@37 144 }
fazekasgy@37 145
fazekasgy@37 146 /// unary call
fazekasgy@37 147 template<typename RET,typename A1>
Chris@66 148 RET genericMethodCallArgs(const char *method, A1 arg1) const
fazekasgy@37 149 {
fazekasgy@37 150 RET rValue = RET();
fazekasgy@37 151 if (m_debugFlag) cerr << DEBUG_NAME << endl;
fazekasgy@37 152 if (!PyObject_HasAttrString(m_pyInstance,method)) {
Chris@67 153 if (m_debugFlag) cerr << DEFAULT_RETURN << endl;
fazekasgy@37 154 return rValue;
fazekasgy@37 155 }
fazekasgy@37 156
fazekasgy@37 157 /// prepare arguments for fast method call
Chris@71 158 PyObject *pyMethod = m_tc.PyValue_From_CValue(method);
fazekasgy@37 159 PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
fazekasgy@37 160 PyObject* pyArgs = PyTuple_New(1);
fazekasgy@37 161 if (!(pyArgs && pyCallable && pyMethod)) {
fazekasgy@37 162 cerr << PLUGIN_ERROR << "Failed to prepare argument for calling method." << endl;
fazekasgy@37 163 Py_CLEAR(pyMethod);
fazekasgy@37 164 Py_CLEAR(pyCallable);
fazekasgy@37 165 Py_CLEAR(pyArgs);
fazekasgy@37 166 return rValue;
fazekasgy@37 167 }
fazekasgy@37 168
Chris@71 169 PyObject *pyArg1 = m_tc.PyValue_From_CValue(arg1);
Chris@71 170 if (m_tc.error) {
fazekasgy@37 171 cerr << PLUGIN_ERROR << "Failed to convert argument for calling method." << endl;
fazekasgy@37 172 typeErrorHandler(method);
fazekasgy@37 173 Py_CLEAR(pyMethod);
fazekasgy@37 174 Py_CLEAR(pyCallable);
fazekasgy@37 175 Py_CLEAR(pyArg1);
fazekasgy@37 176 Py_CLEAR(pyArgs);
fazekasgy@37 177 return rValue;
fazekasgy@37 178 }
fazekasgy@37 179
fazekasgy@37 180 PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
fazekasgy@37 181 Py_INCREF(pyArg1);
fazekasgy@37 182
fazekasgy@37 183 /// call the method
fazekasgy@37 184 PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
fazekasgy@37 185 if (!pyValue)
fazekasgy@37 186 {
fazekasgy@37 187 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
fazekasgy@37 188 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 189 Py_CLEAR(pyMethod);
fazekasgy@37 190 Py_CLEAR(pyCallable);
fazekasgy@37 191 Py_CLEAR(pyArg1);
fazekasgy@37 192 Py_CLEAR(pyArgs);
fazekasgy@37 193 return rValue;
fazekasgy@37 194 }
fazekasgy@37 195
fazekasgy@37 196 Py_DECREF(pyMethod);
fazekasgy@37 197 Py_DECREF(pyCallable);
fazekasgy@37 198 Py_DECREF(pyArg1);
fazekasgy@37 199 Py_DECREF(pyArgs);
fazekasgy@37 200
fazekasgy@37 201 /// convert the returned value
fazekasgy@37 202 m_ti.PyValue_To_rValue(pyValue,rValue);
fazekasgy@37 203 if (!m_ti.error) {
fazekasgy@37 204 Py_DECREF(pyValue);
fazekasgy@37 205 } else {
fazekasgy@37 206 Py_CLEAR(pyValue);
fazekasgy@37 207 typeErrorHandler(method);
fazekasgy@37 208 }
fazekasgy@37 209 return rValue;
fazekasgy@37 210 }
fazekasgy@37 211
fazekasgy@37 212 /// binary call
fazekasgy@37 213 template<typename RET,typename A1,typename A2>
Chris@66 214 RET genericMethodCallArgs(const char *method, A1 arg1, A2 arg2) const
fazekasgy@37 215 {
fazekasgy@37 216 RET rValue = RET();
fazekasgy@37 217 if (m_debugFlag) cerr << DEBUG_NAME << endl;
fazekasgy@37 218 if (!PyObject_HasAttrString(m_pyInstance,method)) {
Chris@67 219 if (m_debugFlag) cerr << DEFAULT_RETURN << endl;
fazekasgy@37 220 return rValue;
fazekasgy@37 221 }
fazekasgy@37 222
fazekasgy@37 223 /// prepare arguments for fast method call
Chris@71 224 PyObject *pyMethod = m_tc.PyValue_From_CValue(method);
fazekasgy@37 225 PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
fazekasgy@37 226 PyObject* pyArgs = PyTuple_New(2);
fazekasgy@37 227 if (!(pyArgs && pyCallable && pyMethod)) {
fazekasgy@37 228 cerr << PLUGIN_ERROR << "Failed to prepare arguments for calling method." << endl;
fazekasgy@37 229 Py_CLEAR(pyMethod);
fazekasgy@37 230 Py_CLEAR(pyCallable);
fazekasgy@37 231 Py_CLEAR(pyArgs);
fazekasgy@37 232 return rValue;
fazekasgy@37 233 }
fazekasgy@37 234
Chris@71 235 PyObject *pyArg1 = m_tc.PyValue_From_CValue(arg1);
Chris@71 236 PyObject *pyArg2 = m_tc.PyValue_From_CValue(arg2);
Chris@71 237 if (m_tc.error) {
fazekasgy@37 238 cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl;
fazekasgy@37 239 typeErrorHandler(method);
fazekasgy@37 240 Py_CLEAR(pyMethod);
fazekasgy@37 241 Py_CLEAR(pyCallable);
fazekasgy@37 242 Py_CLEAR(pyArg1);
fazekasgy@37 243 Py_CLEAR(pyArg2);
fazekasgy@37 244 Py_CLEAR(pyArgs);
fazekasgy@37 245 return rValue;
fazekasgy@37 246 }
fazekasgy@37 247
fazekasgy@37 248 PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
fazekasgy@37 249 Py_INCREF(pyArg1);
fazekasgy@37 250 PyTuple_SET_ITEM(pyArgs, 1, pyArg2);
fazekasgy@37 251 Py_INCREF(pyArg2);
fazekasgy@37 252
fazekasgy@37 253 // calls the method
fazekasgy@37 254 PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
fazekasgy@37 255 if (!pyValue)
fazekasgy@37 256 {
fazekasgy@37 257 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
fazekasgy@37 258 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 259 Py_CLEAR(pyMethod);
fazekasgy@37 260 Py_CLEAR(pyCallable);
fazekasgy@37 261 Py_CLEAR(pyArg1);
fazekasgy@37 262 Py_CLEAR(pyArg2);
fazekasgy@37 263 Py_CLEAR(pyArgs);
fazekasgy@37 264 return rValue;
fazekasgy@37 265 }
fazekasgy@37 266
fazekasgy@37 267 Py_DECREF(pyMethod);
fazekasgy@37 268 Py_DECREF(pyCallable);
fazekasgy@37 269 Py_DECREF(pyArg1);
fazekasgy@37 270 Py_DECREF(pyArg2);
fazekasgy@37 271 Py_DECREF(pyArgs);
fazekasgy@37 272
fazekasgy@37 273 /// convert the returned value
fazekasgy@37 274 m_ti.PyValue_To_rValue(pyValue,rValue);
fazekasgy@37 275 if (!m_ti.error) {
fazekasgy@37 276 Py_DECREF(pyValue);
fazekasgy@37 277 } else {
fazekasgy@37 278 Py_CLEAR(pyValue);
fazekasgy@37 279 typeErrorHandler(method);
fazekasgy@37 280 }
fazekasgy@37 281 return rValue;
fazekasgy@37 282 }
fazekasgy@37 283
fazekasgy@37 284 /// trenary call
fazekasgy@37 285 template<typename RET,typename A1,typename A2,typename A3>
Chris@66 286 RET genericMethodCallArgs(const char *method, A1 arg1, A2 arg2, A3 arg3) const
fazekasgy@37 287 {
fazekasgy@37 288 RET rValue = RET();
fazekasgy@37 289 if (m_debugFlag) cerr << DEBUG_NAME << endl;
fazekasgy@37 290 if (!PyObject_HasAttrString(m_pyInstance,method)) {
Chris@67 291 if (m_debugFlag) cerr << DEFAULT_RETURN << endl;
fazekasgy@37 292 return rValue;
fazekasgy@37 293 }
fazekasgy@37 294
fazekasgy@37 295 /// prepare arguments for fast method call
Chris@71 296 PyObject *pyMethod = m_tc.PyValue_From_CValue(method);
fazekasgy@37 297 PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod);
fazekasgy@37 298 PyObject* pyArgs = PyTuple_New(3);
fazekasgy@37 299 if (!(pyArgs && pyCallable && pyMethod)) {
fazekasgy@37 300 cerr << PLUGIN_ERROR << "Failed to prepare arguments for calling method." << endl;
fazekasgy@37 301 Py_CLEAR(pyMethod);
fazekasgy@37 302 Py_CLEAR(pyCallable);
fazekasgy@37 303 Py_CLEAR(pyArgs);
fazekasgy@37 304 return rValue;
fazekasgy@37 305 }
fazekasgy@37 306
Chris@71 307 PyObject *pyArg1 = m_tc.PyValue_From_CValue(arg1);
Chris@71 308 PyObject *pyArg2 = m_tc.PyValue_From_CValue(arg2);
Chris@71 309 PyObject *pyArg3 = m_tc.PyValue_From_CValue(arg3);
Chris@71 310 if (m_tc.error) {
fazekasgy@37 311 cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl;
fazekasgy@37 312 typeErrorHandler(method);
fazekasgy@37 313 Py_CLEAR(pyMethod);
fazekasgy@37 314 Py_CLEAR(pyCallable);
fazekasgy@37 315 Py_CLEAR(pyArg1);
fazekasgy@37 316 Py_CLEAR(pyArg2);
fazekasgy@37 317 Py_CLEAR(pyArg3);
fazekasgy@37 318 Py_CLEAR(pyArgs);
fazekasgy@37 319 return rValue;
fazekasgy@37 320 }
fazekasgy@37 321
fazekasgy@37 322 /// Optimization: Pack args in a tuple to avoid va_list parsing.
fazekasgy@37 323 PyTuple_SET_ITEM(pyArgs, 0, pyArg1);
fazekasgy@37 324 Py_INCREF(pyArg1);
fazekasgy@37 325 PyTuple_SET_ITEM(pyArgs, 1, pyArg2);
fazekasgy@37 326 Py_INCREF(pyArg2);
fazekasgy@37 327 PyTuple_SET_ITEM(pyArgs, 2, pyArg3);
fazekasgy@37 328 Py_INCREF(pyArg3);
fazekasgy@37 329
fazekasgy@37 330 // PyObject *pyValue = PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyArg1,pyArg2,pyArg3,NULL);
fazekasgy@37 331 /// fast method call
fazekasgy@37 332 PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL);
fazekasgy@37 333 if (!pyValue)
fazekasgy@37 334 {
fazekasgy@37 335 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
fazekasgy@37 336 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 337 Py_CLEAR(pyMethod);
fazekasgy@37 338 Py_CLEAR(pyCallable);
fazekasgy@37 339 Py_CLEAR(pyArg1);
fazekasgy@37 340 Py_CLEAR(pyArg2);
fazekasgy@37 341 Py_CLEAR(pyArg3);
fazekasgy@37 342 Py_CLEAR(pyArgs);
fazekasgy@37 343 return rValue;
fazekasgy@37 344 }
fazekasgy@37 345
fazekasgy@37 346 Py_DECREF(pyMethod);
fazekasgy@37 347 Py_DECREF(pyCallable);
fazekasgy@37 348 Py_DECREF(pyArg1);
fazekasgy@37 349 Py_DECREF(pyArg2);
fazekasgy@37 350 Py_DECREF(pyArg3);
fazekasgy@37 351 Py_DECREF(pyArgs);
fazekasgy@37 352
fazekasgy@37 353 /// convert the returned value
fazekasgy@37 354 m_ti.PyValue_To_rValue(pyValue,rValue);
fazekasgy@37 355 if (!m_ti.error) {
fazekasgy@37 356 Py_DECREF(pyValue);
fazekasgy@37 357 } else {
fazekasgy@37 358 Py_CLEAR(pyValue);
fazekasgy@37 359 typeErrorHandler(method);
fazekasgy@37 360 }
fazekasgy@37 361 return rValue;
fazekasgy@37 362 }
fazekasgy@37 363
fazekasgy@37 364 };
fazekasgy@37 365
fazekasgy@37 366 #endif