# HG changeset patch # User Chris Cannam # Date 1434540941 -3600 # Node ID 9343eee50605d41d42c492bf21e2b4211aa220a8 # Parent 4f590fc46ace8326aa82c75c926ee1852fead6fc Update to Python 3. Currently crashes during tests (and also, two tests are now failing, even with Py2). diff -r 4f590fc46ace -r 9343eee50605 Makefile.inc --- a/Makefile.inc Wed Jun 17 11:04:15 2015 +0100 +++ b/Makefile.inc Wed Jun 17 12:35:41 2015 +0100 @@ -26,8 +26,9 @@ .tests: $(LIBRARY) $(PY) $(TESTPLUG) $(TESTS) VAMP_PATH=$(TESTPLUG_DIR) $(NOSE) @touch $@ - -test: $(LIBRARY) $(PY) $(TESTPLUG) $(TESTS) + +.PHONY: test +test: VAMP_PATH=$(TESTPLUG_DIR) $(NOSE) $(LIBRARY): $(OBJECTS) @@ -51,8 +52,10 @@ # DO NOT DELETE native/PyPluginObject.o: native/PyPluginObject.h native/FloatConversion.h -native/PyPluginObject.o: native/VectorConversion.h native/PyRealTime.h +native/PyPluginObject.o: native/VectorConversion.h native/StringConversion.h +native/PyPluginObject.o: native/PyRealTime.h native/PyRealTime.o: native/PyRealTime.h -native/VectorConversion.o: native/FloatConversion.h native/VectorConversion.h +native/VectorConversion.o: native/VectorConversion.h native/FloatConversion.h +native/VectorConversion.o: native/StringConversion.h native/vampyhost.o: native/PyRealTime.h native/PyPluginObject.h -native/vampyhost.o: native/VectorConversion.h +native/vampyhost.o: native/VectorConversion.h native/StringConversion.h diff -r 4f590fc46ace -r 9343eee50605 Makefile.linux --- a/Makefile.linux Wed Jun 17 11:04:15 2015 +0100 +++ b/Makefile.linux Wed Jun 17 12:35:41 2015 +0100 @@ -6,7 +6,7 @@ #PY_INCLUDE_PATH := /usr/include/python3.4m #NUMPY_INCLUDE_PATH := /usr/lib/python3.4m/site-packages/numpy/core/include -#PY_LIB := python3 +#PY_LIB := python3.4m #PY_TEST := nosetests3 CFLAGS := -O2 -Wall -Werror -fno-strict-aliasing -fPIC \ diff -r 4f590fc46ace -r 9343eee50605 native/PyPluginObject.cpp --- a/native/PyPluginObject.cpp Wed Jun 17 11:04:15 2015 +0100 +++ b/native/PyPluginObject.cpp Wed Jun 17 12:35:41 2015 +0100 @@ -51,6 +51,7 @@ #include "FloatConversion.h" #include "VectorConversion.h" +#include "StringConversion.h" #include "PyRealTime.h" #include @@ -78,28 +79,6 @@ } } -static -PyObject * -pystr(const string &s) -{ -#if PY_MAJOR_VERSION < 3 - return PyString_FromString(s.c_str()); -#else - return PyUnicode_FromString(s.c_str()); -#endif -} - -static -string -py2str(PyObject *obj) -{ -#if PY_MAJOR_VERSION < 3 - return PyString_AsString(obj); -#else - return PyBytes_AsString(PyUnicode_AsUTF8String(obj)); -#endif -} - PyObject * PyPluginObject_From_Plugin(Plugin *plugin) { @@ -111,21 +90,23 @@ pd->blockSize = 0; pd->stepSize = 0; + StringConversion strconv; + PyObject *infodict = PyDict_New(); PyDict_SetItemString (infodict, "apiVersion", PyLong_FromLong(plugin->getVampApiVersion())); PyDict_SetItemString (infodict, "pluginVersion", PyLong_FromLong(plugin->getPluginVersion())); PyDict_SetItemString - (infodict, "identifier", pystr(plugin->getIdentifier())); + (infodict, "identifier", strconv.string2py(plugin->getIdentifier())); PyDict_SetItemString - (infodict, "name", pystr(plugin->getName())); + (infodict, "name", strconv.string2py(plugin->getName())); PyDict_SetItemString - (infodict, "description", pystr(plugin->getDescription())); + (infodict, "description", strconv.string2py(plugin->getDescription())); PyDict_SetItemString - (infodict, "maker", pystr(plugin->getMaker())); + (infodict, "maker", strconv.string2py(plugin->getMaker())); PyDict_SetItemString - (infodict, "copyright", pystr(plugin->getCopyright())); + (infodict, "copyright", strconv.string2py(plugin->getCopyright())); pd->info = infodict; pd->inputDomain = plugin->getInputDomain(); @@ -138,13 +119,13 @@ for (int i = 0; i < (int)pl.size(); ++i) { PyObject *paramdict = PyDict_New(); PyDict_SetItemString - (paramdict, "identifier", pystr(pl[i].identifier)); + (paramdict, "identifier", strconv.string2py(pl[i].identifier)); PyDict_SetItemString - (paramdict, "name", pystr(pl[i].name)); + (paramdict, "name", strconv.string2py(pl[i].name)); PyDict_SetItemString - (paramdict, "description", pystr(pl[i].description)); + (paramdict, "description", strconv.string2py(pl[i].description)); PyDict_SetItemString - (paramdict, "unit", pystr(pl[i].unit)); + (paramdict, "unit", strconv.string2py(pl[i].unit)); PyDict_SetItemString (paramdict, "minValue", PyFloat_FromDouble(pl[i].minValue)); PyDict_SetItemString @@ -174,7 +155,7 @@ PyObject *progs = PyList_New(prl.size()); for (int i = 0; i < (int)prl.size(); ++i) { - PyList_SET_ITEM(progs, i, pystr(prl[i])); + PyList_SET_ITEM(progs, i, strconv.string2py(prl[i])); } pd->programs = progs; @@ -193,16 +174,17 @@ convertOutput(const Plugin::OutputDescriptor &desc, int ix) { VectorConversion conv; + StringConversion strconv; PyObject *outdict = PyDict_New(); PyDict_SetItemString - (outdict, "identifier", pystr(desc.identifier)); + (outdict, "identifier", strconv.string2py(desc.identifier)); PyDict_SetItemString - (outdict, "name", pystr(desc.name)); + (outdict, "name", strconv.string2py(desc.name)); PyDict_SetItemString - (outdict, "description", pystr(desc.description)); + (outdict, "description", strconv.string2py(desc.description)); PyDict_SetItemString - (outdict, "unit", pystr(desc.unit)); + (outdict, "unit", strconv.string2py(desc.unit)); PyDict_SetItemString (outdict, "hasFixedBinCount", PyLong_FromLong(desc.hasFixedBinCount)); if (desc.hasFixedBinCount) { @@ -253,11 +235,17 @@ PyPluginObject *pd = getPluginObject(self); if (!pd) return 0; - int n = -1; + ssize_t n = -1; PyObject *pyId = 0; if (!PyArg_ParseTuple(args, "n", &n) && - !PyArg_ParseTuple(args, "S", &pyId)) { + !PyArg_ParseTuple(args, +#if (PY_MAJOR_VERSION >= 3) + "U", +#else + "S", +#endif + &pyId)) { PyErr_SetString(PyExc_TypeError, "get_output takes either output id (string) or output index (int) argument"); return 0; @@ -267,8 +255,10 @@ Plugin::OutputList ol = pd->plugin->getOutputDescriptors(); + StringConversion strconv; + if (pyId) { - string id = py2str(pyId); + string id = strconv.py2string(pyId); for (int i = 0; i < int(ol.size()); ++i) { if (ol[i].identifier == id) { return convertOutput(ol[i], i); @@ -304,12 +294,12 @@ static PyObject * initialise(PyObject *self, PyObject *args) { - size_t channels, blockSize, stepSize; + ssize_t channels, blockSize, stepSize; if (!PyArg_ParseTuple (args, "nnn", - (size_t) &channels, - (size_t) &stepSize, - (size_t) &blockSize)) { + &channels, + &stepSize, + &blockSize)) { PyErr_SetString(PyExc_TypeError, "initialise() takes channel count, step size, and block size arguments"); return 0; @@ -367,7 +357,13 @@ { PyObject *pyParam; - if (!PyArg_ParseTuple(args, "S", &pyParam)) { + if (!PyArg_ParseTuple(args, +#if (PY_MAJOR_VERSION >= 3) + "U", +#else + "S", +#endif + &pyParam)) { PyErr_SetString(PyExc_TypeError, "get_parameter_value() takes parameter id (string) argument"); return 0; } @@ -375,7 +371,9 @@ PyPluginObject *pd = getPluginObject(self); if (!pd) return 0; - string param = py2str(pyParam); + StringConversion strconv; + + string param = strconv.py2string(pyParam); if (!hasParameter(pd, param)) { PyErr_SetString(PyExc_Exception, @@ -393,7 +391,13 @@ PyObject *pyParam; float value; - if (!PyArg_ParseTuple(args, "Sf", &pyParam, &value)) { + if (!PyArg_ParseTuple(args, +#if (PY_MAJOR_VERSION >= 3) + "Uf", +#else + "Sf", +#endif + &pyParam, &value)) { PyErr_SetString(PyExc_TypeError, "set_parameter_value() takes parameter id (string), and value (float) arguments"); return 0; } @@ -401,7 +405,9 @@ PyPluginObject *pd = getPluginObject(self); if (!pd) return 0; - string param = py2str(pyParam); + StringConversion strconv; + + string param = strconv.py2string(pyParam); if (!hasParameter(pd, param)) { PyErr_SetString(PyExc_Exception, @@ -454,7 +460,8 @@ "Parameter dict values must be convertible to float"); return 0; } - string param = py2str(key); + StringConversion strconv; + string param = strconv.py2string(key); if (paramIds.find(param) == paramIds.end()) { PyErr_SetString(PyExc_Exception, (string("Unknown parameter id \"") + param + "\"").c_str()); @@ -471,7 +478,13 @@ { PyObject *pyParam; - if (!PyArg_ParseTuple(args, "S", &pyParam)) { + if (!PyArg_ParseTuple(args, +#if (PY_MAJOR_VERSION >= 3) + "U", +#else + "S", +#endif + &pyParam)) { PyErr_SetString(PyExc_TypeError, "select_program() takes parameter id (string) argument"); return 0; } @@ -479,7 +492,9 @@ PyPluginObject *pd = getPluginObject(self); if (!pd) return 0; - pd->plugin->selectProgram(py2str(pyParam)); + StringConversion strconv; + + pd->plugin->selectProgram(strconv.py2string(pyParam)); return Py_True; } @@ -515,8 +530,10 @@ (pyF, "duration", PyRealTime_FromRealTime(f.duration)); } + StringConversion strconv; + PyDict_SetItemString - (pyF, "label", pystr(f.label)); + (pyF, "label", strconv.string2py(f.label)); if (!f.values.empty()) { PyDict_SetItemString @@ -764,8 +781,7 @@ /* Doc:: 10.3 Type Objects */ /* static */ PyTypeObject Plugin_Type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT(NULL, 0) "vampyhost.Plugin", /*tp_name*/ sizeof(PyPluginObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ diff -r 4f590fc46ace -r 9343eee50605 native/PyRealTime.cpp --- a/native/PyRealTime.cpp Wed Jun 17 11:04:15 2015 +0100 +++ b/native/PyRealTime.cpp Wed Jun 17 12:35:41 2015 +0100 @@ -182,10 +182,15 @@ /* Object Protocol */ +#if (PY_MAJOR_VERSION >= 3) +#define PyInt_AS_LONG PyLong_AS_LONG +#define PyInt_FromSsize_t PyLong_FromSsize_t +#endif + static int RealTime_setattr(RealTimeObject *self, char *name, PyObject *value) { - if ( !string(name).compare("sec")) { + if ( !string(name).compare("sec")) { self->rt->sec= (int) PyInt_AS_LONG(value); return 0; } @@ -199,8 +204,15 @@ } static PyObject * -RealTime_getattr(RealTimeObject *self, char *name) +RealTime_getattro(RealTimeObject *self, PyObject *nameobj) { + string name; +#if PY_MAJOR_VERSION < 3 + name = PyString_AsString(nameobj); +#else + name = PyBytes_AsString(PyUnicode_AsUTF8String(nameobj)); +#endif + if ( !string(name).compare("sec") ) { return PyInt_FromSsize_t( (Py_ssize_t) self->rt->sec); @@ -211,24 +223,35 @@ (Py_ssize_t) self->rt->nsec); } - return Py_FindMethod(RealTime_methods, - (PyObject *)self, name); + return PyObject_GenericGetAttr((PyObject *)self, nameobj); } -static int -RealTime_compare(PyObject *self, PyObject *other) +static PyObject * +RealTime_richcompare(PyObject *self, PyObject *other, int op) { if (!PyRealTime_Check(self) || !PyRealTime_Check(other)) { PyErr_SetString(PyExc_TypeError, "RealTime Object Expected."); - return -1; + return Py_False; } - RealTime *rt1 = PyRealTime_AS_REALTIME(self); - RealTime *rt2 = PyRealTime_AS_REALTIME(other); + RealTime *a = PyRealTime_AS_REALTIME(self); + RealTime *b = PyRealTime_AS_REALTIME(other); - if (*rt1 == *rt2) return 0; - else if (*rt1 > *rt2) return 1; - else return -1; + if (op == Py_LT) { + return (a < b) ? Py_True : Py_False; + } else if (op == Py_LE) { + return (a <= b) ? Py_True : Py_False; + } else if (op == Py_EQ) { + return (a == b) ? Py_True : Py_False; + } else if (op == Py_NE) { + return (a != b) ? Py_True : Py_False; + } else if (op == Py_GT) { + return (a > b) ? Py_True : Py_False; + } else if (op == Py_GE) { + return (a >= b) ? Py_True : Py_False; + } else { + return Py_False; + } } /* String representation called by e.g. str(realtime), print realtime*/ @@ -269,10 +292,12 @@ static PyNumberMethods realtime_as_number = { - RealTime_add, /*nb_add*/ - RealTime_subtract, /*nb_subtract*/ + (binaryfunc)RealTime_add, /*nb_add*/ + (binaryfunc)RealTime_subtract, /*nb_subtract*/ 0, /*nb_multiply*/ +#if (PY_MAJOR_VERSION < 3) 0, /*nb_divide*/ +#endif 0, /*nb_remainder*/ 0, /*nb_divmod*/ 0, /*nb_power*/ @@ -286,12 +311,12 @@ 0, /*nb_and*/ 0, /*nb_xor*/ 0, /*nb_or*/ +#if (PY_MAJOR_VERSION < 3) 0, /*nb_coerce*/ +#endif 0, /*nb_int*/ 0, /*nb_long*/ (unaryfunc)RealTime_float,/*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ }; /* REAL-TIME TYPE OBJECT */ @@ -302,17 +327,16 @@ /* Doc:: 10.3 Type Objects */ /* static */ PyTypeObject RealTime_Type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT(NULL, 0) "vampy.RealTime", /*tp_name*/ sizeof(RealTimeObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)RealTimeObject_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - (getattrfunc)RealTime_getattr, /*tp_getattr*/ + 0, /*tp_getattr*/ (setattrfunc)RealTime_setattr, /*tp_setattr*/ - (cmpfunc)RealTime_compare, /*tp_compare*/ + 0, /*tp_compare*/ RealTime_repr, /*tp_repr*/ &realtime_as_number, /*tp_as_number*/ 0, /*tp_as_sequence*/ @@ -320,14 +344,14 @@ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ - 0, /*tp_getattro*/ + (getattrofunc)RealTime_getattro, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "RealTime object, used for Vamp plugin timestamps.", /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ - 0, /*tp_richcompare*/ + (richcmpfunc)RealTime_richcompare, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ diff -r 4f590fc46ace -r 9343eee50605 native/StringConversion.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/native/StringConversion.h Wed Jun 17 12:35:41 2015 +0100 @@ -0,0 +1,80 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + VampyHost + + Use Vamp audio analysis plugins in Python + + Gyorgy Fazekas and Chris Cannam + Centre for Digital Music, Queen Mary, University of London + Copyright 2008-2014 Queen Mary, University of London + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and the authors + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +/* + StringConversion: A couple of type safe conversion utilities between + Python types and C++ strings. +*/ + +#ifndef VAMPYHOST_STRING_CONVERSION_H +#define VAMPYHOST_STRING_CONVERSION_H + +#include +#include + +class StringConversion +{ +public: + StringConversion() {} + ~StringConversion() {} + + PyObject *string2py(const std::string &s) { +#if PY_MAJOR_VERSION < 3 + return PyString_FromString(s.c_str()); +#else + return PyUnicode_FromString(s.c_str()); +#endif + } + + std::string py2string(PyObject *obj) { +#if PY_MAJOR_VERSION < 3 + char *cstr = PyString_AsString(obj); + if (!cstr) return std::string(); + else return cstr; +#else + PyObject *uobj = PyUnicode_AsUTF8String(obj); + if (!uobj) return std::string(); + char *cstr = PyBytes_AsString(uobj); + if (!cstr) return std::string(); + else return cstr; +#endif + } +}; + +#endif + + diff -r 4f590fc46ace -r 9343eee50605 native/VectorConversion.cpp --- a/native/VectorConversion.cpp Wed Jun 17 11:04:15 2015 +0100 +++ b/native/VectorConversion.cpp Wed Jun 17 12:35:41 2015 +0100 @@ -37,8 +37,9 @@ #include +#include "VectorConversion.h" #include "FloatConversion.h" -#include "VectorConversion.h" +#include "StringConversion.h" #include #include @@ -237,7 +238,7 @@ { PyObject *pyList = PyList_New(v.size()); for (size_t i = 0; i < v.size(); ++i) { - PyObject *pyStr = PyString_FromString(v[i].c_str()); + PyObject *pyStr = StringConversion().string2py(v[i].c_str()); PyList_SET_ITEM(pyList, i, pyStr); } return pyList; @@ -289,23 +290,20 @@ VectorConversion::PyValue_Get_TypeName(PyObject* pyValue) const { PyObject *pyType = PyObject_Type(pyValue); - if (!pyType) - { + if (!pyType) { cerr << "Warning: Object type name could not be found." << endl; if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} return string ("< unknown type >"); } PyObject *pyString = PyObject_Str(pyType); - if (!pyString) - { + if (!pyString) { cerr << "Warning: Object type name could not be found." << endl; if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} Py_CLEAR(pyType); return string ("< unknown type >"); } - char *cstr = PyString_AS_STRING(pyString); - if (!cstr) - { + string str = StringConversion().py2string(pyString); + if (str == "") { cerr << "Warning: Object type name could not be found." << endl; if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} Py_DECREF(pyType); @@ -314,5 +312,5 @@ } Py_DECREF(pyType); Py_DECREF(pyString); - return string(cstr); + return str; } diff -r 4f590fc46ace -r 9343eee50605 native/vampyhost.cpp --- a/native/vampyhost.cpp Wed Jun 17 11:04:15 2015 +0100 +++ b/native/vampyhost.cpp Wed Jun 17 12:35:41 2015 +0100 @@ -52,6 +52,7 @@ #include "vamp-hostsdk/PluginLoader.h" #include "VectorConversion.h" +#include "StringConversion.h" #include "PyRealTime.h" #include @@ -83,7 +84,7 @@ static string toPluginKey(PyObject *pyPluginKey) { // convert to stl string - string pluginKey(PyString_AS_STRING(pyPluginKey)); + string pluginKey(StringConversion().py2string(pyPluginKey)); // check pluginKey validity string::size_type ki = pluginKey.find(':'); @@ -101,7 +102,13 @@ { PyObject *pyPluginKey; - if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) { + if (!PyArg_ParseTuple(args, +#if (PY_MAJOR_VERSION >= 3) + "U", +#else + "S", +#endif + &pyPluginKey)) { PyErr_SetString(PyExc_TypeError, "get_library_for() takes plugin key (string) argument"); return 0; } @@ -111,7 +118,7 @@ PluginLoader *loader = PluginLoader::getInstance(); string path = loader->getLibraryPathForPlugin(pluginKey); - PyObject *pyPath = PyString_FromString(path.c_str()); + PyObject *pyPath = StringConversion().string2py(path.c_str()); return pyPath; } @@ -120,7 +127,13 @@ { PyObject *pyPluginKey; - if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) { + if (!PyArg_ParseTuple(args, +#if (PY_MAJOR_VERSION >= 3) + "U", +#else + "S", +#endif + &pyPluginKey)) { PyErr_SetString(PyExc_TypeError, "get_category_of() takes plugin key (string) argument"); return 0; } @@ -141,7 +154,13 @@ { PyObject *pyPluginKey; - if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) { + if (!PyArg_ParseTuple(args, +#if (PY_MAJOR_VERSION >= 3) + "U", +#else + "S", +#endif + &pyPluginKey)) { PyErr_SetString(PyExc_TypeError, "get_outputs_of() takes plugin key (string) argument"); return 0; } @@ -166,7 +185,7 @@ for (size_t i = 0; i < outputs.size(); ++i) { PyObject *pyOutputId = - PyString_FromString(outputs[i].identifier.c_str()); + StringConversion().string2py(outputs[i].identifier.c_str()); PyList_SET_ITEM(pyList, i, pyOutputId); } @@ -178,9 +197,14 @@ { PyObject *pyPluginKey; float inputSampleRate; - int adapterFlags; + ssize_t adapterFlags; - if (!PyArg_ParseTuple(args, "Sfn", + if (!PyArg_ParseTuple(args, +#if (PY_MAJOR_VERSION >= 3) + "Ufn", +#else + "Sfn", +#endif &pyPluginKey, &inputSampleRate, &adapterFlags)) { @@ -208,14 +232,14 @@ static PyObject * frame_to_realtime(PyObject *self, PyObject *args) { - int frame; - int rate; + ssize_t frame; + float rate; - if (!PyArg_ParseTuple(args, "nn", + if (!PyArg_ParseTuple(args, "nf", &frame, &rate)) { PyErr_SetString(PyExc_TypeError, - "frame_to_realtime() takes frame (int) and sample rate (int) arguments"); + "frame_to_realtime() takes frame (int) and sample rate (float) arguments"); return 0; } RealTime rt = RealTime::frame2RealTime(frame, rate); @@ -249,14 +273,16 @@ {0, 0} /* sentinel */ }; -PyDoc_STRVAR(module_doc, "Load and run Vamp audio analysis plugins."); - static int setint(PyObject *d, const char *name, int value) { PyObject *v; int err; +#if (PY_MAJOR_VERSION >= 3) + v = PyLong_FromLong((long)value); +#else v = PyInt_FromLong((long)value); +#endif err = PyDict_SetItemString(d, name, v); Py_XDECREF(v); return err; @@ -264,19 +290,49 @@ /* Initialization function for the module (*must* be called initxx) */ +#if (PY_MAJOR_VERSION >= 3) +static struct PyModuleDef vampyhostdef = { + PyModuleDef_HEAD_INIT, + "vampyhost", + "Load and run Vamp audio analysis plugins.", + -1, + vampyhost_methods, + 0, 0, 0, 0 +}; +#else +PyDoc_STRVAR(module_doc, "Load and run Vamp audio analysis plugins."); +#endif + // module initialization (includes extern C {...} as necessary) PyMODINIT_FUNC +#if (PY_MAJOR_VERSION >= 3) +PyInit_vampyhost(void) +#else initvampyhost(void) +#endif { PyObject *m; - if (PyType_Ready(&RealTime_Type) < 0) return; - if (PyType_Ready(&Plugin_Type) < 0) return; +#if (PY_MAJOR_VERSION >= 3) +#define GOOD_RETURN m +#define BAD_RETURN 0 +#else +#define GOOD_RETURN +#define BAD_RETURN +#endif + + if (PyType_Ready(&RealTime_Type) < 0) return BAD_RETURN; + if (PyType_Ready(&Plugin_Type) < 0) return BAD_RETURN; +#if (PY_MAJOR_VERSION >= 3) + m = PyModule_Create(&vampyhostdef); +#else m = Py_InitModule3("vampyhost", vampyhost_methods, module_doc); +#endif + if (!m) { cerr << "ERROR: initvampyhost: Failed to initialise module" << endl; - return; + return BAD_RETURN; } import_array(); @@ -288,7 +344,7 @@ PyObject *dict = PyModule_GetDict(m); if (!dict) { cerr << "ERROR: initvampyhost: Failed to obtain module dictionary" << endl; - return; + return BAD_RETURN; } if (setint(dict, "ONE_SAMPLE_PER_STEP", @@ -314,6 +370,8 @@ setint(dict, "ADAPT_ALL", PluginLoader::ADAPT_ALL) < 0) { cerr << "ERROR: initvampyhost: Failed to add enums to module dictionary" << endl; - return; + return BAD_RETURN; } + + return GOOD_RETURN; } diff -r 4f590fc46ace -r 9343eee50605 test/test_collect.py --- a/test/test_collect.py Wed Jun 17 11:04:15 2015 +0100 +++ b/test/test_collect.py Wed Jun 17 12:35:41 2015 +0100 @@ -6,7 +6,7 @@ plugin_key = "vamp-test-plugin:vamp-test-plugin" plugin_key_freq = "vamp-test-plugin:vamp-test-plugin-freq" -rate = 44100 +rate = 44100.0 # Throughout this file we have the assumption that the plugin gets run with a # blocksize of 1024, and with a step of 1024 for the time-domain version or 512 diff -r 4f590fc46ace -r 9343eee50605 test/test_process.py --- a/test/test_process.py Wed Jun 17 11:04:15 2015 +0100 +++ b/test/test_process.py Wed Jun 17 12:35:41 2015 +0100 @@ -22,18 +22,18 @@ def test_process_n(): buf = input_data(blocksize) - results = list(vamp.process(buf, rate, plugin_key, "input-summary")) + results = list(vamp.process_audio(buf, rate, plugin_key, "input-summary")) assert len(results) == 1 def test_process_freq_n(): buf = input_data(blocksize) - results = list(vamp.process(buf, rate, plugin_key_freq, "input-summary", {})) + results = list(vamp.process_audio(buf, rate, plugin_key_freq, "input-summary", {})) assert len(results) == 2 # one complete block starting at zero, one half-full def test_process_default_output(): # If no output is specified, we should get the first one (instants) buf = input_data(blocksize) - results = list(vamp.process(buf, rate, plugin_key, "", {})) + results = list(vamp.process_audio(buf, rate, plugin_key, "", {})) assert len(results) == 10 for i in range(len(results)): expectedTime = vamp.vampyhost.RealTime('seconds', i * 1.5) @@ -42,7 +42,7 @@ def test_process_summary_param(): buf = input_data(blocksize * 10) - results = list(vamp.process(buf, rate, plugin_key, "input-summary", { "produce_output": 0 })) + results = list(vamp.process_audio(buf, rate, plugin_key, "input-summary", { "produce_output": 0 })) assert len(results) == 0 def test_process_multi_summary_param(): @@ -52,7 +52,7 @@ def test_process_summary_param_bool(): buf = input_data(blocksize * 10) - results = list(vamp.process(buf, rate, plugin_key, "input-summary", { "produce_output": False })) + results = list(vamp.process_audio(buf, rate, plugin_key, "input-summary", { "produce_output": False })) assert len(results) == 0 def test_process_multi_summary_param_bool(): @@ -62,7 +62,7 @@ def test_process_summary(): buf = input_data(blocksize * 10) - results = list(vamp.process(buf, rate, plugin_key, "input-summary", {})) + results = list(vamp.process_audio(buf, rate, plugin_key, "input-summary", {})) assert len(results) == 10 for i in range(len(results)): # @@ -120,7 +120,7 @@ def test_process_freq_summary(): buf = input_data(blocksize * 10) - results = list(vamp.process(buf, rate, plugin_key_freq, "input-summary", {})) + results = list(vamp.process_audio(buf, rate, plugin_key_freq, "input-summary", {})) assert len(results) == 20 for i in range(len(results)): # @@ -171,7 +171,7 @@ def test_process_timestamps(): buf = input_data(blocksize * 10) - results = list(vamp.process(buf, rate, plugin_key, "input-timestamp", {})) + results = list(vamp.process_audio(buf, rate, plugin_key, "input-timestamp", {})) assert len(results) == 10 for i in range(len(results)): # The timestamp should be the frame number of the first frame in the @@ -193,7 +193,7 @@ def test_process_freq_timestamps(): buf = input_data(blocksize * 10) - results = list(vamp.process(buf, rate, plugin_key_freq, "input-timestamp", {})) + results = list(vamp.process_audio(buf, rate, plugin_key_freq, "input-timestamp", {})) assert len(results) == 20 for i in range(len(results)): # The timestamp should be the frame number of the frame just beyond diff -r 4f590fc46ace -r 9343eee50605 vamp/__init__.py --- a/vamp/__init__.py Wed Jun 17 11:04:15 2015 +0100 +++ b/vamp/__init__.py Wed Jun 17 12:35:41 2015 +0100 @@ -2,7 +2,7 @@ import vampyhost -from load import list_plugins, get_outputs_of, get_category_of -from process import process, process_frames, process_multiple_outputs, process_frames_multiple_outputs -from collect import collect +from vamp.load import list_plugins, get_outputs_of, get_category_of +from vamp.process import process_audio, process_frames, process_multiple_outputs, process_frames_multiple_outputs +from vamp.collect import collect diff -r 4f590fc46ace -r 9343eee50605 vamp/collect.py --- a/vamp/collect.py Wed Jun 17 11:04:15 2015 +0100 +++ b/vamp/collect.py Wed Jun 17 12:35:41 2015 +0100 @@ -1,9 +1,9 @@ '''A high-level interface to the vampyhost extension module, for quickly and easily running Vamp audio analysis plugins on audio files and buffers.''' import vampyhost -import load -import process -import frames +import vamp.load +import vamp.process +import vamp.frames import numpy as np @@ -124,7 +124,7 @@ vamp.process() instead. """ - plugin, step_size, block_size = load.load_and_configure(data, sample_rate, key, parameters) + plugin, step_size, block_size = vamp.load.load_and_configure(data, sample_rate, key, parameters) if output == "": output_desc = plugin.get_output(0) @@ -132,9 +132,9 @@ else: output_desc = plugin.get_output(output) - ff = frames.frames_from_array(data, step_size, block_size) + ff = vamp.frames.frames_from_array(data, step_size, block_size) - results = process.process_with_initialised_plugin(ff, sample_rate, step_size, plugin, [output]) + results = vamp.process.process_with_initialised_plugin(ff, sample_rate, step_size, plugin, [output]) rv = reshape(results, sample_rate, step_size, output_desc) diff -r 4f590fc46ace -r 9343eee50605 vamp/process.py --- a/vamp/process.py Wed Jun 17 11:04:15 2015 +0100 +++ b/vamp/process.py Wed Jun 17 12:35:41 2015 +0100 @@ -1,8 +1,8 @@ '''A high-level interface to the vampyhost extension module, for quickly and easily running Vamp audio analysis plugins on audio files and buffers.''' import vampyhost -import frames -import load +import vamp.frames +import vamp.load def process_with_initialised_plugin(ff, sample_rate, step_size, plugin, outputs): @@ -30,7 +30,7 @@ yield { o: r } -def process(data, sample_rate, key, output = "", parameters = {}): +def process_audio(data, sample_rate, key, output = "", parameters = {}): """Process audio data with a Vamp plugin, and make the results from a single plugin output available as a generator. @@ -57,12 +57,12 @@ structure, consider using vamp.collect() instead. """ - plugin, step_size, block_size = load.load_and_configure(data, sample_rate, key, parameters) + plugin, step_size, block_size = vamp.load.load_and_configure(data, sample_rate, key, parameters) if output == "": output = plugin.get_output(0)["identifier"] - ff = frames.frames_from_array(data, step_size, block_size) + ff = vamp.frames.frames_from_array(data, step_size, block_size) for r in process_with_initialised_plugin(ff, sample_rate, step_size, plugin, [output]): yield r[output] @@ -164,9 +164,9 @@ array of float values. """ - plugin, step_size, block_size = load.load_and_configure(data, sample_rate, key, parameters) + plugin, step_size, block_size = vamp.load.load_and_configure(data, sample_rate, key, parameters) - ff = frames.frames_from_array(data, step_size, block_size) + ff = vamp.frames.frames_from_array(data, step_size, block_size) for r in process_with_initialised_plugin(ff, sample_rate, step_size, plugin, outputs): yield r