changeset 31:4f1894c7591b vampy2

Created Vampy2 branch
author fazekasgy
date Sun, 20 Sep 2009 17:31:20 +0000
parents 5139bf30f208
children a8231788216c
files Makefile PyExtensionModule.cpp PyExtensionModule.h PyFeature.cpp PyFeature.h PyFeatureSet.cpp PyFeatureSet.h PyOutputDescriptor.cpp PyOutputDescriptor.h PyParameterDescriptor.cpp PyParameterDescriptor.h PyPlugin.cpp PyPlugin.h PyRealTime.cpp PyRealTime.h PyTypeInterface.cpp PyTypeInterface.h pyvamp-main.cpp vampy-main.cpp
diffstat 19 files changed, 3411 insertions(+), 1217 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Tue Aug 25 08:49:22 2009 +0000
+++ b/Makefile	Sun Sep 20 17:31:20 2009 +0000
@@ -1,9 +1,18 @@
 
-CXXFLAGS	:= -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5 
-#-fvisibility=hidden
+CXXFLAGS	:= -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5 #-I../host/pyRealTime.h #-fvisibility=hidden
+LDFLAGS		:= -L../vamp-plugin-sdk/vamp-sdk -lvamp-sdk -dynamiclib -lpython2.5 -lpthread
 
-vampy.dylib:	PyPlugin.o PyPlugScanner.o pyvamp-main.o Mutex.o
-	g++ -shared $^ -o $@ -L../vamp-plugin-sdk/vamp-sdk -lvamp-sdk -dynamiclib -lpython2.5 -lpthread
+all: vampy.dylib
+
+PyExtensionModule.a: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o 
+	libtool -static $^ -o $@ 
+
+# The standard python extension is .so (even on the Mac)
+PyExtensionModule.so: PyExtensionModule.o PyRealTime.o PyFeature.o PyParameterDescriptor.o PyOutputDescriptor.o PyFeatureSet.o 
+	g++ -shared $^ -o $@ $(LDFLAGS) 
+
+vampy.dylib:	PyPlugin.o PyPlugScanner.o vampy-main.o Mutex.o PyTypeInterface.o PyExtensionModule.a
+	g++ -shared $^ -o $@ $(LDFLAGS) 
 
 # Install plugin
 #
@@ -24,5 +33,6 @@
 
 clean:	
 	rm *.o
+	rm *.a
 	rm *$(PLUGIN_EXT)
 	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyExtensionModule.cpp	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,292 @@
+#include <Python.h>
+#include "PyExtensionModule.h"
+#include "PyRealTime.h"
+#include "PyFeature.h"
+#include "PyFeatureSet.h"
+#include "PyParameterDescriptor.h"
+#include "PyOutputDescriptor.h"
+#include "vamp-sdk/Plugin.h"
+
+using namespace std;
+using namespace Vamp;
+using Vamp::Plugin;
+using Vamp::RealTime;
+
+/* Simple Example Function */
+
+static int five=5;
+
+PyObject*
+get_five(PyObject *self, PyObject *args)
+{
+    if(!PyArg_ParseTuple(args, ":five")) return NULL;
+    return Py_BuildValue("i", five);
+}
+
+
+/*			 Functions Exposed by Vampy 					*/
+
+/*			 Creating PyRealTime Objects 					*/
+
+
+/* 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.frame2RealTime ", 
+	&frame,&sampleRate))
+		return NULL;
+
+	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;
+}
+
+/*			 Creating PyParameterDescriptor Objects 			  	*/
+
+/* New ParameterDescriptor object 
+static PyObject *
+ParameterDescriptor_new(PyObject *ignored, PyObject *args)
+{
+
+    if (!PyArg_ParseTuple(args, ":ParameterDescriptor")) { 
+		PyErr_SetString(PyExc_TypeError, 
+		"Error: ParameterDescriptor initialised with arguments.");
+		return NULL; 
+	  }
+
+	ParameterDescriptorObject *self = 
+	PyObject_New(ParameterDescriptorObject, &ParameterDescriptor_Type); 
+	if (self == NULL) return NULL;
+    self->dict = PyDict_New();
+	if (self->dict == NULL) return NULL;
+	return (PyObject *) self;
+}
+*/
+
+/*			 Creating PyOutputDescriptor Objects 					*/
+
+/* New OutputDescriptor object 
+static PyObject *
+OutputDescriptor_new(PyObject *ignored, PyObject *args)
+{
+
+	if (!PyArg_ParseTuple(args, ":OutputDescriptor")) { 
+		PyErr_SetString(PyExc_TypeError, 
+		"Error: OutputDescriptor initialised with arguments.");
+		return NULL; 
+	  }
+
+	OutputDescriptorObject *self = 
+	PyObject_New(OutputDescriptorObject, &OutputDescriptor_Type); 
+	if (self == NULL) return NULL;
+    self->dict = PyDict_New();
+	if (self->dict == NULL) return NULL;
+	return (PyObject *) self;
+}
+*/
+
+/*			 Creating PyOutputList Objects 					*/
+
+/* New OutputList object */
+static PyObject *
+OutputList_new(PyObject *ignored, PyObject *args)
+{
+	if (!PyArg_ParseTuple(args, ":OutputList")) { 
+		PyErr_SetString(PyExc_TypeError, 
+		"Error: OutputList initialised with arguments.");
+		return NULL; 
+	  }
+
+	return (PyObject *) PyList_New(0);
+}
+
+
+/*			 Creating PyParameterList Objects 					*/
+
+/* New ParameterList object */
+static PyObject *
+ParameterList_new(PyObject *ignored, PyObject *args)
+{
+    if (!PyArg_ParseTuple(args, ":ParameterList")) { 
+		PyErr_SetString(PyExc_TypeError, 
+		"Error: ParameterList initialised with arguments.");
+		return NULL; 
+	  }
+	return (PyObject *) PyList_New(0);
+}
+
+
+/*			 Creating PyFeatureList Objects 					*/
+
+/* New FeatureList object 
+static PyObject *
+FeatureList_new(PyObject *ignored, PyObject *args)
+{
+	if (!PyArg_ParseTuple(args, ":FeatureList")) { 
+		PyErr_SetString(PyExc_TypeError, 
+		"Error: FeatureList initialised with arguments.");
+		return NULL; 
+	  }
+	return (PyObject *) PyList_New(0);
+}
+*/
+
+/*			 Creating PyFeatureSet Objects 					*/
+
+/* New FeatureSet object 
+static PyObject *
+FeatureSet_new(PyObject *ignored, PyObject *args)
+{
+	if (!PyArg_ParseTuple(args, ":FeatureSet")) { 
+		PyErr_SetString(PyExc_TypeError, 
+		"Error: FeatureSet initialised with arguments.");
+		return NULL; 
+	  }
+	return (PyObject *) PyDict_New();
+}
+*/
+
+
+/*		 	Declare the methods exposed by the vampy module 		*/
+
+
+PyMethodDef VampyMethods[] = {
+/*NOTE: This is conventionally static, but limiting the scope
+	here will cause seg fault if the declared functions are 
+	called back from a Python function wrapped in a C++ class.*/
+    {"five", get_five, METH_VARARGS, "Return a number."},
+
+	{"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")},*/
+
+	/*{"Feature",	Feature_new,		METH_VARARGS,
+		PyDoc_STR("Feature() -> returns new Feature object")},*/
+
+	/*{"ParameterDescriptor",	ParameterDescriptor_new,		METH_VARARGS,
+		PyDoc_STR("ParameterDescriptor() -> returns new ParameterDescriptor object")},
+
+	{"OutputDescriptor",	OutputDescriptor_new,		METH_VARARGS,
+		PyDoc_STR("OutputDescriptor() -> returns new OutputDescriptor object")},
+
+	{"FeatureList",	FeatureList_new,		METH_VARARGS,
+		PyDoc_STR("FeatureList() -> returns new FeatureList object")},*/
+
+	{"OutputList",	OutputList_new,		METH_VARARGS,
+		PyDoc_STR("OutputList() -> returns new OutputList object")},
+
+	{"ParameterList",	ParameterList_new,		METH_VARARGS,
+		PyDoc_STR("ParameterList() -> returns new ParameterList object")},
+
+    {NULL, NULL, 0, NULL} 
+};
+
+/* Module Documentation */
+// PyDoc_STRVAR(vampy_doc,"This module exposes Vamp plugin data type wrappers.");
+
+PyMODINIT_FUNC
+initvampy(void)
+{
+	PyObject* module;
+
+	// if (PyType_Ready(&Feature_Type) < 0) return;
+	/// Why do we get a segfault if this is initialised here?
+	/*PyType_Ready adds these object to the GC.
+	This is OK for an extension module, but it is a mistake here, 
+	because the reference count will be decremented in the Vamp 
+	wrapper plugin outside the interpreter.
+	When the GC tries to visit a deallocated object, it will throw up.*/
+	
+	RealTime_Type.ob_type = &PyType_Type;
+	Feature_Type.ob_type = &PyType_Type;
+	OutputDescriptor_Type.ob_type = &PyType_Type;
+	ParameterDescriptor_Type.ob_type = &PyType_Type;
+	initFeatureSetType(); /// this is derived from the builtin dict
+
+	PyImport_AddModule("vampy");
+	module = Py_InitModule("vampy", VampyMethods);
+	if (!module) return;
+	
+	Py_INCREF(&RealTime_Type);
+    PyModule_AddObject(module,"RealTime",(PyObject*)&RealTime_Type);
+	// Py_INCREF(&RealTime_Type);
+
+	Py_INCREF((PyObject*)&Feature_Type);
+	PyModule_AddObject(module,"Feature",(PyObject*)&Feature_Type);
+	// Py_INCREF((PyObject*)&Feature_Type);
+
+	Py_INCREF((PyObject*)&FeatureSet_Type);
+	PyModule_AddObject(module,"FeatureSet",(PyObject*)&FeatureSet_Type);
+	// Py_INCREF((PyObject*)&FeatureSet_Type);
+
+	Py_INCREF((PyObject*)&OutputDescriptor_Type);
+	PyModule_AddObject(module,"OutputDescriptor",(PyObject*)&OutputDescriptor_Type);
+
+	Py_INCREF((PyObject*)&ParameterDescriptor_Type);
+	PyModule_AddObject(module,"ParameterDescriptor",(PyObject*)&ParameterDescriptor_Type);
+	
+	cerr << "Vampy: extension module initialised." << endl;
+}
+
+/*
+NOTE: Why do we need to clean up the module?
+
+The module exposed by Vampy to the embedded interpreter
+contains callback functions. These functions are accessed
+via function pointers stored in the extension module dictionary.
+
+Unfortunately, when the Vampy shared library is unloaded and
+reloaded again during a host session, these addresses might
+change. Therefore, we reinitialise the module dict before 
+each use. However, this will cause garbage collection errors
+or segmentation faults, when elements of the dict of the 
+previous session are attempted to free. Therefore, we hold
+a global reference count to all initialised Vampy plugins,
+and when this reaches zero, we clean up the module dict.
+
+This is an attempt to catch the moment when the shared lib
+is finally unloaded and the references are still point to valid
+memory addresses.
+
+Why doesn't the GC clean this up correctly?
+
+In a normal Python session the GC would deallocate the module
+dict at the end. In embedded python, although the GC appears
+to be called when the shared lib is unloaded, the interpreter
+is reused. Since there is no C/API call to unload modules,
+and at the time of unloading vampy the wrapped function pointers
+are still valid, the GC doesn't collect them, nor are they freed
+by the interpreter. When vampy is reloaded however, the module
+dict will contain invalid addresses. The above procedure solves
+this problem.
+
+
+*/
+
+void cleanModule(void)
+{
+	PyObject *m = PyImport_AddModule("vampy");
+	if (!m) cerr << "Destr: PyImport_AddModule returned NULL!" << endl;
+	else {
+		// cerr << "Destr: Add module found existing." << endl;
+		PyObject *dict = PyModule_GetDict(m);
+		Py_ssize_t ln = PyDict_Size(dict);
+		cerr << "Destr: Size of module dict = " << (int) ln << endl;
+		/// Clean the module dictionary.
+		PyDict_Clear(dict);
+	    ln = PyDict_Size(dict);
+		cerr << "Destr: Cleaned size of module dict = " << (int) ln << endl;
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyExtensionModule.h	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,19 @@
+#ifndef _PYEXTENSIONMODULE_H_
+#define _PYEXTENSIONMODULE_H_
+
+#include <Python.h>
+#include "PyRealTime.h"
+#include "PyFeature.h"
+#include "PyFeatureSet.h"
+#include "PyParameterDescriptor.h"
+#include "PyOutputDescriptor.h"
+
+#define PyDescriptor_Check(v) ((v)->ob_type == &Feature_Type) || ((v)->ob_type == &OutputDescriptor_Type) || ((v)->ob_type == &ParameterDescriptor_Type)
+
+#ifndef PyMODINIT_FUNC
+#define PyMODINIT_FUNC void
+#endif
+PyMODINIT_FUNC initvampy();
+void cleanModule();
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyFeature.cpp	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,189 @@
+#include <Python.h>
+#include "PyExtensionModule.h"
+#include "PyFeature.h"
+#include "vamp-sdk/Plugin.h"
+#include <string>
+/*#include "PyTypeInterface.h"*/
+
+using namespace std;
+using namespace Vamp;
+using Vamp::Plugin;
+
+/*					 Feature Object's Methods 					*/ 
+//Feature objects have no callable methods
+
+/*		   PyFeature methods implementing protocols 		   	   */ 
+// these functions are called by the interpreter automatically
+
+
+/* Function to set basic attributes 
+static int
+Feature_setattr(FeatureObject *self, char *name, PyObject *value)
+{
+	std::string key = std::string(name);
+	if (self->ti.SetValue(*(self->feature),key,value)) return 0;
+	else return -1;
+}*/
+
+/* Function to get basic attributes 
+static PyObject *
+Feature_getattr(FeatureObject *self, char *name)
+{
+	std::string key = std::string(name);
+	PyObject* pyValue;
+	if (self->ti.GetValue(*(self->feature),key,pyValue)) 
+		return pyValue;
+	else return NULL;
+}*/
+
+/* Set attributes */
+static int
+Feature_setattr(FeatureObject *self, char *name, PyObject *v)
+{
+	if (v == NULL) {
+		int rv = PyDict_DelItemString(self->dict, name);
+		if (rv < 0)
+			PyErr_SetString(PyExc_AttributeError,"non-existing Feature attribute");
+		return rv;
+	}
+	else
+		return PyDict_SetItemString(self->dict, name, v);
+}
+
+
+/* Get attributes */
+static PyObject *
+Feature_getattr(FeatureObject *self, char *name)
+{
+	if (self->dict != NULL) {
+		PyObject *v = PyDict_GetItemString(self->dict, name);
+		if (v != NULL) 
+		{
+			Py_INCREF(v);
+			return v;
+		}
+	}
+	return NULL;
+}
+
+/* New Feature object */
+static PyObject *
+Feature_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+	/// TODO support kwargs e.g. Feature(values = val, timestamp = ts)
+	cerr << "FeatureObject new method called" << endl;
+	if (!PyArg_ParseTuple(args, ":Feature")) { 
+		PyErr_SetString(PyExc_TypeError, 
+		"Error: Feature initialised with arguments.");
+		return NULL; 
+	}
+	FeatureObject *self = (FeatureObject*)type->tp_alloc(type, 0);
+	// FeatureObject *self = PyObject_New(FeatureObject, &Feature_Type); 
+	if (self == NULL) return NULL;
+    self->dict = PyDict_New();
+	if (self->dict == NULL) return NULL;
+	return (PyObject *) self;
+}
+
+/* DESTRUCTOR: delete type object */
+static void
+FeatureObject_dealloc(FeatureObject *self)
+{
+	Py_XDECREF(self->dict);
+	// delete self->feature; 	//delete the C object
+	// PyObject_Del(self); //delete the Python object
+	self->ob_type->tp_free((PyObject*)self);
+	cerr << "Feature object deallocated." << endl;
+}
+
+
+static int
+Feature_init(FeatureObject *self, PyObject *args, PyObject *kwds)
+{
+	cerr << "FeatureObject Init called" << endl;
+	return 0;
+}
+
+PyObject*
+Feature_test(PyObject *self, PyObject *args, PyObject *kwds)
+{
+	cerr << "FeatureObject TEST called" << endl;
+	return self;
+}
+
+
+/* String representation */
+static PyObject *
+Feature_repr(PyObject *self)
+{
+	// if (PyFeature_CheckExact(self)) {}
+	// PyObject* intdict = self
+	return Py_BuildValue("s",
+		"not yet implemented");
+	// ((RealTimeObject*)self)->rt->toString().c_str());
+}
+
+#define Feature_alloc PyType_GenericAlloc
+#define Feature_free PyObject_Del
+
+
+/*						FEATURE TYPE OBJECT						*/
+
+PyTypeObject Feature_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,						/*ob_size*/
+	"vampy.Feature",		/*tp_name*/
+	sizeof(FeatureObject),	/*tp_basicsize*/
+	0,						/*tp_itemsize*/
+	(destructor)FeatureObject_dealloc, /*tp_dealloc*/
+	0,						/*tp_print*/
+	(getattrfunc)Feature_getattr, /*tp_getattr*/
+	(setattrfunc)Feature_setattr, /*tp_setattr*/
+	0,						/*tp_compare*/
+	Feature_repr,			/*tp_repr*/
+	0,						/*tp_as_number*/
+	0,						/*tp_as_sequence*/
+	0,						/*tp_as_mapping*/
+	0,						/*tp_hash*/
+	Feature_test,           /*tp_call*/ // call on an instance
+    0,                      /*tp_str*/
+    0,                      /*tp_getattro*/
+    0,                      /*tp_setattro*/
+    0,                      /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,     /*tp_flags*/
+    0,                      /*tp_doc*/
+    0,                      /*tp_traverse*/
+    0,                      /*tp_clear*/
+    0,                      /*tp_richcompare*/
+    0,                      /*tp_weaklistoffset*/
+    0,                      /*tp_iter*/
+    0,                      /*tp_iternext*/
+    0,				        /*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,//(initproc)Feature_init, /*tp_init*/
+    Feature_alloc,          /*tp_alloc*/
+    Feature_new,            /*tp_new*/
+    Feature_free,			/*tp_free*/
+    0,                      /*tp_is_gc*/
+};
+
+/*		  		 	  PyRealTime C++ API  	  		  				*/
+
+/*Feature* from PyFeature
+const Vamp::Plugin::Feature*
+PyFeature_AsFeature (PyObject *self) { 
+
+	FeatureObject *s = (FeatureObject*) self; 
+
+	if (!PyFeature_Check(s)) {
+		PyErr_SetString(PyExc_TypeError, "Feature Object Expected.");
+		cerr << "in call PyFeature_AsPointer(): Feature Object Expected. " << endl;
+		return NULL; }
+	return s->feature; 
+};*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyFeature.h	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,36 @@
+#ifndef _PYFEATURE_H_
+#define _PYFEATURE_H_
+
+#include "vamp-sdk/Plugin.h"
+// #include "PyTypeInterface.h"
+
+typedef struct {
+		PyObject_HEAD
+		PyObject *dict; /* Attributes dictionary */
+		// Vamp::Plugin::Feature *feature;
+		/// pointer to type interface required
+		// PyTypeInterface ti;
+} FeatureObject; 
+
+PyAPI_DATA(PyTypeObject) Feature_Type;
+
+#define PyFeature_CheckExact(v)	((v)->ob_type == &Feature_Type)
+#define PyFeature_Check(v) PyObject_TypeCheck(v, &Feature_Type)
+///fast macro version as per API convention
+#define PyFeature_AS_DICT(v) ((const FeatureObject* const) (v))->dict
+
+
+/*		  		 	  PyFeature C++ API  	  		  				*/
+
+/// Not required: we will never have to pass a feature back from the wrapper
+// PyAPI_FUNC(PyObject *) 
+// PyFeature_FromFeature(Vamp::RealTime&);
+
+// PyAPI_FUNC(const Vamp::Plugin::Feature*) 
+// PyFeature_AsFeature (PyObject *self);
+
+///fast macro version as per API convention
+// #define PyFeature_AS_FEATURE(v) ((const FeatureObject* const) (v))->feature
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyFeatureSet.cpp	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,99 @@
+#include <Python.h>
+#include "PyFeatureSet.h"
+#include "vamp-sdk/Plugin.h"
+
+using namespace std;
+
+static int
+FeatureSet_init(FeatureSetObject *self, PyObject *args, PyObject *kwds)
+{
+    if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
+        return -1;
+    self->state = 0;
+	cerr << "FeatureSet initialised" << endl;
+    return 0;
+}
+
+static int
+FeatureSetObject_ass_sub(FeatureSetObject *mp, PyObject *v, PyObject *w)
+{
+	// cerr << "called FeatureSetObject_ass_sub" << endl;
+	if (!PyInt_CheckExact(v)) {
+		/// TODO: Set ValueError here.
+		cerr << "Output index must be positive integer" << endl;
+		return 0;
+	}
+	if (w == NULL)
+		return PyDict_DelItem((PyObject *)mp, v);
+	else
+		return PyDict_SetItem((PyObject *)mp, v, w);
+}
+
+#define FeatureSet_alloc PyType_GenericAlloc
+#define FeatureSet_free PyObject_Del
+//#define FeatureSet_as_mapping PyDict_Type.tp_as_mapping
+
+static PyMappingMethods FeatureSet_as_mapping = *(PyDict_Type.tp_as_mapping);
+
+PyTypeObject FeatureSet_Type = PyDict_Type;
+// PyTypeObject FeatureSet_Type = {
+// 	PyObject_HEAD_INIT(NULL)
+// 	0,						/*ob_size*/
+// 	"vampy.FeatureSet",		/*tp_name*/
+// 	sizeof(FeatureSetObject),	/*tp_basicsize*/
+// 	0,						/*tp_itemsize*/
+// 	(destructor)FeatureSetObject_dealloc, /*tp_dealloc*/
+// 	0,//PyDict_Type.tp_print,	/*tp_print*/
+// 	0,//PyDict_Type.tp_getattr, /*tp_getattr*/
+// 	0,//PyDict_Type.tp_setattr, /*tp_setattr*/
+// 	0,						/*tp_compare*/
+// 	0,//PyDict_Type.tp_repr,	/*tp_repr*/
+// 	0,						/*tp_as_number*/
+// 	0,						/*tp_as_sequence*/
+// 	FeatureSet_as_mapping,	/*tp_as_mapping*/
+// 	0,						/*tp_hash*/
+// 	0,//Feature_test,           /*tp_call*/ // call on an instance
+//     0,                      /*tp_str*/
+//     PyDict_Type.tp_getattro,/*tp_getattro*/
+//     0,//PyDict_Type.tp_setattro,/*tp_setattro*/
+//     0,                      /*tp_as_buffer*/
+//     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,     /*tp_flags*/
+//     0,                      /*tp_doc*/
+//     PyDict_Type.tp_traverse,                      /*tp_traverse*/
+//     PyDict_Type.tp_clear,                      /*tp_clear*/
+//     0,                      /*tp_richcompare*/
+//     0,                      /*tp_weaklistoffset*/
+//     0,                      /*tp_iter*/
+//     0,                      /*tp_iternext*/
+//     PyDict_Type.tp_methods,	/*tp_methods*/ //TypeObject Methods
+//     PyDict_Type.tp_members, /*tp_members*/
+//     PyDict_Type.tp_getset,  /*tp_getset*/
+//     0,                      /*tp_base*/
+//     PyDict_Type.tp_dict,    /*tp_dict*/
+//     0,                      /*tp_descr_get*/
+//     0,                      /*tp_descr_set*/
+//     PyDict_Type.tp_dictoffset, /*tp_dictoffset*/
+//     (initproc)FeatureSet_init, /*tp_init*/
+//     FeatureSet_alloc,          /*tp_alloc*/
+//     FeatureSet_new,            /*tp_new*/
+//     FeatureSet_free,			/*tp_free*/
+//     0,                      /*tp_is_gc*/
+// };
+
+
+void
+initFeatureSetType(void)
+{
+	/*This type is derived from PyDict. We just override some slots here.*/
+	/*The typical use case is index based assignment as opposed to object memeber access.*/
+	FeatureSet_Type.ob_type = &PyType_Type;
+	FeatureSet_Type.tp_base = &PyDict_Type;
+	FeatureSet_Type.tp_bases = PyTuple_Pack(1, FeatureSet_Type.tp_base);
+	FeatureSet_Type.tp_name = "vampy.FeatureSet";
+	// FeatureSet_Type.tp_new = FeatureSet_new;
+	FeatureSet_Type.tp_init = (initproc)FeatureSet_init;
+	FeatureSet_Type.tp_basicsize = sizeof(FeatureSetObject);
+	FeatureSet_as_mapping.mp_ass_subscript = (objobjargproc)FeatureSetObject_ass_sub;
+	FeatureSet_Type.tp_as_mapping = &FeatureSet_as_mapping;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyFeatureSet.h	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,22 @@
+#ifndef _PYFEATURESET_H_
+#define _PYFEATURESET_H_
+
+#include <Python.h>
+
+typedef struct {
+    PyDictObject dict;
+    int state;
+} FeatureSetObject;
+
+PyAPI_DATA(PyTypeObject) FeatureSet_Type;
+
+#define PyFeatureSet_CheckExact(v)	((v)->ob_type == &FeatureSet_Type)
+#define PyFeatureSet_Check(v) PyObject_TypeCheck(v, &FeatureSet_Type)
+// #define PyFeatureSet_CheckExact(v)	((v)->ob_type == &PyDict_Type)
+// #define PyFeatureSet_Check(v) PyObject_TypeCheck(v, &PyDict_Type)
+
+// #define PyFeature_AS_DICT(v) ((const FeatureObject* const) (v))->dict
+
+void initFeatureSetType(void);
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyOutputDescriptor.cpp	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,140 @@
+#include <Python.h>
+#include "PyOutputDescriptor.h"
+#include "vamp-sdk/Plugin.h"
+#include <string>
+#include "PyTypeInterface.h"
+
+using namespace std;
+using namespace Vamp;
+using Vamp::Plugin;
+
+/*			 OutputDescriptor Object's Methods 					*/ 
+//Feature objects have no callable methods
+
+/*		   PyOutputDescriptor methods implementing protocols   	*/ 
+// these functions are called by the interpreter automatically
+
+/* New OutputDescriptor object */ 
+static PyObject *
+OutputDescriptor_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+
+    if (!PyArg_ParseTuple(args, ":OutputDescriptor")) { 
+		PyErr_SetString(PyExc_TypeError, 
+		"Error: OutputDescriptor initialised with arguments.");
+		return NULL; 
+	  }
+
+	OutputDescriptorObject *self = 
+	(OutputDescriptorObject*)type->tp_alloc(type, 0);
+	
+	if (self == NULL) return NULL;
+    self->dict = PyDict_New();
+	if (self->dict == NULL) return NULL;
+	return (PyObject *) self;
+}
+
+
+/* DESTRUCTOR: delete type object */
+static void
+OutputDescriptorObject_dealloc(OutputDescriptorObject *self)
+{
+	Py_XDECREF(self->dict);
+	PyObject_Del(self);
+}
+
+
+/* Set attributes */
+static int
+OutputDescriptor_setattr(OutputDescriptorObject *self, char *name, PyObject *v)
+{
+	if (v == NULL) {
+		int rv = PyDict_DelItemString(self->dict, name);
+		if (rv < 0)
+			PyErr_SetString(PyExc_AttributeError,"non-existing OutputDescriptor attribute");
+		return rv;
+	}
+	else
+		return PyDict_SetItemString(self->dict, name, v);
+}
+
+
+/* Get attributes */
+static PyObject *
+OutputDescriptor_getattr(OutputDescriptorObject *self, char *name)
+{
+	if (self->dict != NULL) {
+		PyObject *v = PyDict_GetItemString(self->dict, name);
+		if (v != NULL) 
+		{
+			Py_INCREF(v);
+			return v;
+		}
+	}
+	return NULL;
+}
+
+
+/* String representation */
+static PyObject *
+OutputDescriptor_repr(PyObject *self)
+{
+	// if (PyFeature_CheckExact(self)) {}
+	// PyObject* intdict = self
+	return Py_BuildValue("s",
+		"not yet implemented");
+	// ((RealTimeObject*)self)->rt->toString().c_str());
+}
+
+#define OutputDescriptor_alloc PyType_GenericAlloc
+#define OutputDescriptor_free PyObject_Del
+
+
+/*						REAL-TIME TYPE OBJECT						*/
+
+PyTypeObject OutputDescriptor_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,						/*ob_size*/
+	"vampy.OutputDescriptor",/*tp_name*/
+	sizeof(OutputDescriptorObject),	/*tp_basicsize*/
+	0,						/*tp_itemsize*/
+	(destructor)OutputDescriptorObject_dealloc, /*tp_dealloc*/
+	0,						/*tp_print*/
+	(getattrfunc)OutputDescriptor_getattr, /*tp_getattr*/
+	(setattrfunc)OutputDescriptor_setattr, /*tp_setattr*/
+	0,						/*tp_compare*/
+	OutputDescriptor_repr,	/*tp_repr*/
+	0,						/*tp_as_number*/
+	0,						/*tp_as_sequence*/
+	0,						/*tp_as_mapping*/
+	0,						/*tp_hash*/
+	0,                      /*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*/
+    0,				        /*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*/
+    OutputDescriptor_alloc, /*tp_alloc*/
+    OutputDescriptor_new,   /*tp_new*/
+    OutputDescriptor_free,	/*tp_free*/
+    0,                      /*tp_is_gc*/
+};
+
+/*		  		 	  PyOutputDescriptor C++ API    				*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyOutputDescriptor.h	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,22 @@
+#ifndef _PYOUTPUTDESCRIPTOR_H_
+#define _PYOUTPUTDESCRIPTOR_H_
+
+#include "vamp-sdk/Plugin.h"
+
+typedef struct {
+		PyObject_HEAD
+		PyObject *dict;
+} OutputDescriptorObject; 
+
+PyAPI_DATA(PyTypeObject) OutputDescriptor_Type;
+
+#define PyOutputDescriptor_CheckExact(v)	((v)->ob_type == &OutputDescriptor_Type)
+#define PyOutputDescriptor_Check(v) PyObject_TypeCheck(v, &OutputDescriptor_Type)
+
+/*			  		 PyOutputDescriptor C++ API  	  	  	  		*/
+
+
+///fast macro version as per API convention
+#define PyOutputDescriptor_AS_DICT(v) ((const OutputDescriptorObject* const) (v))->dict
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyParameterDescriptor.cpp	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,137 @@
+#include <Python.h>
+#include "PyParameterDescriptor.h"
+#include "vamp-sdk/Plugin.h"
+#include <string>
+#include "PyTypeInterface.h"
+
+using namespace std;
+using namespace Vamp;
+using Vamp::Plugin;
+
+/*			 ParameterDescriptor Object's Methods 					*/ 
+//Feature objects have no callable methods
+
+/*		   PyParameterDescriptor methods implementing protocols   	*/ 
+// these functions are called by the interpreter automatically
+
+/* New ParameterDescriptor object */ 
+static PyObject *
+ParameterDescriptor_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+
+    if (!PyArg_ParseTuple(args, ":ParameterDescriptor")) { 
+		PyErr_SetString(PyExc_TypeError, 
+		"Error: ParameterDescriptor initialised with arguments.");
+		return NULL; 
+	  }
+
+	ParameterDescriptorObject *self = 
+	(ParameterDescriptorObject*)type->tp_alloc(type, 0);
+	
+	if (self == NULL) return NULL;
+    self->dict = PyDict_New();
+	if (self->dict == NULL) return NULL;
+	return (PyObject *) self;
+}
+
+
+/* DESTRUCTOR: delete type object */
+static void
+ParameterDescriptorObject_dealloc(ParameterDescriptorObject *self)
+{
+	Py_XDECREF(self->dict);
+	PyObject_Del(self);
+}
+
+
+/* Set attributes */
+static int
+ParameterDescriptor_setattr(ParameterDescriptorObject *self, char *name, PyObject *v)
+{
+	if (v == NULL) {
+		int rv = PyDict_DelItemString(self->dict, name);
+		if (rv < 0)
+			PyErr_SetString(PyExc_AttributeError,"non-existing ParameterDescriptor attribute");
+		return rv;
+	}
+	else
+		return PyDict_SetItemString(self->dict, name, v);
+}
+
+
+/* Get attributes */
+static PyObject *
+ParameterDescriptor_getattr(ParameterDescriptorObject *self, char *name)
+{
+	if (self->dict != NULL) {
+		PyObject *v = PyDict_GetItemString(self->dict, name);
+		if (v != NULL) 
+		{
+			Py_INCREF(v);
+			return v;
+		}
+	}
+	return NULL;
+}
+
+
+/* String representation */
+static PyObject *
+ParameterDescriptor_repr(PyObject *self)
+{
+	// if (PyFeature_CheckExact(self)) {}
+	// PyObject* intdict = self
+	return Py_BuildValue("s",
+		"not yet implemented");
+	// ((RealTimeObject*)self)->rt->toString().c_str());
+}
+
+#define ParameterDescriptor_alloc PyType_GenericAlloc
+#define ParameterDescriptor_free PyObject_Del
+
+PyTypeObject ParameterDescriptor_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,						/*ob_size*/
+	"vampy.ParameterDescriptor",/*tp_name*/
+	sizeof(ParameterDescriptorObject),	/*tp_basicsize*/
+	0,						/*tp_itemsize*/
+	(destructor)ParameterDescriptorObject_dealloc, /*tp_dealloc*/
+	0,						/*tp_print*/
+	(getattrfunc)ParameterDescriptor_getattr, /*tp_getattr*/
+	(setattrfunc)ParameterDescriptor_setattr, /*tp_setattr*/
+	0,						/*tp_compare*/
+	ParameterDescriptor_repr,			/*tp_repr*/
+	0,						/*tp_as_number*/
+	0,						/*tp_as_sequence*/
+	0,						/*tp_as_mapping*/
+	0,						/*tp_hash*/
+	0,                      /*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*/
+    0,				        /*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*/
+    ParameterDescriptor_alloc,/*tp_alloc*/
+    ParameterDescriptor_new,/*tp_new*/
+    ParameterDescriptor_free,/*tp_free*/
+    0,                      /*tp_is_gc*/
+};
+
+/*		  		 	  PyParameterDescriptor C++ API    				*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyParameterDescriptor.h	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,22 @@
+#ifndef _PYPARAMETERDESCRIPTOR_H_
+#define _PYPARAMETERDESCRIPTOR_H_
+
+#include "vamp-sdk/Plugin.h"
+
+typedef struct {
+		PyObject_HEAD
+		PyObject *dict;
+} ParameterDescriptorObject; 
+
+PyAPI_DATA(PyTypeObject) ParameterDescriptor_Type;
+
+#define PyParameterDescriptor_CheckExact(v)	((v)->ob_type == &ParameterDescriptor_Type)
+#define PyParameterDescriptor_Check(v) PyObject_TypeCheck(v, &ParameterDescriptor_Type)
+
+/*			  		 PyParameterDescriptor C++ API  	  		  	  */
+
+
+///fast macro version as per API convention
+#define PyParameterDescriptor_AS_DICT(v) ((const ParameterDescriptorObject* const) (v))->dict
+
+#endif
\ No newline at end of file
--- a/PyPlugin.cpp	Tue Aug 25 08:49:22 2009 +0000
+++ b/PyPlugin.cpp	Sun Sep 20 17:31:20 2009 +0000
@@ -51,11 +51,16 @@
 
 #include <Python.h>
 #include "PyPlugin.h"
