Mercurial > hg > vampy-host
changeset 16:7987e3123909
Rationalise plugin handle management
author | Chris Cannam |
---|---|
date | Mon, 24 Nov 2014 14:39:56 +0000 |
parents | 8b264cabbc28 |
children | 3893b76daf80 |
files | system.h vampyhost.cpp vampyhost.h |
diffstat | 3 files changed, 93 insertions(+), 249 deletions(-) [+] |
line wrap: on
line diff
--- a/system.h Mon Nov 24 11:02:28 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - - 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 Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#ifndef _SYSTEM_H_ -#define _SYSTEM_H_ - -#ifdef _WIN32 - -#include <windows.h> - -#define DLOPEN(a,b) LoadLibrary((a).c_str()) -#define DLSYM(a,b) GetProcAddress((HINSTANCE)(a),(b)) -#define DLCLOSE(a) FreeLibrary((HINSTANCE)(a)) -#define DLERROR() "" - -#define PLUGIN_SUFFIX "dll" - -#else - -#include <dlfcn.h> - -#define DLOPEN(a,b) dlopen((a).c_str(),(b)) -#define DLSYM(a,b) dlsym((a),(b)) -#define DLCLOSE(a) dlclose((a)) -#define DLERROR() dlerror() - -#ifdef __APPLE__ - -#define PLUGIN_SUFFIX "dylib" -#define HAVE_OPENDIR 1 - -#else - -#define PLUGIN_SUFFIX "so" -#define HAVE_OPENDIR 1 - -#endif /* __APPLE__ */ - -#endif /* ! _WIN32 */ - -#endif -
--- a/vampyhost.cpp Mon Nov 24 11:02:28 2014 +0000 +++ b/vampyhost.cpp Mon Nov 24 14:39:56 2014 +0000 @@ -10,13 +10,6 @@ #include <vampyhost.h> -#include "PyTypeConversions.h" -#include "PyRealTime.h" - -//!!! NB all our NumPy stuff is currently using the deprecated API -- -//!!! need to work out how to update this -//#include "numpy/arrayobject.h" - #define HAVE_NUMPY 1 // Required //includes for vamp host @@ -25,7 +18,9 @@ #include "vamp-hostsdk/PluginChannelAdapter.h" #include "vamp-hostsdk/PluginInputDomainAdapter.h" #include "vamp-hostsdk/PluginLoader.h" -//#include "vamp/vamp.h" + +#include "PyTypeConversions.h" +#include "PyRealTime.h" #include <iostream> #include <fstream> @@ -36,11 +31,8 @@ #include <cstdlib> #include <string> -#include "system.h" - #include <cmath> - using namespace std; using namespace Vamp; @@ -51,60 +43,50 @@ #define HOST_VERSION "1.1" +// structure for holding plugin instance data +struct PyPluginData +{ + PyPluginData(string k, Plugin *p, float rate) : + key(k), + plugin(p), + inputSampleRate(rate), + isInitialised(false), + channels(0), + blockSize(0), + stepSize(0) { + } + + string key; + Plugin *plugin; + float inputSampleRate; + bool isInitialised; + size_t channels; + size_t blockSize; + size_t stepSize; + Vamp::Plugin::FeatureSet output; +}; /* MODULE HELPER FUNCTIONS */ PyDoc_STRVAR(xx_foo_doc, "Some description"); //!!! -/*obtain C plugin handle and key from pyCobject */ -bool getPluginHandle -(PyObject *pyPluginHandle, Plugin **plugin, string **pKey=NULL) { +//!!! nb "The CObject API is deprecated" https://docs.python.org/2/c-api/cobject.html - //char errormsg[]="Wrong input argument: Plugin Handle required."; - - *plugin = NULL; - if (!PyCObject_Check(pyPluginHandle)) return false; - - //try to convert to Plugin pointer - Plugin *p = (Plugin*) PyCObject_AsVoidPtr(pyPluginHandle); - if (!p) return false; - - string pId; - - if (pKey) { - *pKey = (string*) PyCObject_GetDesc(pyPluginHandle); - if (!*pKey) return false; - pId = *(string*) *pKey; - +PyPluginData * +getPluginData(PyObject *pyPluginHandle) +{ + PyPluginData *pd = 0; + if (PyCObject_Check(pyPluginHandle)) { + pd = (PyPluginData *)PyCObject_AsVoidPtr(pyPluginHandle); + } + if (!pd || !pd->plugin) { + PyErr_SetString(PyExc_AttributeError, + "Invalid or already deleted plugin handle."); + return 0; } else { - - void *pKey = PyCObject_GetDesc(pyPluginHandle); - if (!pKey) return false; - pId = *(string*) pKey; + return pd; } - - string::size_type pos = pId.find(':'); - if (pos == string::npos) return false; - - pId = pId.substr(pId.rfind(':')+1); - string identifier = p->getIdentifier(); - - if (pId.compare(identifier)) return false; - - *plugin = p; - return true; } -/* - ---------------------------------------------------------------- -*/ - - - -/* - VAMPYHOST MAIN - --------------------------------------------------------------------- -*/ - static PyObject * vampyhost_enumeratePlugins(PyObject *self, PyObject *args) { @@ -146,10 +128,10 @@ if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) { PyErr_SetString(PyExc_TypeError, "getLibraryPathForPlugin() takes plugin key (string) argument"); - return NULL; } + return 0; } string pluginKey = toPluginKey(pyPluginKey); - if (pluginKey == "") return NULL; + if (pluginKey == "") return 0; PluginLoader *loader = PluginLoader::getInstance(); string path = loader->getLibraryPathForPlugin(pluginKey); @@ -165,10 +147,10 @@ if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) { PyErr_SetString(PyExc_TypeError, "getPluginCategory() takes plugin key (string) argument"); - return NULL; } + return 0; } string pluginKey = toPluginKey(pyPluginKey); - if (pluginKey == "") return NULL; + if (pluginKey == "") return 0; PluginLoader *loader = PluginLoader::getInstance(); PluginLoader::PluginCategoryHierarchy @@ -181,21 +163,21 @@ static PyObject * vampyhost_getOutputList(PyObject *self, PyObject *args) { - PyObject *pyPluginHandle; + PyObject *keyOrHandle; Plugin::OutputList outputs; - if (!PyArg_ParseTuple(args, "O", &pyPluginHandle)) { + if (!PyArg_ParseTuple(args, "O", &keyOrHandle)) { PyErr_SetString(PyExc_TypeError, "getOutputList() takes plugin handle (object) or plugin key (string) argument"); - return NULL; + return 0; } - if (PyString_Check(pyPluginHandle) ) { + if (PyString_Check(keyOrHandle) ) { // we have a plugin key - string pluginKey = toPluginKey(pyPluginHandle); - if (pluginKey == "") return NULL; + string pluginKey = toPluginKey(keyOrHandle); + if (pluginKey == "") return 0; PluginLoader *loader = PluginLoader::getInstance(); @@ -204,7 +186,7 @@ if (!plugin) { string pyerr("Failed to load plugin: "); pyerr += pluginKey; PyErr_SetString(PyExc_TypeError,pyerr.c_str()); - return NULL; + return 0; } outputs = plugin->getOutputDescriptors(); @@ -215,15 +197,10 @@ // we have a loaded plugin handle - string *key; - Plugin *plugin; + PyPluginData *pd = getPluginData(keyOrHandle); + if (!pd) return 0; - if ( !getPluginHandle(pyPluginHandle, &plugin, &key) ) { - PyErr_SetString(PyExc_TypeError, - "Invalid or deleted plugin handle."); - return NULL; } - - outputs = plugin->getOutputDescriptors(); + outputs = pd->plugin->getOutputDescriptors(); } PyObject *pyList = PyList_New(outputs.size()); @@ -248,10 +225,10 @@ &inputSampleRate)) { PyErr_SetString(PyExc_TypeError, "loadPlugin() takes plugin key (string) and sample rate (number) arguments"); - return NULL; } + return 0; } string pluginKey = toPluginKey(pyPluginKey); - if (pluginKey == "") return NULL; + if (pluginKey == "") return 0; PluginLoader *loader = PluginLoader::getInstance(); @@ -260,25 +237,13 @@ if (!plugin) { string pyerr("Failed to load plugin: "); pyerr += pluginKey; PyErr_SetString(PyExc_TypeError,pyerr.c_str()); - return NULL; + return 0; } - PyPluginDescriptor *pd = new PyPluginDescriptor; - - pd->key = pluginKey; - pd->isInitialised = false; - pd->inputSampleRate = inputSampleRate; - - PyObject *pyPluginHandle = PyCObject_FromVoidPtrAndDesc( - (void*) plugin, (void*) pd, NULL); - - return pyPluginHandle; + PyPluginData *pd = new PyPluginData(pluginKey, plugin, inputSampleRate); + return PyCObject_FromVoidPtr(pd, 0); } - - -/* UNLOAD PLUGIN */ - static PyObject * vampyhost_unloadPlugin(PyObject *self, PyObject *args) { @@ -286,27 +251,20 @@ if (!PyArg_ParseTuple(args, "O", &pyPluginHandle)) { PyErr_SetString(PyExc_TypeError, - "Wrong input argument: Plugin Handle required."); - return NULL; } + "unloadPlugin() takes plugin handle (object) argument"); + return 0; + } - string *key; - Plugin *plugin; + PyPluginData *pd = getPluginData(pyPluginHandle); + if (!pd) return 0; - if ( !getPluginHandle(pyPluginHandle, &plugin, &key) ) { - PyErr_SetString(PyExc_TypeError, - "Invalid or already deleted plugin handle."); - return NULL; } + /* Prevent repeated calls from causing segfault since it will fail + * type checking the 2nd time: */ + PyCObject_SetVoidPtr(pyPluginHandle, 0); -/* Prevent repeated calls from causing segfault - sice it will fail type checking the 2nd time: */ - PyCObject_SetVoidPtr(pyPluginHandle,NULL); - - PyPluginDescriptor *pd = (PyPluginDescriptor*) key; - - delete plugin; + delete pd->plugin; delete pd; return pyPluginHandle; - } @@ -325,34 +283,24 @@ { PyErr_SetString(PyExc_TypeError, "Wrong input arguments: requires a valid plugin handle,channels,stepSize,blockSize."); - return NULL; + return 0; } - Plugin *plugin; - string *key; + PyPluginData *pd = getPluginData(pyPluginHandle); + if (!pd) return 0; - if ( !getPluginHandle(pyPluginHandle, &plugin, &key) ) { - PyErr_SetString(PyExc_TypeError, - "Invalid plugin handle."); - return NULL; } + pd->channels = channels; + pd->stepSize = stepSize; + pd->blockSize = blockSize; - // here we cast the void pointer as PyPluginDescriptor instead of string - PyPluginDescriptor *plugDesc = (PyPluginDescriptor*) key; - - plugDesc->channels = channels; - plugDesc->stepSize = stepSize; - plugDesc->blockSize = blockSize; - - if (!plugin->initialise(channels, stepSize, blockSize)) { + if (!pd->plugin->initialise(channels, stepSize, blockSize)) { std::cerr << "Failed to initialise native plugin adapter with channels = " << channels << ", stepSize = " << stepSize << ", blockSize = " << blockSize << " and ADAPT_ALL_SAFE set" << std::endl; PyErr_SetString(PyExc_TypeError, "Plugin initialization failed."); - return NULL; + return 0; } - plugDesc->identifier = - plugDesc->key.substr(plugDesc->key.rfind(':')+1); - plugDesc->isInitialised = true; + pd->isInitialised = true; return Py_True; } @@ -372,40 +320,33 @@ &pyRealTime)) { // TimeStamp PyErr_SetString(PyExc_TypeError, "Required: plugin handle, buffer, timestmap."); - return NULL; } + return 0; } if (!PyRealTime_Check(pyRealTime)) { PyErr_SetString(PyExc_TypeError,"Valid timestamp required."); - return NULL; } + return 0; } - string *key; - Plugin *plugin; - - if (!getPluginHandle(pyPluginHandle, &plugin, &key)) { - PyErr_SetString(PyExc_AttributeError, - "Invalid or already deleted plugin handle."); - return NULL; - } - - PyPluginDescriptor *pd = (PyPluginDescriptor*) key; + PyPluginData *pd = getPluginData(pyPluginHandle); + if (!pd) return 0; if (!pd->isInitialised) { PyErr_SetString(PyExc_StandardError, "Plugin has not been initialised."); - return NULL; } + return 0; + } int channels = pd->channels; // int blockSize = pd->blockSize; if (!PyList_Check(pyBuffer)) { PyErr_SetString(PyExc_TypeError, "List of NumPy Array required for process input."); - return NULL; + return 0; } if (PyList_GET_SIZE(pyBuffer) != channels) { std::cerr << "Wrong number of channels: got " << PyList_GET_SIZE(pyBuffer) << ", expected " << channels << std::endl; PyErr_SetString(PyExc_TypeError, "Wrong number of channels"); - return NULL; + return 0; } float **inbuf = new float *[channels]; @@ -426,14 +367,14 @@ RealTime timeStamp = *PyRealTime_AsRealTime(pyRealTime); //Call process and store the output - pd->output = plugin->process(inbuf, timeStamp); + pd->output = pd->plugin->process(inbuf, timeStamp); /* TODO: DO SOMETHONG WITH THE FEATURE SET HERE */ /// convert to appropriate python objects, reuse types and conversion utilities from Vampy ... delete[] inbuf; - return NULL; //!!! Need to return actual features! + return 0; //!!! Need to return actual features! } @@ -453,17 +394,10 @@ &pyOutput)) { // Output reference PyErr_SetString(PyExc_TypeError, "Required: plugin handle, buffer, timestmap."); - return NULL; } + return 0; } - string *key; - Plugin *plugin; - - if ( !getPluginHandle(pyPluginHandle, &plugin, &key) ) { - PyErr_SetString(PyExc_AttributeError, - "Invalid or already deleted plugin handle."); - return NULL; } - - PyPluginDescriptor *pd = (PyPluginDescriptor*) key; + PyPluginData *pd = getPluginData(pyPluginHandle); + if (!pd) return 0; unsigned int outputNo = (unsigned int) PyInt_AS_LONG(pyOutput); @@ -479,9 +413,9 @@ // Test: /* XxoObject *pyFeature = PyObject_New(XxoObject, &Xxo_Type); - if (pyFeature == NULL) break; //return NULL; + if (pyFeature == 0) break; //return 0; - pyFeature->x_attr = NULL; + pyFeature->x_attr = 0; pyFeature->feature = &pd->output[outputNo][i]; PyList_SET_ITEM(pyFeatureList,i,(PyObject*)pyFeature); @@ -504,7 +438,7 @@ // if (outputs.size()<1) { // string pyerr("Plugin has no output: "); pyerr += pluginKey; // PyErr_SetString(PyExc_TypeError,pyerr.c_str()); - // return NULL; + // return 0; // } // // //New list object @@ -563,7 +497,7 @@ {"realtime", (PyCFunction)RealTime_new, METH_VARARGS, PyDoc_STR("realtime() -> returns new RealTime object")}, */ - {NULL, NULL} /* sentinel */ + {0, 0} /* sentinel */ }; //Documentation for our new module @@ -589,7 +523,7 @@ /* Create the module and add the functions */ m = Py_InitModule3("vampyhost", vampyhost_methods, module_doc); - if (m == NULL) return; + if (!m) return; import_array();
--- a/vampyhost.h Mon Nov 24 11:02:28 2014 +0000 +++ b/vampyhost.h Mon Nov 24 14:39:56 2014 +0000 @@ -3,19 +3,4 @@ #ifndef _VAMPYHOST_H_ #define _VAMPYHOST_H_ -#include "vamp-hostsdk/Plugin.h" -#include <string> - -//structure for holding plugin instance data -typedef struct { - std::string key; - std::string identifier; - bool isInitialised; - float inputSampleRate; - size_t channels; - size_t blockSize; - size_t stepSize; - Vamp::Plugin::FeatureSet output; -} PyPluginDescriptor; - #endif