annotate PyPlugin.h @ 32:a8231788216c vampy2

Vampy2: accept numpy array return types.
author fazekasgy
date Mon, 21 Sep 2009 13:56:28 +0000
parents 4f1894c7591b
children
rev   line source
cannam@18 1 /* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */
fazekasgy@0 2 /*
fazekasgy@0 3 Vamp
fazekasgy@0 4
fazekasgy@0 5 An API for audio analysis and feature extraction plugins.
fazekasgy@0 6
fazekasgy@0 7 Centre for Digital Music, Queen Mary, University of London.
fazekasgy@0 8 Copyright 2006 Chris Cannam.
fazekasgy@0 9
fazekasgy@0 10 Permission is hereby granted, free of charge, to any person
fazekasgy@0 11 obtaining a copy of this software and associated documentation
fazekasgy@0 12 files (the "Software"), to deal in the Software without
fazekasgy@0 13 restriction, including without limitation the rights to use, copy,
fazekasgy@0 14 modify, merge, publish, distribute, sublicense, and/or sell copies
fazekasgy@0 15 of the Software, and to permit persons to whom the Software is
fazekasgy@0 16 furnished to do so, subject to the following conditions:
fazekasgy@0 17
fazekasgy@0 18 The above copyright notice and this permission notice shall be
fazekasgy@0 19 included in all copies or substantial portions of the Software.
fazekasgy@0 20
fazekasgy@0 21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
fazekasgy@0 22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
fazekasgy@0 23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
fazekasgy@0 24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
fazekasgy@0 25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
fazekasgy@0 26 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
fazekasgy@0 27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
fazekasgy@0 28
fazekasgy@0 29 Except as contained in this notice, the names of the Centre for
fazekasgy@0 30 Digital Music; Queen Mary, University of London; and Chris Cannam
fazekasgy@0 31 shall not be used in advertising or otherwise to promote the sale,
fazekasgy@0 32 use or other dealings in this Software without prior written
fazekasgy@0 33 authorization.
fazekasgy@0 34 */
fazekasgy@0 35
fazekasgy@0 36 #ifndef _PYTHON_WRAPPER_PLUGIN_H_
fazekasgy@0 37 #define _PYTHON_WRAPPER_PLUGIN_H_
fazekasgy@0 38
fazekasgy@31 39 #define _CLASS_METHOD_ m_class << "::" << method
fazekasgy@31 40 #define PLUGIN_ERROR "ERROR: In Vampy plugin [" << _CLASS_METHOD_ << "]" << endl << "Cause: "
fazekasgy@31 41 #define DEBUG_NAME "[Vampy::call] " << _CLASS_METHOD_ << " "
fazekasgy@31 42 #define DEAFULT_RETURN "Method [" << _CLASS_METHOD_ << "] is not implemented." << endl << "Returning default value: " << rValue
fazekasgy@31 43 #define FLAG_VALUE "Flag: " << flagName << ": " << ((rValue==0)?"False":"True")
fazekasgy@31 44
fazekasgy@0 45 #include "vamp-sdk/Plugin.h"
cannam@3 46 #include <Python.h>
fazekasgy@31 47 // #include <typeinfo>
fazekasgy@31 48 // #include <stdarg.h>
fazekasgy@31 49 #include "PyTypeInterface.h"
cannam@3 50
cannam@3 51 #include "Mutex.h"
fazekasgy@0 52
fazekasgy@31 53 using std::string;
fazekasgy@31 54 using std::cerr;
fazekasgy@31 55 using std::endl;
fazekasgy@0 56
fazekasgy@6 57 enum eProcessType {
fazekasgy@6 58 not_implemented,
fazekasgy@6 59 legacyProcess,
fazekasgy@6 60 numpyProcess
fazekasgy@6 61 };
fazekasgy@0 62
fazekasgy@0 63 class PyPlugin : public Vamp::Plugin
fazekasgy@0 64 {
fazekasgy@0 65 public:
fazekasgy@31 66 PyPlugin(std::string plugin,float inputSampleRate, PyObject *pyClass, int &instcount);
cannam@18 67 virtual ~PyPlugin();
fazekasgy@0 68
cannam@18 69 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
cannam@18 70 void reset();
fazekasgy@6 71
fazekasgy@0 72 InputDomain getInputDomain() const;
fazekasgy@0 73 size_t getPreferredBlockSize() const;
fazekasgy@0 74 size_t getPreferredStepSize() const;
fazekasgy@0 75 size_t getMinChannelCount() const;
fazekasgy@0 76 size_t getMaxChannelCount() const;
fazekasgy@0 77
cannam@18 78 std::string getIdentifier() const;
cannam@18 79 std::string getName() const;
cannam@18 80 std::string getDescription() const;
cannam@18 81 std::string getMaker() const;
cannam@18 82 int getPluginVersion() const;
cannam@18 83 std::string getCopyright() const;
cannam@18 84
cannam@18 85 OutputList getOutputDescriptors() const;
cannam@18 86 ParameterList getParameterDescriptors() const;
fazekasgy@0 87 float getParameter(std::string paramid) const;
fazekasgy@0 88 void setParameter(std::string paramid, float newval);
fazekasgy@0 89
cannam@18 90 FeatureSet process(const float *const *inputBuffers,
cannam@18 91 Vamp::RealTime timestamp);
fazekasgy@0 92
cannam@18 93 FeatureSet getRemainingFeatures();
fazekasgy@31 94
fazekasgy@0 95 protected:
fazekasgy@31 96 static Mutex m_pythonInterpreterMutex;
cannam@24 97 PyObject *m_pyClass;
fazekasgy@0 98 PyObject *m_pyInstance;
fazekasgy@31 99 int &m_instcount;
cannam@18 100 size_t m_stepSize;
cannam@18 101 size_t m_blockSize;
cannam@18 102 size_t m_channels;
fazekasgy@0 103 std::string m_plugin;
fazekasgy@0 104 std::string m_class;
fazekasgy@0 105 std::string m_path;
fazekasgy@6 106 int m_processType;
fazekasgy@6 107 PyObject *m_pyProcess;
fazekasgy@6 108 InputDomain m_inputDomain;
fazekasgy@31 109 PyTypeInterface m_ti;
fazekasgy@31 110 bool m_quitOnErrorFlag;
fazekasgy@31 111 bool m_debugFlag;
fazekasgy@31 112
fazekasgy@31 113 void setProcessType();
fazekasgy@6 114
fazekasgy@31 115 PyObject* numpyProcessCall(const float *const *inputBuffers, Vamp::RealTime timestamp);
fazekasgy@31 116 PyObject* legacyProcessCall(const float *const *inputBuffers, Vamp::RealTime timestamp);
fazekasgy@31 117
fazekasgy@31 118 bool getBooleanFlag(char flagName[],bool) const;
fazekasgy@31 119 /*
fazekasgy@31 120 Flags may be used to control the behaviour of the interface.
fazekasgy@31 121 Flags can be set in any Vampy plugin's __init__() function.
fazekasgy@31 122 Their scope is limited to an instance.
fazekasgy@31 123 Default values for all flags are False.
fazekasgy@31 124 Python Example:
fazekasgy@31 125 def __init__(self,inputSampleRate):
fazekasgy@31 126 self.use_strict_type_conversion = True
fazekasgy@31 127 self.vampy_debug_messages = True
fazekasgy@31 128 self.use_realtime_timestamp = False
fazekasgy@31 129 self.use_numpy_interface = False
fazekasgy@31 130 self.quit_on_type_error = False
fazekasgy@31 131
fazekasgy@31 132 */
fazekasgy@31 133
fazekasgy@31 134 void genericMethodCall(char *method) const
fazekasgy@31 135 {
fazekasgy@31 136 if (m_debugFlag) cerr << DEBUG_NAME << endl;
fazekasgy@31 137 if ( PyObject_HasAttrString(m_pyInstance,method) )
fazekasgy@31 138 {
fazekasgy@31 139 PyObject *pyValue = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@31 140 if (!pyValue) {
fazekasgy@31 141 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
fazekasgy@31 142 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@31 143 }
fazekasgy@31 144 }
fazekasgy@31 145 }
fazekasgy@31 146
fazekasgy@31 147 template<typename RET>
fazekasgy@31 148 RET &genericMethodCall(char *method, RET &rValue) const
fazekasgy@31 149 {
fazekasgy@31 150 if (m_debugFlag) cerr << DEBUG_NAME << endl;
fazekasgy@31 151 if ( PyObject_HasAttrString(m_pyInstance,method) )
fazekasgy@31 152 {
fazekasgy@31 153 PyObject *pyValue = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@31 154 if (pyValue) {
fazekasgy@31 155 m_ti.PyValue_To_rValue(pyValue,rValue);
fazekasgy@31 156 if (!m_ti.error) {
fazekasgy@31 157 Py_DECREF(pyValue);
fazekasgy@31 158 return rValue;
fazekasgy@31 159 } else {
fazekasgy@31 160 cerr << PLUGIN_ERROR << m_ti.lastError().message << endl;
fazekasgy@31 161 Py_CLEAR(pyValue);
fazekasgy@31 162 if (m_quitOnErrorFlag) exit(EXIT_FAILURE);
fazekasgy@31 163 return rValue;
fazekasgy@31 164 }
fazekasgy@31 165 } else {
fazekasgy@31 166 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
fazekasgy@31 167 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@31 168 return rValue;
fazekasgy@31 169 }
fazekasgy@31 170 }
fazekasgy@31 171 // TODO: this fails to generalise because the << operator
fazekasgy@31 172 // doesn't accept all types.
fazekasgy@31 173 // if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
fazekasgy@31 174 return rValue;
fazekasgy@31 175 }
cannam@3 176
fazekasgy@31 177 template<typename RET,typename A1>
fazekasgy@31 178 RET genericMethodCallArgs(char *method, A1 arg1) const
fazekasgy@31 179 {
fazekasgy@31 180 RET rValue = RET();
fazekasgy@31 181 if (m_debugFlag) cerr << DEBUG_NAME << endl;
fazekasgy@31 182 if (!PyObject_HasAttrString(m_pyInstance,method)) {
fazekasgy@31 183 // if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
fazekasgy@31 184 return rValue;
fazekasgy@31 185 }
fazekasgy@31 186
fazekasgy@31 187 // These functions always return valid PyObjects
fazekasgy@31 188 PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
fazekasgy@31 189 PyObject* pyTuple = PyTuple_New(3);
fazekasgy@31 190 if (!pyTuple) return rValue;
fazekasgy@31 191
fazekasgy@31 192 PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
fazekasgy@31 193
fazekasgy@31 194 PyObject *pyValue = PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyArg1,NULL);
fazekasgy@31 195 if (!pyValue)
fazekasgy@31 196 {
fazekasgy@31 197 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
fazekasgy@31 198 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@31 199 }
fazekasgy@31 200
fazekasgy@31 201 Py_DECREF(pyMethod);
fazekasgy@31 202 Py_DECREF(pyArg1);
fazekasgy@31 203
fazekasgy@31 204 m_ti.PyValue_To_rValue(pyValue,rValue);
fazekasgy@31 205 if (!m_ti.error) {
fazekasgy@31 206 Py_DECREF(pyValue);
fazekasgy@31 207 } else {
fazekasgy@31 208 cerr << PLUGIN_ERROR << m_ti.lastError().message << endl;
fazekasgy@31 209 Py_CLEAR(pyValue);
fazekasgy@31 210 if (m_quitOnErrorFlag) exit(EXIT_FAILURE);
fazekasgy@31 211 }
fazekasgy@31 212 return rValue;
fazekasgy@31 213 }
fazekasgy@31 214
fazekasgy@31 215 template<typename RET,typename A1,typename A2>
fazekasgy@31 216 RET genericMethodCallArgs(char *method, A1 arg1, A2 arg2)
fazekasgy@31 217 {
fazekasgy@31 218 RET rValue = RET();
fazekasgy@31 219 if (m_debugFlag) cerr << DEBUG_NAME << endl;
fazekasgy@31 220 if (!PyObject_HasAttrString(m_pyInstance,method)) {
fazekasgy@31 221 // if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
fazekasgy@31 222 return rValue;
fazekasgy@31 223 }
fazekasgy@31 224
fazekasgy@31 225 // These functions always return valid PyObjects
fazekasgy@31 226 PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
fazekasgy@31 227 PyObject* pyTuple = PyTuple_New(3);
fazekasgy@31 228 if (!pyTuple) return rValue;
fazekasgy@31 229
fazekasgy@31 230 PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
fazekasgy@31 231 PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
fazekasgy@31 232
fazekasgy@31 233 PyObject *pyValue = PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyArg1,pyArg2,NULL);
fazekasgy@31 234 if (!pyValue)
fazekasgy@31 235 {
fazekasgy@31 236 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
fazekasgy@31 237 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@31 238 }
fazekasgy@31 239
fazekasgy@31 240 Py_DECREF(pyMethod);
fazekasgy@31 241 Py_DECREF(pyArg1);
fazekasgy@31 242 Py_DECREF(pyArg2);
fazekasgy@31 243
fazekasgy@31 244 m_ti.PyValue_To_rValue(pyValue,rValue);
fazekasgy@31 245 if (!m_ti.error) {
fazekasgy@31 246 Py_DECREF(pyValue);
fazekasgy@31 247 } else {
fazekasgy@31 248 cerr << PLUGIN_ERROR << m_ti.lastError().message << endl;
fazekasgy@31 249 Py_CLEAR(pyValue);
fazekasgy@31 250 if (m_quitOnErrorFlag) exit(EXIT_FAILURE);
fazekasgy@31 251 }
fazekasgy@31 252 return rValue;
fazekasgy@31 253 }
fazekasgy@31 254
fazekasgy@31 255
fazekasgy@31 256 template<typename RET,typename A1,typename A2,typename A3>
fazekasgy@31 257 RET genericMethodCallArgs(char *method, A1 arg1, A2 arg2, A3 arg3)
fazekasgy@31 258 {
fazekasgy@31 259 RET rValue = RET();
fazekasgy@31 260 if (m_debugFlag) cerr << DEBUG_NAME << endl;
fazekasgy@31 261 if (!PyObject_HasAttrString(m_pyInstance,method)) {
fazekasgy@31 262 if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
fazekasgy@31 263 return rValue;
fazekasgy@31 264 }
fazekasgy@31 265
fazekasgy@31 266 // These functions always return valid PyObjects
fazekasgy@31 267 PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
fazekasgy@31 268 PyObject* pyTuple = PyTuple_New(3);
fazekasgy@31 269 if (!pyTuple) return rValue;
fazekasgy@31 270
fazekasgy@31 271 PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
fazekasgy@31 272 PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
fazekasgy@31 273 PyObject *pyArg3 = m_ti.PyValue_From_CValue(arg3);
fazekasgy@31 274
fazekasgy@31 275 // TODO: Pack it in a tuple to avoid va_list parsing!
fazekasgy@31 276
fazekasgy@31 277 // callable = PyObject_GetAttr(callable, name);
fazekasgy@31 278 // if (callable == NULL)
fazekasgy@31 279 // return NULL;
fazekasgy@31 280 // PyObject* args; // pyTuple of input arguments
fazekasgy@31 281 //tmp = PyObject_Call(callable, args, NULL);
fazekasgy@31 282
fazekasgy@31 283
fazekasgy@31 284 PyObject *pyValue = PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyArg1,pyArg2,pyArg3,NULL);
fazekasgy@31 285 if (!pyValue)
fazekasgy@31 286 {
fazekasgy@31 287 cerr << PLUGIN_ERROR << "Failed to call method." << endl;
fazekasgy@31 288 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@31 289 }
fazekasgy@31 290
fazekasgy@31 291 Py_DECREF(pyMethod);
fazekasgy@31 292 Py_DECREF(pyArg1);
fazekasgy@31 293 Py_DECREF(pyArg2);
fazekasgy@31 294 Py_DECREF(pyArg3);
fazekasgy@31 295
fazekasgy@31 296 m_ti.PyValue_To_rValue(pyValue,rValue);
fazekasgy@31 297 if (!m_ti.error) {
fazekasgy@31 298 Py_DECREF(pyValue);
fazekasgy@31 299 } else {
fazekasgy@31 300 cerr << PLUGIN_ERROR << m_ti.lastError().message << endl;
fazekasgy@31 301 Py_CLEAR(pyValue);
fazekasgy@31 302 if (m_quitOnErrorFlag) exit(EXIT_FAILURE);
fazekasgy@31 303 }
fazekasgy@31 304 return rValue;
fazekasgy@31 305 }
fazekasgy@31 306
fazekasgy@0 307 };
fazekasgy@0 308
fazekasgy@0 309
fazekasgy@0 310 #endif