+#include "PyTypeInterface.h"
+#include <stdlib.h>
+#include "PyExtensionModule.h"
+//#include "PyRealTime.h"
+
 
 #ifdef _WIN32
-#define pathsep ('\\')
+#define PATHSEP ('\\')
 #else 
-#define pathsep ('/')
+#define PATHSEP ('/')
 #endif
 
 //#define _DEBUG
@@ -66,30 +71,35 @@
 using std::endl;
 using std::map;
 
-// Maps to associate strings with enum values
-static std::map<std::string, o::eOutDescriptors> outKeys;
-static std::map<std::string, eSampleTypes> sampleKeys;
-static std::map<std::string, eFeatureFields> ffKeys;
-static std::map<std::string, p::eParmDescriptors> parmKeys;
+Mutex PyPlugin::m_pythonInterpreterMutex;
 
-Mutex PyPlugin::m_pythonInterpreterMutex;
-static bool isMapInitialised = false;
-
-PyPlugin::PyPlugin(std::string pluginKey, float inputSampleRate, PyObject *pyClass) :
+PyPlugin::PyPlugin(std::string pluginKey, float inputSampleRate, PyObject *pyClass, int &instcount) :
 	Plugin(inputSampleRate),
 	m_pyClass(pyClass),
+	m_instcount(instcount),
 	m_stepSize(0),
 	m_blockSize(0),
 	m_channels(0),
 	m_plugin(pluginKey),
 	m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)),
-	m_path((pluginKey.substr(0,pluginKey.rfind(pathsep)))),
+	m_path((pluginKey.substr(0,pluginKey.rfind(PATHSEP)))),
 	m_processType(0),
 	m_pyProcess(NULL),
-	m_inputDomain(TimeDomain)
+	m_inputDomain(TimeDomain),
+	m_quitOnErrorFlag(false),
+	m_debugFlag(false)
 {	
+	m_ti.setInputSampleRate(inputSampleRate);
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	cerr << "Creating instance " << m_instcount << " of " << pluginKey << endl;
+
+	if (m_instcount == 0) initvampy();
+	m_instcount++;
+	
+	// if (!PyImport_ImportModule("vampy"))
+	// 	cerr << "Could not import extension." << endl;
+
 	// Create an instance
-	MutexLocker locker(&m_pythonInterpreterMutex);
 	Py_INCREF(m_pyClass);
 	PyObject *pyInputSampleRate = PyFloat_FromDouble(inputSampleRate);
 	PyObject *args = PyTuple_Pack(1, pyInputSampleRate);
@@ -100,24 +110,43 @@
 		Py_DECREF(m_pyClass);
 		Py_CLEAR(args);
 		Py_CLEAR(pyInputSampleRate);
-		cerr << "PyPlugin::PyPlugin: Failed to create Python plugin instance for key \"" << pluginKey << "\" (is the 1-arg class constructor from sample rate correctly provided?)" << endl;
+		cerr << "PyPlugin::PyPlugin: Failed to create Python plugin instance for key \"" 
+		<< pluginKey << "\" (is the 1-arg class constructor from sample rate correctly provided?)" << endl;
 		throw std::string("Constructor failed");
 	}
 	Py_INCREF(m_pyInstance);
 	Py_DECREF(args);
 	Py_DECREF(pyInputSampleRate);
