fazekasgy@37: /*
fazekasgy@37: 
fazekasgy@37:  * Vampy : This plugin is a wrapper around the Vamp plugin API.
fazekasgy@37:  * It allows for writing Vamp plugins in Python.
fazekasgy@37: 
fazekasgy@37:  * Centre for Digital Music, Queen Mary University of London.
fazekasgy@37:  * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources 
fazekasgy@37:  * for licence information.)
fazekasgy@37: 
fazekasgy@37: */
fazekasgy@37: 
fazekasgy@37: #include <Python.h>
fazekasgy@37: #include "PyExtensionModule.h"
fazekasgy@37: #include "PyFeature.h"
fazekasgy@37: #include "vamp-sdk/Plugin.h"
fazekasgy@37: #include <string>
fazekasgy@37: 
fazekasgy@37: using namespace std;
fazekasgy@37: using namespace Vamp;
fazekasgy@37: using Vamp::Plugin;
fazekasgy@37: 
fazekasgy@37: /* CONSTRUCTOR: New Feature object */
fazekasgy@37: static PyObject *
fazekasgy@37: Feature_new(PyTypeObject *type, PyObject *args, PyObject *kw)
fazekasgy@37: {
fazekasgy@37: 	// FeatureObject *self = PyObject_New(FeatureObject, &Feature_Type); 
fazekasgy@37: 	FeatureObject *self = (FeatureObject*)type->tp_alloc(type, 0);
fazekasgy@37: 	if (self == NULL) return NULL;
fazekasgy@37:     self->dict = PyDict_New();
fazekasgy@37: 	if (self->dict == NULL) return NULL;
fazekasgy@37: 
fazekasgy@37: 	/// 4 args max.: {values|self_copy},timestamp,duration,label 
fazekasgy@37: 	if(args && PyTuple_GET_SIZE(args)>0) {
fazekasgy@37: 		int s =  PyTuple_GET_SIZE(args);
fazekasgy@37: 		PyObject* arg0 = PyTuple_GET_ITEM(args,0);
fazekasgy@37: 		if (s == 1 && PyFeature_CheckExact(arg0))
fazekasgy@37: 			PyDict_Merge(self->dict,PyFeature_AS_DICT(arg0),0);
fazekasgy@37: 		else
fazekasgy@37: 			PyDict_SetItemString(self->dict, "values", arg0);
fazekasgy@37: 		if (s>1) {
fazekasgy@37: 			PyDict_SetItemString(self->dict, "timestamp", PyTuple_GET_ITEM(args,1));
fazekasgy@37: 			PyDict_SetItemString(self->dict, "hasTimestamp", Py_True);
fazekasgy@37: 		}
fazekasgy@37: 		if (s>2) {
fazekasgy@37: 			PyDict_SetItemString(self->dict, "duration", PyTuple_GET_ITEM(args,2));
fazekasgy@37: 			PyDict_SetItemString(self->dict, "hasDuration", Py_True);
fazekasgy@37: 		}
fazekasgy@37: 		if (s>3) {
fazekasgy@37: 			PyDict_SetItemString(self->dict, "label", PyTuple_GET_ITEM(args,3));
fazekasgy@37: 		}
fazekasgy@37: 	}
fazekasgy@37: 
fazekasgy@37: 	/// accept keyword arguments: 
fazekasgy@37: 	/// e.g. Feature(values = theOutputArray)
fazekasgy@37: 	if (!kw || !PyDict_Size(kw)) return (PyObject *) self;
fazekasgy@37: 	PyDict_Merge(self->dict,kw,0);
fazekasgy@37: 
Chris@66: 	static const char *kwlist[] = {"timestamp", "hasTimestamp", "duration", "hasDuration", 0};
fazekasgy@37: 
fazekasgy@37: 	int i = 0;
fazekasgy@37: 	while (kwlist[i]) {
Chris@66: 		const char* name = kwlist[i];
Chris@66: 		const char* attr = kwlist[++i];
fazekasgy@37: 		i++;
fazekasgy@37: 		PyObject *key = PyString_FromString(name);
fazekasgy@37: 		if (!key) break;
fazekasgy@37: 		if (PyDict_Contains(kw,key)) {
fazekasgy@37: 			if (PyDict_SetItem(self->dict,PyString_FromString(attr),Py_True) != 0)
fazekasgy@37: 				PyErr_SetString(PyExc_TypeError, 
fazekasgy@37: 					"Error: in keyword arguments of vampy.Feature().");
fazekasgy@37: 		}
fazekasgy@37: 		Py_DECREF(key);
fazekasgy@37: 	}
fazekasgy@37: 
fazekasgy@37: 	return (PyObject *) self;
fazekasgy@37: }
fazekasgy@37: 
fazekasgy@37: /* DESTRUCTOR: delete type object */
fazekasgy@37: static void
fazekasgy@37: FeatureObject_dealloc(FeatureObject *self)
fazekasgy@37: {
fazekasgy@37: 	Py_XDECREF(self->dict);
fazekasgy@37: 	self->ob_type->tp_free((PyObject*)self);
fazekasgy@37: }
fazekasgy@37: 
fazekasgy@37: /*					 Feature Object's Methods 					*/ 
fazekasgy@37: //Feature objects have no callable methods
fazekasgy@37: 
fazekasgy@37: /*		   PyFeature methods implementing protocols 		   	   */ 
fazekasgy@37: // these functions are called by the interpreter automatically
fazekasgy@37: 
fazekasgy@37: /* Set attributes */
fazekasgy@37: static int
fazekasgy@37: Feature_setattr(FeatureObject *self, char *name, PyObject *v)
fazekasgy@37: {
fazekasgy@37: 	if (v == NULL) 
fazekasgy@37: 	{
fazekasgy@37: 		int rv = PyDict_DelItemString(self->dict, name);
fazekasgy@37: 		if (rv < 0)
fazekasgy@37: 			PyErr_SetString(PyExc_AttributeError,"non-existing Feature attribute");
fazekasgy@37: 		return rv;
fazekasgy@37: 	}
fazekasgy@37: 	else return PyDict_SetItemString(self->dict, name, v);
fazekasgy@37: }
fazekasgy@37: 
fazekasgy@37: 
fazekasgy@37: /* Get attributes */
fazekasgy@37: static PyObject *
fazekasgy@37: Feature_getattr(FeatureObject *self, char *name)
fazekasgy@37: {
fazekasgy@37: 	if (self->dict != NULL) {
fazekasgy@37: 		PyObject *v = PyDict_GetItemString(self->dict, name);
fazekasgy@37: 		if (v != NULL) 
fazekasgy@37: 		{
fazekasgy@37: 			Py_INCREF(v);
fazekasgy@37: 			return v;
fazekasgy@37: 		}
fazekasgy@37: 	}
fazekasgy@37: 	return NULL;
fazekasgy@37: }
fazekasgy@37: 
fazekasgy@37: /* The problem with this is that we'd need to implement two-way
fazekasgy@37: conversions which is really unnecesary: The case for using 
fazekasgy@37: a Vamp::Feature in Python for anything else than returning 
fazekasgy@37: values is rather obscure. It's not really worth it. */
fazekasgy@37: 
fazekasgy@37: /* Set Attribute: Using wrapped Vamp::Feature 
fazekasgy@37: static int
fazekasgy@37: Feature_setattr(FeatureObject *self, char *name, PyObject *value)
fazekasgy@37: {
fazekasgy@37: 	std::string key = std::string(name);
fazekasgy@37: 	if (self->ti.SetValue(*(self->feature),key,value)) return 0;
fazekasgy@37: 	else return -1;
fazekasgy@37: }*/
fazekasgy@37: 
fazekasgy@37: /* Get Attribute: Using wrapped Vamp::Feature 
fazekasgy@37: static PyObject *
fazekasgy@37: Feature_getattr(FeatureObject *self, char *name)
fazekasgy@37: {
fazekasgy@37: 	std::string key = std::string(name);
fazekasgy@37: 	PyObject* pyValue;
fazekasgy@37: 	if (self->ti.GetValue(*(self->feature),key,pyValue)) 
fazekasgy@37: 		return pyValue;
fazekasgy@37: 	else return NULL;
fazekasgy@37: }*/
fazekasgy@37: 
fazekasgy@37: /*
fazekasgy@37: static int
fazekasgy@37: Feature_init(FeatureObject *self, PyObject *args, PyObject *kwds)
fazekasgy@37: {
fazekasgy@37: 	cerr << "FeatureObject Init called" << endl;
fazekasgy@37: 	return 0;
fazekasgy@37: }
fazekasgy@37: 
fazekasgy@37: PyObject*
fazekasgy@37: Feature_test(PyObject *self, PyObject *args, PyObject *kwds)
fazekasgy@37: {
fazekasgy@37: 	cerr << "FeatureObject TEST called" << endl;
fazekasgy@37: 	return self;
fazekasgy@37: }
fazekasgy@37: */
fazekasgy@37: 
fazekasgy@37: /* String representation */
fazekasgy@37: static PyObject *
fazekasgy@37: Feature_repr(PyObject *self)
fazekasgy@37: {
fazekasgy@37: 	FeatureObject* v = (FeatureObject*)self;
fazekasgy@37: 	if (v->dict) return PyDict_Type.tp_repr((PyObject *)v->dict);
fazekasgy@37: 	else return PyString_FromString("Feature()");
fazekasgy@37: }
fazekasgy@37: 
fazekasgy@37: #define Feature_alloc PyType_GenericAlloc
fazekasgy@37: #define Feature_free PyObject_Del
fazekasgy@37: 
fazekasgy@37: 
fazekasgy@37: /*						FEATURE TYPE OBJECT						*/
fazekasgy@37: 
fazekasgy@37: PyTypeObject Feature_Type = {
fazekasgy@37: 	PyObject_HEAD_INIT(NULL)
fazekasgy@37: 	0,						/*ob_size*/
fazekasgy@37: 	"vampy.Feature",		/*tp_name*/
fazekasgy@37: 	sizeof(FeatureObject),	/*tp_basicsize*/
fazekasgy@37: 	0,						/*tp_itemsize*/
fazekasgy@37: 	(destructor)FeatureObject_dealloc, /*tp_dealloc*/
fazekasgy@37: 	0,						/*tp_print*/
fazekasgy@37: 	(getattrfunc)Feature_getattr, /*tp_getattr*/
fazekasgy@37: 	(setattrfunc)Feature_setattr, /*tp_setattr*/
fazekasgy@37: 	0,						/*tp_compare*/
fazekasgy@37: 	Feature_repr,			/*tp_repr*/
fazekasgy@37: 	0,						/*tp_as_number*/
fazekasgy@37: 	0,						/*tp_as_sequence*/
fazekasgy@37: 	0,						/*tp_as_mapping*/
fazekasgy@37: 	0,						/*tp_hash*/
fazekasgy@37: 	0,//Feature_test,           /*tp_call*/ // call on an instance
fazekasgy@37:     0,                      /*tp_str*/
fazekasgy@37:     0,                      /*tp_getattro*/
fazekasgy@37:     0,                      /*tp_setattro*/
fazekasgy@37:     0,                      /*tp_as_buffer*/
fazekasgy@37:     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,     /*tp_flags*/
fazekasgy@37:     0,                      /*tp_doc*/
fazekasgy@37:     0,                      /*tp_traverse*/
fazekasgy@37:     0,                      /*tp_clear*/
fazekasgy@37:     0,                      /*tp_richcompare*/
fazekasgy@37:     0,                      /*tp_weaklistoffset*/
fazekasgy@37:     0,                      /*tp_iter*/
fazekasgy@37:     0,                      /*tp_iternext*/
fazekasgy@37:     0,				        /*tp_methods*/ //TypeObject Methods
fazekasgy@37:     0,                      /*tp_members*/
fazekasgy@37:     0,                      /*tp_getset*/
fazekasgy@37:     0,                      /*tp_base*/
fazekasgy@37:     0,                      /*tp_dict*/
fazekasgy@37:     0,                      /*tp_descr_get*/
fazekasgy@37:     0,                      /*tp_descr_set*/
fazekasgy@37:     0,                      /*tp_dictoffset*/
fazekasgy@37:     0,//(initproc)Feature_init, /*tp_init*/
fazekasgy@37:     Feature_alloc,          /*tp_alloc*/
fazekasgy@37:     Feature_new,            /*tp_new*/
fazekasgy@37:     Feature_free,			/*tp_free*/
fazekasgy@37:     0,                      /*tp_is_gc*/
fazekasgy@37: };
fazekasgy@37: 
fazekasgy@37: /*		  		 	  PyRealTime C++ API  	  		  				*/
fazekasgy@37: 
fazekasgy@37: /*Feature* from PyFeature
fazekasgy@37: const Vamp::Plugin::Feature*
fazekasgy@37: PyFeature_AsFeature (PyObject *self) { 
fazekasgy@37: 
fazekasgy@37: 	FeatureObject *s = (FeatureObject*) self; 
fazekasgy@37: 
fazekasgy@37: 	if (!PyFeature_Check(s)) {
fazekasgy@37: 		PyErr_SetString(PyExc_TypeError, "Feature Object Expected.");
fazekasgy@37: 		cerr << "in call PyFeature_AsPointer(): Feature Object Expected. " << endl;
fazekasgy@37: 		return NULL; }
fazekasgy@37: 	return s->feature; 
fazekasgy@37: };*/