view 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
line wrap: on
line source
/*

This module exposes a Type Object wrapping VAMP::RealTime
together with module level functions to create 
new pyRealTime objects from frame count, samplerate or sec,nsec tuples.

A small API is provided for the C/C++ programmer and relevant
functions are exposed to Python.

TODO: implement number protocol (i.e. wrap arithmetic operators) 
partly done

*/

#include <Python.h>
#include <pyRealTime.h>
#include "vamp-sdk/Plugin.h"
#include <string>

using namespace std;
using namespace Vamp;

using Vamp::Plugin;
using Vamp::RealTime;

/*						REAL-TIME TYPE OBJECT						*/


/* Documentation for our new module */
PyDoc_STRVAR(module_doc,
"This module is a thin wrapper around VAMP::RealTime.");


/*					 RealTime Object's Methods 					*/ 
//Note: these are internals, not exposed by the module but the object

/* Returns a Tuple containing sec and nsec values */
static PyObject *
RealTime_values(RealTimeObject *self)
{
	return Py_BuildValue("(ii)",
	self->rt->sec,self->rt->nsec);
}

/* Returns a Text representation */
static PyObject *
RealTime_toText(RealTimeObject *self, PyObject *args)
{
	return Py_BuildValue("s",
	self->rt->toText().c_str());
}

/* String representation called by e.g. str(realtime), print realtime*/
static PyObject *
RealTime_repr(PyObject *self)
{
	return Py_BuildValue("s",
	((RealTimeObject*)self)->rt->toString().c_str());
}


/* Frame representation */
static PyObject *
RealTime_toFrame(PyObject *self, PyObject *args)
{
	unsigned int samplerate;
	
	if ( !PyArg_ParseTuple(args, "I:realtime.toFrame object ", 
	(unsigned int *) &samplerate )) {
		PyErr_SetString(PyExc_ValueError, 
		"Sample Rate Required.");
		return NULL;
	}
	
	return Py_BuildValue("k", 
	RealTime::realTime2Frame( 
	*(const RealTime*) ((RealTimeObject*)self)->rt, 
	(unsigned int) samplerate));
}

/* Conversion of realtime to a double precision floating point value */
/* ...in Python called by e.g. float(realtime) */
static PyObject *
RealTime_float(PyObject *s)
{
	double drt = ((double) ((RealTimeObject*)s)->rt->sec + 
	(double)((double) ((RealTimeObject*)s)->rt->nsec)/1000000000);
	return PyFloat_FromDouble(drt);	
}

/* test */
static PyObject *
RealTime_test(PyObject *self)
{

	long frame = 100;
	unsigned int sampleRate = 22050;
	
	const RealTime t = RealTime::frame2RealTime(frame,sampleRate);
	long back = RealTime::realTime2Frame(t,sampleRate);
	cerr << "Reverse Conversion: " << back << endl;

	return Py_BuildValue("s",
	((RealTimeObject*)self)->rt->toString().c_str());
}


/* Type object's (RealTime) methods table */
static PyMethodDef RealTime_methods[] = {

	{"toText",	(PyCFunction)RealTime_toText,	METH_NOARGS,
		PyDoc_STR("toText() -> Return a user-readable string to the nearest millisecond in a form like HH:MM:SS.mmm")},

	{"values",	(PyCFunction)RealTime_values,	METH_NOARGS,
		PyDoc_STR("values() -> Tuple of sec,nsec representation.")},

	{"toFrame",	(PyCFunction)RealTime_toFrame,	METH_VARARGS,
		PyDoc_STR("frame(samplerate) -> Sample count for given sample rate.")},

	{"toFloat",	(PyCFunction)RealTime_float,	METH_NOARGS,
		PyDoc_STR("float() -> Floating point representation.")},

	{"test",	(PyCFunction)RealTime_test,	METH_VARARGS,
		PyDoc_STR("test() -> .")},
	
	{NULL,		NULL}		/* sentinel */
};



/* Function to set basic attributes */
static int
RealTime_setattr(RealTimeObject *self, char *name, PyObject *value)
{

	if ( !string(name).compare("sec")) { 
		self->rt->sec= (int) PyInt_AS_LONG(value);
		return 0;
	}

	if ( !string(name).compare("nsec")) { 
		self->rt->nsec= (int) PyInt_AS_LONG(value);
		return 0;
	}

	return -1;
}

