annotate PyExtensionModule.cpp @ 99:b9cddb57a7f4

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