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: /* fazekasgy@37: Vamp fazekasgy@37: fazekasgy@37: An API for audio analysis and feature extraction plugins. fazekasgy@37: fazekasgy@37: Centre for Digital Music, Queen Mary, University of London. fazekasgy@37: Copyright 2006 Chris Cannam. fazekasgy@37: fazekasgy@37: Permission is hereby granted, free of charge, to any person fazekasgy@37: obtaining a copy of this software and associated documentation fazekasgy@37: files (the "Software"), to deal in the Software without fazekasgy@37: restriction, including without limitation the rights to use, copy, fazekasgy@37: modify, merge, publish, distribute, sublicense, and/or sell copies fazekasgy@37: of the Software, and to permit persons to whom the Software is fazekasgy@37: furnished to do so, subject to the following conditions: fazekasgy@37: fazekasgy@37: The above copyright notice and this permission notice shall be fazekasgy@37: included in all copies or substantial portions of the Software. fazekasgy@37: fazekasgy@37: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, fazekasgy@37: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF fazekasgy@37: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND fazekasgy@37: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR fazekasgy@37: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF fazekasgy@37: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION fazekasgy@37: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. fazekasgy@37: fazekasgy@37: Except as contained in this notice, the names of the Centre for fazekasgy@37: Digital Music; Queen Mary, University of London; and Chris Cannam fazekasgy@37: shall not be used in advertising or otherwise to promote the sale, fazekasgy@37: use or other dealings in this Software without prior written fazekasgy@37: authorization. fazekasgy@37: */ fazekasgy@37: fazekasgy@37: #ifndef _PYTHON_WRAPPER_PLUGIN_H_ fazekasgy@37: #define _PYTHON_WRAPPER_PLUGIN_H_ fazekasgy@37: fazekasgy@37: #define _CLASS_METHOD_ m_class << "::" << method fazekasgy@37: #define PLUGIN_ERROR "ERROR: In Vampy plugin [" << _CLASS_METHOD_ << "]" << endl << "Cause: " fazekasgy@37: #define DEBUG_NAME "[Vampy::call] " << _CLASS_METHOD_ << " " fazekasgy@37: #define DEAFULT_RETURN "Method [" << _CLASS_METHOD_ << "] is not implemented. Returning default value." fazekasgy@37: #define FLAG_VALUE "Flag: " << flagName << ": " << ((rValue==0)?"False":"True") fazekasgy@37: fazekasgy@37: #include fazekasgy@37: #include "PyExtensionModule.h" fazekasgy@37: #include "PyTypeInterface.h" fazekasgy@37: #include "vamp-sdk/Plugin.h" fazekasgy@37: #include "Mutex.h" fazekasgy@37: fazekasgy@37: using std::string; fazekasgy@37: using std::cerr; fazekasgy@37: using std::endl; fazekasgy@37: fazekasgy@37: enum eProcessType { fazekasgy@37: not_implemented, fazekasgy@37: legacyProcess, fazekasgy@37: numpyProcess, fazekasgy@37: numpy_bufferProcess, fazekasgy@37: numpy_arrayProcess fazekasgy@37: }; fazekasgy@37: fazekasgy@37: class PyPlugin : public Vamp::Plugin fazekasgy@37: { fazekasgy@37: public: fazekasgy@51: PyPlugin(std::string plugin,float inputSampleRate, PyObject *pyClass, int &instcount, bool &numpyInstalled); fazekasgy@37: virtual ~PyPlugin(); fazekasgy@37: fazekasgy@37: bool initialise(size_t channels, size_t stepSize, size_t blockSize); fazekasgy@37: void reset(); fazekasgy@37: fazekasgy@37: InputDomain getInputDomain() const; fazekasgy@37: size_t getPreferredBlockSize() const; fazekasgy@37: size_t getPreferredStepSize() const; fazekasgy@37: size_t getMinChannelCount() const; fazekasgy@37: size_t getMaxChannelCount() const; fazekasgy@37: fazekasgy@37: std::string getIdentifier() const; fazekasgy@37: std::string getName() const; fazekasgy@37: std::string getDescription() const; fazekasgy@37: std::string getMaker() const; fazekasgy@37: int getPluginVersion() const; fazekasgy@37: std::string getCopyright() const; fazekasgy@37: fazekasgy@37: OutputList getOutputDescriptors() const; fazekasgy@37: ParameterList getParameterDescriptors() const; fazekasgy@37: float getParameter(std::string paramid) const; fazekasgy@37: void setParameter(std::string paramid, float newval); fazekasgy@37: fazekasgy@37: FeatureSet process(const float *const *inputBuffers, fazekasgy@37: Vamp::RealTime timestamp); fazekasgy@37: fazekasgy@37: FeatureSet getRemainingFeatures(); fazekasgy@37: fazekasgy@37: protected: fazekasgy@37: static Mutex m_pythonInterpreterMutex; fazekasgy@37: PyObject *m_pyClass; fazekasgy@37: PyObject *m_pyInstance; fazekasgy@37: int &m_instcount; fazekasgy@37: size_t m_stepSize; fazekasgy@37: size_t m_blockSize; fazekasgy@37: size_t m_channels; fazekasgy@37: std::string m_plugin; fazekasgy@37: std::string m_class; fazekasgy@37: std::string m_path; fazekasgy@37: eProcessType m_processType; fazekasgy@37: PyObject *m_pyProcess; fazekasgy@37: PyObject *m_pyProcessCallable; fazekasgy@37: mutable InputDomain m_inputDomain; fazekasgy@37: PyTypeInterface m_ti; fazekasgy@37: int m_vampyFlags; fazekasgy@37: bool m_quitOnErrorFlag; fazekasgy@37: bool m_debugFlag; fazekasgy@37: bool m_useRealTimeFlag; fazekasgy@51: bool m_numpyInstalled; fazekasgy@51: mutable bool m_processFailure; fazekasgy@37: fazekasgy@37: void setProcessType(); fazekasgy@37: fazekasgy@37: FeatureSet processMethodCall(const float *const *inputBuffers,Vamp::RealTime timestamp); fazekasgy@37: fazekasgy@37: bool getBooleanFlag(char flagName[],bool) const; fazekasgy@37: int getBinaryFlags(char flagName[], eVampyFlags) const; fazekasgy@51: void typeErrorHandler(char *method, bool process = false) const; fazekasgy@37: fazekasgy@37: /// simple 'void return' call with no args fazekasgy@37: void genericMethodCall(char *method) const fazekasgy@37: { fazekasgy@37: if (m_debugFlag) cerr << DEBUG_NAME << endl; fazekasgy@37: if ( PyObject_HasAttrString(m_pyInstance,method) ) fazekasgy@37: { fazekasgy@37: PyObject *pyValue = PyObject_CallMethod(m_pyInstance, method, NULL); fazekasgy@37: if (!pyValue) { fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to call method." << endl; fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: } fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// 'no arg with default return value' call fazekasgy@37: template fazekasgy@37: RET &genericMethodCall(char *method, RET &rValue) const fazekasgy@37: { fazekasgy@37: if (m_debugFlag) cerr << DEBUG_NAME << endl; fazekasgy@37: if ( PyObject_HasAttrString(m_pyInstance,method) ) fazekasgy@37: { fazekasgy@37: PyObject *pyValue = PyObject_CallMethod(m_pyInstance, method, NULL); fazekasgy@37: if (!pyValue) { fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to call method." << endl; fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// convert the returned value fazekasgy@37: m_ti.PyValue_To_rValue(pyValue,rValue); fazekasgy@37: if (!m_ti.error) { fazekasgy@37: Py_DECREF(pyValue); fazekasgy@37: } else { fazekasgy@37: Py_CLEAR(pyValue); fazekasgy@37: typeErrorHandler(method); fazekasgy@37: } fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: if (m_debugFlag) cerr << DEAFULT_RETURN << endl; fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// unary call fazekasgy@37: template fazekasgy@37: RET genericMethodCallArgs(char *method, A1 arg1) const fazekasgy@37: { fazekasgy@37: RET rValue = RET(); fazekasgy@37: if (m_debugFlag) cerr << DEBUG_NAME << endl; fazekasgy@37: if (!PyObject_HasAttrString(m_pyInstance,method)) { fazekasgy@37: if (m_debugFlag) cerr << DEAFULT_RETURN << endl; fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// prepare arguments for fast method call fazekasgy@37: PyObject *pyMethod = m_ti.PyValue_From_CValue(method); fazekasgy@37: PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod); fazekasgy@37: PyObject* pyArgs = PyTuple_New(1); fazekasgy@37: if (!(pyArgs && pyCallable && pyMethod)) { fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to prepare argument for calling method." << endl; fazekasgy@37: Py_CLEAR(pyMethod); fazekasgy@37: Py_CLEAR(pyCallable); fazekasgy@37: Py_CLEAR(pyArgs); fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1); fazekasgy@37: if (m_ti.error) { fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to convert argument for calling method." << endl; fazekasgy@37: typeErrorHandler(method); fazekasgy@37: Py_CLEAR(pyMethod); fazekasgy@37: Py_CLEAR(pyCallable); fazekasgy@37: Py_CLEAR(pyArg1); fazekasgy@37: Py_CLEAR(pyArgs); fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: PyTuple_SET_ITEM(pyArgs, 0, pyArg1); fazekasgy@37: Py_INCREF(pyArg1); fazekasgy@37: fazekasgy@37: /// call the method fazekasgy@37: PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL); fazekasgy@37: if (!pyValue) fazekasgy@37: { fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to call method." << endl; fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: Py_CLEAR(pyMethod); fazekasgy@37: Py_CLEAR(pyCallable); fazekasgy@37: Py_CLEAR(pyArg1); fazekasgy@37: Py_CLEAR(pyArgs); fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: Py_DECREF(pyMethod); fazekasgy@37: Py_DECREF(pyCallable); fazekasgy@37: Py_DECREF(pyArg1); fazekasgy@37: Py_DECREF(pyArgs); fazekasgy@37: fazekasgy@37: /// convert the returned value fazekasgy@37: m_ti.PyValue_To_rValue(pyValue,rValue); fazekasgy@37: if (!m_ti.error) { fazekasgy@37: Py_DECREF(pyValue); fazekasgy@37: } else { fazekasgy@37: Py_CLEAR(pyValue); fazekasgy@37: typeErrorHandler(method); fazekasgy@37: } fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// binary call fazekasgy@37: template fazekasgy@37: RET genericMethodCallArgs(char *method, A1 arg1, A2 arg2) const fazekasgy@37: { fazekasgy@37: RET rValue = RET(); fazekasgy@37: if (m_debugFlag) cerr << DEBUG_NAME << endl; fazekasgy@37: if (!PyObject_HasAttrString(m_pyInstance,method)) { fazekasgy@37: if (m_debugFlag) cerr << DEAFULT_RETURN << endl; fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// prepare arguments for fast method call fazekasgy@37: PyObject *pyMethod = m_ti.PyValue_From_CValue(method); fazekasgy@37: PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod); fazekasgy@37: PyObject* pyArgs = PyTuple_New(2); fazekasgy@37: if (!(pyArgs && pyCallable && pyMethod)) { fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to prepare arguments for calling method." << endl; fazekasgy@37: Py_CLEAR(pyMethod); fazekasgy@37: Py_CLEAR(pyCallable); fazekasgy@37: Py_CLEAR(pyArgs); fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1); fazekasgy@37: PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2); fazekasgy@37: if (m_ti.error) { fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl; fazekasgy@37: typeErrorHandler(method); fazekasgy@37: Py_CLEAR(pyMethod); fazekasgy@37: Py_CLEAR(pyCallable); fazekasgy@37: Py_CLEAR(pyArg1); fazekasgy@37: Py_CLEAR(pyArg2); fazekasgy@37: Py_CLEAR(pyArgs); fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: PyTuple_SET_ITEM(pyArgs, 0, pyArg1); fazekasgy@37: Py_INCREF(pyArg1); fazekasgy@37: PyTuple_SET_ITEM(pyArgs, 1, pyArg2); fazekasgy@37: Py_INCREF(pyArg2); fazekasgy@37: fazekasgy@37: // calls the method fazekasgy@37: PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL); fazekasgy@37: if (!pyValue) fazekasgy@37: { fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to call method." << endl; fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: Py_CLEAR(pyMethod); fazekasgy@37: Py_CLEAR(pyCallable); fazekasgy@37: Py_CLEAR(pyArg1); fazekasgy@37: Py_CLEAR(pyArg2); fazekasgy@37: Py_CLEAR(pyArgs); fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: Py_DECREF(pyMethod); fazekasgy@37: Py_DECREF(pyCallable); fazekasgy@37: Py_DECREF(pyArg1); fazekasgy@37: Py_DECREF(pyArg2); fazekasgy@37: Py_DECREF(pyArgs); fazekasgy@37: fazekasgy@37: /// convert the returned value fazekasgy@37: m_ti.PyValue_To_rValue(pyValue,rValue); fazekasgy@37: if (!m_ti.error) { fazekasgy@37: Py_DECREF(pyValue); fazekasgy@37: } else { fazekasgy@37: Py_CLEAR(pyValue); fazekasgy@37: typeErrorHandler(method); fazekasgy@37: } fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// trenary call fazekasgy@37: template fazekasgy@37: RET genericMethodCallArgs(char *method, A1 arg1, A2 arg2, A3 arg3) const fazekasgy@37: { fazekasgy@37: RET rValue = RET(); fazekasgy@37: if (m_debugFlag) cerr << DEBUG_NAME << endl; fazekasgy@37: if (!PyObject_HasAttrString(m_pyInstance,method)) { fazekasgy@37: if (m_debugFlag) cerr << DEAFULT_RETURN << endl; fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// prepare arguments for fast method call fazekasgy@37: PyObject *pyMethod = m_ti.PyValue_From_CValue(method); fazekasgy@37: PyObject *pyCallable = PyObject_GetAttr(m_pyInstance,pyMethod); fazekasgy@37: PyObject* pyArgs = PyTuple_New(3); fazekasgy@37: if (!(pyArgs && pyCallable && pyMethod)) { fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to prepare arguments for calling method." << endl; fazekasgy@37: Py_CLEAR(pyMethod); fazekasgy@37: Py_CLEAR(pyCallable); fazekasgy@37: Py_CLEAR(pyArgs); fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: PyObject *pyArg1 = m_ti.PyValue_From_CValue(arg1); fazekasgy@37: PyObject *pyArg2 = m_ti.PyValue_From_CValue(arg2); fazekasgy@37: PyObject *pyArg3 = m_ti.PyValue_From_CValue(arg3); fazekasgy@37: if (m_ti.error) { fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to convert arguments for calling method." << endl; fazekasgy@37: typeErrorHandler(method); fazekasgy@37: Py_CLEAR(pyMethod); fazekasgy@37: Py_CLEAR(pyCallable); fazekasgy@37: Py_CLEAR(pyArg1); fazekasgy@37: Py_CLEAR(pyArg2); fazekasgy@37: Py_CLEAR(pyArg3); fazekasgy@37: Py_CLEAR(pyArgs); fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: /// Optimization: Pack args in a tuple to avoid va_list parsing. fazekasgy@37: PyTuple_SET_ITEM(pyArgs, 0, pyArg1); fazekasgy@37: Py_INCREF(pyArg1); fazekasgy@37: PyTuple_SET_ITEM(pyArgs, 1, pyArg2); fazekasgy@37: Py_INCREF(pyArg2); fazekasgy@37: PyTuple_SET_ITEM(pyArgs, 2, pyArg3); fazekasgy@37: Py_INCREF(pyArg3); fazekasgy@37: fazekasgy@37: // PyObject *pyValue = PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyArg1,pyArg2,pyArg3,NULL); fazekasgy@37: /// fast method call fazekasgy@37: PyObject *pyValue = PyObject_Call(pyCallable,pyArgs,NULL); fazekasgy@37: if (!pyValue) fazekasgy@37: { fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to call method." << endl; fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: Py_CLEAR(pyMethod); fazekasgy@37: Py_CLEAR(pyCallable); fazekasgy@37: Py_CLEAR(pyArg1); fazekasgy@37: Py_CLEAR(pyArg2); fazekasgy@37: Py_CLEAR(pyArg3); fazekasgy@37: Py_CLEAR(pyArgs); fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: Py_DECREF(pyMethod); fazekasgy@37: Py_DECREF(pyCallable); fazekasgy@37: Py_DECREF(pyArg1); fazekasgy@37: Py_DECREF(pyArg2); fazekasgy@37: Py_DECREF(pyArg3); fazekasgy@37: Py_DECREF(pyArgs); fazekasgy@37: fazekasgy@37: /// convert the returned value fazekasgy@37: m_ti.PyValue_To_rValue(pyValue,rValue); fazekasgy@37: if (!m_ti.error) { fazekasgy@37: Py_DECREF(pyValue); fazekasgy@37: } else { fazekasgy@37: Py_CLEAR(pyValue); fazekasgy@37: typeErrorHandler(method); fazekasgy@37: } fazekasgy@37: return rValue; fazekasgy@37: } fazekasgy@37: fazekasgy@37: }; fazekasgy@37: fazekasgy@37: /// optimised process call fazekasgy@37: inline PyPlugin::FeatureSet fazekasgy@37: PyPlugin::processMethodCall(const float *const *inputBuffers,Vamp::RealTime timestamp) fazekasgy@37: { fazekasgy@51: fazekasgy@37: /// Optimizations: 1) we avoid ...ObjArg functions since we know fazekasgy@37: /// the number of arguments, and we don't like va_list parsing fazekasgy@37: /// in the process. 2) Also: we're supposed to incref args, fazekasgy@37: /// but instead, we let the arguments tuple steal the references fazekasgy@37: /// and decref them when it is deallocated. fazekasgy@37: /// 3) all conversions are now using the fast sequence protocol fazekasgy@37: /// (indexing the underlying object array). fazekasgy@37: fazekasgy@37: FeatureSet rFeatureSet; fazekasgy@37: PyObject *pyChannelList = NULL; fazekasgy@37: fazekasgy@37: if (m_processType == numpy_bufferProcess) { fazekasgy@51: pyChannelList = m_ti.InputBuffers_As_SharedMemoryList( fazekasgy@51: inputBuffers,m_channels,m_blockSize,m_inputDomain); fazekasgy@37: } fazekasgy@37: fazekasgy@37: if (m_processType == legacyProcess) { fazekasgy@51: pyChannelList = m_ti.InputBuffers_As_PythonLists( fazekasgy@51: inputBuffers,m_channels,m_blockSize,m_inputDomain); fazekasgy@37: } fazekasgy@37: fazekasgy@37: #ifdef HAVE_NUMPY fazekasgy@37: if (m_processType == numpy_arrayProcess) { fazekasgy@51: pyChannelList = m_ti.InputBuffers_As_NumpyArray( fazekasgy@51: inputBuffers,m_channels,m_blockSize,m_inputDomain); fazekasgy@37: } fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: /// we don't expect these to fail unless out of memory (which is very unlikely on modern systems) fazekasgy@37: #ifdef _DEBUG fazekasgy@37: if (!pyChannelList) { fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: std::string method = PyString_AsString(m_pyProcess); fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to create channel list." << endl; fazekasgy@37: return rFeatureSet; fazekasgy@37: } fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: PyObject *pyTimeStamp = NULL; fazekasgy@37: fazekasgy@37: if (m_useRealTimeFlag) { fazekasgy@37: //(1) pass TimeStamp as PyRealTime object fazekasgy@37: pyTimeStamp = PyRealTime_FromRealTime(timestamp); fazekasgy@37: fazekasgy@37: } else { fazekasgy@37: //(2) pass TimeStamp as frame count (long Sample Count) fazekasgy@37: pyTimeStamp = PyLong_FromLong(Vamp::RealTime::realTime2Frame fazekasgy@37: (timestamp, (unsigned int) m_inputSampleRate)); fazekasgy@37: } fazekasgy@37: fazekasgy@37: fazekasgy@37: #ifdef _DEBUG fazekasgy@37: if (!pyTimeStamp) { fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: std::string method = PyString_AsString(m_pyProcess); fazekasgy@37: cerr << PLUGIN_ERROR << "Failed to create RealTime time stamp." << endl; fazekasgy@37: Py_DECREF(pyChannelList); fazekasgy@37: return rFeatureSet; fazekasgy@37: } fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: /// Old method: Call python process (returns new reference) fazekasgy@37: /// PyObject *pyValue = PyObject_CallMethodObjArgs fazekasgy@37: /// (m_pyInstance,m_pyProcess,pyChannelList,pyTimeStamp,NULL); fazekasgy@37: fazekasgy@37: PyObject *pyArgs = PyTuple_New(2); fazekasgy@37: PyTuple_SET_ITEM(pyArgs, 0, pyChannelList); fazekasgy@37: PyTuple_SET_ITEM(pyArgs, 1, pyTimeStamp); fazekasgy@37: fazekasgy@37: /// Call python process (returns new reference) {kwArgs = NULL} fazekasgy@37: PyObject *pyValue = PyObject_Call(m_pyProcessCallable,pyArgs,NULL); fazekasgy@37: fazekasgy@37: if (!pyValue) { fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: std::string method = PyString_AsString(m_pyProcess); fazekasgy@37: cerr << PLUGIN_ERROR << "An error occurred while evaluating Python process." << endl; fazekasgy@37: Py_CLEAR(pyValue); fazekasgy@37: Py_CLEAR(pyArgs); fazekasgy@37: return rFeatureSet; fazekasgy@37: } fazekasgy@37: fazekasgy@37: rFeatureSet = m_ti.PyValue_To_FeatureSet(pyValue); fazekasgy@37: if (!m_ti.error) { fazekasgy@37: Py_DECREF(pyValue); fazekasgy@37: Py_DECREF(pyArgs); fazekasgy@37: } else { fazekasgy@51: typeErrorHandler(PyString_AsString(m_pyProcess),true); fazekasgy@37: Py_CLEAR(pyValue); fazekasgy@37: Py_CLEAR(pyArgs); fazekasgy@37: } fazekasgy@37: return rFeatureSet; fazekasgy@37: } fazekasgy@37: fazekasgy@37: #endif