-
+	
+	//query the debug flag
+	m_debugFlag = getBooleanFlag("vampy_debug_messages",true);
+	if (m_debugFlag) cerr << "Debug messages ON for Vampy plugin: " << m_class << endl;
+	else cerr << "Debug messages OFF for Vampy plugin: " << m_class << endl;
+	
+	//query the quit on error flag
+	m_quitOnErrorFlag = getBooleanFlag("quit_on_type_error",false);
+	if (m_debugFlag && m_quitOnErrorFlag) cerr << "Quit on type error ON for: " << m_class << endl;
+   
+	//query the type conversion mode flag
+	bool st_flag = getBooleanFlag("use_strict_type_conversion",false);
+	if (m_debugFlag && st_flag) cerr << "Strict type conversion ON for: " << m_class << endl;
+	m_ti.setStrictTypingFlag(st_flag);
 }
 
 PyPlugin::~PyPlugin()
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	m_instcount--;
+	cerr << "Deleting plugin instance. Count: " << m_instcount << endl;
+	
 	if (m_pyInstance) Py_DECREF(m_pyInstance);
-	if (m_pyClass) Py_DECREF(m_pyClass);
+	//we increase the class refcount before creating an instance 
+	if (m_pyClass) Py_DECREF(m_pyClass); 
 	if (m_pyProcess) Py_CLEAR(m_pyProcess);
+	if (m_instcount == 0) cleanModule();
 
 #ifdef _DEBUG
-	cerr << "PyPlugin::PyPlugin:" << m_class 
-	     << " Instance deleted." << endl;
+	cerr << "PyPlugin::PyPlugin:" << m_class << " instance " << m_instcount << " deleted." << endl;
 #endif
 }
 
@@ -126,647 +155,159 @@
 PyPlugin::getIdentifier() const
 {	
 	MutexLocker locker(&m_pythonInterpreterMutex);
+	string rString="vampy-xxx";
+	if (!m_debugFlag) return genericMethodCall("getIdentifier",rString);
 
-	char method[]="getIdentifier"; 
-	cerr << "[call] " << method << endl;
-	string rString="vampy-x";
-
-	if ( PyObject_HasAttrString(m_pyInstance,method) ) {
-
-		//Call the method
-		PyObject *pyString = 
-		PyObject_CallMethod(m_pyInstance, method, NULL);
-
-		//Check return value
-		if (!PyString_Check(pyString)) {
-			Py_CLEAR(pyString);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected String return value." << endl;
-			return rString;
-		}
-
-		rString=PyString_AsString(pyString);
-		Py_CLEAR(pyString);
-		return rString;
-	}
-	cerr << "Warning: Plugin must return a unique identifier." << endl;
+	rString = genericMethodCall("getIdentifier",rString);
+	if (rString == "vampy-xxx")
+		cerr << "Warning: Plugin must return a unique identifier." << endl;
 	return rString;
 }
 
-
 string
 PyPlugin::getName() const
 {
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	char method[]="getName";
-	cerr << "[call] " << method << endl;
 	string rString="VamPy Plugin (Noname)";
-	
-	if ( PyObject_HasAttrString(m_pyInstance,method) ) {
-
-		//Call the method
-		PyObject *pyString = 
-		PyObject_CallMethod(m_pyInstance, method, NULL);
-
-		//Check return value
-		if (!PyString_Check(pyString)) {
-			Py_CLEAR(pyString);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected String return value." << endl;
-			return rString;
-		}
-
-		rString=PyString_AsString(pyString);
-		Py_CLEAR(pyString);
-	}
-    return rString;
+    return genericMethodCall("getName",rString);
 }
 
 string
 PyPlugin::getDescription() const
 {
 	MutexLocker locker(&m_pythonInterpreterMutex);
+	string rString="Not given. (Hint: Implement getDescription method.)";
+	return genericMethodCall("getDescription",rString);
+}
 
-	char method[]="getDescription";
-	cerr << "[call] " << method << endl;
-	string rString="Not given. (Hint: Implement getDescription method.)";
-	
-	if ( PyObject_HasAttrString(m_pyInstance,method) ) {
-
-		//Call the method
-		PyObject *pyString = 
-		PyObject_CallMethod(m_pyInstance, method, NULL);
-
-		//Check return value
-		if (!PyString_Check(pyString)) {
-			Py_CLEAR(pyString);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected String return value." << endl;
-			return rString;
-		}
-
-		rString=PyString_AsString(pyString);
-		Py_CLEAR(pyString);
-	}
-	return rString;
-}
 
 string
 PyPlugin::getMaker() const
 {
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	char method[]="getMaker";
-	cerr << "[call] " << method << endl;
-	string rString="Generic VamPy Plugin.";
-	
-	if ( PyObject_HasAttrString(m_pyInstance,method) ) {
-
-		//Call the method
-		PyObject *pyString = 
-		PyObject_CallMethod(m_pyInstance, method, NULL);
-
-		//Check return value
-		if (!PyString_Check(pyString)) {
-			Py_CLEAR(pyString);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected String return value." << endl;
-			return rString;
-		}
-
-		rString=PyString_AsString(pyString);
-		Py_CLEAR(pyString);
-	}
-    return rString;
+	string rString="VamPy Plugin.";
+	return genericMethodCall("getMaker",rString);
 }
 
 int
 PyPlugin::getPluginVersion() const
 {
-	//!!! implement
-
-	return 2;
+	MutexLocker locker(&m_pythonInterpreterMutex);
+	size_t rValue=2;
+	return genericMethodCall("getPluginVersion",rValue);
 }
 
 string
 PyPlugin::getCopyright() const
 {
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	char method[]="getCopyright";
-	cerr << "[call] " << method << endl;
-	string rString="BSD License";
-	
-	if ( PyObject_HasAttrString(m_pyInstance,method) ) {
-
-		//Call the method
-		PyObject *pyString = 
-		PyObject_CallMethod(m_pyInstance, method, NULL);
-
-		//Check return value
-		if (!PyString_Check(pyString)) {
-			Py_CLEAR(pyString);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected String return value." << endl;
-			return rString;
-		}
-
-		
-		rString=PyString_AsString(pyString);
-		Py_CLEAR(pyString);
-	}
-
-	return rString;
+	string rString="Licence information not available.";
+	return genericMethodCall("getCopyright",rString);
 }
 
 
 bool
 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
 {
-	//useful for debugging Python plugins
-	char method[]="initialise";
-	cerr << "[call] " << method << endl;
-	
-	//placing Mutex before these calls causes deadlock
+
 	if (channels < getMinChannelCount() ||
 	    channels > getMaxChannelCount()) return false;
-	
+
 	m_inputDomain = getInputDomain();
 
+	//Note: placing Mutex before the calls above causes deadlock !!
 	MutexLocker locker(&m_pythonInterpreterMutex);
 
-	initMaps();
-
 	m_stepSize = stepSize;
 	m_blockSize = blockSize;
 	m_channels = channels;
 
-	//quering process implementation type
-	char legacyMethod[]="process";
-	char numpyMethod[]="processN";
-
-	if (PyObject_HasAttrString(m_pyInstance,legacyMethod) &&
-	    m_processType == 0) 
-	{ 
-		m_processType = legacyProcess;
-		m_pyProcess = PyString_FromString(legacyMethod);
-	}
-
-	if (PyObject_HasAttrString(m_pyInstance,numpyMethod) &&
-	    m_processType == 0)
-	{
-		m_processType = numpyProcess;
-		m_pyProcess = PyString_FromString(numpyMethod);
-	}
+	//query the process implementation type
+	//two optional flags can be used: 'use_numpy_interface' or 'use_legacy_interface'
+	//if they are not provided, we fall back to the original method
+	setProcessType();
 	
-	if (!m_processType)
-	{
-		m_processType = not_implemented;
-		m_pyProcess = NULL;		
-		cerr << "Warning: Python plugin [" << m_class << "::" << method 
-		     << "] No process implementation found. Plugin will do nothing." << endl;
-	}
-
-	//Check if the method is implemented in Python else return false
-	if (PyObject_HasAttrString(m_pyInstance,method)) {
-   			
-		PyObject *pyMethod = PyString_FromString(method);
-		PyObject *pyChannels = PyInt_FromSsize_t((Py_ssize_t)channels);
-		PyObject *pyStepSize = PyInt_FromSsize_t((Py_ssize_t)m_stepSize);
-		PyObject *pyBlockSize = PyInt_FromSsize_t((Py_ssize_t)blockSize);
-		//Call the method
-		PyObject *pyBool = 
-			PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyChannels,pyStepSize,pyBlockSize,NULL);
-						
-		Py_DECREF(pyMethod);
-		Py_DECREF(pyChannels);
-		Py_DECREF(pyStepSize);
-		Py_DECREF(pyBlockSize);
-
-		//Check return value
-		if (PyErr_Occurred() || !PyBool_Check(pyBool)) {
-			PyErr_Print(); PyErr_Clear();
-			Py_CLEAR(pyBool);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			     << "] Expected Bool return value." << endl;
-			return false;
-		}
-		
-		if (pyBool == Py_True) {  
-			Py_CLEAR(pyBool); 
-			return true;
-		} else {
-			Py_CLEAR(pyBool); 
-			return false;
-		}
-	} 
-    	return false;
+	return genericMethodCallArgs<bool>("initialise",channels,stepSize,blockSize);
 }
 
 void
 PyPlugin::reset()
 {
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	char method[]="reset";
-	cerr << "[call] " << method << endl;
-	
-	if ( PyObject_HasAttrString(m_pyInstance,method) ) {
-
-		PyObject_CallMethod(m_pyInstance, method, NULL);
-		if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }		
-
-	}
+	genericMethodCall("reset");
 }
 
-PyPlugin::InputDomain PyPlugin::getInputDomain() const  
+PyPlugin::InputDomain 
+PyPlugin::getInputDomain() const  
 { 
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	char method[]="getInputDomain";
-	cerr << "[call] " << method << endl;
-	PyPlugin::InputDomain rValue = TimeDomain; // TimeDomain
-	
-	if ( PyObject_HasAttrString(m_pyInstance,method) ) {
-
-		PyObject *pyString = PyObject_CallMethod(m_pyInstance, method, NULL);
-		
-		//Check return value
-		if (!PyString_Check(pyString)) {
-			Py_CLEAR(pyString);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected String return value." << endl;
-			return rValue;
-		}
-		
-		string domain = (string) PyString_AsString(pyString);
-		if (domain == "FrequencyDomain") rValue = FrequencyDomain;
-		Py_CLEAR(pyString);
-	}
-    return rValue; 
+	// Note: Vamp enum type is mapped to Python string !!
+	// Is there a better way? (Enums are not native to Python)
+	string rValue = "TimeDomain";
+	genericMethodCall("getInputDomain",rValue);
+	return (rValue == "FrequencyDomain")?FrequencyDomain:TimeDomain;
 }
 
-
-size_t PyPlugin::getPreferredBlockSize() const 
+size_t 
+PyPlugin::getPreferredBlockSize() const 
 { 
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	char method[]="getPreferredBlockSize";
-	cerr << "[call] " << method << endl;
-	size_t rValue=0; //not set by default
-	if ( PyObject_HasAttrString(m_pyInstance,method) ) {
-		PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
-		
-		//Check return value
-		if (!PyInt_Check(pyInt)) {
-			Py_CLEAR(pyInt);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected Integer return value." << endl;
-			return rValue;
-		}
-		
-		rValue=(size_t)PyInt_AS_LONG(pyInt);
-		Py_CLEAR(pyInt);
-	}
-    return rValue; 
+	size_t rValue = 0;
+	return genericMethodCall("getPreferredBlockSize",rValue); 
 }
 
-//size_t PyPlugin::getPreferredStepSize() const { return 0; }
-size_t PyPlugin::getPreferredStepSize() const 
+size_t 
+PyPlugin::getPreferredStepSize() const 
 { 
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	char method[]="getPreferredStepSize";
-	cerr << "[call] " << method << endl;
-	size_t rValue=1024; //not set by default
-	if ( PyObject_HasAttrString(m_pyInstance,method) ) {
-		PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
-		
-		//Check return value
-		if (!PyInt_Check(pyInt)) {
-			Py_CLEAR(pyInt);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected Integer return value." << endl;
-			return rValue;
-		}
-		
-		rValue=(size_t)PyInt_AS_LONG(pyInt);
-		Py_CLEAR(pyInt);
-	}
-    return rValue; 
+	size_t rValue = 0;
+    return genericMethodCall("getPreferredStepSize",rValue); 
 }
 
-size_t PyPlugin::getMinChannelCount() const 
+size_t 
+PyPlugin::getMinChannelCount() const 
 { 
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	char method[]="getMinChannelCount";
-	cerr << "[call] " << method << endl;
-	size_t rValue=1; //default value
-	if ( PyObject_HasAttrString(m_pyInstance,method) ) {
-		PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
-
-		//Check return value
-		if (!PyInt_Check(pyInt)) {
-			Py_CLEAR(pyInt);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected String return value." << endl;
-			return rValue;
-		}
-
-		rValue=(size_t)PyInt_AS_LONG(pyInt);
-		Py_CLEAR(pyInt);
-	}
-    return rValue; 
+	size_t rValue = 1;
+    return genericMethodCall("getMinChannelCount",rValue); 
 }
 
-size_t PyPlugin::getMaxChannelCount() const 
+size_t 
+PyPlugin::getMaxChannelCount() const 
 { 
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	char method[]="getMaxChannelCount";	
-	cerr << "[call] " << method << endl;
-	size_t rValue=1; //default value
-	if ( PyObject_HasAttrString(m_pyInstance,method) ) {
-		PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
-
-		//Check return value
-		if (!PyInt_Check(pyInt)) {
-			Py_CLEAR(pyInt);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected String return value." << endl;
-			return rValue;
-		}
-
-		rValue=(size_t)PyInt_AS_LONG(pyInt);
-		Py_CLEAR(pyInt);
-	}
-    return rValue; 
-}
-
+	size_t rValue = 1;
+    return genericMethodCall("getMaxChannelCount",rValue); 
+}	
 
 PyPlugin::OutputList
 PyPlugin::getOutputDescriptors() const
 {
-	
 	MutexLocker locker(&m_pythonInterpreterMutex);
-	
-	//PyEval_AcquireThread(newThreadState);
 	OutputList list;
-	OutputDescriptor od;
-	char method[]="getOutputDescriptors";
-	cerr << "[call] " << method << endl;
-
-	//Check if the method is implemented in Python
-	if ( ! PyObject_HasAttrString(m_pyInstance,method) ) return list;
-			
-		//Call the method: must return list object (new reference)
-		PyObject *pyList = 
-		PyObject_CallMethod(m_pyInstance,method, NULL);
-
-		//Check return type
-		if (! PyList_Check(pyList) ) {
-			Py_CLEAR(pyList);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected List return type." << endl;
-			return list;
-		}
-
-		//These will all be borrowed references (no need to DECREF)
-		PyObject *pyDict, *pyKey, *pyValue;
-		
-		//Parse Output List
-		for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
-	
-			//Get i-th Vamp output descriptor (Borrowed Reference)
-			pyDict = PyList_GET_ITEM(pyList,i);
-			
-			//We only care about dictionaries holding output descriptors
-			if ( !PyDict_Check(pyDict) ) continue;
-			
-			Py_ssize_t pyPos = NULL;
-			initMaps();
-
-			//Python Sequence Iterator
-			while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue)) 
-			{		
-				switch (outKeys[PyString_AsString(pyKey)]) 
-				{
-					case o::not_found : 	
-						cerr << "Unknown key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl; 
-						break;
-					case o::identifier: 	
-						od.identifier = PyString_AsString(pyValue); 
-						break;				
-					case o::name: 			
-						od.name = PyString_AsString(pyValue); 
-						break;
-					case o::description: 	
-						od.description = PyString_AsString(pyValue); 
-						break; 								
-					case o::unit: 			
-						od.unit = PyString_AsString(pyValue); 
-						break; 													
-					case o::hasFixedBinCount:
-						od.hasFixedBinCount = (bool) PyInt_AS_LONG(pyValue); 
-						break;
-					case o::binCount:
-						od.binCount = (size_t) PyInt_AS_LONG(pyValue);
-						break;
-					case o::binNames:
-						od.binNames = PyList_To_StringVector(pyValue);
-						break;
-					case o::hasKnownExtents:
-						od.hasKnownExtents = (bool) PyInt_AS_LONG(pyValue); 
-						break;					
-					case o::minValue:
-						od.minValue = (float) PyFloat_AS_DOUBLE(pyValue);
-						break;
-					case o::maxValue:
-						od.maxValue = (float) PyFloat_AS_DOUBLE(pyValue);
-						break;
-					case o::isQuantized:
-						od.isQuantized = (bool) PyInt_AS_LONG(pyValue); 
-						break;					
-					case o::quantizeStep:
-						od.quantizeStep = (float) PyFloat_AS_DOUBLE(pyValue);
-						break;
-					case o::sampleType: 				
-						od.sampleType = (OutputDescriptor::SampleType) sampleKeys[PyString_AsString(pyValue)];
-						break;
-					case o::sampleRate:
-						od.sampleRate = (float) PyFloat_AS_DOUBLE(pyValue);
-//						od.sampleRate = m_inputSampleRate / m_stepSize;
-						cerr << od.sampleRate << endl;
-						break;					
-					case o::hasDuration:
-						od.hasDuration = (bool)PyInt_AS_LONG(pyValue);
-						break;
-					default : 	
-						cerr << "Invalid key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl; 
-				} 					
-			} // while dict
-			list.push_back(od);
-		} // for list
-		Py_CLEAR(pyList);
-	return list;
+	return genericMethodCall("getOutputDescriptors",list);
 }
 
 PyPlugin::ParameterList
 PyPlugin::getParameterDescriptors() const
 {
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
 	ParameterList list;
-	ParameterDescriptor pd;
-	char method[]="getParameterDescriptors";
-	cerr << "[call] " << method << endl;
-	
+	///Note: This function is often called first by the host.
 	if (!m_pyInstance) {cerr << "Error: pyInstance is NULL" << endl; return list;}
-
-	//Check if the method is implemented in Python
-	if ( ! PyObject_HasAttrString(m_pyInstance,method) ) return list;
-			
-		//Call the method: must return list object (new reference)
-		PyObject *pyList = 
-		PyObject_CallMethod(m_pyInstance,method, NULL);
-
-		//Check return type
-		if (! PyList_Check(pyList) ) {
-			Py_CLEAR(pyList);
-			cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-			<< "] Expected List return type." << endl;
-			return list;
-		}
-
-
-		//These will all be borrowed references (no need to DECREF)
-		PyObject *pyDict, *pyKey, *pyValue;
-		
-		//Parse Output List
-		for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
-	
-			//Get i-th Vamp output descriptor (Borrowed Reference)
-			pyDict = PyList_GET_ITEM(pyList,i);
-			
-			//We only care about dictionaries holding output descriptors
-			if ( !PyDict_Check(pyDict) ) continue;
-			
-			Py_ssize_t pyPos = NULL;
-			initMaps();
-
-			//Python Sequence Iterator
-			while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue)) 
-			{		
-				switch (parmKeys[PyString_AsString(pyKey)]) 
-				{
-					case p::not_found : 	
-						cerr << "Unknown key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl; 
-						break;
-					case p::identifier: 	
-						pd.identifier = PyString_AsString(pyValue); 
-						break;				
-					case p::name: 			
-						pd.name = PyString_AsString(pyValue); 
-						break;
-					case p::description: 	
-						pd.description = PyString_AsString(pyValue); 
-						break; 								
-					case p::unit: 			
-						pd.unit = PyString_AsString(pyValue); 
-						break; 																		
-					case p::minValue:
-						pd.minValue = (float) PyFloat_AS_DOUBLE(pyValue);
-						break;
-					case p::maxValue:
-						pd.maxValue = (float) PyFloat_AS_DOUBLE(pyValue);
-						break;
-					case p::defaultValue:
-						pd.defaultValue = (float) PyFloat_AS_DOUBLE(pyValue);
-						break;
-					case p::isQuantized:
-						pd.isQuantized = (bool) PyInt_AS_LONG(pyValue); 
-						break;									
-					case p::quantizeStep:
-						pd.quantizeStep = (float) PyFloat_AS_DOUBLE(pyValue);
-						break;
-					default : 	
-						cerr << "Invalid key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl; 
-				} 				
-			} // while dict
-			list.push_back(pd);
-		} // for list
-		Py_CLEAR(pyList);
-	return list;
+	return genericMethodCall("getParameterDescriptors",list);
 }
 
 void PyPlugin::setParameter(std::string paramid, float newval)
 {
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	char method[]="setParameter";
-	cerr << "[call] " << method << endl;
-
-		//Check if the method is implemented in Python
-		if (PyObject_HasAttrString(m_pyInstance,method)) {
-   			
-			PyObject *pyMethod = PyString_FromString(method);
-			PyObject *pyParamid = PyString_FromString(paramid.c_str());
-			PyObject *pyNewval = PyFloat_FromDouble((double)newval);
-			
-			//Call the method
-			PyObject *pyBool = 
-			PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyParamid,pyNewval,NULL);
-
-			//This only happens if there is a syntax error or so
-			if (pyBool == NULL) {
-				cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-				<< "] Error setting parameter: " << paramid << endl;
-				if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
-			}
-
-			Py_DECREF(pyMethod);
-			Py_DECREF(pyParamid);
-			Py_DECREF(pyNewval);
-		}
+	genericMethodCallArgs<NoneType>("setParameter",paramid,newval);
 }
 
 float PyPlugin::getParameter(std::string paramid) const
 {
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	char method[]="getParameter";
-	cerr << "[call] " << method << endl;
-	float rValue = 0.0f;
-	
-		//Check if the method is implemented in Python
-		if (PyObject_HasAttrString(m_pyInstance,method)) {
-   			
-			PyObject *pyMethod = PyString_FromString(method);
-			PyObject *pyParamid = PyString_FromString(paramid.c_str());
-			
-			//Call the method
-			PyObject *pyFloat = 
-			PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyParamid,NULL);
-
-			//Check return type
-			if (! PyFloat_Check(pyFloat) ) {
-				cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-					<< "] Expected Float return type." << endl;
-				if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
-				Py_CLEAR(pyFloat);
-				return rValue;
-			}
-	
-			rValue = (float) PyFloat_AS_DOUBLE(pyFloat); 
-			
-			Py_DECREF(pyMethod);
-			Py_DECREF(pyParamid);
-			Py_DECREF(pyFloat);
-		}
-
-    return rValue;
+	return genericMethodCallArgs<float>("getParameter",paramid);
 }
 
 #ifdef _DEBUG
