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 fazekasgy@37: #include "PyExtensionModule.h" fazekasgy@37: #include "PyFeature.h" fazekasgy@37: #include "vamp-sdk/Plugin.h" fazekasgy@37: #include 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: };*/