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 {
|
fazekasgy@37
|
100 if (args and 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 {
|
fazekasgy@37
|
110 if (args and 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 {
|
fazekasgy@37
|
119 if (args and 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
|