@@ -774,8 +315,7 @@
 #endif
 
 PyPlugin::FeatureSet
-PyPlugin::process(const float *const *inputBuffers,
-                      Vamp::RealTime timestamp)
+PyPlugin::process(const float *const *inputBuffers,Vamp::RealTime timestamp)
 {
 	MutexLocker locker(&m_pythonInterpreterMutex);
 
@@ -796,395 +336,172 @@
 	return FeatureSet();
 	}
 
-	string method=PyString_AsString(m_pyProcess);
+	// string method=PyString_AsString(m_pyProcess);
 
 		PyObject *pyOutputList = NULL;
 		
-		/*new numPy support*/
 		if (m_processType == numpyProcess) {
-			
-			//create a list of buffers
-			PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels);
-			for (size_t i=0; i < m_channels; ++i) {
-
-				//Expose memory using the Buffer Interface of C/API		
-				//This will virtually pass a pointer which can be 
-				//recasted in Python code as float or complex array             
-				PyObject *pyBuffer = PyBuffer_FromMemory
-				((void *) (float *) inputBuffers[i], 
-				(Py_ssize_t) sizeof(float) * m_blockSize);
-
-			PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyBuffer);
-			}
-
-			//pass RealTime as frameCount
-			PyObject *pyLongSample = PyLong_FromLong (
-			Vamp::RealTime::realTime2Frame 
-			(timestamp, (unsigned int) m_inputSampleRate));
-		
-			//Call python process (returns new reference)
-			pyOutputList = PyObject_CallMethodObjArgs
-			(m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL);
-			
-			Py_DECREF(pyChannelList);
-			Py_DECREF(pyLongSample);
-
+			pyOutputList = numpyProcessCall(inputBuffers,timestamp);
 		} 
 		
 		if (m_processType == legacyProcess) { 
-
-			//create a list of lists
-			PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels);
-			for (size_t i=0; i < m_channels; ++i) {
-
-				//Declare new list object
-				PyObject *pyFloat, *pyList;
-				pyList = PyList_New((Py_ssize_t) m_blockSize);
-
-				//Pack samples into a Python List Object
-				//pyFloat types will always be new references, 
-				//these will be discarded when the list is deallocated
-				for (size_t j = 0; j < m_blockSize; ++j) {
-					pyFloat=PyFloat_FromDouble(
-						(double) inputBuffers[i][j]);
-					PyList_SET_ITEM(pyList, (Py_ssize_t) j, pyFloat);
-				}
-				PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyList);				
-			}
-
-			//pass RealTime as frameCount
-			PyObject *pyLongSample = PyLong_FromLong (
-			Vamp::RealTime::realTime2Frame 
-			(timestamp, (unsigned int) m_inputSampleRate));
-
-			//Call python process (returns new reference)
-			pyOutputList = PyObject_CallMethodObjArgs
-			(m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL);
-			
-			Py_DECREF(pyChannelList);
-			Py_DECREF(pyLongSample);
-
+			pyOutputList = legacyProcessCall(inputBuffers,timestamp);
 		}
 
-		//return nothing
-		//Py_CLEAR(pyOutputList);
-		//return FeatureSet();
-
-		//Check return type
-		if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) {
-			if (pyOutputList == NULL) {				
-				cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-				<< "] Unexpected result." << endl;
-				if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
-			} else {
-				cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-				<< "] Expected List return type." << endl;				
-			}
-			Py_CLEAR(pyOutputList);
-			return FeatureSet();
-		}
-			
-		// Py_DECREF(pyList); 
-		// This appears to be tracked by the cyclic garbage collector
-		// hence decrefing produces GC error
-#ifdef _DEBUG								
-		cerr << "Process Returned Features" << endl;
-#endif
-		// These will ALL be borrowed references
-		PyObject *pyFeatureList, *pyDict, *pyKey, *pyValue;
-
-		FeatureSet returnFeatures;
-
-		//Parse Output List for each element (FeatureSet)
-		for (Py_ssize_t i = 0; 
-					i < PyList_GET_SIZE(pyOutputList); ++i) {
-			//cerr << "output (FeatureSet): " << i << endl; 
-
-			//Get i-th FeatureList (Borrowed Reference)
-			pyFeatureList = PyList_GET_ITEM(pyOutputList,i);
-
-			//Parse FeatureList for each element (Feature)
-			for (Py_ssize_t j = 0; j < PyList_GET_SIZE(pyFeatureList); ++j) {				
-				//cerr << "element (FeatureList): " << j << endl; 
-
-				//Get j-th Feature (Borrowed Reference)
-				pyDict = PyList_GET_ITEM(pyFeatureList,j);
-
-				//We only care about dictionaries holding a Feature struct
-				if ( !PyDict_Check(pyDict) ) continue;
-
-				Py_ssize_t pyPos = NULL;
-				bool emptyFeature = true;
-				Feature feature;
-
-				//process::Python Sequence Iterator for dictionary
-				while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue)) 
-				{	
-					emptyFeature = false;
-					switch (ffKeys[PyString_AsString(pyKey)]) 
-					{
-						case unknown: 	
-							cerr << "Unknown key in Vamp FeatureSet: " 
-							<< PyString_AsString(pyKey) << endl; 
-							break;
-						case hasTimestamp: 	
-							feature.hasTimestamp = (bool) PyInt_AS_LONG(pyValue); 
-							break;				
-						case timeStamp: 			
-							feature.timestamp =  
-							Vamp::RealTime::frame2RealTime(
-							PyLong_AsLong(pyValue), 
-							(unsigned int) m_inputSampleRate );
-#ifdef _DEBUG
-							cerr << "Timestamp: " 
-							<< (long)PyLong_AsLong(pyValue) << ", ->" 
-							<< feature.timestamp.toString() << endl;
-#endif
-							break;
-						case hasDuration: 	
-							feature.hasDuration = (bool) PyInt_AS_LONG(pyValue); 
-							break;				
-						case duration: 			
-							feature.duration =  
-							Vamp::RealTime::frame2RealTime(
-							PyLong_AsLong(pyValue), 
-							(unsigned int) m_inputSampleRate );
-#ifdef _DEBUG
-							cerr << "Duration: " 
-							<< (long)PyLong_AsLong(pyValue) << ", ->" 
-							<< feature.duration.toString() << endl;
-#endif
-							break;
-						case values: 	
-							feature.values = PyList_As_FloatVector(pyValue); 
-							break; 								
-						case label: 			
-							feature.label = PyString_AsString(pyValue); 
-							break; 													
-						default : 	
-							cerr << "Invalid key in Vamp FeatureSet: " 
-							<< PyString_AsString(pyKey) << endl; 
-					} // switch					
-
-				} // while 
-				if (emptyFeature) cerr << "Warning: This feature is empty or badly formatted." << endl;
-				else returnFeatures[i].push_back(feature);
-
-			}// for j = FeatureList			
-
-		}//for i = FeatureSet
+		FeatureSet rFeatureset;
+		rFeatureset = m_ti.PyValue_To_FeatureSet(pyOutputList);
 		Py_CLEAR(pyOutputList);
-		return returnFeatures;
+		return rFeatureset;
+		
 }
 
+PyObject*
+PyPlugin::numpyProcessCall(const float *const *inputBuffers,Vamp::RealTime timestamp)
+{
+	PyObject *pyOutputList = NULL;
+	
+	//create a list of buffers
+	PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels);
+	for (size_t i=0; i < m_channels; ++i) {
+		//Expose memory using the Buffer Interface of C/API		
+		//This will virtually pass a pointer which can be 
+		//recasted in Python code as float or complex array             
+		PyObject *pyBuffer = PyBuffer_FromMemory
+		((void *) (float *) inputBuffers[i], 
+		(Py_ssize_t) sizeof(float) * m_blockSize);
 
+		PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyBuffer);
+		}
+/*
+		//(1) pass RealTime as frameCount
+		PyObject *pyLongSample = PyLong_FromLong (
+		Vamp::RealTime::realTime2Frame 
+		(timestamp, (unsigned int) m_inputSampleRate));
+		
+		//Call python process (returns new reference)
+		pyOutputList = PyObject_CallMethodObjArgs
+		(m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL);
+ */   	
+		//(2) pass RealTime as PyRealTime
+		PyObject *pyRealTime = PyRealTime_FromRealTime(timestamp);
+
+		//Call python process (returns new reference)
+		pyOutputList = PyObject_CallMethodObjArgs
+		(m_pyInstance,m_pyProcess,pyChannelList,pyRealTime,NULL);
+					
+		Py_DECREF(pyChannelList);
+		// Py_DECREF(pyLongSample);
+		Py_DECREF(pyRealTime);
+		return pyOutputList;
+}
+
+PyObject*
+PyPlugin::legacyProcessCall(const float *const *inputBuffers,Vamp::RealTime timestamp)
+{
+	PyObject *pyOutputList = NULL;
+	
+	//create a list of lists
+	PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels);
+	for (size_t i=0; i < m_channels; ++i) {
+		//New list object
+		PyObject *pyFloat, *pyList;
+		pyList = PyList_New((Py_ssize_t) m_blockSize);
+
+		//Pack samples into a Python List Object
+		//pyFloat types will always be new references, 
+		//these will be discarded when the list is deallocated
+		for (size_t j = 0; j < m_blockSize; ++j) {
+			pyFloat=PyFloat_FromDouble(
+				(double) inputBuffers[i][j]);
+			PyList_SET_ITEM(pyList, (Py_ssize_t) j, pyFloat);
+		}
+		PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyList);				
+	}
+
+	//pass RealTime as frameCount
+	PyObject *pyLongSample = PyLong_FromLong (
+	Vamp::RealTime::realTime2Frame 
+	(timestamp, (unsigned int) m_inputSampleRate));
+
+	//Call python process (returns new reference)
+	pyOutputList = PyObject_CallMethodObjArgs
+	(m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL);
+
+	Py_DECREF(pyChannelList);
+	Py_DECREF(pyLongSample);
+	return pyOutputList;
+}
 
 PyPlugin::FeatureSet
 PyPlugin::getRemainingFeatures()
 {
 	MutexLocker locker(&m_pythonInterpreterMutex);
-
-	static char method[]="getRemainingFeatures";
-	cerr << "[call] " << method << endl;
-
-	//check if the method is implemented
-	if ( ! PyObject_HasAttrString(m_pyInstance,method) ) {
-		return FeatureSet(); 
-		}
-			
-		PyObject *pyMethod = PyString_FromString(method);		
-
-		PyObject *pyOutputList = 
-		PyObject_CallMethod(m_pyInstance,method, NULL);
-					
-		//Check return type
-		if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) {
-			if (pyOutputList == NULL) {				
-				cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-				<< "] Unexpected result." << endl;
-				if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
-			} else {
-				cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
-				<< "] Expected List return type." << endl;				
-			}
-			Py_CLEAR(pyMethod);
-			Py_CLEAR(pyOutputList);
-			return FeatureSet();
-		}
-		Py_DECREF(pyMethod);
-	
-		PyObject *pyFeatureList, *pyDict, *pyKey, *pyValue;
-		FeatureSet returnFeatures;
-		
-		//iterate through list of outputs
-		for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyOutputList); ++i) {
-
-			pyFeatureList = PyList_GET_ITEM(pyOutputList,i);
-
-			//iterate list of Features
-			for (Py_ssize_t j = 0; j < PyList_GET_SIZE(pyFeatureList); ++j) {				
-#ifdef _DEBUG
-				cerr << "feature: " << j << endl;
-#endif
-				pyDict = PyList_GET_ITEM(pyFeatureList,j);
-
-				if ( !PyDict_Check(pyDict) ) continue;
-
-				Py_ssize_t pyPos = NULL;
-				bool emptyFeature = true;
-				Feature feature;
-
-				while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue)) 
-				{	
-					emptyFeature = false;
-					switch (ffKeys[PyString_AsString(pyKey)]) 
-					{
-						case unknown : 	
-							cerr << "Unknown key in Vamp FeatureSet: " 
-							<< PyString_AsString(pyKey) << endl; 
-							break;
-						case hasTimestamp: 	
-							feature.hasTimestamp = (bool) PyInt_AS_LONG(pyValue); 
-							break;				
-						case timeStamp: 			
-							feature.timestamp =  
-							Vamp::RealTime::frame2RealTime(
-							PyLong_AsLong(pyValue), 
-							(unsigned int) m_inputSampleRate );
-#ifdef _DEBUG
-							cerr << "Timestamp: " 
-							<< (long)PyLong_AsLong(pyValue) << ", ->" 
-							<< feature.timestamp.toString() << endl;
-#endif
-							break;
-						case hasDuration: 	
-							feature.hasDuration = (bool) PyInt_AS_LONG(pyValue); 
-							break;				
-						case duration:
-							feature.duration =  
-							Vamp::RealTime::frame2RealTime(
-							PyLong_AsLong(pyValue), 
-							(unsigned int) m_inputSampleRate );
-#ifdef _DEBUG
-							cerr << "Duration: " 
-							<< (long)PyLong_AsLong(pyValue) << ", ->" 
-							<< feature.duration.toString() << endl;
-#endif
-							break;
-						case values: 	
-							feature.values = PyList_As_FloatVector(pyValue); 
-							break; 								
-						case label: 			
-							feature.label = PyString_AsString(pyValue); 
-							break; 													
-					} // switch					
-				} // while 
-				if (emptyFeature) cerr << "Warning: This feature is empty or badly formatted." << endl;
-				else returnFeatures[i].push_back(feature);
-			}// for j 			
-		}//for i 
-		Py_CLEAR(pyOutputList);
-		return returnFeatures;
+	FeatureSet rValue;
+	return genericMethodCall("getRemainingFeatures",rValue); 
 }
 
+
 bool
-PyPlugin::initMaps() const
+PyPlugin::getBooleanFlag(char flagName[], bool defValue = false) const
 {
-
-	if (isMapInitialised) return true;
-
-	outKeys["identifier"] = o::identifier;
-	outKeys["name"] = o::name;
-	outKeys["description"] = o::description;
-	outKeys["unit"] = o::unit;
-	outKeys["hasFixedBinCount"] = o::hasFixedBinCount; 
-	outKeys["binCount"] = o::binCount;
-	outKeys["binNames"] = o::binNames;
-	outKeys["hasKnownExtents"] = o::hasKnownExtents;
-	outKeys["minValue"] = o::minValue;
-	outKeys["maxValue"] = o::maxValue;
-	outKeys["isQuantized"] = o::isQuantized;
-	outKeys["quantizeStep"] = o::quantizeStep;
-	outKeys["sampleType"] = o::sampleType;
-	outKeys["sampleRate"] = o::sampleRate;
-	outKeys["hasDuration"] = o::hasDuration;
-
-	sampleKeys["OneSamplePerStep"] = OneSamplePerStep;
-	sampleKeys["FixedSampleRate"] = FixedSampleRate;
-	sampleKeys["VariableSampleRate"] = VariableSampleRate;
-
-	ffKeys["hasTimestamp"] = hasTimestamp;
-	ffKeys["timeStamp"] = timeStamp;
-	ffKeys["hasDuration"] = hasDuration;
-	ffKeys["duration"] = duration;
-	ffKeys["values"] = values;
-	ffKeys["label"] = label;
-
-	parmKeys["identifier"] = p::identifier;
-	parmKeys["name"] = p::name;
-	parmKeys["description"] = p::description;
-	parmKeys["unit"] = p::unit;
-	parmKeys["minValue"] = p::minValue;
-	parmKeys["maxValue"] = p::maxValue;
-	parmKeys["defaultValue"] = p::defaultValue;
-	parmKeys["isQuantized"] = p::isQuantized;
-	parmKeys["quantizeStep"] = p::quantizeStep;
-
-	isMapInitialised = true;
-	return true;
+	bool rValue = defValue;
+	if (PyObject_HasAttrString(m_pyInstance,flagName))
+	{
+		PyObject *pyValue = PyObject_GetAttrString(m_pyInstance,flagName);
+		if (!pyValue) 
+		{
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		} else {
+			rValue = m_ti.PyValue_To_Bool(pyValue);
+			if (m_ti.error) { 
+				cerr << m_ti.lastError().message << endl;
+				Py_CLEAR(pyValue);
+				rValue = defValue;
+			} else Py_DECREF(pyValue);
+		}
+	}
+	if (m_debugFlag) cerr << FLAG_VALUE << endl;
+	return rValue;
 }
 
