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