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