+void
+PyPlugin::setProcessType()
+{
+	//quering process implementation type
+	char legacyMethod[]="process";
+	char numpyMethod[]="processN";
 
-//missing API helper: convert Python list to C++ vector of strings
-//TODO: these could be templates if we need more of this kind
-std::vector<std::string> 
-PyPlugin::PyList_To_StringVector (PyObject *inputList) const {
+	if (PyObject_HasAttrString(m_pyInstance,legacyMethod) &&
+	    m_processType == 0) 
+	{ 
+		m_processType = legacyProcess;
+		m_pyProcess = PyString_FromString(legacyMethod);
+	}
+
+	if (PyObject_HasAttrString(m_pyInstance,numpyMethod) &&
+	    m_processType == 0)
+	{
+		m_processType = numpyProcess;
+		m_pyProcess = PyString_FromString(numpyMethod);
+	}
+
+	// These flags are optional. If provided, they override the
+	// implementation type making the use of the odd processN() 
+	// function redundant.
+	// However, the code above provides backwards compatibility.
+	if (getBooleanFlag("use_numpy_interface",false)) 
+		m_processType = numpyProcess;
+	if (getBooleanFlag("use_legacy_interface",false)) 
+		m_processType = legacyProcess;
+	if (m_debugFlag && m_processType) 
+		cerr << "Process type: " << ((m_processType==numpyProcess)?"numpy process":"legacy process") << endl;
 	
-	std::vector<std::string> Output;
-	std::string ListElement;
-	PyObject *pyString = NULL;
-	
-	if (!PyList_Check(inputList)) return Output;
-
-	for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
-		//Get next list item (Borrowed Reference)
-		pyString = PyList_GET_ITEM(inputList,i);
-		ListElement = (string) PyString_AsString(PyObject_Str(pyString));
-		Output.push_back(ListElement);
+	if (!m_processType)
+	{
+		m_processType = not_implemented;
+		m_pyProcess = NULL;
+		char method[]="initialise::setProcessType";
+		cerr << PLUGIN_ERROR << " No process implementation found. Plugin will do nothing." << endl;
 	}
-	return Output;
 }
 
-//missing API helper: convert Python list to C++ vector of floats
-std::vector<float> 
-PyPlugin::PyList_As_FloatVector (PyObject *inputList) const {
-	
-	std::vector<float> Output;
-	float ListElement;
-	PyObject *pyFloat = NULL;
-	
-	if (!PyList_Check(inputList)) return Output; 
-
-	for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) {
-		//Get next list item (Borrowed Reference)
-		pyFloat =  PyList_GET_ITEM(inputList,k);
-		ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
-#ifdef _DEBUG
-		cerr << "value: " << ListElement << endl;
-#endif
-		Output.push_back(ListElement);
-	}
-
-	return Output;
-}
-
-/* TODO: find out why this produces error, also 
-		do sg more clever about handling RealTime
-Vamp::RealTime 
-PyFrame_As_RealTime (PyObject *frameNo,size_t inputSampleRate) {
-Vamp::RealTime result =  
-Vamp::RealTime::frame2RealTime((size_t)PyInt_AS_LONG(frameNo), inputSampleRate);
-return result;
-}
-*/
-
--- a/PyPlugin.h	Tue Aug 25 08:49:22 2009 +0000
+++ b/PyPlugin.h	Sun Sep 20 17:31:20 2009 +0000
@@ -33,71 +33,26 @@
     authorization.
 */
 
-	/**
-	 * This plugin abstracts appropriate Python Scripts as a Vamp plugin.
-	*/
-
 #ifndef _PYTHON_WRAPPER_PLUGIN_H_
 #define _PYTHON_WRAPPER_PLUGIN_H_
 
+#define _CLASS_METHOD_ m_class << "::" << method
+#define PLUGIN_ERROR "ERROR: In Vampy plugin [" << _CLASS_METHOD_ << "]" << endl << "Cause: "
+#define DEBUG_NAME "[Vampy::call] " << _CLASS_METHOD_ << " "
+#define DEAFULT_RETURN "Method [" << _CLASS_METHOD_ << "] is not implemented." << endl << "Returning default value: " << rValue
+#define FLAG_VALUE "Flag: " << flagName << ": " << ((rValue==0)?"False":"True")
+
 #include "vamp-sdk/Plugin.h"
 #include <Python.h>
+// #include <typeinfo>
+// #include <stdarg.h>
+#include "PyTypeInterface.h"
 
 #include "Mutex.h"
 
