annotate host/pyRealTime.cpp @ 24:7d28bed0864e

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