Chris@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: /* Chris@0: Chris@0: This module exposes a Type Object wrapping Vamp::RealTime Chris@0: together with module level functions to create Chris@0: new pyRealTime objects from frame count, samplerate or sec,nsec tuples. Chris@0: Chris@0: A small API is provided for the C/C++ programmer and relevant Chris@0: functions are exposed to Python. Chris@0: Chris@0: TODO: implement number protocol (i.e. wrap arithmetic operators) Chris@0: partly done Chris@0: Chris@0: */ Chris@0: Chris@0: #include Chris@0: #include Chris@1: #include "vamp-hostsdk/Plugin.h" Chris@0: #include Chris@0: Chris@0: using namespace std; Chris@0: using namespace Vamp; Chris@0: Chris@0: using Vamp::Plugin; Chris@0: using Vamp::RealTime; Chris@0: Chris@0: /* REAL-TIME TYPE OBJECT */ Chris@0: Chris@0: Chris@0: /* Documentation for our new module */ Chris@0: PyDoc_STRVAR(module_doc, Chris@0: "This module is a thin wrapper around Vamp::RealTime."); Chris@0: Chris@0: Chris@0: /* RealTime Object's Methods */ Chris@0: //Note: these are internals, not exposed by the module but the object Chris@0: Chris@0: /* Returns a Tuple containing sec and nsec values */ Chris@0: static PyObject * Chris@0: RealTime_values(RealTimeObject *self) Chris@0: { Chris@0: return Py_BuildValue("(ii)", Chris@0: self->rt->sec,self->rt->nsec); Chris@0: } Chris@0: Chris@0: /* Returns a Text representation */ Chris@0: static PyObject * Chris@0: RealTime_toText(RealTimeObject *self, PyObject *args) Chris@0: { Chris@0: return Py_BuildValue("s", Chris@0: self->rt->toText().c_str()); Chris@0: } Chris@0: Chris@0: /* String representation called by e.g. str(realtime), print realtime*/ Chris@0: static PyObject * Chris@0: RealTime_repr(PyObject *self) Chris@0: { Chris@0: return Py_BuildValue("s", Chris@0: ((RealTimeObject*)self)->rt->toString().c_str()); Chris@0: } Chris@0: Chris@0: Chris@0: /* Frame representation */ Chris@0: static PyObject * Chris@0: RealTime_toFrame(PyObject *self, PyObject *args) Chris@0: { Chris@0: unsigned int samplerate; Chris@0: Chris@0: if ( !PyArg_ParseTuple(args, "I:realtime.toFrame object ", Chris@0: (unsigned int *) &samplerate )) { Chris@0: PyErr_SetString(PyExc_ValueError, Chris@0: "Sample Rate Required."); Chris@0: return NULL; Chris@0: } Chris@0: Chris@0: return Py_BuildValue("k", Chris@0: RealTime::realTime2Frame( Chris@0: *(const RealTime*) ((RealTimeObject*)self)->rt, Chris@0: (unsigned int) samplerate)); Chris@0: } Chris@0: Chris@0: /* Conversion of realtime to a double precision floating point value */ Chris@0: /* ...in Python called by e.g. float(realtime) */ Chris@0: static PyObject * Chris@0: RealTime_float(PyObject *s) Chris@0: { Chris@0: double drt = ((double) ((RealTimeObject*)s)->rt->sec + Chris@0: (double)((double) ((RealTimeObject*)s)->rt->nsec)/1000000000); Chris@0: return PyFloat_FromDouble(drt); Chris@0: } Chris@0: Chris@0: /* test */ Chris@0: static PyObject * Chris@0: RealTime_test(PyObject *self) Chris@0: { Chris@0: Chris@0: long frame = 100; Chris@0: unsigned int sampleRate = 22050; Chris@0: Chris@0: const RealTime t = RealTime::frame2RealTime(frame,sampleRate); Chris@0: long back = RealTime::realTime2Frame(t,sampleRate); Chris@0: cerr << "Reverse Conversion: " << back << endl; Chris@0: Chris@0: return Py_BuildValue("s", Chris@0: ((RealTimeObject*)self)->rt->toString().c_str()); Chris@0: } Chris@0: Chris@0: Chris@0: /* Type object's (RealTime) methods table */ Chris@0: static PyMethodDef RealTime_methods[] = { Chris@0: Chris@0: {"toText", (PyCFunction)RealTime_toText, METH_NOARGS, Chris@0: PyDoc_STR("toText() -> Return a user-readable string to the nearest millisecond in a form like HH:MM:SS.mmm")}, Chris@0: Chris@0: {"values", (PyCFunction)RealTime_values, METH_NOARGS, Chris@0: PyDoc_STR("values() -> Tuple of sec,nsec representation.")}, Chris@0: Chris@0: {"toFrame", (PyCFunction)RealTime_toFrame, METH_VARARGS, Chris@0: PyDoc_STR("toFrame(samplerate) -> Sample count for given sample rate.")}, Chris@0: Chris@0: {"toFloat", (PyCFunction)RealTime_float, METH_NOARGS, Chris@0: PyDoc_STR("float() -> Floating point representation.")}, Chris@0: Chris@0: {"test", (PyCFunction)RealTime_test, METH_VARARGS, Chris@0: PyDoc_STR("test() -> .")}, Chris@0: Chris@0: {NULL, NULL} /* sentinel */ Chris@0: }; Chris@0: Chris@0: Chris@0: Chris@0: /* Function to set basic attributes */ Chris@0: static int Chris@0: RealTime_setattr(RealTimeObject *self, char *name, PyObject *value) Chris@0: { Chris@0: Chris@0: if ( !string(name).compare("sec")) { Chris@0: self->rt->sec= (int) PyInt_AS_LONG(value); Chris@0: return 0; Chris@0: } Chris@0: Chris@0: if ( !string(name).compare("nsec")) { Chris@0: self->rt->nsec= (int) PyInt_AS_LONG(value); Chris@0: return 0; Chris@0: } Chris@0: Chris@0: return -1; Chris@0: } Chris@0: Chris@0: /* Function to get basic attributes */ Chris@0: static PyObject * Chris@0: RealTime_getattr(RealTimeObject *self, char *name) Chris@0: { Chris@0: Chris@0: if ( !string(name).compare("sec") ) { Chris@0: return PyInt_FromSsize_t( Chris@0: (Py_ssize_t) self->rt->sec); Chris@0: } Chris@0: Chris@0: if ( !string(name).compare("nsec") ) { Chris@0: return PyInt_FromSsize_t( Chris@0: (Py_ssize_t) self->rt->nsec); Chris@0: } Chris@0: Chris@0: return Py_FindMethod(RealTime_methods, Chris@0: (PyObject *)self, name); Chris@0: } Chris@0: Chris@0: Chris@0: /* DESTRUCTOR: delete type object */ Chris@0: static void Chris@0: RealTimeObject_dealloc(RealTimeObject *self) Chris@0: { Chris@0: delete self->rt; //delete the C object Chris@0: PyObject_Del(self); //delete the Python object Chris@0: } Chris@0: Chris@0: /* Number Protocol */ Chris@0: Chris@0: Chris@0: static PyObject * Chris@0: RealTime_add(PyObject *s, PyObject *w) Chris@0: { Chris@0: Chris@0: RealTimeObject *result = Chris@0: PyObject_New(RealTimeObject, &RealTime_Type); Chris@0: if (result == NULL) return NULL; Chris@0: Chris@1: result->rt = new RealTime( Chris@0: *((RealTimeObject*)s)->rt + *((RealTimeObject*)w)->rt); Chris@0: return (PyObject*)result; Chris@0: } Chris@0: Chris@0: static PyObject * Chris@0: RealTime_subtract(PyObject *s, PyObject *w) Chris@0: { Chris@0: Chris@0: RealTimeObject *result = Chris@0: PyObject_New(RealTimeObject, &RealTime_Type); Chris@0: if (result == NULL) return NULL; Chris@0: Chris@1: result->rt = new RealTime( Chris@0: *((RealTimeObject*)s)->rt - *((RealTimeObject*)w)->rt); Chris@0: return (PyObject*)result; Chris@0: } Chris@0: Chris@0: Chris@0: static PyNumberMethods realtime_as_number = { Chris@0: RealTime_add, /*nb_add*/ Chris@0: RealTime_subtract, /*nb_subtract*/ Chris@0: 0, /*nb_multiply*/ Chris@0: 0, /*nb_divide*/ Chris@0: 0, /*nb_remainder*/ Chris@0: 0, /*nb_divmod*/ Chris@0: 0, /*nb_power*/ Chris@0: 0, /*nb_neg*/ Chris@0: 0, /*nb_pos*/ Chris@0: 0, /*(unaryfunc)array_abs,*/ Chris@0: 0, /*nb_nonzero*/ Chris@0: 0, /*nb_invert*/ Chris@0: 0, /*nb_lshift*/ Chris@0: 0, /*nb_rshift*/ Chris@0: 0, /*nb_and*/ Chris@0: 0, /*nb_xor*/ Chris@0: 0, /*nb_or*/ Chris@0: 0, /*nb_coerce*/ Chris@0: 0, /*nb_int*/ Chris@0: 0, /*nb_long*/ Chris@0: (unaryfunc)RealTime_float, /*nb_float*/ Chris@0: 0, /*nb_oct*/ Chris@0: 0, /*nb_hex*/ Chris@0: }; Chris@0: Chris@0: /* pyRealTime TypeObject */ Chris@0: Chris@0: Chris@0: /* Doc:: 10.3 Type Objects */ Chris@0: /* static */ PyTypeObject RealTime_Type = { Chris@0: /* The ob_type field must be initialized in the module init function Chris@0: * to be portable to Windows without using C++. */ Chris@0: PyObject_HEAD_INIT(NULL) Chris@0: 0, /*ob_size*/ Chris@0: "pyRealTime.realtime", /*tp_name*/ Chris@0: sizeof(RealTimeObject), /*tp_basicsize*/ Chris@0: sizeof(RealTime), /*tp_itemsize*/ Chris@0: /* methods */ Chris@0: (destructor)RealTimeObject_dealloc, /*tp_dealloc*/ Chris@0: 0, /*tp_print*/ Chris@0: (getattrfunc)RealTime_getattr, /*tp_getattr*/ Chris@0: (setattrfunc)RealTime_setattr, /*tp_setattr*/ Chris@0: 0, /*tp_compare*/ Chris@0: RealTime_repr, /*tp_repr*/ Chris@0: &realtime_as_number, /*tp_as_number*/ Chris@0: 0, /*tp_as_sequence*/ Chris@0: 0, /*tp_as_mapping*/ Chris@0: 0, /*tp_hash*/ Chris@0: 0,//(ternaryfunc)RealTime_new, /*tp_call*/ Chris@0: 0, /*tp_str*/ Chris@0: 0, /*tp_getattro*/ Chris@0: 0, /*tp_setattro*/ Chris@0: 0, /*tp_as_buffer*/ Chris@0: Py_TPFLAGS_DEFAULT, /*tp_flags*/ Chris@0: 0, /*tp_doc*/ Chris@0: 0, /*tp_traverse*/ Chris@0: 0, /*tp_clear*/ Chris@0: 0, /*tp_richcompare*/ Chris@0: 0, /*tp_weaklistoffset*/ Chris@0: 0, /*tp_iter*/ Chris@0: 0, /*tp_iternext*/ Chris@0: RealTime_methods, /*tp_methods*/ //TypeObject Methods Chris@0: 0, /*tp_members*/ Chris@0: 0, /*tp_getset*/ Chris@0: 0, /*tp_base*/ Chris@0: 0, /*tp_dict*/ Chris@0: 0, /*tp_descr_get*/ Chris@0: 0, /*tp_descr_set*/ Chris@0: 0, /*tp_dictoffset*/ Chris@0: 0, /*tp_init*/ Chris@0: 0, /*tp_alloc*/ Chris@0: 0, /*tp_new*/ Chris@0: 0, /*tp_free*/ Chris@0: 0, /*tp_is_gc*/ Chris@0: }; Chris@0: Chris@0: Chris@0: /* Remaining Functions Exposed by the MODULE */ Chris@0: Chris@0: Chris@0: /* New RealTime object from Frame (with given samplerate) */ Chris@0: /*static*/ PyObject * Chris@0: RealTime_frame2RealTime(PyObject *ignored, PyObject *args) Chris@0: { Chris@0: Chris@0: long frame; Chris@0: unsigned int sampleRate; Chris@0: Chris@0: if (!PyArg_ParseTuple(args, "lI:realtime.fame2RealTime ", Chris@0: &frame, Chris@0: &sampleRate)) Chris@0: return NULL; Chris@0: /*Doc:: 5.5 Parsing arguments and building values*/ Chris@0: Chris@0: RealTimeObject *self; Chris@0: self = PyObject_New(RealTimeObject, &RealTime_Type); Chris@0: if (self == NULL) Chris@0: return NULL; Chris@0: Chris@1: self->rt = new RealTime( Chris@0: RealTime::frame2RealTime(frame,sampleRate)); Chris@0: Chris@0: return (PyObject *) self; Chris@0: } Chris@0: Chris@0: /* New RealTime object from sec and nsec */ Chris@0: /*static*/ PyObject * Chris@0: RealTime_new(PyObject *ignored, PyObject *args) Chris@0: { Chris@0: Chris@0: unsigned int sec = 0; Chris@0: unsigned int nsec = 0; Chris@0: double unary = 0; Chris@0: const char *fmt = NULL; Chris@0: Chris@0: /*Doc:: 5.5 Parsing arguments and building values*/ Chris@0: if ( Chris@0: Chris@0: !PyArg_ParseTuple(args, "|sd:realtime.new ", Chris@0: (const char *) &fmt, Chris@0: (double *) &unary) && Chris@0: Chris@0: !PyArg_ParseTuple(args, "|II:realtime.new ", Chris@0: (unsigned int*) &sec, Chris@0: (unsigned int*) &nsec) Chris@0: Chris@0: ) { Chris@0: PyErr_SetString(PyExc_TypeError, Chris@0: "RealTime initialised with wrong arguments."); Chris@0: return NULL; } Chris@0: Chris@0: PyErr_Clear(); Chris@0: Chris@0: RealTimeObject *self = Chris@0: PyObject_New(RealTimeObject, &RealTime_Type); Chris@0: if (self == NULL) return NULL; Chris@0: Chris@0: self->rt = NULL; Chris@0: Chris@0: if (sec == 0 && nsec == 0 && fmt == 0) Chris@1: self->rt = new RealTime(); Chris@0: else if (fmt == 0) Chris@1: self->rt = new RealTime(sec,nsec); Chris@0: else { Chris@0: Chris@0: if (!string(fmt).compare("float") || Chris@0: !string(fmt).compare("seconds")) Chris@1: self->rt = new RealTime( Chris@0: RealTime::fromSeconds((double) unary)); Chris@0: Chris@0: if (!string(fmt).compare("milliseconds")) { Chris@1: self->rt = new RealTime( Chris@0: RealTime::fromSeconds((double) unary / 1000.0)); } Chris@0: } Chris@0: Chris@0: if (!self->rt) { Chris@0: PyErr_SetString(PyExc_TypeError, Chris@0: "RealTime initialised with wrong arguments."); Chris@0: return NULL; Chris@0: } Chris@0: Chris@0: return (PyObject *) self; Chris@0: } Chris@0: Chris@0: Chris@0: /* pyRealTime Module's methods table */ Chris@0: static PyMethodDef Module_methods[] = { Chris@0: Chris@0: {"frame2RealTime", (PyCFunction)RealTime_frame2RealTime, METH_VARARGS, Chris@0: PyDoc_STR("frame2RealTime((int64)frame, (uint32)sampleRate ) -> returns new RealTime object from frame.")}, Chris@0: Chris@0: {"realtime", RealTime_new, METH_VARARGS, Chris@0: PyDoc_STR("realtime() -> returns new RealTime object")}, Chris@0: Chris@0: {NULL, NULL} /* sentinel */ Chris@0: }; Chris@0: Chris@0: Chris@0: /* PyRealTime C API functions */ Chris@0: Chris@0: Chris@0: Chris@0: /*RealTime from PyRealTime*/ Chris@0: RealTime* Chris@0: PyRealTime_AsPointer (PyObject *self) { Chris@0: Chris@0: RealTimeObject *s = (RealTimeObject*) self; Chris@0: Chris@0: if (!PyRealTime_Check(s)) { Chris@0: PyErr_SetString(PyExc_TypeError, "RealTime Object Expected."); Chris@0: cerr << "in call PyRealTime_AsPointer(): RealTime Object Expected. " << endl; Chris@0: return NULL; } Chris@0: return s->rt; }; Chris@0: Chris@0: /*PyRealTime from RealTime*/ Chris@0: PyObject* Chris@0: PyRealTime_FromRealTime(Vamp::RealTime *rt) { Chris@0: Chris@0: RealTimeObject *self = Chris@0: PyObject_New(RealTimeObject, &RealTime_Type); Chris@0: if (self == NULL) return NULL; Chris@0: Chris@1: self->rt = new RealTime(*rt); Chris@0: return (PyObject*) self; Chris@0: //TODO: check if we need to INCREF here Chris@0: } Chris@0: Chris@0: Chris@0: /* Module initialization (includes extern "C" {...}) */ Chris@0: PyMODINIT_FUNC Chris@0: initpyRealTime(void) Chris@0: { Chris@0: PyObject *m; Chris@0: Chris@0: /* Finalize the type object including setting type of the new type Chris@0: * object; doing it here is required for portability to Windows Chris@0: * without requiring C++. */ Chris@0: if (PyType_Ready(&RealTime_Type) < 0) Chris@0: return; Chris@0: Chris@0: /* Create the module and add the functions */ Chris@0: m = Py_InitModule3("pyRealTime", Module_methods, module_doc); Chris@0: if (m == NULL) Chris@0: return; Chris@0: Chris@0: // PyModule_AddObject(m, "realtime", (PyObject *)&RealTime_Type); Chris@0: Chris@0: }