-//fields in OutputDescriptor
-namespace o {
-enum eOutDescriptors {
-	not_found,
-	identifier,
-	name,
-	description,
-	unit, 
-	hasFixedBinCount,
-	binCount,
-	binNames,
-	hasKnownExtents,
-	minValue,
-	maxValue,
-	isQuantized,
-	quantizeStep,
-	sampleType,	
-	sampleRate,
-	hasDuration,
-	endNode
-	}; 
-}
-
-namespace p {
-enum eParmDescriptors {
-	not_found,
-	identifier,
-	name,
-	description,
-	unit, 
-	minValue,
-	maxValue,
-	defaultValue,
-	isQuantized,
-	quantizeStep
-	};
-}
-
-enum eSampleTypes {
-	OneSamplePerStep,
-	FixedSampleRate,
-	VariableSampleRate
-	};
-
-enum eFeatureFields {
-	unknown,
-	hasTimestamp,
-	timeStamp,
-	hasDuration,
-	duration,
-	values,
-	label
-	};
+using std::string;
+using std::cerr;
+using std::endl;
 
 enum eProcessType {
 	not_implemented,
@@ -108,7 +63,7 @@
 class PyPlugin : public Vamp::Plugin
 {
 public:
-	PyPlugin(std::string plugin,float inputSampleRate, PyObject *pyClass);
+	PyPlugin(std::string plugin,float inputSampleRate, PyObject *pyClass, int &instcount);
 	virtual ~PyPlugin();
 
 	bool initialise(size_t channels, size_t stepSize, size_t blockSize);
@@ -136,10 +91,12 @@
 			   Vamp::RealTime timestamp);
 
 	FeatureSet getRemainingFeatures();
-
+	
 protected:
+	static Mutex m_pythonInterpreterMutex;
 	PyObject *m_pyClass;
 	PyObject *m_pyInstance;
+	int &m_instcount;
 	size_t m_stepSize;
 	size_t m_blockSize;
 	size_t m_channels;
@@ -149,12 +106,204 @@
 	int m_processType;
 	PyObject *m_pyProcess;
 	InputDomain m_inputDomain;
+	PyTypeInterface m_ti;
+	bool m_quitOnErrorFlag;
+	bool m_debugFlag;
+
+	void setProcessType();
 	
-	bool initMaps() const;
-	std::vector<std::string> PyList_To_StringVector (PyObject *inputList) const;
-	std::vector<float> PyList_As_FloatVector (PyObject *inputList) const;
+	PyObject* numpyProcessCall(const float *const *inputBuffers, Vamp::RealTime timestamp);
+	PyObject* legacyProcessCall(const float *const *inputBuffers, Vamp::RealTime timestamp);
+	
+	bool getBooleanFlag(char flagName[],bool) const;
+/*
+		Flags may be used to control the behaviour of the interface.
+		Flags can be set in any Vampy plugin's __init__() function.
+		Their scope is limited to an instance.
+		Default values for all flags are False.
+		Python Example:
+		def __init__(self,inputSampleRate):
+			self.use_strict_type_conversion = True
+			self.vampy_debug_messages = True
+			self.use_realtime_timestamp = False
+			self.use_numpy_interface = False
+			self.quit_on_type_error = False
+			
+*/
+	
+	void genericMethodCall(char *method) const
+	{
+		if (m_debugFlag) cerr << DEBUG_NAME << endl;
+		if ( PyObject_HasAttrString(m_pyInstance,method) ) 
+		{
+			PyObject *pyValue = PyObject_CallMethod(m_pyInstance, method, NULL);
+			if (!pyValue) {
+				cerr << PLUGIN_ERROR << "Failed to call method." << endl;
+				if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			}
+		}
+	}
+	
+	template<typename RET> 
+	RET &genericMethodCall(char *method, RET &rValue) const
+	{
+		if (m_debugFlag) cerr << DEBUG_NAME << endl;
+		if ( PyObject_HasAttrString(m_pyInstance,method) ) 
+		{
+			PyObject *pyValue = PyObject_CallMethod(m_pyInstance, method, NULL);
+			if (pyValue) {
+				m_ti.PyValue_To_rValue(pyValue,rValue);
+				if (!m_ti.error) {
+					Py_DECREF(pyValue);
+					return rValue;
+				} else {
+					cerr << PLUGIN_ERROR << m_ti.lastError().message << endl;
+					Py_CLEAR(pyValue);
+					if (m_quitOnErrorFlag) exit(EXIT_FAILURE);
+					return rValue;
+				}
+			} else {
+				cerr << PLUGIN_ERROR << "Failed to call method." << endl;
+				if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+				return rValue;
+			}
+		}
+		// TODO: this fails to generalise because the << operator
+		// doesn't accept all types.
+		// if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
+		return rValue;
+	}
 
-	static Mutex m_pythonInterpreterMutex;
+	template<typename RET,typename A1>
+	RET genericMethodCallArgs(char *method, A1 arg1) const
+	{
+		RET rValue = RET();
+		if (m_debugFlag) cerr << DEBUG_NAME << endl;
+		if (!PyObject_HasAttrString(m_pyInstance,method)) {
+			// if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
+			return rValue;
+		}
+		
+		// These functions always return valid PyObjects 
+		PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
+		PyObject* pyTuple = PyTuple_New(3);
+		if (!pyTuple) return rValue;
+		
+		PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
+				
+		PyObject *pyValue = PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyArg1,NULL);
+		if (!pyValue) 
+		{
+			cerr << PLUGIN_ERROR << "Failed to call method." << endl;
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		}
+			
+		Py_DECREF(pyMethod);
+		Py_DECREF(pyArg1);
+
+		m_ti.PyValue_To_rValue(pyValue,rValue);
+		if (!m_ti.error) {
+			Py_DECREF(pyValue);
+		} else {
+			cerr << PLUGIN_ERROR << m_ti.lastError().message << endl;
+			Py_CLEAR(pyValue);
+			if (m_quitOnErrorFlag) exit(EXIT_FAILURE);
+		}
+		return rValue;
+	}
+
+	template<typename RET,typename A1,typename A2>
+	RET genericMethodCallArgs(char *method, A1 arg1, A2 arg2)
+	{
+		RET rValue = RET();
+		if (m_debugFlag) cerr << DEBUG_NAME << endl;
+		if (!PyObject_HasAttrString(m_pyInstance,method)) {
+			// if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
+			return rValue;
+		}
+		
+		// These functions always return valid PyObjects 
+		PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
+		PyObject* pyTuple = PyTuple_New(3);
+		if (!pyTuple) return rValue;
+		
+		PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
+		PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
+				
+		PyObject *pyValue = PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyArg1,pyArg2,NULL);
+		if (!pyValue) 
+		{
+			cerr << PLUGIN_ERROR << "Failed to call method." << endl;
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		}
+			
+		Py_DECREF(pyMethod);
+		Py_DECREF(pyArg1);
+		Py_DECREF(pyArg2);
+
+		m_ti.PyValue_To_rValue(pyValue,rValue);
+		if (!m_ti.error) {
+			Py_DECREF(pyValue);
+		} else {
+			cerr << PLUGIN_ERROR << m_ti.lastError().message << endl;
+			Py_CLEAR(pyValue);
+			if (m_quitOnErrorFlag) exit(EXIT_FAILURE);
+		}
+		return rValue;
+	}
+
+	
+	template<typename RET,typename A1,typename A2,typename A3>
+	RET genericMethodCallArgs(char *method, A1 arg1, A2 arg2, A3 arg3)
+	{
+		RET rValue = RET();
+		if (m_debugFlag) cerr << DEBUG_NAME << endl;
+		if (!PyObject_HasAttrString(m_pyInstance,method)) {
+			if (m_debugFlag) cerr << DEAFULT_RETURN << endl;
+			return rValue;
+		}
+		
+		// These functions always return valid PyObjects 
+		PyObject *pyMethod = m_ti.PyValue_From_CValue(method);
+		PyObject* pyTuple = PyTuple_New(3);
+		if (!pyTuple) return rValue;
+		
+		PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1);
+		PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2);
+		PyObject *pyArg3 = m_ti.PyValue_From_CValue(arg3);
+		
+		// TODO: Pack it in a tuple to avoid va_list parsing!
+		
+		// callable = PyObject_GetAttr(callable, name);
+		// if (callable == NULL)
+		// 	return NULL;
+		// PyObject* args; // pyTuple of input arguments
+		//tmp = PyObject_Call(callable, args, NULL);
+		
+		
+		PyObject *pyValue = PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyArg1,pyArg2,pyArg3,NULL);
+		if (!pyValue) 
+		{
+			cerr << PLUGIN_ERROR << "Failed to call method." << endl;
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		}
+			
+		Py_DECREF(pyMethod);
+		Py_DECREF(pyArg1);
+		Py_DECREF(pyArg2);
+		Py_DECREF(pyArg3);
+
+		m_ti.PyValue_To_rValue(pyValue,rValue);
+		if (!m_ti.error) {
+			Py_DECREF(pyValue);
+		} else {
+			cerr << PLUGIN_ERROR << m_ti.lastError().message << endl;
+			Py_CLEAR(pyValue);
+			if (m_quitOnErrorFlag) exit(EXIT_FAILURE);
+		}
+		return rValue;
+	}
+
 };
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyRealTime.cpp	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,345 @@
+#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;
+
+
+/* CONSTRUCTOR: New RealTime object from sec and nsec */
+static PyObject*
+RealTime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+	unsigned int sec = 0;
+	unsigned int nsec = 0;
+	double unary = 0;
+	const char *fmt = NULL;
+
+	if (
+	/// new RealTime from ('format',float) e.g. ('seconds',2.34123)   
+	!PyArg_ParseTuple(args, "|sd:RealTime.new ", 
+	(const char *) &fmt, 
+	(double *) &unary) 	&&
+
+	/// new RealTime from (sec{int},nsec{int}) e.g. (2,34)
+	!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); 
+	RealTimeObject *self = (RealTimeObject*)type->tp_alloc(type, 0);
+	
+	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 { 
+        /// new RealTime from seconds or milliseconds: i.e. >>>RealTime('seconds',12.3)
+		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;
+}
+
+/* DESTRUCTOR: delete type object */
+static void
+RealTimeObject_dealloc(RealTimeObject *self)
+{
+	if (self->rt) delete self->rt; 	//delete the C object
+	PyObject_Del(self); //delete the Python object (original)
+	/// this requires PyType_Ready() which fills ob_type
+	// self->ob_type->tp_free((PyObject*)self); 
+}
+
+/*					 RealTime Object's Methods 					*/ 
+//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_toString(RealTimeObject *self, PyObject *args)
+{
+	return Py_BuildValue("s",self->rt->toText().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,"Integer 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);	
+}
+
+
+/* Type object's (RealTime) methods table */
+static PyMethodDef RealTime_methods[] = 
+{
+	{"values",	(PyCFunction)RealTime_values,	METH_NOARGS,
+		PyDoc_STR("values() -> Tuple of sec,nsec representation.")},
+
+	{"toString",	(PyCFunction)RealTime_toString,	METH_NOARGS,
+		PyDoc_STR("toString() -> Return a user-readable string to the nearest millisecond in a form like HH:MM:SS.mmm")},
+
+	{"toFrame",	(PyCFunction)RealTime_toFrame,	METH_VARARGS,
+		PyDoc_STR("toFrame(samplerate) -> Sample count for given sample rate.")},
+
+	{"toFloat",	(PyCFunction)RealTime_float,	METH_NOARGS,
+		PyDoc_STR("toFloat() -> Floating point representation.")},
+	
+	{NULL,		NULL}		/* sentinel */
+};
+
+
+/*		   			 Methods implementing protocols 		   	     */ 
+// these functions are called by the interpreter 
+
+/*					 Object Protocol 					*/
+
+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;
+}
+
+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);
+}
+
+/* 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());
+}
+
+
+/*					 Number Protocol 					*/
+/// Only add and substract make sense, or what about the
+/// square root of Monday morning?
+/// Divide by integer maybe for durations?
+
+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*/
+};
+
+/*						REAL-TIME TYPE OBJECT						*/
+
+#define RealTime_alloc PyType_GenericAlloc
+#define RealTime_free PyObject_Del
+
+/* Doc:: 10.3 Type Objects */ /* static */ 
+PyTypeObject RealTime_Type = 
+{
+	PyObject_HEAD_INIT(NULL)
+	0,						/*ob_size*/
+	"vampy.RealTime",				/*tp_name*/
+	sizeof(RealTimeObject),	/*tp_basicsize*/
+	0,//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*/
+    "RealTime Object",      /*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*/
+    RealTime_alloc,         /*tp_alloc*/
+	RealTime_new,           /*tp_new*/
+    RealTime_free,			/*tp_free*/
+    0,                      /*tp_is_gc*/
+};
+
+
+
+/*		  		 	  PyRealTime C++ API  	  		  				*/
+
+/*PyRealTime from RealTime pointer
+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;
+}*/
+
+
+/*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;
+}
+
+/*RealTime* from PyRealTime*/
+const Vamp::RealTime::RealTime*
+PyRealTime_AsRealTime (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; 
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyRealTime.h	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,28 @@
+#ifndef _PYREALTIME_H_
+#define _PYREALTIME_H_
+
+#include "vamp-sdk/Plugin.h"
+
+typedef struct {
+		PyObject_HEAD
+		Vamp::RealTime::RealTime *rt;
+} RealTimeObject; 
+
+PyAPI_DATA(PyTypeObject) RealTime_Type;
+
+#define PyRealTime_CheckExact(v)	((v)->ob_type == &RealTime_Type)
+#define PyRealTime_Check(v) PyObject_TypeCheck(v, &RealTime_Type)
+///fast macro version as per API convention
+#define PyRealTime_AS_REALTIME(v) ((const RealTimeObject* const) (v))->rt
+
+/*		  		 	  PyRealTime C++ API  	  		  				*/
+
+
+PyAPI_FUNC(PyObject *) 
+PyRealTime_FromRealTime(Vamp::RealTime&);
+
+PyAPI_FUNC(const Vamp::RealTime::RealTime*) 
+PyRealTime_AsRealTime (PyObject *self);
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyTypeInterface.cpp	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,1039 @@
+/*
+*/
+
+#include <Python.h>
+#include "PyTypeInterface.h"
+#include "PyRealTime.h"
+#include "PyExtensionModule.h"
+#include <math.h>
+#include <float.h>
+#include <limits.h>
+#ifndef SIZE_T_MAX
+#define (SIZE_T_MAX (size_t) -1)
+#endif
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+using std::map;
+
+static std::map<std::string, o::eOutDescriptors> outKeys;
+static std::map<std::string, p::eParmDescriptors> parmKeys;
+static std::map<std::string, eSampleTypes> sampleKeys;
+static std::map<std::string, eFeatureFields> ffKeys;
+static bool isMapInitialised = false;
+
+/*  Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS
+	(EXCEPT FOR TEMPORARY PYOBJECTS)!  						   		*/
+
+PyTypeInterface::PyTypeInterface() : 
+	m_strict(false),
+	m_error(false),
+	m_lastError(m_noError),
+	error(m_error)
+{
+}
+
+PyTypeInterface::~PyTypeInterface()
+{
+}
+
+/// floating point numbers (TODO: check numpy.float128)
+float 
+PyTypeInterface::PyValue_To_Float(PyObject* pyValue) const
+{
+	// convert float
+	if (PyFloat_Check(pyValue)) 
+	{	
+		float rValue = (float) PyFloat_AS_DOUBLE(pyValue);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError("Error while converting float object.",m_strict);
+			return 0.0;
+		}
+		return rValue;
+	}
+
+	// in strict mode we will not try harder
+	if (m_strict) {
+		setValueError("Strict conversion error: object is not float.",m_strict);
+		return 0.0;
+	}
+	
+	// convert other objects supporting the number protocol
+	if (PyNumber_Check(pyValue)) 
+	{	
+		// PEP353: Py_ssize_t is size_t but signed !
+		// This will work up to numpy.float64
+		Py_ssize_t rValue = PyNumber_AsSsize_t(pyValue,NULL);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError("Error while converting integer object.",m_strict);
+			return 0.0;
+		}
+		if (rValue > FLT_MAX || rValue < FLT_MIN)
+		{
+			setValueError("Overflow error. Object can not be converted to float.",m_strict);
+			return 0.0;
+		}
+		return (float) rValue;
+	}
+	
+    // convert string
+	if (PyString_Check(pyValue))
+	{
+		PyObject* pyFloat = PyFloat_FromString(pyValue,NULL);
+		if (!pyFloat) 
+		{
+			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+			setValueError("String value can not be converted to float.",m_strict);
+			return 0.0;
+		}
+		float rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear(); 
+			Py_CLEAR(pyFloat);
+			setValueError("Error while converting float object.",m_strict);
+			return 0.0;
+		}
+		Py_DECREF(pyFloat);
+		return rValue;
+	}
+	
+	// convert the first element of any iterable sequence (for convenience and backwards compatibility)
+	if (PySequence_Check(pyValue) and PySequence_Size(pyValue) > 0) 
+	{
+		PyObject* item = PySequence_GetItem(pyValue,0);
+		if (item)
+		{
+			float rValue = this->PyValue_To_Float(item);
+			if (!m_error) {
+				Py_DECREF(item);
+				return rValue;
+			} else {
+				Py_CLEAR(item);
+				std::string msg = "Could not convert sequence element. " + lastError().message;
+				setValueError(msg,m_strict);
+				return 0.0;
+			}
+		}
+	}
+	
+    // give up
+	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+	std::string msg = "Conversion from " + PyValue_Get_TypeName(pyValue) + " to float is not possible.";
+	setValueError(msg,m_strict);
+	return 0.0;
+}
+
+/// size_t (unsigned integer types)
+size_t 
+PyTypeInterface::PyValue_To_Size_t(PyObject* pyValue) const
+{
+	// convert objects supporting the number protocol 
+	if (PyNumber_Check(pyValue)) 
+	{	
+		if (m_strict && !PyInt_Check(pyValue) && !PyLong_Check(pyValue)) 
+			setValueError("Strict conversion error: object is not integer type.",m_strict);
+		// Note: this function handles Bool,Int,Long,Float
+		// PEP353: Py_ssize_t is size_t but signed ! 
+		Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError("Error while converting integer object.",m_strict);
+			return 0;
+		}
+		if ((unsigned long)rValue > SIZE_T_MAX || (unsigned long)rValue < 0)
+		{
+			setValueError("Overflow error. Object can not be converted to size_t.",m_strict);
+			return 0;
+		}
+		return (size_t) rValue;
+	}
+	
+	// in strict mode we will not try harder and throw an exception
+	// then the caller should decide what to do with it
+	if (m_strict) {
+		setValueError("Strict conversion error: object is not integer.",m_strict);
+		return 0;
+	}
+	
+	// convert string
+	if (PyString_Check(pyValue))
+	{
+		PyObject* pyLong = PyNumber_Long(pyValue);
+		if (!pyLong) 
+		{
+			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+			setValueError("String object can not be converted to size_t.",m_strict);
+			return 0;
+		}
+		size_t rValue = this->PyValue_To_Size_t(pyLong);
+		if (!m_error) {
+			Py_DECREF(pyLong);
+			return rValue;
+		} else {
+			Py_CLEAR(pyLong);
+			setValueError (lastError().message,m_strict);
+			return 0;
+		}
+	}
+	
+	// convert the first element of iterable sequences
+	if (PySequence_Check(pyValue) and PySequence_Size(pyValue) > 0) 
+	{
+		PyObject* item = PySequence_GetItem(pyValue,0);
+		if (item)
+		{
+			size_t rValue = this->PyValue_To_Size_t(item);
+			if (!m_error) {
+				Py_DECREF(item);
+				return rValue;
+			} else {
+				Py_CLEAR(item);
+				std::string msg = "Could not convert sequence element. " + lastError().message;
+				setValueError(msg,m_strict);
+				return 0;
+			}
+		}
+	}
+	
+    // give up
+	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to size_t is not possible.";
+	setValueError(msg,m_strict);
+	return 0;
+}
+
+bool 
+PyTypeInterface::PyValue_To_Bool(PyObject* pyValue) const
+{
+	// convert objects supporting the number protocol
+	// Note: PyBool is a subclass of PyInt
+	if (PyNumber_Check(pyValue)) 
+	{	
+		if (m_strict && !PyBool_Check(pyValue)) 
+			setValueError
+			("Strict conversion error: object is not boolean type.",m_strict);
+
+		// Note: this function handles Bool,Int,Long,Float
+		Py_ssize_t rValue = PyInt_AsSsize_t(pyValue);
+		if (PyErr_Occurred()) 
+		{
+			PyErr_Print(); PyErr_Clear();
+			setValueError ("Error while converting boolean object.",m_strict);
+		}
+		if (rValue != 1 && rValue != 0)
+		{
+			setValueError ("Overflow error. Object can not be converted to boolean.",m_strict);
+		}
+		return (bool) rValue;
+	}
+	
+	if (m_strict) {
+		setValueError ("Strict conversion error: object is not numerical type.",m_strict);
+		return false;
+	}
+	
+	// convert iterables: the rule is the same as of the interpreter:
+	// empty sequence evaluates to False, anything else is True
+	if (PySequence_Check(pyValue)) 
+	{
+		return PySequence_Size(pyValue)?true:false;
+	}
+	
+    // give up
+	if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to boolean is not possible.";
+	setValueError(msg,m_strict);
+	return false;
+}
+
+/// string and objects that support .__str__() (TODO: check unicode objects)
+std::string 
+PyTypeInterface::PyValue_To_String(PyObject* pyValue) const
+{
+	// convert string
+	if (PyString_Check(pyValue)) 
+	{	
+		char *cstr = PyString_AS_STRING(pyValue);
+		if (!cstr) 
+		{
+			if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+			setValueError("Error while converting string object.",m_strict);
+			return std::string();
+		}
+		return std::string(cstr);
+	}
+	// TODO: deal with unicode here (argh!)
+
+	// in strict mode we will not try harder
+	if (m_strict) {
+		setValueError("Strict conversion error: object is not string.",m_strict);
+		return std::string();
+	}
+		
+	// convert list or tuple: empty lists are turned into empty strings
+	if (PyList_Check(pyValue) || PyTuple_Check(pyValue)) 
+	{
+		if (!PySequence_Size(pyValue)) return std::string();
+		PyObject* item = PySequence_GetItem(pyValue,0);
+		if (item)
+		{
+			std::string rValue = this->PyValue_To_String(item);
+			if (m_error) {
+				Py_DECREF(item);
+				return rValue;
+			} else {
+				Py_CLEAR(item);
+				std::string msg = "Could not convert sequence element. " + lastError().message;
+				setValueError(msg,m_strict);
+				return std::string();
+			}
+		}
+	}
+
+	// convert any other object that has .__str__() or .__repr__()
+	PyObject* pyString = PyObject_Str(pyValue);
+	if (pyString && !PyErr_Occurred())
+	{
+		std::string rValue = this->PyValue_To_String(pyString);
+		if (m_error) {
+			Py_DECREF(pyString);
+			return rValue;
+		} else {
+			Py_CLEAR(pyString);
+			std::string msg = "Object " + this->PyValue_Get_TypeName(pyValue) +" can not be represented as string. " + lastError().message;
+			setValueError (msg,m_strict);
+			return std::string();
+		}
+	}
+
+	// give up
+	PyErr_Print(); PyErr_Clear();
+	std::string msg = "Conversion from " + this->PyValue_Get_TypeName(pyValue) + " to string is not possible.";
+	setValueError(msg,m_strict);
+	return std::string();
+}
+
+/*			 			C Values to Py Values				  		*/
+
+
+PyObject*
+PyTypeInterface::PyValue_From_CValue(const char* cValue) const
+{
+	// returns new reference
+	if (!cValue) 
+		setValueError("Invalid pointer encountered while converting from char* .",m_strict);
+	PyObject *pyValue = PyString_FromString(cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from char* or string.",m_strict);
+		return NULL;
+	}
+	return pyValue;
+}
+
+PyObject*
+PyTypeInterface::PyValue_From_CValue(size_t cValue) const
+{
+	// returns new reference
+	PyObject *pyValue = PyInt_FromSsize_t((Py_ssize_t)cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from size_t.",m_strict);
+		return NULL;
+	}
+	return pyValue;
+}
+
+PyObject*
+PyTypeInterface::PyValue_From_CValue(double cValue) const
+{
+	// returns new reference
+	PyObject *pyValue = PyFloat_FromDouble(cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from float or double.",m_strict);
+		return NULL;
+	}
+	return pyValue;
+}
+
+PyObject*
+PyTypeInterface::PyValue_From_CValue(bool cValue) const
+{
+	// returns new reference
+	PyObject *pyValue = PyBool_FromLong((long)cValue);
+	if (!pyValue)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		setValueError("Error while converting from bool.",m_strict);
+		return NULL;
+	}
+	return pyValue;
+}
+
+
+/*			 			Sequence Types to C++ Types	    		  	*/
+
+//convert Python list to C++ vector of strings
+std::vector<std::string> 
+PyTypeInterface::PyValue_To_StringVector (PyObject *inputList) const 
+{
+	
+	std::vector<std::string> Output;
+	std::string ListElement;
+	PyObject *pyString = NULL;
+	
+	if (!PyList_Check(inputList)) return Output;
+
+	for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
+		//Get next list item (Borrowed Reference)
+		pyString = PyList_GET_ITEM(inputList,i);
+		ListElement = (string) PyString_AsString(PyObject_Str(pyString));
+		Output.push_back(ListElement);
+	}
+	return Output;
+}
+
+//convert Python list to C++ vector of floats
+std::vector<float> 
+PyTypeInterface::PyValue_To_FloatVector (PyObject *inputList) const 
+{
+	typedef std::vector<float> floatVector;
+	std::vector<float> Output;
+	
+	/// Check for NumPy Array
+	if (PyObject_HasAttrString(inputList,"__array_struct__")) {
+		int vectorLength;
+		float *dataptr = getNumPyObjectData(inputList,vectorLength);
+		if (dataptr != 0) cerr << "Numpy array found: " << vectorLength << endl;
+		// Output = *dataptr;
+	}
+	
+	float ListElement;
+	PyObject *pyFloat = NULL;
+	
+	if (!PyList_Check(inputList)) return Output; 
+
+	for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) {
+		//Get next list item (Borrowed Reference)
+		pyFloat =  PyList_GET_ITEM(inputList,k);
+		ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
+#ifdef _DEBUG
+		cerr << "value: " << ListElement << endl;
+#endif
+		Output.push_back(ListElement);
+	}
+
+	return Output;
+}
+
+
+/*			 			Vamp API Specific Types				  		
+
+Vamp::Plugin::OutputList 
+PyTypeInterface::PyValue_To_OutputList(PyObject* pyList) const
+{
+	Vamp::Plugin::OutputList list;
+	Vamp::Plugin::OutputDescriptor od;
+	
+	// Type checking
+	if (! PyList_Check(pyList) ) {
+		Py_CLEAR(pyList);
+		// cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
+		// << "] Expected List return type." << endl;
+		return list;
+	}
+	
+	//These will all be borrowed references (no need to DECREF)
+	PyObject *pyDict;
+		
+	//Parse Output List
+	for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
+		//Get i-th Vamp output descriptor (Borrowed Reference)
+		pyDict = PyList_GET_ITEM(pyList,i);
+		od = PyValue_To_OutputDescriptor(pyDict);
+		list.push_back(od);
+	}
+	return list;
+}
+
+Vamp::Plugin::ParameterList 
+PyTypeInterface::PyValue_To_ParameterList(PyObject* pyList) const
+{
+	Vamp::Plugin::ParameterList list;
+	Vamp::Plugin::ParameterDescriptor pd;
+	
+	// Type checking
+	if (! PyList_Check(pyList) ) {
+		Py_CLEAR(pyList);
+		// cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
+		// << "] Expected List return type." << endl;
+		return list;
+	}
+	
+	//These will all be borrowed references (no need to DECREF)
+	PyObject *pyDict;
+		
+	//Parse Output List
+	for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
+		//Get i-th Vamp output descriptor (Borrowed Reference)
+		pyDict = PyList_GET_ITEM(pyList,i);
+		pd = PyValue_To_ParameterDescriptor(pyDict);
+		list.push_back(pd);
+	}
+	return list;
+}
+
+Vamp::Plugin::OutputDescriptor
+PyTypeInterface::PyValue_To_OutputDescriptor(PyObject* pyDict) const
+{
+	//We only care about dictionaries holding output descriptors
+	if (!PyDict_Check(pyDict)) 
+		return Vamp::Plugin::OutputDescriptor();
+                       
+	Py_ssize_t pyPos = 0;
+	PyObject *pyKey, *pyValue;
+	initMaps();
+	Vamp::Plugin::OutputDescriptor od;
+
+	//Python Dictionary Iterator:
+	while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
+	{
+		std::string key = PyValue_To_String(pyKey);
+		SetValue(od,key,pyValue);
+		if (m_error) {
+			_lastError().location += "parameter: '" 
+			+ key +"' descriptor: '" + od.identifier + "'";
+		}
+	}
+	if (!m_errorQueue.empty()) m_error = true;
+	return od;
+}
+
+Vamp::Plugin::ParameterDescriptor
+PyTypeInterface::PyValue_To_ParameterDescriptor(PyObject* pyDict) const
+{
+	//We only care about dictionaries holding output descriptors
+	if (!PyDict_Check(pyDict)) 
+		return Vamp::Plugin::ParameterDescriptor();
+                       
+	Py_ssize_t pyPos = 0;
+	PyObject *pyKey, *pyValue;
+	initMaps();
+	Vamp::Plugin::ParameterDescriptor pd;
+
+	//Python Dictionary Iterator:
+	while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
+	{
+		std::string key = PyValue_To_String(pyKey);
+		SetValue(pd,key,pyValue);
+		if (m_error) {
+			_lastError().location += "parameter: '" 
+			+ key +"' descriptor: '" + pd.identifier + "'";
+		}
+	}
+	if (!m_errorQueue.empty()) m_error = true;
+	return pd;
+}
+ 
+Vamp::Plugin::Feature
+PyTypeInterface::PyValue_To_Feature(PyObject* pyDict) const
+{
+	//We only care about dictionaries holding output descriptors
+	if (!PyDict_Check(pyDict)) 
+		return Vamp::Plugin::Feature();
+                       
+	Py_ssize_t pyPos = 0;
+	PyObject *pyKey, *pyValue;
+	initMaps();
+	Vamp::Plugin::Feature feature;
+
+	//Python Dictionary Iterator:
+	while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
+	{
+		std::string key = PyValue_To_String(pyKey);
+		float isr = 22050.0;
+		Feature_SetValue(feature,key,pyValue,isr);
+		if (m_error) {
+			_lastError().location += "key: '" + key + "'";
+			// _lastError().location += "parameter: '" 
+			// + key +"' descriptor: '" + pd.identifier + "'";
+		}
+	}
+	if (!m_errorQueue.empty()) m_error = true;
+	return feature;
+}
+*/
+
+/// FeatureSet (an int map of OutputLists)
+Vamp::Plugin::FeatureSet
+PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const
+{
+	Vamp::Plugin::FeatureSet rFeatureSet; /// PyFeatureSet is an int map
+	if (pyValue == NULL) {
+		cerr << "NULL FeatureSet" << endl;
+		return rFeatureSet;
+	}
+
+	cerr << "PyValue_To_FeatureSet" << endl;
+	//Convert PyFeatureSet 
+	if (PyFeatureSet_CheckExact(pyValue)) { 
+		cerr << "FeatureSet Return type" << endl;
+		Py_ssize_t pyPos = 0;
+		//Borrowed References
+		PyObject *pyKey, *pyDictValue;
+		int key;
+
+			//Python Dictionary Iterator:
+			while (PyDict_Next(pyValue, &pyPos, &pyKey, &pyDictValue))
+			{
+				/// DictValue -> Vamp::FeatureList
+				key = (int) PyInt_AS_LONG(pyKey);
+				cerr << "FeatureSet key = " << key << endl;
+				/// Error checking is done at value assignment
+				PyValue_To_rValue(pyDictValue,rFeatureSet[key]);
+			}
+			if (!m_errorQueue.empty()) m_error = true;
+			return rFeatureSet;
+	}
+	cerr << "not FeatureSet Return type" << endl;
+	
+		
+	//Check return type
+	if (pyValue == NULL || !PyList_Check(pyValue) ) {
+		if (pyValue == NULL) {
+			// cerr << "ERROR: In Python plugin [" << m_class << "::" << method << "] Unexpected result." << endl;
+			if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
+		} else {
+			// cerr << "ERROR: In Python plugin [" << m_class << "::" << method << "] Expected List return type." << endl;
+		}
+		Py_CLEAR(pyValue);
+		return Vamp::Plugin::FeatureSet();
+	}
+		
+	// This will be borrowed reference
+	PyObject *pyFeatureList;
+
+	//Parse Output List for each element (FeatureSet)
+	for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyValue); ++i) {
+		//Get i-th FeatureList (Borrowed Reference)
+		pyFeatureList = PyList_GET_ITEM(pyValue,i);
+		PyValue_To_rValue(pyFeatureList,rFeatureSet[i]);
+	}
+	// Py_CLEAR(pyOutputList);
+	return rFeatureSet;
+}
+
+Vamp::RealTime::RealTime
+PyTypeInterface::PyValue_To_RealTime(PyObject* pyValue) const
+{
+// We accept integer sample counts (for backwards compatibility)
+// or PyRealTime objects and convert them to Vamp::RealTime
+	
+	if (PyRealTime_CheckExact(pyValue))
+	{
+#ifdef _DEBUG
+		cerr << "Converting from PyRealTime" << endl;
+#endif
+		/// just create a copy of the wrapped object
+		return Vamp::RealTime::RealTime(
+			*PyRealTime_AS_REALTIME(pyValue));
+	}
+	// assume integer sample count
+	long sampleCount = PyLong_AsLong(pyValue);
+	if (PyErr_Occurred()) 
+	{
+		PyErr_Print(); PyErr_Clear();
+		setValueError("Error while converting integer to RealTime.",m_strict);
+		return Vamp::RealTime::RealTime();
+	}
+#ifdef _DEBUG
+	Vamp::RealTime::RealTime rt = 
+		Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate );
+	cerr << "RealTime: " << (long)sampleCount << ", ->" << rt.toString() << endl;
+	return rt;
+#else
+	return Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate );	
+#endif
+
+}
+
+
+/// OutputDescriptor
+void
+PyTypeInterface::SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const
+{
+	switch (outKeys[key])
+	{
+		case o::not_found:
+			cerr << "Unknown key in Vamp OutputDescriptor: " << key << endl;
+			break;
+			case o::identifier: 
+			_convert(pyValue,od.identifier);
+			break;				
+		case o::name: 			
+			_convert(pyValue,od.name);
+			break;
+		case o::description:
+			_convert(pyValue,od.description);
+			break;
+		case o::unit:
+			_convert(pyValue,od.unit);
+			break;
+		case o::hasFixedBinCount:
+			_convert(pyValue,od.hasFixedBinCount);
+			break;
+		case o::binCount:
+			_convert(pyValue,od.binCount);
+			break;
+		case o::binNames:
+			_convert(pyValue,od.binNames);
+			break;
+		case o::hasKnownExtents:
+			_convert(pyValue,od.hasKnownExtents);
+			break;
+		case o::minValue:
+			_convert(pyValue,od.minValue);
+			break;
+		case o::maxValue:
+			_convert(pyValue,od.maxValue);
+			break;
+		case o::isQuantized:
+			_convert(pyValue,od.isQuantized);
+			break;					
+		case o::quantizeStep:
+			_convert(pyValue,od.quantizeStep);
+			break;
+		case o::sampleType:
+			// implements specific conversion!
+			od.sampleType = (Vamp::Plugin::OutputDescriptor::SampleType) sampleKeys[PyValue_To_String(pyValue)];
+			break;
+		case o::sampleRate:
+			_convert(pyValue,od.sampleRate);
+			break;
+		case o::hasDuration:
+			_convert(pyValue,od.hasDuration);
+			break;
+		default:
+			cerr << "Invalid key in Vamp OutputDescriptor: " << key << endl; 
+	}
+}
+
+/// ParameterDescriptor
+void
+PyTypeInterface::SetValue(Vamp::Plugin::ParameterDescriptor& pd, std::string& key, PyObject* pyValue) const
+{
+	switch (parmKeys[key]) 
+	{
+		case p::not_found : 	
+			cerr << "Unknown key in Vamp ParameterDescriptor: " << key << endl; 
+			break;
+		case p::identifier:
+			_convert(pyValue,pd.identifier);
+			break;				
+		case p::name:
+			_convert(pyValue,pd.name);
+			break;
+		case p::description: 	
+			_convert(pyValue,pd.description);
+			break; 								
+		case p::unit:
+			_convert(pyValue,pd.unit);
+			break; 																		
+		case p::minValue:	
+			_convert(pyValue,pd.minValue);
+			break;
+		case p::maxValue:
+			_convert(pyValue,pd.maxValue);
+			break;
+		case p::defaultValue:
+			_convert(pyValue,pd.defaultValue);
+			break;
+		case p::isQuantized:
+			_convert(pyValue,pd.isQuantized);
+			break;									
+		case p::quantizeStep:
+			_convert(pyValue,pd.quantizeStep);
+			break;
+		default : 	
+			cerr << "Invalid key in Vamp ParameterDescriptor: " << key << endl; 
+	}
+}
+
+/// Feature (it's like a Descriptor)
+bool
+PyTypeInterface::SetValue(Vamp::Plugin::Feature& feature, std::string& key, PyObject* pyValue) const
+{
+	bool found = true;
+	switch (ffKeys[key])
+	{
+		case unknown :
+			cerr << "Unknown key in Vamp Feature: " << key << endl; 
+			found = false;
+			break;
+		case hasTimestamp:
+			_convert(pyValue,feature.hasTimestamp);
+			break;				
+		case timeStamp:
+			_convert(pyValue,feature.timestamp);
+			break;
+		case hasDuration: 	
+			_convert(pyValue,feature.hasDuration);
+			break;
+		case duration:
+			_convert(pyValue,feature.duration);
+			break;
+		case values:
+			_convert(pyValue,feature.values);
+			break; 								
+		case label:
+			_convert(pyValue,feature.label);
+			break;
+		default:
+			found = false;
+	}
+	return found;
+}
+
+/*
+/// Feature (it's like a Descriptor)
+bool
+PyTypeInterface::GetValue(Vamp::Plugin::Feature& feature, std::string& key, PyObject* pyValue) const
+{
+	bool found = true;
+	switch (ffKeys[key])
+	{
+		case unknown :
+			cerr << "Unknown key in Vamp Feature: " << key << endl; 
+			found = false;
+			break;
+		case hasTimestamp:
+			_convert(pyValue,feature.hasTimestamp);
+			// pyValue = PyValue_From_CValue(feature.hasTimestamp)
+			break;				
+		case timeStamp:
+			_convert(pyValue,feature.timestamp);
+			break;
+		case hasDuration: 	
+			_convert(pyValue,feature.hasDuration);
+			break;
+		case duration:
+			_convert(pyValue,feature.duration);
+			break;
+		case values:
+			_convert(pyValue,feature.values);
+			break; 								
+		case label:
+			_convert(pyValue,feature.label); //vector<string>
+			break;
+		default:
+			found = false;
+	}
+	return found;
+}
+*/
+
+/*			   			  	Error handling		   			  		*/
+
+void
+PyTypeInterface::setValueError (std::string message, bool strict) const
+{
+	m_error = true;
+	m_errorQueue.push(ValueError(message,strict));
+}
+
+/// return a reference to the last error or creates a new one.
+PyTypeInterface::ValueError&
+PyTypeInterface::_lastError() const 
+{
+	m_error = false;
+	if (!m_errorQueue.empty()) return m_errorQueue.back();
+	else {
+		m_errorQueue.push(ValueError("Type conversion error.",m_strict));
+		return m_errorQueue.back();
+	}
+}
+
+/// return the last error message and clear the error flag
+const PyTypeInterface::ValueError&
+PyTypeInterface::lastError() const 
+{
+	// PyTypeInterface *self = const_cast<PyTypeInterface*> (this);
+	m_error = false;
+	if (!m_errorQueue.empty()) return m_errorQueue.back();
+	else return m_noError;
+}
+
+/// iterate over the error message queue and pop the oldest item
+PyTypeInterface::ValueError 
+PyTypeInterface::getError() const
+{
+	if (!m_errorQueue.empty()) {
+		PyTypeInterface::ValueError e = m_errorQueue.front();
+		m_errorQueue.pop();
+		if (m_errorQueue.empty()) m_error = false;
+		return e;
+	}
+	else {
+		m_error = false;
+		return PyTypeInterface::ValueError();
+	}
+}
+
+/*			   			  	Utilities						  		*/
+
+//return a pointer to the data in the numPy array
+float* 
+PyTypeInterface::getNumPyObjectData(PyObject *object, int &length) const
+{
+
+	char attr_name[]="__array_struct__";
+
+	//check if we passed in a NumPy array object
+	if (!PyObject_HasAttrString(object,attr_name)) {
+		// PyErr_SetString(PyExc_TypeError,
+		// "Input object has no __array_struct__ attribute. NumPy array required.");
+		return NULL;		
+	}
+
+	//retrieve __array_struct__ interface
+	object = PyObject_GetAttrString(object,attr_name);	
+
+	//check whether we found CObjects
+	if (!PyCObject_Check(object)) {
+		PyErr_SetString(PyExc_TypeError,
+		"The passed __array_struct__ interface is not a valid C Object.");
+		return NULL; 
+	}
+
+
+	//check if the pointers directed to the integer '2'
+	int *check = (int *) PyCObject_AsVoidPtr (object);
+
+	if (*check != 2 ) {
+		PyErr_SetString(PyExc_TypeError,
+		"A C Object __array_struct__ required as inputs");
+		return NULL; 
+	}
+
+	//convert CObjects to Array interfaces
+	PyArrayInterface *arrayInterface = 
+	(PyArrayInterface *) PyCObject_AsVoidPtr (object);
+
+	//check array dimension: should be 1
+	int inputDim = arrayInterface->nd;
+	
+	if (inputDim > 1 ) {
+		PyErr_SetString(PyExc_TypeError,
+		"Array dimensions must not exceed one.");
+		return NULL;		
+	}
+
+	// check if vector size is sane	
+	Py_intptr_t arrayLength = arrayInterface->shape[0];
+	length = (int) arrayLength;
+	
+	// if (arrayLength < 8 || arrayLength > 65536 ) {
+	// 	PyErr_SetString(PyExc_TypeError,
+	// 	"Array length is out of bounds.");
+	// 	return NULL;		
+	// 	}
+
+	//check type; must be float32
+	char arrayType = arrayInterface->typekind;
+
+	if (arrayType != 'f' ) {
+		PyErr_SetString(PyExc_TypeError,
+		"Floating point arrays required.");
+		return NULL;		
+	}
+
+	//return data vector address
+	return (float*) arrayInterface->data;
+	
+}
+
+/// get the type name of an object
+std::string
+PyTypeInterface::PyValue_Get_TypeName(PyObject* pyValue) const
+{
+	PyObject *pyType = PyObject_Type(pyValue);
+	if (!pyType) return std::string ("< unknown type >");
+	PyObject *pyString = PyObject_Str(pyType);
+	if (!pyString)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		Py_CLEAR(pyType);
+		return std::string ("< unknown type >");
+	}
+	char *cstr = PyString_AS_STRING(pyString);
+	if (!cstr)
+	{
+		if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
+		Py_DECREF(pyType);
+		Py_CLEAR(pyString);
+		cerr << "Warning: Object type name could not be found." << endl;
+		return std::string("< unknown type >");
+	}
+	Py_DECREF(pyType);
+	Py_DECREF(pyString);
+	return std::string(cstr);
+}
+
+bool
+PyTypeInterface::initMaps() const
+{
+
+	if (isMapInitialised) return true;
+
+	outKeys["identifier"] = o::identifier;
+	outKeys["name"] = o::name;
+	outKeys["description"] = o::description;
+	outKeys["unit"] = o::unit;
+	outKeys["hasFixedBinCount"] = o::hasFixedBinCount; 
+	outKeys["binCount"] = o::binCount;
+	outKeys["binNames"] = o::binNames;
+	outKeys["hasKnownExtents"] = o::hasKnownExtents;
+	outKeys["minValue"] = o::minValue;
+	outKeys["maxValue"] = o::maxValue;
+	outKeys["isQuantized"] = o::isQuantized;
+	outKeys["quantizeStep"] = o::quantizeStep;
+	outKeys["sampleType"] = o::sampleType;
+	outKeys["sampleRate"] = o::sampleRate;
+	outKeys["hasDuration"] = o::hasDuration;
+
+	sampleKeys["OneSamplePerStep"] = OneSamplePerStep;
+	sampleKeys["FixedSampleRate"] = FixedSampleRate;
+	sampleKeys["VariableSampleRate"] = VariableSampleRate;
+
+	ffKeys["hasTimestamp"] = hasTimestamp;
+	ffKeys["timeStamp"] = timeStamp;
+	ffKeys["hasDuration"] = hasDuration;
+	ffKeys["duration"] = duration;
+	ffKeys["values"] = values;
+	ffKeys["label"] = label;
+
+	parmKeys["identifier"] = p::identifier;
+	parmKeys["name"] = p::name;
+	parmKeys["description"] = p::description;
+	parmKeys["unit"] = p::unit;
+	parmKeys["minValue"] = p::minValue;
+	parmKeys["maxValue"] = p::maxValue;
+	parmKeys["defaultValue"] = p::defaultValue;
+	parmKeys["isQuantized"] = p::isQuantized;
+	parmKeys["quantizeStep"] = p::quantizeStep;
+
+	isMapInitialised = true;
+	return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyTypeInterface.h	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,304 @@
+/*
+
+Type safe conversion utilities from Python types to C/C++ types,
+mainly using Py/C API macros.
+
+*/
+
+#ifndef _PY_TYPE_INTERFACE_H_
+#define _PY_TYPE_INTERFACE_H_
+
+#include "vamp-sdk/Plugin.h"
+#include <Python.h>
+#include "PyExtensionModule.h"
+#include <vector>
+#include <queue>
+#include <string>
+//#include <typeinfo>
+
+
+using std::cerr;
+using std::endl;
+
+namespace o {
+enum eOutDescriptors {
+	not_found,
+	identifier,
+	name,
+	description,
+	unit, 
+	hasFixedBinCount,
+	binCount,
+	binNames,
+	hasKnownExtents,
+	minValue,
+	maxValue,
+	isQuantized,
+	quantizeStep,
+	sampleType,	
+	sampleRate,
+	hasDuration,
+	endNode
+	}; 
+}
+
+namespace p {
+enum eParmDescriptors {
+	not_found,
+	identifier,
+	name,
+	description,
+	unit, 
+	minValue,
+	maxValue,
+	defaultValue,
+	isQuantized,
+	quantizeStep
+	};
+}
+
+enum eSampleTypes {
+	OneSamplePerStep,
+	FixedSampleRate,
+	VariableSampleRate
+	};
+
+enum eFeatureFields {
+	unknown,
+	hasTimestamp,
+	timeStamp,
+	hasDuration,
+	duration,
+	values,
+	label
+	};
+
+
+/// sutructure of NumPy array interface:
+/// this is all we need to support numpy without direct dependency
+typedef struct {
+    int two;              /* contains the integer 2 -- simple sanity check */
+    int nd;               /* number of dimensions */
+    char typekind;        /* kind in array --- character code of typestr */
+    int itemsize;         /* size of each element */
+    int flags;            /* flags indicating how the data should be interpreted */
+                          /*   must set ARR_HAS_DESCR bit to validate descr */
+    Py_intptr_t *shape;   /* A length-nd array of shape information */
+    Py_intptr_t *strides; /* A length-nd array of stride information */
+    void *data;           /* A pointer to the first element of the array */
+    PyObject *descr;      /* NULL or data-description (same as descr key */
+                          /*        of __array_interface__) -- must set ARR_HAS_DESCR */
+                          /*        flag or this will be ignored. */
+} PyArrayInterface;
+
+/* C++ mapping of PyNone Type*/
+typedef struct NoneType {};
+
+class PyTypeInterface
+{
+public:
+	PyTypeInterface();
+	~PyTypeInterface();
+	
+	// Data
+	class ValueError
+	{
+	public:
+		ValueError() {}
+		ValueError(std::string m, bool s) : message(m),strict(s) {}
+		std::string location;
+		std::string message;
+		bool strict;
+		std::string get() const { return message + "\nLocation: " + location + "\n";}
+		void print() const { cerr << get(); }
+	};
+	
+	// Utilities
+	void setStrictTypingFlag(bool b) {m_strict = b;}
+	const ValueError &lastError() const;
+	ValueError getError() const;
+	std::string PyValue_Get_TypeName(PyObject*) const;
+	bool initMaps() const;
+
+	// Basic type conversion: Python to C++ 
+	float 	PyValue_To_Float(PyObject*) const;
+	size_t 	PyValue_To_Size_t(PyObject*) const;
+	bool 	PyValue_To_Bool(PyObject*) const;
+	std::string PyValue_To_String(PyObject*) const;
+	// int PyValue_To_Int(PyObject*) const;
+	
+	// C++ to Python
+	PyObject *PyValue_From_CValue(const char*) const;
+	PyObject *PyValue_From_CValue(const std::string& x) const { return PyValue_From_CValue(x.c_str()); }
+	PyObject *PyValue_From_CValue(size_t) const;
+	PyObject *PyValue_From_CValue(double) const;
+	PyObject *PyValue_From_CValue(float x) const { return PyValue_From_CValue((double)x); }
+	PyObject *PyValue_From_CValue(bool) const;
+	
+	// Sequence types
+	std::vector<std::string> PyValue_To_StringVector (PyObject*) const;
+	std::vector<float> PyValue_To_FloatVector (PyObject*) const;
+
+	// Numpy types
+	float* getNumPyObjectData(PyObject *object, int &length) const; 
+	
+
+/* 						Template functions 							*/
+
+
+	/// Common wrappers to set a value in one of these structs. (to be used in template functions)
+	void SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const;
+	void SetValue(Vamp::Plugin::ParameterDescriptor& od, std::string& key, PyObject* pyValue) const;
+	bool SetValue(Vamp::Plugin::Feature& od, std::string& key, PyObject* pyValue) const;
+    PyObject* GetDescriptor_As_Dict(PyObject* pyValue) const 
+	{
+		if PyFeature_CheckExact(pyValue) return PyFeature_AS_DICT(pyValue);
+		if PyOutputDescriptor_CheckExact(pyValue) return PyOutputDescriptor_AS_DICT(pyValue);
+		if PyParameterDescriptor_CheckExact(pyValue) return PyParameterDescriptor_AS_DICT(pyValue);
+		return NULL;
+	}
+	
+
+	template<typename RET> 
+	RET PyTypeInterface::PyValue_To_VampDescriptor(PyObject* pyValue) const
+	//returns e.g. Vamp::Plugin::OutputDescriptor or Vamp::Plugin::Feature
+	{
+		PyObject* pyDict;
+
+		// Descriptors encoded as dicts
+		pyDict = GetDescriptor_As_Dict(pyValue);
+		if (!pyDict) pyDict = pyValue;
+	
+		// TODO: support full mapping protocol as fallback.
+		if (!PyDict_Check(pyDict)) {
+			setValueError("Error while converting descriptor or feature object.\nThe value is neither a dictionary nor a Vamp Feature or Descriptor type.",m_strict);
+			return RET();
+		}
+
+		Py_ssize_t pyPos = 0;
+		PyObject *pyKey, *pyDictValue;
+		initMaps();
+		RET rd;
+
+		//Python Dictionary Iterator:
+		while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyDictValue))
+		{
+			std::string key = PyValue_To_String(pyKey);
+			SetValue(rd,key,pyDictValue);
+			if (m_error) {
+				_lastError().location += "parameter: '" + key + "'";//"' descriptor: '" + rd.identifier + "'";
+			}
+		}
+		if (!m_errorQueue.empty()) m_error = true;
+		return rd;
+	}
+
+	/// Convert a sequence (tipically list) of PySomething to 
+	/// OutputList,ParameterList or FeatureList
+	template<typename RET,typename ELEM> //<OutputList> <OutputDescriptor>
+	RET PyTypeInterface::PyValue_To_VampList(PyObject* pyList) const
+	{
+		// Vamp::Plugin::OutputList list;
+		// Vamp::Plugin::OutputDescriptor od;
+		RET list;
+		ELEM element;
+
+		// Type checking
+		if (! PyList_Check(pyList) ) {
+			Py_CLEAR(pyList);
+			// cerr << "ERROR: In Python plugin [" << m_class << "::" << method 
+			// << "] Expected List return type." << endl;
+			return list;
+		}
+
+		//This reference will be borrowed
+		PyObject *pyDict;
+
+		//Parse Output List
+		for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
+			//Get i-th Vamp output descriptor (Borrowed Reference)
+			pyDict = PyList_GET_ITEM(pyList,i);
+			element = PyValue_To_VampDescriptor<ELEM>(pyDict);
+			// Check for empty Feature/Descriptor as before?
+			list.push_back(element);
+		}
+		return list;
+	}
+
+	
+	//Vamp specific types
+
+	Vamp::Plugin::FeatureSet PyValue_To_FeatureSet(PyObject*) const;
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureSet &r) const
+		{ r = this->PyValue_To_FeatureSet(pyValue); }
+
+	Vamp::RealTime::RealTime PyValue_To_RealTime(PyObject*) const;
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::RealTime::RealTime &r) const
+		{ r = this->PyValue_To_RealTime(pyValue); }
+	
+	
+	/* Overloaded PyValue_To_rValue() to support generic functions */
+	inline void PyValue_To_rValue(PyObject *pyValue, float &defValue) const 
+		{ float tmp = this->PyValue_To_Float(pyValue);                                              
+			if(!m_error) defValue = tmp; }
+	inline void PyValue_To_rValue(PyObject *pyValue, size_t &defValue) const
+		{ size_t tmp = this->PyValue_To_Size_t(pyValue); 
+			if(!m_error) defValue = tmp; }
+	inline void PyValue_To_rValue(PyObject *pyValue, bool &defValue) const
+		{ bool tmp = this->PyValue_To_Bool(pyValue); 
+			if(!m_error) defValue = tmp; }
+	inline void PyValue_To_rValue(PyObject *pyValue, std::string &defValue) const
+		{ std::string tmp = this->PyValue_To_String(pyValue); 
+			if(!m_error) defValue = tmp; }
+	/*used by templates where we expect no return value, if there is one it will be ignored*/			
+	inline void PyValue_To_rValue(PyObject *pyValue, NoneType &defValue) const
+		{ if (m_strict && pyValue != Py_None) 
+				setValueError("Strict conversion error: expected 'None' type.",m_strict); 
+		}
+
+	/* convert sequence types to Vamp List types */			
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::OutputList &r) const
+		{ r = this->PyValue_To_VampList<Vamp::Plugin::OutputList,Vamp::Plugin::OutputDescriptor>(pyValue); }
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::ParameterList &r) const
+		{ r = this->PyValue_To_VampList<Vamp::Plugin::ParameterList,Vamp::Plugin::ParameterDescriptor>(pyValue); }
+	inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureList &r) const
+		{ r = this->PyValue_To_VampList<Vamp::Plugin::FeatureList,Vamp::Plugin::Feature>(pyValue); }
+	
+	/// this is only needed for RealTime->Frame conversion
+	void setInputSampleRate(float inputSampleRate)
+		{ m_inputSampleRate = (unsigned int) inputSampleRate; }
+	
+private:
+	bool m_strict;
+	ValueError m_noError;
+	mutable bool m_error;
+	mutable ValueError& m_lastError;
+	mutable std::queue<ValueError> m_errorQueue;
+	// we only use it for RealTime conversion which requires unsigned int
+	unsigned int m_inputSampleRate; 
+	
+	void setValueError(std::string,bool) const;
+	ValueError& _lastError() const;
+
+	/* Overloaded _convert(), bypasses error checking to avoid doing it twice in internals. */
+	inline void _convert(PyObject *pyValue,float &r) const 
+		{ r = PyValue_To_Float(pyValue); }
+	inline void _convert(PyObject *pyValue,size_t &r) const 
+		{ r = PyValue_To_Size_t(pyValue); }
+    inline void _convert(PyObject *pyValue,bool &r) const 
+		{ r = PyValue_To_Bool(pyValue); }
+	inline void _convert(PyObject *pyValue,std::string &r) const
+		{ r = PyValue_To_String(pyValue); }
+	inline void _convert(PyObject *pyValue,std::vector<std::string> &r) const
+		{ r = PyValue_To_StringVector(pyValue); }
+	inline void _convert(PyObject *pyValue,std::vector<float> &r) const
+		{ r = PyValue_To_FloatVector(pyValue); }
+    inline void _convert(PyObject *pyValue,Vamp::RealTime::RealTime &r) const 
+		{ r = PyValue_To_RealTime(pyValue); }
+	
+public:
+	const bool& error;
+
+};
+
+#endif
\ No newline at end of file
--- a/pyvamp-main.cpp	Tue Aug 25 08:49:22 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,224 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
-
-/**
- * This Vamp plugin is a wrapper for Python Scripts. (VamPy)
- * Centre for Digital Music, Queen Mary, University of London.
- * Copyright 2008, George Fazekas.
- */
-
-#include <Python.h>
-#include "vamp/vamp.h"
-#include "vamp-sdk/PluginAdapter.h"
-#include "PyPlugScanner.h"
-#include "PyPlugin.h"
-
-#ifdef _WIN32
-#define pathsep ('\\')
-#include <windows.h>
-#include <tchar.h>
-#else 
-#define pathsep ('/')
-#include <dirent.h>
-#include <dlfcn.h>
-#endif
-
-using std::cerr;
-using std::endl;
-using std::string;
-using std::vector;
-
-//volatile bool mutex = false;
-static int adinstcount;
-
-class PyPluginAdapter : public Vamp::PluginAdapterBase
-{
-public: 
-    PyPluginAdapter(std::string pyPlugId, PyObject* pyClass) :
-        PluginAdapterBase(),
-        m_plug(pyPlugId),		
-        m_pyClass(pyClass)
-    { 
-        cerr << "PyPluginAdapter:ctor:"<< adinstcount << ": " << m_plug << endl; 
-        adinstcount++;
-        m_instanceCount = 0;
-    }
-    
-    ~PyPluginAdapter() 
-    {
-    }
-    
-protected:
-    Vamp::Plugin *createPlugin(float inputSampleRate)
-    {
-        try {
-            PyPlugin *plugin = new PyPlugin(m_plug, inputSampleRate, m_pyClass);
-            m_instanceCount++;
-            return plugin;
-        } catch (...) {
-            cerr << "PyPluginAdapter::createPlugin: Failed to construct PyPlugin" << endl;
-            return 0;
-        }
-    }
-    
-    std::string m_plug;
-    bool m_haveInitialized;
-    PyObject *m_pyClass;
-    int m_instanceCount;
-};
-
-
-static std::vector<PyPluginAdapter *> adapters;
-static bool haveScannedPlugins = false;
-
-static bool tryPreload(string name)
-{
-    cerr << "Trying to load Python interpreter library \"" << name << "\"...";
-#ifdef _WIN32
-    void *lib = LoadLibrary(name.c_str());
-    if (!lib) {
-        cerr << " failed" << endl;
-        return false;
-    }
-#else
-    void *lib = dlopen(name.c_str(), RTLD_NOW | RTLD_GLOBAL);
-    if (!lib) {
-        cerr << " failed" << endl;
-        return false;
-    }
-#endif
-    cerr << " succeeded" << endl;
-    return true;
-}
-
-static bool preloadPython()
-{
-#ifdef _WIN32
-    // this doesn't seem to be necessary at all on Windows
-    return true;
-#endif
-
-    string pyver = Py_GetVersion();
-    int dots = 2;
-    string shortver;
-    for (size_t i = 0; i < pyver.length(); ++i) {
-        if (pyver[i] == '.') {
-            if (--dots == 0) {
-                shortver = pyver.substr(0, i);
-                break;
-            }
-        }
-    }
-    cerr << "Short version: " << shortver << endl;
-
-    vector<string> pfxs;
-    pfxs.push_back("");
-    pfxs.push_back(string(Py_GetExecPrefix()) + "/lib/");
-    pfxs.push_back(string(Py_GetExecPrefix()) + "/");
-    pfxs.push_back("/usr/lib/");
-    pfxs.push_back("/usr/local/lib/");
-    char buffer[5];
-
-    // hahaha! grossness is like a brother to us
-#ifdef __APPLE__
-    for (size_t pfxidx = 0; pfxidx < pfxs.size(); ++pfxidx) {
-        for (int minor = 8; minor >= 0; --minor) {
-            sprintf(buffer, "%d", minor);
-            if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".dylib." + buffer)) return true;
-        }
-        if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".dylib")) return true;
-        if (tryPreload(pfxs[pfxidx] + string("libpython.dylib"))) return true;
-    }
-#else
-    for (size_t pfxidx = 0; pfxidx < pfxs.size(); ++pfxidx) {
-        for (int minor = 8; minor >= 0; --minor) {
-            sprintf(buffer, "%d", minor);
-            if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".so." + buffer)) return true;
-        }
-        if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".so")) return true;
-        if (tryPreload(pfxs[pfxidx] + string("libpython.so"))) return true;
-    }
-#endif
-        
-    return false;
-}
-
-/* This doesn't work: don't try it again.
-static bool initPython()
-{
-	// preloadPython();
-	Py_Initialize();
-#ifndef _WIN32
-	//set dlopen flags form Python 
-	string pyCmd = "from sys import setdlopenflags\nimport dl\nsetdlopenflags(dl.RTLD_NOW|dl.RTLD_GLOBAL)\n";
-	if (PyRun_SimpleString(pyCmd.c_str()) == -1) 
-	{   
-	    cerr << "Warning: Could not set dlopen flasgs. Dynamic loading in scripts will fail." << endl;
-		return false;
-	}
-#endif	
-	PyEval_InitThreads();			
-	return Py_IsInitialized();
-}    
-*/
-
-const VampPluginDescriptor 
-*vampGetPluginDescriptor(unsigned int version,unsigned int index)
-{	
-    if (version < 1) return 0;
-
-	int isPythonInitialized = Py_IsInitialized();
-	cerr << "# isPythonInitialized: " << isPythonInitialized << endl;
-	cerr << "# haveScannedPlugins: " << haveScannedPlugins << endl;
-
-	if (!haveScannedPlugins) {
-
-		if (!isPythonInitialized){
-
-			if (!preloadPython())
-				cerr << "Warning: Could not preload Python. Dynamic loading in scripts will fail." << endl;
-			Py_Initialize();
-		    cerr << "# isPythonInitialized after initialize: " << Py_IsInitialized() << endl;
-			// PyEval_InitThreads(); //not sure why this was needed
-		}
-
-		vector<string> pyPlugs;
-		vector<string> pyPath;
-		vector<PyObject *> pyClasses;
-		static PyPlugScanner *scanner;
-		
-		//Scanning Plugins
-		cerr << "Scanning PyPlugins" << endl;
-		scanner = PyPlugScanner::getInstance();
-		pyPath=scanner->getAllValidPath();
-		//add this as extra path for development
-		//pyPath.push_back("/Users/Shared/Development/vamp-experiments");
-		scanner->setPath(pyPath);
-		pyPlugs = scanner->getPyPlugs();
-		cerr << "Found " << pyPlugs.size() << " Scripts ...OK" << endl;
-		//TODO: this will support multiple classes per script
-		pyClasses = scanner->getPyClasses();
-		cerr << "Found " << pyClasses.size() << " Classes ...OK" << endl;
-
-		for (size_t i = 0; i < pyPlugs.size(); ++i) {
-			adapters.push_back( new PyPluginAdapter(pyPlugs[i],pyClasses[i]));
-		} 
-		haveScannedPlugins=true;		
-		
-	}
-
-	cerr << "Accessing adapter index: " << index << " (adapters: " << adapters.size() << ")" << endl;
-	if (index<adapters.size()) {
-		const VampPluginDescriptor *tmp = adapters[index]->getDescriptor();
-		return tmp;
-	} else return 0;
-
-	
-}
-
-
-
-
-
-
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vampy-main.cpp	Sun Sep 20 17:31:20 2009 +0000
@@ -0,0 +1,248 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/**
+ * This Vamp plugin is a wrapper for Python Scripts. (VamPy)
+ * Centre for Digital Music, Queen Mary, University of London.
+ * Copyright 2008, George Fazekas.
+ */
+
+#include <Python.h>
+#include "vamp/vamp.h"
+#include "vamp-sdk/PluginAdapter.h"
+#include "PyPlugScanner.h"
+#include "PyPlugin.h"
+// #include "host/pyRealTime.h"
+#include "PyExtensionModule.h"
+
+
+#ifdef _WIN32
+#define pathsep ('\\')
+#include <windows.h>
+#include <tchar.h>
+#else 
+#define pathsep ('/')
+#include <dirent.h>
+#include <dlfcn.h>
+#endif
+
+using std::cerr;
+using std::endl;
+using std::string;
+using std::vector;
+
+
+//volatile bool mutex = false;
+static int adinstcount;
+static int totinstcount;
+
+class PyPluginAdapter : public Vamp::PluginAdapterBase
+{
+public: 
+    PyPluginAdapter(std::string pyPlugId, PyObject* pyClass) :
+        PluginAdapterBase(),
+        m_plug(pyPlugId),		
+        m_pyClass(pyClass)
+    { 
+        cerr << "PyPluginAdapter:ctor:"<< adinstcount << ": " << m_plug << endl; 
+        adinstcount++;
+        m_instanceCount = 0;
+    }
+    
+    ~PyPluginAdapter() 
+    {
+    }
+    
+protected:
+    Vamp::Plugin *createPlugin(float inputSampleRate)
+    {
+        try {
+            PyPlugin *plugin = new PyPlugin(m_plug, inputSampleRate, m_pyClass, totinstcount);
+            // m_instanceCount++; /// do this in the ctors
+            return plugin;
+        } catch (...) {
+            cerr << "PyPluginAdapter::createPlugin: Failed to construct PyPlugin" << endl;
+            return 0;
+        }
+    }
+    
+    std::string m_plug;
+    bool m_haveInitialized;
+    PyObject *m_pyClass;
+    int m_instanceCount;
+};
+
+
+static std::vector<PyPluginAdapter *> adapters;
+static bool haveScannedPlugins = false;
+static bool haveVampyInitialised = false;
+
+static bool tryPreload(string name)
+{
+    cerr << "Trying to load Python interpreter library \"" << name << "\"...";
+#ifdef _WIN32
+    void *lib = LoadLibrary(name.c_str());
+    if (!lib) {
+        cerr << " failed" << endl;
+        return false;
+    }
+#else
+    void *lib = dlopen(name.c_str(), RTLD_NOW | RTLD_GLOBAL);
+    if (!lib) {
+        cerr << " failed" << endl;
+        return false;
+    }
+#endif
+    cerr << " succeeded" << endl;
+    return true;
+}
+
+static bool preloadPython()
+{
+#ifdef _WIN32
+    // this doesn't seem to be necessary at all on Windows
+    return true;
+#endif
+
+    string pyver = Py_GetVersion();
+    int dots = 2;
+    string shortver;
+    for (size_t i = 0; i < pyver.length(); ++i) {
+        if (pyver[i] == '.') {
+            if (--dots == 0) {
+                shortver = pyver.substr(0, i);
+                break;
+            }
+        }
+    }
+    cerr << "Short version: " << shortver << endl;
+
+    vector<string> pfxs;
+    pfxs.push_back("");
+    pfxs.push_back(string(Py_GetExecPrefix()) + "/lib/");
+    pfxs.push_back(string(Py_GetExecPrefix()) + "/");
+    pfxs.push_back("/usr/lib/");
+    pfxs.push_back("/usr/local/lib/");
+    char buffer[5];
+
+    // hahaha! grossness is like a brother to us
+#ifdef __APPLE__
+    for (size_t pfxidx = 0; pfxidx < pfxs.size(); ++pfxidx) {
+        for (int minor = 8; minor >= 0; --minor) {
+            sprintf(buffer, "%d", minor);
+            if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".dylib." + buffer)) return true;
+        }
+        if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".dylib")) return true;
+        if (tryPreload(pfxs[pfxidx] + string("libpython.dylib"))) return true;
+    }
+#else
+    for (size_t pfxidx = 0; pfxidx < pfxs.size(); ++pfxidx) {
+        for (int minor = 8; minor >= 0; --minor) {
+            sprintf(buffer, "%d", minor);
+            if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".so." + buffer)) return true;
+        }
+        if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".so")) return true;
+        if (tryPreload(pfxs[pfxidx] + string("libpython.so"))) return true;
+    }
+#endif
+        
+    return false;
+}
+
+/* This doesn't work: don't try it again.
+static bool initPython()
+{
+	// preloadPython();
+	Py_Initialize();
+#ifndef _WIN32
+	//set dlopen flags form Python 
+	string pyCmd = "from sys import setdlopenflags\nimport dl\nsetdlopenflags(dl.RTLD_NOW|dl.RTLD_GLOBAL)\n";
+	if (PyRun_SimpleString(pyCmd.c_str()) == -1) 
+	{   
+	    cerr << "Warning: Could not set dlopen flasgs. Dynamic loading in scripts will fail." << endl;
+		return false;
+	}
+#endif	
+	PyEval_InitThreads();			
+	return Py_IsInitialized();
+}    
+*/
+
+const VampPluginDescriptor 
+*vampGetPluginDescriptor(unsigned int version,unsigned int index)
+{	
+    if (version < 1) return 0;
+
+	int isPythonInitialized = Py_IsInitialized();
+	cerr << "# isPythonInitialized: " << isPythonInitialized << endl;
+	cerr << "# haveScannedPlugins: " << haveScannedPlugins << endl;
+
+	if (!haveScannedPlugins) {
+
+		if (!isPythonInitialized){
+
+			if (!preloadPython())
+				cerr << "Warning: Could not preload Python. Dynamic loading in scripts will fail." << endl;
+			
+			int ext = PyImport_AppendInittab("vampy",initvampy);
+			if (ext == -1) cerr << "Extension unsuccessful." << endl;
+			else cerr << "Extension successful." << endl;
+			Py_Initialize();
+			initvampy();
+			// if (!PyImport_ImportModule("vampy"))
+			// 	cerr << "Could not import extension." << endl;
+
+			// Py_InitModule("vampy", VampyMethods);
+			
+			// initpyRealTime();
+		    cerr << "# isPythonInitialized after initialize: " << Py_IsInitialized() << endl;
+			// PyEval_InitThreads(); //not sure why this was needed
+		}
+
+		vector<string> pyPlugs;
+		vector<string> pyPath;
+		vector<PyObject *> pyClasses;
+		static PyPlugScanner *scanner;
+		
+		//Scanning Plugins
+		cerr << "Scanning PyPlugins" << endl;
+		scanner = PyPlugScanner::getInstance();
+		pyPath=scanner->getAllValidPath();
+		//add this as extra path for development
+		//pyPath.push_back("/Users/Shared/Development/vamp-experiments");
+		scanner->setPath(pyPath);
+		pyPlugs = scanner->getPyPlugs();
+		cerr << "Found " << pyPlugs.size() << " Scripts ...OK" << endl;
+		//TODO: this should support multiple classes per script (?)
+		pyClasses = scanner->getPyClasses();
+		cerr << "Found " << pyClasses.size() << " Classes ...OK" << endl;
+
+		for (size_t i = 0; i < pyPlugs.size(); ++i) {
+			adapters.push_back( new PyPluginAdapter(pyPlugs[i],pyClasses[i]));
+		} 
+		haveScannedPlugins=true;
+		// if (!haveVampyInitialised) {
+		// 	// PyImport_AddModule("vampy");
+		// 	// if (!PyImport_ImportModule("vampy")) 
+		// 	cerr << "Could not import extension." << endl;
+		// 	initvampy();
+		// 	haveVampyInitialised = true;
+		// 	cerr << "Extension initialised from main." << endl;
+		// }
+	}
+
+	cerr << "Accessing adapter index: " << index << " (adapters: " << adapters.size() << ")" << endl;
+	if (index<adapters.size()) {
+		const VampPluginDescriptor *tmp = adapters[index]->getDescriptor();
+		return tmp;
+	} else return 0;
+
+	
+}
+
+
+
+
+
+
+
+