Chris@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@0
|
2 /*
|
Chris@0
|
3
|
Chris@0
|
4 This module exposes a Type Object wrapping Vamp::RealTime
|
Chris@0
|
5 together with module level functions to create
|
Chris@0
|
6 new pyRealTime objects from frame count, samplerate or sec,nsec tuples.
|
Chris@0
|
7
|
Chris@0
|
8 A small API is provided for the C/C++ programmer and relevant
|
Chris@0
|
9 functions are exposed to Python.
|
Chris@0
|
10
|
Chris@0
|
11 TODO: implement number protocol (i.e. wrap arithmetic operators)
|
Chris@0
|
12 partly done
|
Chris@0
|
13
|
Chris@0
|
14 */
|
Chris@0
|
15
|
Chris@0
|
16 #include <Python.h>
|
Chris@0
|
17 #include <pyRealTime.h>
|
Chris@1
|
18 #include "vamp-hostsdk/Plugin.h"
|
Chris@0
|
19 #include <string>
|
Chris@0
|
20
|
Chris@0
|
21 using namespace std;
|
Chris@0
|
22 using namespace Vamp;
|
Chris@0
|
23
|
Chris@0
|
24 using Vamp::Plugin;
|
Chris@0
|
25 using Vamp::RealTime;
|
Chris@0
|
26
|
Chris@0
|
27 /* REAL-TIME TYPE OBJECT */
|
Chris@0
|
28
|
Chris@0
|
29
|
Chris@0
|
30 /* Documentation for our new module */
|
Chris@0
|
31 PyDoc_STRVAR(module_doc,
|
Chris@0
|
32 "This module is a thin wrapper around Vamp::RealTime.");
|
Chris@0
|
33
|
Chris@0
|
34
|
Chris@0
|
35 /* RealTime Object's Methods */
|
Chris@0
|
36 //Note: these are internals, not exposed by the module but the object
|
Chris@0
|
37
|
Chris@0
|
38 /* Returns a Tuple containing sec and nsec values */
|
Chris@0
|
39 static PyObject *
|
Chris@0
|
40 RealTime_values(RealTimeObject *self)
|
Chris@0
|
41 {
|
Chris@0
|
42 return Py_BuildValue("(ii)",
|
Chris@0
|
43 self->rt->sec,self->rt->nsec);
|
Chris@0
|
44 }
|
Chris@0
|
45
|
Chris@0
|
46 /* Returns a Text representation */
|
Chris@0
|
47 static PyObject *
|
Chris@0
|
48 RealTime_toText(RealTimeObject *self, PyObject *args)
|
Chris@0
|
49 {
|
Chris@0
|
50 return Py_BuildValue("s",
|
Chris@0
|
51 self->rt->toText().c_str());
|
Chris@0
|
52 }
|
Chris@0
|
53
|
Chris@0
|
54 /* String representation called by e.g. str(realtime), print realtime*/
|
Chris@0
|
55 static PyObject *
|
Chris@0
|
56 RealTime_repr(PyObject *self)
|
Chris@0
|
57 {
|
Chris@0
|
58 return Py_BuildValue("s",
|
Chris@0
|
59 ((RealTimeObject*)self)->rt->toString().c_str());
|
Chris@0
|
60 }
|
Chris@0
|
61
|
Chris@0
|
62
|
Chris@0
|
63 /* Frame representation */
|
Chris@0
|
64 static PyObject *
|
Chris@0
|
65 RealTime_toFrame(PyObject *self, PyObject *args)
|
Chris@0
|
66 {
|
Chris@0
|
67 unsigned int samplerate;
|
Chris@0
|
68
|
Chris@0
|
69 if ( !PyArg_ParseTuple(args, "I:realtime.toFrame object ",
|
Chris@0
|
70 (unsigned int *) &samplerate )) {
|
Chris@0
|
71 PyErr_SetString(PyExc_ValueError,
|
Chris@0
|
72 "Sample Rate Required.");
|
Chris@0
|
73 return NULL;
|
Chris@0
|
74 }
|
Chris@0
|
75
|
Chris@0
|
76 return Py_BuildValue("k",
|
Chris@0
|
77 RealTime::realTime2Frame(
|
Chris@0
|
78 *(const RealTime*) ((RealTimeObject*)self)->rt,
|
Chris@0
|
79 (unsigned int) samplerate));
|
Chris@0
|
80 }
|
Chris@0
|
81
|
Chris@0
|
82 /* Conversion of realtime to a double precision floating point value */
|
Chris@0
|
83 /* ...in Python called by e.g. float(realtime) */
|
Chris@0
|
84 static PyObject *
|
Chris@0
|
85 RealTime_float(PyObject *s)
|
Chris@0
|
86 {
|
Chris@0
|
87 double drt = ((double) ((RealTimeObject*)s)->rt->sec +
|
Chris@0
|
88 (double)((double) ((RealTimeObject*)s)->rt->nsec)/1000000000);
|
Chris@0
|
89 return PyFloat_FromDouble(drt);
|
Chris@0
|
90 }
|
Chris@0
|
91
|
Chris@0
|
92 /* test */
|
Chris@0
|
93 static PyObject *
|
Chris@0
|
94 RealTime_test(PyObject *self)
|
Chris@0
|
95 {
|
Chris@0
|
96
|
Chris@0
|
97 long frame = 100;
|
Chris@0
|
98 unsigned int sampleRate = 22050;
|
Chris@0
|
99
|
Chris@0
|
100 const RealTime t = RealTime::frame2RealTime(frame,sampleRate);
|
Chris@0
|
101 long back = RealTime::realTime2Frame(t,sampleRate);
|
Chris@0
|
102 cerr << "Reverse Conversion: " << back << endl;
|
Chris@0
|
103
|
Chris@0
|
104 return Py_BuildValue("s",
|
Chris@0
|
105 ((RealTimeObject*)self)->rt->toString().c_str());
|
Chris@0
|
106 }
|
Chris@0
|
107
|
Chris@0
|
108
|
Chris@0
|
109 /* Type object's (RealTime) methods table */
|
Chris@0
|
110 static PyMethodDef RealTime_methods[] = {
|
Chris@0
|
111
|
Chris@0
|
112 {"toText", (PyCFunction)RealTime_toText, METH_NOARGS,
|
Chris@0
|
113 PyDoc_STR("toText() -> Return a user-readable string to the nearest millisecond in a form like HH:MM:SS.mmm")},
|
Chris@0
|
114
|
Chris@0
|
115 {"values", (PyCFunction)RealTime_values, METH_NOARGS,
|
Chris@0
|
116 PyDoc_STR("values() -> Tuple of sec,nsec representation.")},
|
Chris@0
|
117
|
Chris@0
|
118 {"toFrame", (PyCFunction)RealTime_toFrame, METH_VARARGS,
|
Chris@0
|
119 PyDoc_STR("toFrame(samplerate) -> Sample count for given sample rate.")},
|
Chris@0
|
120
|
Chris@0
|
121 {"toFloat", (PyCFunction)RealTime_float, METH_NOARGS,
|
Chris@0
|
122 PyDoc_STR("float() -> Floating point representation.")},
|
Chris@0
|
123
|
Chris@0
|
124 {"test", (PyCFunction)RealTime_test, METH_VARARGS,
|
Chris@0
|
125 PyDoc_STR("test() -> .")},
|
Chris@0
|
126
|
Chris@0
|
127 {NULL, NULL} /* sentinel */
|
Chris@0
|
128 };
|
Chris@0
|
129
|
Chris@0
|
130
|
Chris@0
|
131
|
Chris@0
|
132 /* Function to set basic attributes */
|
Chris@0
|
133 static int
|
Chris@0
|
134 RealTime_setattr(RealTimeObject *self, char *name, PyObject *value)
|
Chris@0
|
135 {
|
Chris@0
|
136
|
Chris@0
|
137 if ( !string(name).compare("sec")) {
|
Chris@0
|
138 self->rt->sec= (int) PyInt_AS_LONG(value);
|
Chris@0
|
139 return 0;
|
Chris@0
|
140 }
|
Chris@0
|
141
|
Chris@0
|
142 if ( !string(name).compare("nsec")) {
|
Chris@0
|
143 self->rt->nsec= (int) PyInt_AS_LONG(value);
|
Chris@0
|
144 return 0;
|
Chris@0
|
145 }
|
Chris@0
|
146
|
Chris@0
|
147 return -1;
|
Chris@0
|
148 }
|
Chris@0
|
149
|
Chris@0
|
150 /* Function to get basic attributes */
|
Chris@0
|
151 static PyObject *
|
Chris@0
|
152 RealTime_getattr(RealTimeObject *self, char *name)
|
Chris@0
|
153 {
|
Chris@0
|
154
|
Chris@0
|
155 if ( !string(name).compare("sec") ) {
|
Chris@0
|
156 return PyInt_FromSsize_t(
|
Chris@0
|
157 (Py_ssize_t) self->rt->sec);
|
Chris@0
|
158 }
|
Chris@0
|
159
|
Chris@0
|
160 if ( !string(name).compare("nsec") ) {
|
Chris@0
|
161 return PyInt_FromSsize_t(
|
Chris@0
|
162 (Py_ssize_t) self->rt->nsec);
|
Chris@0
|
163 }
|
Chris@0
|
164
|
Chris@0
|
165 return Py_FindMethod(RealTime_methods,
|
Chris@0
|
166 (PyObject *)self, name);
|
Chris@0
|
167 }
|
Chris@0
|
168
|
Chris@0
|
169
|
Chris@0
|
170 /* DESTRUCTOR: delete type object */
|
Chris@0
|
171 static void
|
Chris@0
|
172 RealTimeObject_dealloc(RealTimeObject *self)
|
Chris@0
|
173 {
|
Chris@0
|
174 delete self->rt; //delete the C object
|
Chris@0
|
175 PyObject_Del(self); //delete the Python object
|
Chris@0
|
176 }
|
Chris@0
|
177
|
Chris@0
|
178 /* Number Protocol */
|
Chris@0
|
179
|
Chris@0
|
180
|
Chris@0
|
181 static PyObject *
|
Chris@0
|
182 RealTime_add(PyObject *s, PyObject *w)
|
Chris@0
|
183 {
|
Chris@0
|
184
|
Chris@0
|
185 RealTimeObject *result =
|
Chris@0
|
186 PyObject_New(RealTimeObject, &RealTime_Type);
|
Chris@0
|
187 if (result == NULL) return NULL;
|
Chris@0
|
188
|
Chris@1
|
189 result->rt = new RealTime(
|
Chris@0
|
190 *((RealTimeObject*)s)->rt + *((RealTimeObject*)w)->rt);
|
Chris@0
|
191 return (PyObject*)result;
|
Chris@0
|
192 }
|
Chris@0
|
193
|
Chris@0
|
194 static PyObject *
|
Chris@0
|
195 RealTime_subtract(PyObject *s, PyObject *w)
|
Chris@0
|
196 {
|
Chris@0
|
197
|
Chris@0
|
198 RealTimeObject *result =
|
Chris@0
|
199 PyObject_New(RealTimeObject, &RealTime_Type);
|
Chris@0
|
200 if (result == NULL) return NULL;
|
Chris@0
|
201
|
Chris@1
|
202 result->rt = new RealTime(
|
Chris@0
|
203 *((RealTimeObject*)s)->rt - *((RealTimeObject*)w)->rt);
|
Chris@0
|
204 return (PyObject*)result;
|
Chris@0
|
205 }
|
Chris@0
|
206
|
Chris@0
|
207
|
Chris@0
|
208 static PyNumberMethods realtime_as_number = {
|
Chris@0
|
209 RealTime_add, /*nb_add*/
|
Chris@0
|
210 RealTime_subtract, /*nb_subtract*/
|
Chris@0
|
211 0, /*nb_multiply*/
|
Chris@0
|
212 0, /*nb_divide*/
|
Chris@0
|
213 0, /*nb_remainder*/
|
Chris@0
|
214 0, /*nb_divmod*/
|
Chris@0
|
215 0, /*nb_power*/
|
Chris@0
|
216 0, /*nb_neg*/
|
Chris@0
|
217 0, /*nb_pos*/
|
Chris@0
|
218 0, /*(unaryfunc)array_abs,*/
|
Chris@0
|
219 0, /*nb_nonzero*/
|
Chris@0
|
220 0, /*nb_invert*/
|
Chris@0
|
221 0, /*nb_lshift*/
|
Chris@0
|
222 0, /*nb_rshift*/
|
Chris@0
|
223 0, /*nb_and*/
|
Chris@0
|
224 0, /*nb_xor*/
|
Chris@0
|
225 0, /*nb_or*/
|
Chris@0
|
226 0, /*nb_coerce*/
|
Chris@0
|
227 0, /*nb_int*/
|
Chris@0
|
228 0, /*nb_long*/
|
Chris@0
|
229 (unaryfunc)RealTime_float, /*nb_float*/
|
Chris@0
|
230 0, /*nb_oct*/
|
Chris@0
|
231 0, /*nb_hex*/
|
Chris@0
|
232 };
|
Chris@0
|
233
|
Chris@0
|
234 /* pyRealTime TypeObject */
|
Chris@0
|
235
|
Chris@0
|
236
|
Chris@0
|
237 /* Doc:: 10.3 Type Objects */
|
Chris@0
|
238 /* static */ PyTypeObject RealTime_Type = {
|
Chris@0
|
239 /* The ob_type field must be initialized in the module init function
|
Chris@0
|
240 * to be portable to Windows without using C++. */
|
Chris@0
|
241 PyObject_HEAD_INIT(NULL)
|
Chris@0
|
242 0, /*ob_size*/
|
Chris@0
|
243 "pyRealTime.realtime", /*tp_name*/
|
Chris@0
|
244 sizeof(RealTimeObject), /*tp_basicsize*/
|
Chris@0
|
245 sizeof(RealTime), /*tp_itemsize*/
|
Chris@0
|
246 /* methods */
|
Chris@0
|
247 (destructor)RealTimeObject_dealloc, /*tp_dealloc*/
|
Chris@0
|
248 0, /*tp_print*/
|
Chris@0
|
249 (getattrfunc)RealTime_getattr, /*tp_getattr*/
|
Chris@0
|
250 (setattrfunc)RealTime_setattr, /*tp_setattr*/
|
Chris@0
|
251 0, /*tp_compare*/
|
Chris@0
|
252 RealTime_repr, /*tp_repr*/
|
Chris@0
|
253 &realtime_as_number, /*tp_as_number*/
|
Chris@0
|
254 0, /*tp_as_sequence*/
|
Chris@0
|
255 0, /*tp_as_mapping*/
|
Chris@0
|
256 0, /*tp_hash*/
|
Chris@0
|
257 0,//(ternaryfunc)RealTime_new, /*tp_call*/
|
Chris@0
|
258 0, /*tp_str*/
|
Chris@0
|
259 0, /*tp_getattro*/
|
Chris@0
|
260 0, /*tp_setattro*/
|
Chris@0
|
261 0, /*tp_as_buffer*/
|
Chris@0
|
262 Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
Chris@0
|
263 0, /*tp_doc*/
|
Chris@0
|
264 0, /*tp_traverse*/
|
Chris@0
|
265 0, /*tp_clear*/
|
Chris@0
|
266 0, /*tp_richcompare*/
|
Chris@0
|
267 0, /*tp_weaklistoffset*/
|
Chris@0
|
268 0, /*tp_iter*/
|
Chris@0
|
269 0, /*tp_iternext*/
|
Chris@0
|
270 RealTime_methods, /*tp_methods*/ //TypeObject Methods
|
Chris@0
|
271 0, /*tp_members*/
|
Chris@0
|
272 0, /*tp_getset*/
|
Chris@0
|
273 0, /*tp_base*/
|
Chris@0
|
274 0, /*tp_dict*/
|
Chris@0
|
275 0, /*tp_descr_get*/
|
Chris@0
|
276 0, /*tp_descr_set*/
|
Chris@0
|
277 0, /*tp_dictoffset*/
|
Chris@0
|
278 0, /*tp_init*/
|
Chris@0
|
279 0, /*tp_alloc*/
|
Chris@0
|
280 0, /*tp_new*/
|
Chris@0
|
281 0, /*tp_free*/
|
Chris@0
|
282 0, /*tp_is_gc*/
|
Chris@0
|
283 };
|
Chris@0
|
284
|
Chris@0
|
285
|
Chris@0
|
286 /* Remaining Functions Exposed by the MODULE */
|
Chris@0
|
287
|
Chris@0
|
288
|
Chris@0
|
289 /* New RealTime object from Frame (with given samplerate) */
|
Chris@0
|
290 /*static*/ PyObject *
|
Chris@0
|
291 RealTime_frame2RealTime(PyObject *ignored, PyObject *args)
|
Chris@0
|
292 {
|
Chris@0
|
293
|
Chris@0
|
294 long frame;
|
Chris@0
|
295 unsigned int sampleRate;
|
Chris@0
|
296
|
Chris@0
|
297 if (!PyArg_ParseTuple(args, "lI:realtime.fame2RealTime ",
|
Chris@0
|
298 &frame,
|
Chris@0
|
299 &sampleRate))
|
Chris@0
|
300 return NULL;
|
Chris@0
|
301 /*Doc:: 5.5 Parsing arguments and building values*/
|
Chris@0
|
302
|
Chris@0
|
303 RealTimeObject *self;
|
Chris@0
|
304 self = PyObject_New(RealTimeObject, &RealTime_Type);
|
Chris@0
|
305 if (self == NULL)
|
Chris@0
|
306 return NULL;
|
Chris@0
|
307
|
Chris@1
|
308 self->rt = new RealTime(
|
Chris@0
|
309 RealTime::frame2RealTime(frame,sampleRate));
|
Chris@0
|
310
|
Chris@0
|
311 return (PyObject *) self;
|
Chris@0
|
312 }
|
Chris@0
|
313
|
Chris@0
|
314 /* New RealTime object from sec and nsec */
|
Chris@0
|
315 /*static*/ PyObject *
|
Chris@0
|
316 RealTime_new(PyObject *ignored, PyObject *args)
|
Chris@0
|
317 {
|
Chris@0
|
318
|
Chris@0
|
319 unsigned int sec = 0;
|
Chris@0
|
320 unsigned int nsec = 0;
|
Chris@0
|
321 double unary = 0;
|
Chris@0
|
322 const char *fmt = NULL;
|
Chris@0
|
323
|
Chris@0
|
324 /*Doc:: 5.5 Parsing arguments and building values*/
|
Chris@0
|
325 if (
|
Chris@0
|
326
|
Chris@0
|
327 !PyArg_ParseTuple(args, "|sd:realtime.new ",
|
Chris@0
|
328 (const char *) &fmt,
|
Chris@0
|
329 (double *) &unary) &&
|
Chris@0
|
330
|
Chris@0
|
331 !PyArg_ParseTuple(args, "|II:realtime.new ",
|
Chris@0
|
332 (unsigned int*) &sec,
|
Chris@0
|
333 (unsigned int*) &nsec)
|
Chris@0
|
334
|
Chris@0
|
335 ) {
|
Chris@0
|
336 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
337 "RealTime initialised with wrong arguments.");
|
Chris@0
|
338 return NULL; }
|
Chris@0
|
339
|
Chris@0
|
340 PyErr_Clear();
|
Chris@0
|
341
|
Chris@0
|
342 RealTimeObject *self =
|
Chris@0
|
343 PyObject_New(RealTimeObject, &RealTime_Type);
|
Chris@0
|
344 if (self == NULL) return NULL;
|
Chris@0
|
345
|
Chris@0
|
346 self->rt = NULL;
|
Chris@0
|
347
|
Chris@0
|
348 if (sec == 0 && nsec == 0 && fmt == 0)
|
Chris@1
|
349 self->rt = new RealTime();
|
Chris@0
|
350 else if (fmt == 0)
|
Chris@1
|
351 self->rt = new RealTime(sec,nsec);
|
Chris@0
|
352 else {
|
Chris@0
|
353
|
Chris@0
|
354 if (!string(fmt).compare("float") ||
|
Chris@0
|
355 !string(fmt).compare("seconds"))
|
Chris@1
|
356 self->rt = new RealTime(
|
Chris@0
|
357 RealTime::fromSeconds((double) unary));
|
Chris@0
|
358
|
Chris@0
|
359 if (!string(fmt).compare("milliseconds")) {
|
Chris@1
|
360 self->rt = new RealTime(
|
Chris@0
|
361 RealTime::fromSeconds((double) unary / 1000.0)); }
|
Chris@0
|
362 }
|
Chris@0
|
363
|
Chris@0
|
364 if (!self->rt) {
|
Chris@0
|
365 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
366 "RealTime initialised with wrong arguments.");
|
Chris@0
|
367 return NULL;
|
Chris@0
|
368 }
|
Chris@0
|
369
|
Chris@0
|
370 return (PyObject *) self;
|
Chris@0
|
371 }
|
Chris@0
|
372
|
Chris@0
|
373
|
Chris@0
|
374 /* pyRealTime Module's methods table */
|
Chris@0
|
375 static PyMethodDef Module_methods[] = {
|
Chris@0
|
376
|
Chris@0
|
377 {"frame2RealTime", (PyCFunction)RealTime_frame2RealTime, METH_VARARGS,
|
Chris@0
|
378 PyDoc_STR("frame2RealTime((int64)frame, (uint32)sampleRate ) -> returns new RealTime object from frame.")},
|
Chris@0
|
379
|
Chris@0
|
380 {"realtime", RealTime_new, METH_VARARGS,
|
Chris@0
|
381 PyDoc_STR("realtime() -> returns new RealTime object")},
|
Chris@0
|
382
|
Chris@0
|
383 {NULL, NULL} /* sentinel */
|
Chris@0
|
384 };
|
Chris@0
|
385
|
Chris@0
|
386
|
Chris@0
|
387 /* PyRealTime C API functions */
|
Chris@0
|
388
|
Chris@0
|
389
|
Chris@0
|
390
|
Chris@0
|
391 /*RealTime from PyRealTime*/
|
Chris@0
|
392 RealTime*
|
Chris@0
|
393 PyRealTime_AsPointer (PyObject *self) {
|
Chris@0
|
394
|
Chris@0
|
395 RealTimeObject *s = (RealTimeObject*) self;
|
Chris@0
|
396
|
Chris@0
|
397 if (!PyRealTime_Check(s)) {
|
Chris@0
|
398 PyErr_SetString(PyExc_TypeError, "RealTime Object Expected.");
|
Chris@0
|
399 cerr << "in call PyRealTime_AsPointer(): RealTime Object Expected. " << endl;
|
Chris@0
|
400 return NULL; }
|
Chris@0
|
401 return s->rt; };
|
Chris@0
|
402
|
Chris@0
|
403 /*PyRealTime from RealTime*/
|
Chris@0
|
404 PyObject*
|
Chris@0
|
405 PyRealTime_FromRealTime(Vamp::RealTime *rt) {
|
Chris@0
|
406
|
Chris@0
|
407 RealTimeObject *self =
|
Chris@0
|
408 PyObject_New(RealTimeObject, &RealTime_Type);
|
Chris@0
|
409 if (self == NULL) return NULL;
|
Chris@0
|
410
|
Chris@1
|
411 self->rt = new RealTime(*rt);
|
Chris@0
|
412 return (PyObject*) self;
|
Chris@0
|
413 //TODO: check if we need to INCREF here
|
Chris@0
|
414 }
|
Chris@0
|
415
|
Chris@0
|
416
|
Chris@0
|
417 /* Module initialization (includes extern "C" {...}) */
|
Chris@0
|
418 PyMODINIT_FUNC
|
Chris@0
|
419 initpyRealTime(void)
|
Chris@0
|
420 {
|
Chris@0
|
421 PyObject *m;
|
Chris@0
|
422
|
Chris@0
|
423 /* Finalize the type object including setting type of the new type
|
Chris@0
|
424 * object; doing it here is required for portability to Windows
|
Chris@0
|
425 * without requiring C++. */
|
Chris@0
|
426 if (PyType_Ready(&RealTime_Type) < 0)
|
Chris@0
|
427 return;
|
Chris@0
|
428
|
Chris@0
|
429 /* Create the module and add the functions */
|
Chris@0
|
430 m = Py_InitModule3("pyRealTime", Module_methods, module_doc);
|
Chris@0
|
431 if (m == NULL)
|
Chris@0
|
432 return;
|
Chris@0
|
433
|
Chris@0
|
434 // PyModule_AddObject(m, "realtime", (PyObject *)&RealTime_Type);
|
Chris@0
|
435
|
Chris@0
|
436 }
|