/* Function to get basic attributes */
static PyObject *
RealTime_getattr(RealTimeObject *self, char *name)
{

	if ( !string(name).compare("sec") ) { 
		return PyInt_FromSsize_t(
		(Py_ssize_t) self->rt->sec); 
	} 

	if ( !string(name).compare("nsec") ) { 
		return PyInt_FromSsize_t(
		(Py_ssize_t) self->rt->nsec); 
	} 

	return Py_FindMethod(RealTime_methods, 
	(PyObject *)self, name);
}


/* DESTRUCTOR: delete type object */
static void
RealTimeObject_dealloc(RealTimeObject *self)
{
	delete self->rt; 	//delete the C object
	PyObject_Del(self); //delete the Python object
}

/*					 Number Protocol 					*/


static PyObject *
RealTime_add(PyObject *s, PyObject *w)
{

	RealTimeObject *result = 
    PyObject_New(RealTimeObject, &RealTime_Type); 
	if (result == NULL) return NULL;

	result->rt = new RealTime::RealTime(
	*((RealTimeObject*)s)->rt + *((RealTimeObject*)w)->rt);
	return (PyObject*)result;
}

static PyObject *
RealTime_subtract(PyObject *s, PyObject *w)
{

	RealTimeObject *result = 
    PyObject_New(RealTimeObject, &RealTime_Type); 
	if (result == NULL) return NULL;

	result->rt = new RealTime::RealTime(
	*((RealTimeObject*)s)->rt - *((RealTimeObject*)w)->rt);
	return (PyObject*)result;
}


static PyNumberMethods realtime_as_number = {
	RealTime_add,			/*nb_add*/
	RealTime_subtract,		/*nb_subtract*/
	0,						/*nb_multiply*/
	0,				 		/*nb_divide*/
    0,						/*nb_remainder*/
    0,      	            /*nb_divmod*/
    0,                   	/*nb_power*/
    0,                  	/*nb_neg*/
    0,                		/*nb_pos*/
    0,                  	/*(unaryfunc)array_abs,*/
    0,                    	/*nb_nonzero*/
    0,                    	/*nb_invert*/
    0,       				/*nb_lshift*/
    0,      				/*nb_rshift*/
    0,      				/*nb_and*/
    0,      				/*nb_xor*/
    0,       				/*nb_or*/
    0,                      /*nb_coerce*/
    0,						/*nb_int*/
    0,				        /*nb_long*/
    (unaryfunc)RealTime_float,             /*nb_float*/
    0,               		/*nb_oct*/
    0,               		/*nb_hex*/
};

/*					 pyRealTime TypeObject 					*/


/* Doc:: 10.3 Type Objects */
/* static */ PyTypeObject RealTime_Type = {
	/* The ob_type field must be initialized in the module init function
	 * to be portable to Windows without using C++. */
	PyObject_HEAD_INIT(NULL)
	0,						/*ob_size*/
	"pyRealTime.realtime",				/*tp_name*/
	sizeof(RealTimeObject),	/*tp_basicsize*/
	sizeof(RealTime),		/*tp_itemsize*/
	/*	 	methods	 	*/
	(destructor)RealTimeObject_dealloc, /*tp_dealloc*/
	0,						/*tp_print*/
	(getattrfunc)RealTime_getattr, /*tp_getattr*/
	(setattrfunc)RealTime_setattr, /*tp_setattr*/
	0,						/*tp_compare*/
	RealTime_repr,			/*tp_repr*/
	&realtime_as_number,	/*tp_as_number*/
	0,						/*tp_as_sequence*/
	0,						/*tp_as_mapping*/
	0,						/*tp_hash*/
	0,//(ternaryfunc)RealTime_new,                      /*tp_call*/
    0,                      /*tp_str*/
    0,                      /*tp_getattro*/
    0,                      /*tp_setattro*/
    0,                      /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT,     /*tp_flags*/
    0,                      /*tp_doc*/
    0,                      /*tp_traverse*/
    0,                      /*tp_clear*/
    0,                      /*tp_richcompare*/
    0,                      /*tp_weaklistoffset*/
    0,                      /*tp_iter*/
    0,                      /*tp_iternext*/
    RealTime_methods,       /*tp_methods*/ //TypeObject Methods
    0,                      /*tp_members*/
    0,                      /*tp_getset*/
    0,                      /*tp_base*/
    0,                      /*tp_dict*/
    0,                      /*tp_descr_get*/
    0,                      /*tp_descr_set*/
    0,                      /*tp_dictoffset*/
    0,                      /*tp_init*/
    0,                      /*tp_alloc*/
    0,                      /*tp_new*/
    0,			            /*tp_free*/
    0,                      /*tp_is_gc*/
};


