annotate PyExtensionModule.cpp @ 48:cb207d275e8e

* Add mention of example plugins
author cannam
date Tue, 06 Oct 2009 11:48:15 +0000
parents af9c4cee95a8
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 #include <Python.h>
fazekasgy@37 13 #include "PyExtensionModule.h"
fazekasgy@37 14 #include "PyRealTime.h"
fazekasgy@37 15 #include "PyFeature.h"
fazekasgy@37 16 #include "PyFeatureSet.h"
fazekasgy@37 17 #include "PyParameterDescriptor.h"
fazekasgy@37 18 #include "PyOutputDescriptor.h"
fazekasgy@37 19 #include "vamp/vamp.h"
fazekasgy@37 20 #include "vamp-sdk/Plugin.h"
fazekasgy@37 21
fazekasgy@37 22 using namespace std;
fazekasgy@37 23 using namespace Vamp;
fazekasgy@37 24 using Vamp::Plugin;
fazekasgy@37 25 using Vamp::RealTime;
fazekasgy@37 26
fazekasgy@37 27 /* Functions Exposed by Vampy */
fazekasgy@37 28
fazekasgy@37 29 /* Creating PyRealTime Objects from frame count */
fazekasgy@37 30
fazekasgy@37 31 /* New RealTime object from Frame (with given samplerate) */
fazekasgy@37 32 static PyObject *
fazekasgy@37 33 RealTime_frame2RealTime(PyObject *ignored, PyObject *args)
fazekasgy@37 34 {
fazekasgy@37 35 long frame;
fazekasgy@37 36 unsigned int sampleRate;
fazekasgy@37 37
fazekasgy@37 38 if (!(args && PyTuple_GET_SIZE(args) == 2)) {
fazekasgy@37 39 PyErr_SetString(PyExc_ValueError,"frame2RealTime requires two arguments: frame and sample rate.");
fazekasgy@37 40 return NULL;
fazekasgy@37 41 }
fazekasgy@37 42
fazekasgy@37 43 PyObject* pyFrame = PyTuple_GET_ITEM(args,0);
fazekasgy@37 44 PyObject* pySampleRate = PyTuple_GET_ITEM(args,1);
fazekasgy@37 45
fazekasgy@37 46 /// frame
fazekasgy@37 47 if (PyInt_Check(pyFrame)) frame = PyInt_AS_LONG(pyFrame);
fazekasgy@37 48 else if (PyLong_Check(pyFrame)) frame = PyLong_AsLong(pyFrame);
fazekasgy@37 49 else {
fazekasgy@37 50 PyErr_SetString(PyExc_ValueError,"frame2RealTime 'frame' argument must be long integer.");
fazekasgy@37 51 return NULL;
fazekasgy@37 52 }
fazekasgy@37 53
fazekasgy@37 54 /// sample rate
fazekasgy@37 55 if (PyInt_Check(pySampleRate))
fazekasgy@37 56 sampleRate = _long2uint(PyInt_AS_LONG(pySampleRate));
fazekasgy@37 57 else if (PyFloat_Check(pySampleRate))
fazekasgy@37 58 sampleRate = _dbl2uint(PyFloat_AS_DOUBLE(pySampleRate));
fazekasgy@37 59 else if (PyLong_Check(pySampleRate))
fazekasgy@37 60 sampleRate = _long2uint(PyLong_AsLong(pySampleRate));
fazekasgy@37 61 else {
fazekasgy@37 62 PyErr_SetString(PyExc_ValueError,"frame2RealTime 'sample rate' argument must be int, long or float.");
fazekasgy@37 63 return NULL;
fazekasgy@37 64 }
fazekasgy@37 65
fazekasgy@37 66 if (!sampleRate) {
fazekasgy@37 67 PyErr_SetString(PyExc_ValueError,"frame2RealTime 'sample rate' argument overflow error. Argument must be 0 < arg < UINT_MAX.");
fazekasgy@37 68 cerr << "Value: " << sampleRate << endl;
fazekasgy@37 69 return NULL;
fazekasgy@37 70 }
fazekasgy@37 71
fazekasgy@37 72 // simpler but slower:
fazekasgy@37 73 // if (!PyArg_ParseTuple(args, "lI:realtime.frame2RealTime ",
fazekasgy@37 74 // &frame,&sampleRate))
fazekasgy@37 75 // return NULL;
fazekasgy@37 76
fazekasgy@37 77 RealTimeObject *self;
fazekasgy@37 78 self = PyObject_New(RealTimeObject, &RealTime_Type);
fazekasgy@37 79 if (self == NULL) return NULL;
fazekasgy@37 80
fazekasgy@37 81 self->rt = new RealTime(
fazekasgy@37 82 RealTime::frame2RealTime(frame,sampleRate));
fazekasgy@37 83
fazekasgy@37 84 return (PyObject *) self;
fazekasgy@37 85 }
fazekasgy@37 86
fazekasgy@37 87 /*
fazekasgy@37 88
fazekasgy@37 89 Note: these functions are not very interesting on their own, but
fazekasgy@37 90 they can be used to make the semantics of the plugin clearer.
fazekasgy@37 91 They return ordinary Python list objects. All type checking
fazekasgy@37 92 is performed in the type interface.
fazekasgy@37 93
fazekasgy@37 94 */
fazekasgy@37 95
fazekasgy@37 96 /* New PyOutputList Objects */
fazekasgy@37 97 static PyObject *
fazekasgy@37 98 OutputList_new(PyObject *ignored, PyObject *args)
fazekasgy@37 99 {
cannam@46 100 if (args && PyTuple_Check(args))
fazekasgy@37 101 return PySequence_List(args);
fazekasgy@37 102 else return (PyObject *) PyList_New(0);
fazekasgy@37 103 }
fazekasgy@37 104
fazekasgy@37 105
fazekasgy@37 106 /* New PyParameterList Objects */
fazekasgy@37 107 static PyObject *
fazekasgy@37 108 ParameterList_new(PyObject *ignored, PyObject *args)
fazekasgy@37 109 {
cannam@46 110 if (args && PyTuple_Check(args))
fazekasgy@37 111 return PySequence_List(args);
fazekasgy@37 112 else return (PyObject *) PyList_New(0);
fazekasgy@37 113 }
fazekasgy@37 114
fazekasgy@37 115 /* New PyFeatureList Objects */
fazekasgy@37 116 static PyObject *
fazekasgy@37 117 FeatureList_new(PyObject *ignored, PyObject *args)
fazekasgy@37 118 {
cannam@46 119 if (args && PyTuple_Check(args))
fazekasgy@37 120 return PySequence_List(args);
fazekasgy@37 121 else return (PyObject *) PyList_New(0);
fazekasgy@37 122 }
fazekasgy@37 123
fazekasgy@37 124
fazekasgy@37 125 /* Declare the methods exposed by the vampy module */
fazekasgy@37 126
fazekasgy@37 127
fazekasgy@37 128 PyMethodDef VampyMethods[] = {
fazekasgy@37 129 /*NOTE: This is conventionally static, but limiting the scope
fazekasgy@37 130 here will cause seg fault if the declared functions are
fazekasgy@37 131 called back from a Python function wrapped in a C++ class.*/
fazekasgy@37 132
fazekasgy@37 133 {"frame2RealTime", (PyCFunction)RealTime_frame2RealTime, METH_VARARGS,
fazekasgy@37 134 PyDoc_STR("frame2RealTime((int64)frame, (uint32)sampleRate ) -> returns new RealTime object from frame.")},
fazekasgy@37 135
fazekasgy@37 136 {"OutputList", OutputList_new, METH_VARARGS,
fazekasgy@37 137 PyDoc_STR("OutputList() -> returns new OutputList object")},
fazekasgy@37 138
fazekasgy@37 139 {"ParameterList", ParameterList_new, METH_VARARGS,
fazekasgy@37 140 PyDoc_STR("ParameterList() -> returns new ParameterList object")},
fazekasgy@37 141
fazekasgy@37 142 {"FeatureList", FeatureList_new, METH_VARARGS,
fazekasgy@37 143 PyDoc_STR("FeatureList() -> returns new FeatureList object")},
fazekasgy@37 144
fazekasgy@37 145 {NULL, NULL, 0, NULL}
fazekasgy@37 146 };
fazekasgy@37 147
fazekasgy@37 148 /* Module Documentation */
fazekasgy@37 149 // PyDoc_STRVAR(vampy_doc,"This module exposes Vamp plugin data type wrappers.");
fazekasgy@37 150
fazekasgy@37 151 static int
fazekasgy@37 152 setint(PyObject *d, char *name, int value)
fazekasgy@37 153 {
fazekasgy@37 154 PyObject *v;
fazekasgy@37 155 int err;
fazekasgy@37 156 v = PyInt_FromLong((long)value);
fazekasgy@37 157 err = PyDict_SetItemString(d, name, v);
fazekasgy@37 158 Py_XDECREF(v);
fazekasgy@37 159 return err;
fazekasgy@37 160 }
fazekasgy@37 161
fazekasgy@37 162 static int
fazekasgy@37 163 setdbl(PyObject *d, char *name, double value)
fazekasgy@37 164 {
fazekasgy@37 165 PyObject *v;
fazekasgy@37 166 int err;
fazekasgy@37 167 v = PyFloat_FromDouble(value);
fazekasgy@37 168 err = PyDict_SetItemString(d, name, v);
fazekasgy@37 169 Py_XDECREF(v);
fazekasgy@37 170 return err;
fazekasgy@37 171 }
fazekasgy@37 172
fazekasgy@37 173 static int
fazekasgy@37 174 setstr(PyObject *d, char *name, char *value)
fazekasgy@37 175 {
fazekasgy@37 176 PyObject *v;
fazekasgy@37 177 int err;
fazekasgy@37 178 v = PyString_FromString(value);
fazekasgy@37 179 err = PyDict_SetItemString(d, name, v);
fazekasgy@37 180 Py_XDECREF(v);
fazekasgy@37 181 return err;
fazekasgy@37 182 }
fazekasgy@37 183
fazekasgy@37 184
fazekasgy@37 185 PyMODINIT_FUNC
fazekasgy@37 186 initvampy(void)
fazekasgy@37 187 {
fazekasgy@37 188 PyObject *module, *mdict;
fazekasgy@37 189
fazekasgy@37 190 /* if (PyType_Ready(&Feature_Type) < 0) return;
fazekasgy@37 191 Note: Why do we get a segfault if this is initialised here?
fazekasgy@37 192 PyType_Ready adds these object to the GC.
fazekasgy@37 193 This is OK for an extension module, but it is a mistake here,
fazekasgy@37 194 because the adresses become invalid when the shared library
fazekasgy@37 195 is unloaded. When the GC tries to visit a these objects,
fazekasgy@37 196 it will fail.*/
fazekasgy@37 197
fazekasgy@37 198 RealTime_Type.ob_type = &PyType_Type;
fazekasgy@37 199 Feature_Type.ob_type = &PyType_Type;
fazekasgy@37 200 OutputDescriptor_Type.ob_type = &PyType_Type;
fazekasgy@37 201 ParameterDescriptor_Type.ob_type = &PyType_Type;
fazekasgy@37 202 initFeatureSetType(); // this is derived from the builtin dict
fazekasgy@37 203
fazekasgy@37 204 PyImport_AddModule("vampy");
fazekasgy@37 205 module = Py_InitModule("vampy", VampyMethods);
fazekasgy@37 206 if (!module) goto failure;
fazekasgy@37 207 mdict = PyModule_GetDict(module);
fazekasgy@37 208 if (!mdict) goto failure;
fazekasgy@37 209
fazekasgy@37 210 /// vampy plugin wrapper flags
fazekasgy@37 211 if (setint(mdict, "vf_NULL", vf_NULL) < 0) goto failure;
fazekasgy@37 212 if (setint(mdict, "vf_DEBUG", vf_DEBUG) < 0) goto failure;
fazekasgy@37 213 if (setint(mdict, "vf_STRICT", vf_STRICT) < 0) goto failure;
fazekasgy@37 214 if (setint(mdict, "vf_QUIT", vf_QUIT) < 0) goto failure;
fazekasgy@37 215 if (setint(mdict, "vf_REALTIME", vf_REALTIME) < 0) goto failure;
fazekasgy@37 216 if (setint(mdict, "vf_BUFFER", vf_BUFFER) < 0) goto failure;
fazekasgy@37 217 if (setint(mdict, "vf_ARRAY", vf_ARRAY) < 0) goto failure;
fazekasgy@37 218 if (setint(mdict, "vf_DEFAULT_V2", vf_DEFAULT_V2) < 0) goto failure;
fazekasgy@37 219
fazekasgy@37 220 /// Vamp enum types simulation
fazekasgy@37 221 if (setint(mdict, "OneSamplePerStep", Vamp::Plugin::OutputDescriptor::OneSamplePerStep) < 0) goto failure;
fazekasgy@37 222 if (setint(mdict, "FixedSampleRate", Vamp::Plugin::OutputDescriptor::FixedSampleRate) < 0) goto failure;
fazekasgy@37 223 if (setint(mdict, "VariableSampleRate", Vamp::Plugin::OutputDescriptor::VariableSampleRate) < 0) goto failure;
fazekasgy@37 224 if (setint(mdict, "TimeDomain", Vamp::Plugin::TimeDomain) < 0) goto failure;
fazekasgy@37 225 if (setint(mdict, "FrequencyDomain", Vamp::Plugin::FrequencyDomain) < 0) goto failure;
fazekasgy@37 226
fazekasgy@37 227 /// module attributes
fazekasgy@37 228 if (setstr(mdict, "__name__", "vampy") < 0) goto failure;
fazekasgy@37 229 if (setdbl(mdict, "__version__", 2.0) < 0) goto failure;
fazekasgy@37 230 if (setdbl(mdict, "__VAMP_API_VERSION__", (double) VAMP_API_VERSION) < 0) goto failure;
fazekasgy@37 231 #ifdef HAVE_NUMPY
fazekasgy@37 232 if (setint(mdict, "__numpy__", 1) < 0) goto failure;
fazekasgy@37 233 #else
fazekasgy@37 234 if (setint(mdict, "__numpy__", 0) < 0) goto failure;
fazekasgy@37 235 #endif
fazekasgy@37 236
fazekasgy@37 237 /// type objects
fazekasgy@37 238 Py_INCREF(&RealTime_Type);
fazekasgy@37 239 if (PyModule_AddObject(module,"RealTime",(PyObject*)&RealTime_Type) !=0) goto failure;
fazekasgy@37 240
fazekasgy@37 241 Py_INCREF((PyObject*)&Feature_Type);
fazekasgy@37 242 if (PyModule_AddObject(module,"Feature",(PyObject*)&Feature_Type) !=0) goto failure;
fazekasgy@37 243
fazekasgy@37 244 Py_INCREF((PyObject*)&FeatureSet_Type);
fazekasgy@37 245 if (PyModule_AddObject(module,"FeatureSet",(PyObject*)&FeatureSet_Type) !=0) goto failure;
fazekasgy@37 246
fazekasgy@37 247 Py_INCREF((PyObject*)&OutputDescriptor_Type);
fazekasgy@37 248 if (PyModule_AddObject(module,"OutputDescriptor",(PyObject*)&OutputDescriptor_Type) !=0) goto failure;
fazekasgy@37 249
fazekasgy@37 250 Py_INCREF((PyObject*)&ParameterDescriptor_Type);
fazekasgy@37 251 if (PyModule_AddObject(module,"ParameterDescriptor",(PyObject*)&ParameterDescriptor_Type) !=0) goto failure;
fazekasgy@37 252
fazekasgy@37 253 #ifdef _DEBUG
fazekasgy@37 254 cerr << "Vampy: extension module initialised." << endl;
fazekasgy@37 255 #endif
fazekasgy@37 256
fazekasgy@37 257 return;
fazekasgy@37 258
fazekasgy@37 259 failure :
fazekasgy@37 260 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 261 cerr << "Vampy::PyExtensionModule::initvampy: Failed to initialise extension module." << endl;
fazekasgy@37 262 return;
fazekasgy@37 263 }
fazekasgy@37 264
fazekasgy@37 265