Mercurial > hg > vampy
changeset 6:e1b508f2f914
Added support to memory buffers to be used with NumPy (and some rationalisation of code)
author | fazekasgy |
---|---|
date | Wed, 19 Mar 2008 16:02:29 +0000 |
parents | 6ed5ebd38fde |
children | a4c955e9a70b |
files | Example VamPy plugins/PyZeroCrossing.py Makefile Mutex.cpp PyPlugin.cpp PyPlugin.h pyvamp-main.cpp |
diffstat | 6 files changed, 259 insertions(+), 425 deletions(-) [+] |
line wrap: on
line diff
--- a/Example VamPy plugins/PyZeroCrossing.py Fri Mar 14 12:09:34 2008 +0000 +++ b/Example VamPy plugins/PyZeroCrossing.py Wed Mar 19 16:02:29 2008 +0000 @@ -7,7 +7,7 @@ class PyZeroCrossing: def __init__(self): - self.m_imputSampleRate = 44100 + self.m_imputSampleRate = 0.0 self.m_stepSize = 0 self.m_blockSize = 0 self.m_channels = 0 @@ -38,7 +38,7 @@ def getOutputDescriptors(self): - #descriptors are python dictionary + #descriptors are python dictionaries output0={ 'identifier':'vampy-counts', 'name':'Number of Zero Crossings', @@ -131,7 +131,7 @@ self.previousSample = prev else : count = 0.0 - self.previousSample = inbuf[len(inbuf)-2] + self.previousSample = inbuf[len(inbuf)-1] feature0={ 'hasTimestamp':False,
--- a/Makefile Fri Mar 14 12:09:34 2008 +0000 +++ b/Makefile Wed Mar 19 16:02:29 2008 +0000 @@ -1,289 +1,26 @@ -# Makefile for the Vamp plugin SDK. This builds the SDK objects, -# libraries, example plugins, and the test host. Please adjust to -# suit your operating system requirements. +CXXFLAGS := -I../vamp-plugin-sdk -O2 -Wall -I/usr/include/python2.5 -APIDIR = sdk/vamp -SDKDIR = sdk/vamp-sdk -HOSTEXTDIR = sdk/vamp-sdk/hostext -#EXAMPLEDIR = sdk/examples -HOSTDIR = sdk/host -EXAMPLEDIR = . +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 -### -### Start of user-serviceable parts -### +clean: + rm *.o -# Default build target (or use "make <target>" to select one). -# Targets are: -# all -- build everything -# sdk -- build all the Vamp SDK libraries for plugins and hosts -# sdkstatic -- build only the static versions of the SDK libraries -# plugins -- build the example plugins (and the SDK if required) -# host -- build the simple Vamp plugin host (and the SDK if required) -# test -- build the host and example plugins, and run a quick test -# _clean -- remove binary targets -# distclean -- remove all targets -# cleanplug -- remove compiled plugin files -default: plugins - -# Compile flags +# Install plugin # -CXXFLAGS := $(CXXFLAGS) -O2 -Wall -I. -fPIC - -# ar, ranlib -# -AR := ar -RANLIB := ranlib - -# Libraries required for the plugins. -# (Note that it is desirable to statically link libstdc++ if possible, -# because our plugin exposes only a C API so there are no boundary -# compatibility problems.) -# -PLUGIN_LIBS = $(SDKDIR)/libvamp-sdk.a -#PLUGIN_LIBS = $(SDKDIR)/libvamp-sdk.a $(shell g++ -print-file-name=libstdc++.a) - -# File extension for a dynamically loadable object -# -#PLUGIN_EXT = .so -#PLUGIN_EXT = .dll -PLUGIN_EXT = .dylib - -# Libraries required for the host. -# -HOST_LIBS = $(SDKDIR)/libvamp-hostsdk.a -lsndfile -ldl - -# Locations for "make install". This will need quite a bit of -# editing for non-Linux platforms. Of course you don't necessarily -# have to use "make install". -# -INSTALL_PREFIX := /usr/local -INSTALL_API_HEADERS := $(INSTALL_PREFIX)/include/vamp -INSTALL_SDK_HEADERS := $(INSTALL_PREFIX)/include/vamp-sdk -INSTALL_HOSTEXT_HEADERS := $(INSTALL_PREFIX)/include/vamp-sdk/hostext -INSTALL_SDK_LIBS := $(INSTALL_PREFIX)/lib - -INSTALL_SDK_LIBNAME := libvamp-sdk.dylib.1.1.0 -INSTALL_SDK_LINK_ABI := libvamp-sdk.dylib.1 -INSTALL_SDK_LINK_DEV := libvamp-sdk.dylib -INSTALL_SDK_STATIC := libvamp-sdk.o -INSTALL_SDK_LA := libvamp-sdk.la - -INSTALL_HOSTSDK_LIBNAME := libvamp-hostsdk.dylib.2.0.0 -INSTALL_HOSTSDK_LINK_ABI := libvamp-hostsdk.dylib.2 -INSTALL_HOSTSDK_LINK_DEV := libvamp-hostsdk.dylib -INSTALL_HOSTSDK_STATIC := libvamp-hostsdk.a -INSTALL_HOSTSDK_LA := libvamp-hostsdk.la - -INSTALL_PKGCONFIG := $(INSTALL_PREFIX)/lib/pkgconfig - -# Install plugins to this location -# -LIBRARY_PREFIX :=/Library -INSTALL_PLUGIN :=$(LIBRARY_PREFIX)/Audio/Plug-Ins/Vamp - -# Flags required to tell the compiler to create a dynamically loadable object -# -#DYNAMIC_LDFLAGS = --static-libgcc -shared -Wl,-Bsymbolic -DYNAMIC_LDFLAGS = -dynamiclib -PLUGIN_LDFLAGS = $(DYNAMIC_LDFLAGS) -SDK_DYNAMIC_LDFLAGS = $(DYNAMIC_LDFLAGS) -Wl,-soname=$(INSTALL_SDK_LINK_ABI) -HOSTSDK_DYNAMIC_LDFLAGS = $(DYNAMIC_LDFLAGS) -Wl,-soname=$(INSTALL_HOSTSDK_LINK_ABI) - -## For OS/X with g++: -#DYNAMIC_LDFLAGS = -dynamiclib -PLUGIN_LDFLAGS = $(DYNAMIC_LDFLAGS) -SDK_DYNAMIC_LDFLAGS = $(DYNAMIC_LDFLAGS) -HOSTSDK_DYNAMIC_LDFLAGS = $(DYNAMIC_LDFLAGS) - - -### End of user-serviceable parts - -# Plugin headers, compiler objects and targets - -PLUGIN_HEADERS = \ - $(EXAMPLEDIR)/PyPlugScanner.h \ - $(EXAMPLEDIR)/PyPlugin.h - -PLUGIN_OBJECTS = \ - $(EXAMPLEDIR)/PyPlugScanner.o \ - $(EXAMPLEDIR)/PyPlugin.o \ - $(EXAMPLEDIR)/pyvamp-main.o - -PLUGIN_NAME = vamp-pyvamp-plugin - -PLUGIN_TARGET = \ - $(EXAMPLEDIR)/$(PLUGIN_NAME)$(PLUGIN_EXT) - -PLUGIN_DESCRIPTORS = \ - $(EXAMPLEDIR)/exampleplugin.n3 - -# We need to link with python -# Links the actual python executable. forces to export symbol _PyMac_Error -PYTHON_LINK_AS_SHARED := \ - -u _PyMac_Error /Library/Frameworks/Python.framework/Versions/2.5/Python - -API_HEADERS = \ - $(APIDIR)/vamp.h - -SDK_HEADERS = \ - $(SDKDIR)/Plugin.h \ - $(SDKDIR)/PluginAdapter.h \ - $(SDKDIR)/PluginBase.h \ - $(SDKDIR)/RealTime.h - -HOSTSDK_HEADERS = \ - $(SDKDIR)/Plugin.h \ - $(SDKDIR)/PluginBase.h \ - $(SDKDIR)/PluginHostAdapter.h \ - $(SDKDIR)/RealTime.h - -HOSTEXT_HEADERS = \ - $(HOSTEXTDIR)/PluginBufferingAdapter.h \ - $(HOSTEXTDIR)/PluginChannelAdapter.h \ - $(HOSTEXTDIR)/PluginInputDomainAdapter.h \ - $(HOSTEXTDIR)/PluginLoader.h \ - $(HOSTEXTDIR)/PluginWrapper.h - -SDK_OBJECTS = \ - $(SDKDIR)/PluginAdapter.o \ - $(SDKDIR)/RealTime.o - -HOSTSDK_OBJECTS = \ - $(SDKDIR)/PluginHostAdapter.o \ - $(HOSTEXTDIR)/PluginBufferingAdapter.o \ - $(HOSTEXTDIR)/PluginChannelAdapter.o \ - $(HOSTEXTDIR)/PluginInputDomainAdapter.o \ - $(HOSTEXTDIR)/PluginLoader.o \ - $(HOSTEXTDIR)/PluginWrapper.o \ - $(SDKDIR)/RealTime.o - -SDK_STATIC = \ - $(SDKDIR)/libvamp-sdk.a - -HOSTSDK_STATIC = \ - $(SDKDIR)/libvamp-hostsdk.a - -SDK_DYNAMIC = \ - $(SDKDIR)/libvamp-sdk$(PLUGIN_EXT) - -HOSTSDK_DYNAMIC = \ - $(SDKDIR)/libvamp-hostsdk$(PLUGIN_EXT) - -SDK_LA = \ - $(SDKDIR)/libvamp-sdk.la - -HOSTSDK_LA = \ - $(SDKDIR)/libvamp-hostsdk.la - -HOST_HEADERS = \ - $(HOSTDIR)/system.h - -HOST_OBJECTS = \ - $(HOSTDIR)/vamp-simple-host.o - -HOST_TARGET = \ - $(HOSTDIR)/vamp-simple-host - -#Primary Make rules -# - -sdk: sdkstatic $(SDK_DYNAMIC) $(HOSTSDK_DYNAMIC) - -sdkstatic: - $(SDK_STATIC) $(HOSTSDK_STATIC) - $(RANLIB) $(SDK_STATIC) - $(RANLIB) $(HOSTSDK_STATIC) - -plugins: $(PLUGIN_TARGET) - -host: $(HOST_TARGET) - -all: sdk plugins host test - -#This is where all the stuff gets built -# - -$(SDK_STATIC): $(SDK_OBJECTS) $(API_HEADERS) $(SDK_HEADERS) - $(AR) r $@ $(SDK_OBJECTS) - -$(HOSTSDK_STATIC): $(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS) $(HOSTEXT_HEADERS) - $(AR) r $@ $(HOSTSDK_OBJECTS) - -$(SDK_DYNAMIC): $(SDK_OBJECTS) $(API_HEADERS) $(SDK_HEADERS) - $(CXX) $(LDFLAGS) $(SDK_DYNAMIC_LDFLAGS) -o $@ $(SDK_OBJECTS) - -$(HOSTSDK_DYNAMIC): $(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS) $(HOSTEXT_HEADERS) - $(CXX) $(LDFLAGS) $(HOSTSDK_DYNAMIC_LDFLAGS) -o $@ $(HOSTSDK_OBJECTS) - -$(PLUGIN_TARGET): $(PLUGIN_OBJECTS) $(SDK_STATIC) $(PLUGIN_HEADERS) - $(CXX) $(LDFLAGS) $(PLUGIN_LDFLAGS) -o $@ $(PLUGIN_OBJECTS) $(PLUGIN_LIBS) $(PYTHON_LINK_AS_SHARED) - -$(HOST_TARGET): $(HOST_OBJECTS) $(HOSTSDK_STATIC) $(HOST_HEADERS) - $(CXX) $(LDFLAGS) $(HOST_LDFLAGS) -o $@ $(HOST_OBJECTS) $(HOST_LIBS) - -test: plugins host - VAMP_PATH=$(EXAMPLEDIR) $(HOST_TARGET) -l - -_clean: - rm -f $(SDK_OBJECTS) $(HOSTSDK_OBJECTS) $(PLUGIN_OBJECTS) $(HOST_OBJECTS) - -cleanplug : - rm -f $(PLUGIN_OBJECTS) - rm -f $(EXAMPLEDIR)/$(PLUGIN_NAME)$(PLUGIN_EXT) -# rm -f $(LIBRARY_PREFIX)/$(INSTALL_PLUGIN)/$(PLUGIN_NAME)$(PLUGIN_EXT) - - -distclean: clean - rm -f $(SDK_STATIC) $(SDK_DYNAMIC) $(HOSTSDK_STATIC) $(HOSTSDK_DYNAMIC) $(PLUGIN_TARGET) $(HOST_TARGET) *~ */*~ - -_install: $(SDK_STATIC) $(SDK_DYNAMIC) $(HOSTSDK_STATIC) $(HOSTSDK_DYNAMIC) $(PLUGIN_TARGET) $(HOST_TARGET) - mkdir -p $(DESTDIR)$(INSTALL_API_HEADERS) - mkdir -p $(DESTDIR)$(INSTALL_SDK_HEADERS) - mkdir -p $(DESTDIR)$(INSTALL_HOSTEXT_HEADERS) - mkdir -p $(DESTDIR)$(INSTALL_SDK_LIBS) - mkdir -p $(DESTDIR)$(INSTALL_PKGCONFIG) - cp $(API_HEADERS) $(DESTDIR)$(INSTALL_API_HEADERS) - cp $(SDK_HEADERS) $(DESTDIR)$(INSTALL_SDK_HEADERS) - cp $(HOSTSDK_HEADERS) $(DESTDIR)$(INSTALL_SDK_HEADERS) - cp $(HOSTEXT_HEADERS) $(DESTDIR)$(INSTALL_HOSTEXT_HEADERS) - cp $(SDK_STATIC) $(DESTDIR)$(INSTALL_SDK_LIBS) - cp $(HOSTSDK_STATIC) $(DESTDIR)$(INSTALL_SDK_LIBS) - cp $(SDK_DYNAMIC) $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LIBNAME) - cp $(HOSTSDK_DYNAMIC) $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LIBNAME) - rm -f $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_ABI) - ln -s $(INSTALL_SDK_LIBNAME) $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_ABI) - rm -f $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_ABI) - ln -s $(INSTALL_HOSTSDK_LIBNAME) $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_ABI) - rm -f $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_DEV) - ln -s $(INSTALL_SDK_LIBNAME) $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_DEV) - rm -f $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_DEV) - ln -s $(INSTALL_HOSTSDK_LIBNAME) $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_DEV) - sed "s,%PREFIX%,$(INSTALL_PREFIX)," $(APIDIR)/vamp.pc.in \ - > $(DESTDIR)$(INSTALL_PKGCONFIG)/vamp.pc - sed "s,%PREFIX%,$(INSTALL_PREFIX)," $(SDKDIR)/vamp-sdk.pc.in \ - > $(DESTDIR)$(INSTALL_PKGCONFIG)/vamp-sdk.pc - sed "s,%PREFIX%,$(INSTALL_PREFIX)," $(SDKDIR)/vamp-hostsdk.pc.in \ - > $(DESTDIR)$(INSTALL_PKGCONFIG)/vamp-hostsdk.pc - sed -e "s,%LIBNAME%,$(INSTALL_SDK_LIBNAME),g" \ - -e "s,%LINK_ABI%,$(INSTALL_SDK_LINK_ABI),g" \ - -e "s,%LINK_DEV%,$(INSTALL_SDK_LINK_DEV),g" \ - -e "s,%STATIC%,$(INSTALL_SDK_STATIC),g" \ - -e "s,%LIBS%,$(INSTALL_SDK_LIBS),g" $(SDK_LA).in \ - > $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LA) - sed -e "s,%LIBNAME%,$(INSTALL_HOSTSDK_LIBNAME),g" \ - -e "s,%LINK_ABI%,$(INSTALL_HOSTSDK_LINK_ABI),g" \ - -e "s,%LINK_DEV%,$(INSTALL_HOSTSDK_LINK_DEV),g" \ - -e "s,%STATIC%,$(INSTALL_HOSTSDK_STATIC),g" \ - -e "s,%LIBS%,$(INSTALL_SDK_LIBS),g" $(HOSTSDK_LA).in \ - > $(DESTDIR)$(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LA) - -installplug: - mkdir -p $(INSTALL_PLUGIN) - rm -f $(INSTALL_PLUGIN)/$(PLUGIN_NAME)$(PLUGIN_EXT) - cp $(PLUGIN_NAME)$(PLUGIN_EXT) $(INSTALL_PLUGIN)/$(PLUGIN_NAME)$(PLUGIN_EXT) -# cp $(PLUGIN_DESCRIPTORS) $(INSTALL_PLUGIN) - -installplugin: installplug +LIBRARY_PREFIX :=/Library +INSTALL_DIR :=$(LIBRARY_PREFIX)/Audio/Plug-Ins/Vamp +PYEXAMPLE_DIR :='Example VamPy Plugins' +PLUGIN_NAME :=vampy +PLUGIN_EXT :=.dylib + +install: + mkdir -p $(INSTALL_DIR) + rm -f $(INSTALL_DIR)/$(PLUGIN_NAME)$(PLUGIN_EXT) + cp $(PLUGIN_NAME)$(PLUGIN_EXT) $(INSTALL_DIR)/$(PLUGIN_NAME)$(PLUGIN_EXT) + cp $(PYEXAMPLE_DIR)/*.py $(INSTALL_DIR) + +installplug : install +cleanplug : clean
--- a/Mutex.cpp Fri Mar 14 12:09:34 2008 +0000 +++ b/Mutex.cpp Wed Mar 19 16:02:29 2008 +0000 @@ -6,7 +6,6 @@ */ #include "Mutex.h" - #include <iostream> #ifndef _WIN32
--- a/PyPlugin.cpp Fri Mar 14 12:09:34 2008 +0000 +++ b/PyPlugin.cpp Wed Mar 19 16:02:29 2008 +0000 @@ -57,7 +57,7 @@ #define pathsep ('/') #endif -#define _DEBUG +//#define _DEBUG using std::string; using std::vector; @@ -72,109 +72,30 @@ static std::map<std::string, p::eParmDescriptors> parmKeys; Mutex PyPlugin::m_pythonInterpreterMutex; - -void initMaps() -{ - outKeys["identifier"] = identifier; - outKeys["name"] = name; - outKeys["description"] = description; - outKeys["unit"] = unit; - outKeys["hasFixedBinCount"] = hasFixedBinCount; - outKeys["binCount"] = binCount; - outKeys["binNames"] = binNames; - outKeys["hasKnownExtents"] = hasKnownExtents; - outKeys["minValue"] = minValue; - outKeys["maxValue"] = maxValue; - outKeys["isQuantized"] = isQuantized; - outKeys["quantizeStep"] = quantizeStep; - outKeys["sampleType"] = sampleType; - outKeys["sampleRate"] = sampleRate; - - sampleKeys["OneSamplePerStep"] = OneSamplePerStep; - sampleKeys["FixedSampleRate"] = FixedSampleRate; - sampleKeys["VariableSampleRate"] = VariableSampleRate; - - ffKeys["hasTimestamp"] = hasTimestamp; - ffKeys["timeStamp"] = timeStamp; - 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; - -} - - -//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> PyList_To_StringVector (PyObject *inputList) { - - 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; -} - -//missing API helper: convert Python list to C++ vector of floats -std::vector<float> PyList_As_FloatVector (PyObject *inputList) { - - 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); - 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; -} -*/ - +static bool isMapInitialised = false; PyPlugin::PyPlugin(std::string pluginKey,float inputSampleRate, PyObject *pyInstance) : Plugin(inputSampleRate), m_pyInstance(pyInstance), m_stepSize(0), - m_previousSample(0.0f), + 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) { } PyPlugin::~PyPlugin() { + Py_CLEAR(m_pyProcess); +#ifdef _DEBUG cerr << "PyPlugin::PyPlugin:" << m_class << " Instance deleted." << endl; +#endif } @@ -185,7 +106,7 @@ char method[]="getIdentifier"; cerr << "[call] " << method << endl; - string rString="VampPy-x"; + string rString="vampy-x"; if ( PyObject_HasAttrString(m_pyInstance,method) ) { @@ -203,6 +124,7 @@ rString=PyString_AsString(pyString); Py_CLEAR(pyString); + return rString; } cerr << "Warning: Plugin must return a unique identifier." << endl; return rString; @@ -336,15 +258,51 @@ bool PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) { + + //placing Mutex before these calls causes deadlock + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_inputDomain = getInputDomain(); + MutexLocker locker(&m_pythonInterpreterMutex); - if (channels < getMinChannelCount() || - channels > getMaxChannelCount()) return false; - - m_stepSize = std::min(stepSize, blockSize); + //useful for debugging Python plugins char method[]="initialise"; cerr << "[call] " << method << endl; + initMaps(); + + m_stepSize = stepSize; + m_blockSize = blockSize; + m_channels = channels; + + //quering process implementation type + char legacyMethod[]="process"; + char numpyMethod[]="processN"; + m_processType = 0; + + if (PyObject_HasAttrString(m_pyInstance,legacyMethod)) + { + m_processType = legacyProcess; + m_pyProcess = PyString_FromString(legacyMethod); + } + + if (PyObject_HasAttrString(m_pyInstance,numpyMethod)) + { + m_processType = numpyProcess; + m_pyProcess = PyString_FromString(numpyMethod); + } + + 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)) { @@ -379,17 +337,26 @@ Py_CLEAR(pyBool); return false;} } - return true; + return false; } void PyPlugin::reset() { - //!!! implement this! - m_previousSample = 0.0f; + 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(); } + + } } -PyPlugin::InputDomain PyPlugin::getInputDomain() const +PyPlugin::InputDomain PyPlugin::getInputDomain() const { MutexLocker locker(&m_pythonInterpreterMutex); @@ -416,6 +383,7 @@ return rValue; } + size_t PyPlugin::getPreferredBlockSize() const { MutexLocker locker(&m_pythonInterpreterMutex); @@ -517,8 +485,9 @@ PyPlugin::OutputList PyPlugin::getOutputDescriptors() const { + MutexLocker locker(&m_pythonInterpreterMutex); - + //PyEval_AcquireThread(newThreadState); OutputList list; OutputDescriptor od; @@ -526,7 +495,7 @@ cerr << "[call] " << method << endl; //Check if the method is implemented in Python - if ( PyObject_HasAttrString(m_pyInstance,method) ) { + if ( ! PyObject_HasAttrString(m_pyInstance,method) ) return list; //Call the method: must return list object (new reference) PyObject *pyList = @@ -607,13 +576,11 @@ break; default : cerr << "Invalid key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl; - } // switch - } // while dict keys + } + } // while dict list.push_back(od); - } // for each memeber in outputlist + } // for list Py_CLEAR(pyList); - } // if method is implemented - //PyEval_ReleaseThread(newThreadState); return list; } @@ -628,7 +595,7 @@ cerr << "[call] " << method << endl; //Check if the method is implemented in Python - if ( PyObject_HasAttrString(m_pyInstance,method) ) { + if ( ! PyObject_HasAttrString(m_pyInstance,method) ) return list; //Call the method: must return list object (new reference) PyObject *pyList = @@ -692,12 +659,11 @@ break; default : cerr << "Invalid key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl; - } // switch - } // while dict keys + } + } // while dict list.push_back(pd); - } // for each memeber in outputlist + } // for list Py_CLEAR(pyList); - } // if return list; } @@ -779,41 +745,68 @@ { MutexLocker locker(&m_pythonInterpreterMutex); - if (m_stepSize == 0) { +#ifdef _DEBUG + cerr << "[call] process, frame:" << proccounter << endl; + proccounter++; +#endif + + if (m_blockSize == 0) { cerr << "ERROR: PyPlugin::process: " << "Plugin has not been initialised" << endl; return FeatureSet(); } - static char method[]="process"; -#ifdef _DEBUG - cerr << "[call] " << method << " frame:" << proccounter << endl; - proccounter++; - //cerr << "C: proc..." << proccounter << " " << endl; -#endif + if (m_processType == not_implemented) { + cerr << "ERROR: In Python plugin [" << m_class + << "] No process implementation found. Returning empty feature set." << endl; + return FeatureSet(); + } - //proces::Check if the method is implemented in Python - if ( PyObject_HasAttrString(m_pyInstance,method) ) - { + string method=PyString_AsString(m_pyProcess); + + + + PyObject *pyOutputList = NULL; - //Pack method name into Python Object - PyObject *pyMethod = PyString_FromString(method); + /*new numPy support*/ + if (m_processType == numpyProcess) { + + //declare buffer object + PyObject *pyBuffer; + + //Expose memory using the Buffer Interface of C/API + //This will virtually pass a pointer only that can be + //recasted in Python code + pyBuffer = + PyBuffer_FromMemory((void *) (float *) inputBuffers[0], + (Py_ssize_t) sizeof(float) * m_blockSize); + + //Call python process (returns new reference) + pyOutputList = + PyObject_CallMethodObjArgs(m_pyInstance,m_pyProcess,pyBuffer,NULL); + + } + + if (m_processType == legacyProcess) { //Declare new list object PyObject *pyFloat, *pyList; - pyList = PyList_New((Py_ssize_t) m_stepSize); + pyList = PyList_New((Py_ssize_t) m_blockSize); //Pack samples into a Python List Object - //pyFloat will always be new references, + //pyFloat types will always be new references, //these will be discarded when the list is deallocated - for (size_t i = 0; i < m_stepSize; ++i) { + for (size_t i = 0; i < m_blockSize; ++i) { pyFloat=PyFloat_FromDouble((double) inputBuffers[0][i]); PyList_SET_ITEM(pyList, (Py_ssize_t) i, pyFloat); } - + //Call python process (returns new reference) - PyObject *pyOutputList = - PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyList,NULL); + pyOutputList = + PyObject_CallMethodObjArgs(m_pyInstance,m_pyProcess,pyList,NULL); + + } + //Check return type if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) { @@ -825,12 +818,12 @@ cerr << "ERROR: In Python plugin [" << m_class << "::" << method << "] Expected List return type." << endl; } - Py_CLEAR(pyMethod); + //Py_CLEAR(pyMethod); Py_CLEAR(pyOutputList); return FeatureSet(); } - Py_DECREF(pyMethod); + //Py_DECREF(pyMethod); // Py_DECREF(pyList); // This appears to be tracked by the cyclic garbage collector // hence decrefing produces GC error @@ -902,9 +895,6 @@ }//for i = FeatureSet Py_CLEAR(pyOutputList); return returnFeatures; - - }//if (has_attribute) - return FeatureSet(); } @@ -994,3 +984,97 @@ return returnFeatures; } +bool +PyPlugin::initMaps() const +{ + + if (isMapInitialised) return true; + + outKeys["identifier"] = identifier; + outKeys["name"] = name; + outKeys["description"] = description; + outKeys["unit"] = unit; + outKeys["hasFixedBinCount"] = hasFixedBinCount; + outKeys["binCount"] = binCount; + outKeys["binNames"] = binNames; + outKeys["hasKnownExtents"] = hasKnownExtents; + outKeys["minValue"] = minValue; + outKeys["maxValue"] = maxValue; + outKeys["isQuantized"] = isQuantized; + outKeys["quantizeStep"] = quantizeStep; + outKeys["sampleType"] = sampleType; + outKeys["sampleRate"] = sampleRate; + + sampleKeys["OneSamplePerStep"] = OneSamplePerStep; + sampleKeys["FixedSampleRate"] = FixedSampleRate; + sampleKeys["VariableSampleRate"] = VariableSampleRate; + + ffKeys["hasTimestamp"] = hasTimestamp; + ffKeys["timeStamp"] = timeStamp; + 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; + + isMapInitialised = true; + return true; +} + + +//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 { + + 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; +} + +//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); + 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 Fri Mar 14 12:09:34 2008 +0000 +++ b/PyPlugin.h Wed Mar 19 16:02:29 2008 +0000 @@ -92,6 +92,11 @@ label }; +enum eProcessType { + not_implemented, + legacyProcess, + numpyProcess + }; class PyPlugin : public Vamp::Plugin { @@ -101,7 +106,7 @@ bool initialise(size_t channels, size_t stepSize, size_t blockSize); void reset(); - //virtuals: + InputDomain getInputDomain() const; size_t getPreferredBlockSize() const; size_t getPreferredStepSize() const; @@ -128,10 +133,18 @@ protected: PyObject *m_pyInstance; size_t m_stepSize; - float m_previousSample; + size_t m_blockSize; + size_t m_channels; std::string m_plugin; std::string m_class; std::string m_path; + int m_processType; + PyObject *m_pyProcess; + InputDomain m_inputDomain; + + bool initMaps() const; + std::vector<std::string> PyList_To_StringVector (PyObject *inputList) const; + std::vector<float> PyList_As_FloatVector (PyObject *inputList) const; static Mutex m_pythonInterpreterMutex; };
--- a/pyvamp-main.cpp Fri Mar 14 12:09:34 2008 +0000 +++ b/pyvamp-main.cpp Wed Mar 19 16:02:29 2008 +0000 @@ -61,7 +61,7 @@ using std::string; using std::vector; -volatile bool mutex = false; +//volatile bool mutex = false; static int adinstcount; class PyPluginAdapter : public Vamp::PluginAdapterBase @@ -149,7 +149,7 @@ scanner = PyPlugScanner::getInstance(); pyPath=scanner->getAllValidPath(); //add this as extra path for development - pyPath.push_back("/Users/Shared/Development/vamp-experiments"); + //pyPath.push_back("/Users/Shared/Development/vamp-experiments"); scanner->setPath(pyPath); pyPlugs = scanner->getPyPlugs(); cerr << "Found " << pyPlugs.size() << " Scripts ...OK" << endl; @@ -161,6 +161,7 @@ adapters.push_back( new PyPluginAdapter(pyPlugs[i],pyInstances[i])); } haveScannedPlugins=true; + } cerr << "Accessing adapter index: " << index << " (adapters: " << adapters.size() << ")" << endl;