/*		 Remaining Functions Exposed by the MODULE 					*/


/* New RealTime object from Frame (with given samplerate) */
/*static*/ PyObject *
RealTime_frame2RealTime(PyObject *ignored, PyObject *args)
{

	long frame;
	unsigned int sampleRate;

	if (!PyArg_ParseTuple(args, "lI:realtime.fame2RealTime ", 
	&frame, 
	&sampleRate))
		return NULL;
	/*Doc:: 5.5 Parsing arguments and building values*/

	RealTimeObject *self;
	self = PyObject_New(RealTimeObject, &RealTime_Type); 
	if (self == NULL)
		return NULL;

	self->rt = new RealTime::RealTime(
	RealTime::frame2RealTime(frame,sampleRate));

	return (PyObject *) self;
}

/* New RealTime object from sec and nsec */
/*static*/ PyObject *
RealTime_new(PyObject *ignored, PyObject *args)
{

	unsigned int sec = 0;
	unsigned int nsec = 0;
	double unary = 0;
	const char *fmt = NULL;

	/*Doc:: 5.5 Parsing arguments and building values*/
	if (
		
	!PyArg_ParseTuple(args, "|sd:realtime.new ", 
	(const char *) &fmt, 
	(double *) &unary) 	&&

	!PyArg_ParseTuple(args, "|II:realtime.new ", 
	(unsigned int*) &sec, 
	(unsigned int*) &nsec) 
		
	) { 
		PyErr_SetString(PyExc_TypeError, 
		"RealTime initialised with wrong arguments.");
		return NULL; }

	PyErr_Clear();

	RealTimeObject *self = 
	PyObject_New(RealTimeObject, &RealTime_Type); 
	if (self == NULL) return NULL;

	self->rt = NULL;

	if (sec == 0 && nsec == 0 && fmt == 0) 
		self->rt = new RealTime::RealTime();
	else if (fmt == 0)
		self->rt = new RealTime::RealTime(sec,nsec);
	else { 

		if (!string(fmt).compare("float") ||
			!string(fmt).compare("seconds"))  
			self->rt = new RealTime::RealTime( 
			RealTime::fromSeconds((double) unary)); 

		if (!string(fmt).compare("milliseconds")) {
			self->rt = new RealTime::RealTime( 
			RealTime::fromSeconds((double) unary / 1000.0)); }
	}

	if (!self->rt) { 
		PyErr_SetString(PyExc_TypeError, 
		"RealTime initialised with wrong arguments.");
		return NULL; 
	}

	return (PyObject *) self;
}


/* pyRealTime Module's methods table */
static PyMethodDef Module_methods[] = {

	{"frame2RealTime",	(PyCFunction)RealTime_frame2RealTime,	METH_VARARGS,
		PyDoc_STR("frame2RealTime((int64)frame, (uint32)sampleRate ) -> returns new RealTime object from frame.")},

	{"realtime",	RealTime_new,		METH_VARARGS,
		PyDoc_STR("realtime() -> returns new RealTime object")},
	
	{NULL,		NULL}		/* sentinel */
};


/*				 PyRealTime C API functions 					*/



/*RealTime from PyRealTime*/
RealTime*
PyRealTime_AsPointer (PyObject *self) { 

	RealTimeObject *s = (RealTimeObject*) self; 

	if (!PyRealTime_Check(s)) {
		PyErr_SetString(PyExc_TypeError, "RealTime Object Expected.");
		cerr << "in call PyRealTime_AsPointer(): RealTime Object Expected. " << endl;
		return NULL; }
	return s->rt; };

/*PyRealTime from RealTime*/
PyObject* 
PyRealTime_FromRealTime(Vamp::RealTime *rt) {

	RealTimeObject *self =
	PyObject_New(RealTimeObject, &RealTime_Type); 
	if (self == NULL) return NULL;

	self->rt = new RealTime::RealTime(*rt);
	return (PyObject*) self;
}


/* Module initialization (includes extern "C" {...}) */
PyMODINIT_FUNC
initpyRealTime(void)
{
	PyObject *m;

	/* Finalize the type object including setting type of the new type
	 * object; doing it here is required for portability to Windows 
	 * without requiring C++. */
	if (PyType_Ready(&RealTime_Type) < 0)
		return;

	/* Create the module and add the functions */
	m = Py_InitModule3("pyRealTime", Module_methods, module_doc);
	if (m == NULL)
		return;

//	PyModule_AddObject(m, "realtime", (PyObject *)&RealTime_Type);

}