annotate PyExtensionModule.cpp @ 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 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