cannam@18: /* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */ fazekasgy@0: /* fazekasgy@0: Vamp fazekasgy@0: fazekasgy@0: An API for audio analysis and feature extraction plugins. fazekasgy@0: fazekasgy@0: Centre for Digital Music, Queen Mary, University of London. fazekasgy@0: Copyright 2006 Chris Cannam. fazekasgy@0: fazekasgy@0: Permission is hereby granted, free of charge, to any person fazekasgy@0: obtaining a copy of this software and associated documentation fazekasgy@0: files (the "Software"), to deal in the Software without fazekasgy@0: restriction, including without limitation the rights to use, copy, fazekasgy@0: modify, merge, publish, distribute, sublicense, and/or sell copies fazekasgy@0: of the Software, and to permit persons to whom the Software is fazekasgy@0: furnished to do so, subject to the following conditions: fazekasgy@0: fazekasgy@0: The above copyright notice and this permission notice shall be fazekasgy@0: included in all copies or substantial portions of the Software. fazekasgy@0: fazekasgy@0: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, fazekasgy@0: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF fazekasgy@0: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND fazekasgy@0: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR fazekasgy@0: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF fazekasgy@0: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION fazekasgy@0: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. fazekasgy@0: fazekasgy@0: Except as contained in this notice, the names of the Centre for fazekasgy@0: Digital Music; Queen Mary, University of London; and Chris Cannam fazekasgy@0: shall not be used in advertising or otherwise to promote the sale, fazekasgy@0: use or other dealings in this Software without prior written fazekasgy@0: authorization. fazekasgy@0: */ fazekasgy@0: fazekasgy@0: fazekasgy@0: fazekasgy@0: /** fazekasgy@8: * This Vamp plugin is a wrapper for Python Scripts. (VamPy) fazekasgy@0: * Centre for Digital Music, Queen Mary, University of London. fazekasgy@0: * Copyright 2008, George Fazekas. fazekasgy@0: fazekasgy@0: TODO: needs more complete error checking fazekasgy@0: needs correct implementation of Python threading fazekasgy@0: more efficient data conversion using the buffering interface or ctypes cannam@7: Vamp programs not implemented fazekasgy@0: support multiple plugins per script in scanner fazekasgy@0: ensure proper cleanup, host do a good job though fazekasgy@0: fazekasgy@0: */ fazekasgy@0: cannam@3: #include fazekasgy@0: #include "PyPlugin.h" fazekasgy@31: #include "PyTypeInterface.h" fazekasgy@31: #include fazekasgy@31: #include "PyExtensionModule.h" fazekasgy@31: //#include "PyRealTime.h" fazekasgy@31: fazekasgy@0: fazekasgy@0: #ifdef _WIN32 fazekasgy@31: #define PATHSEP ('\\') fazekasgy@0: #else fazekasgy@31: #define PATHSEP ('/') fazekasgy@0: #endif fazekasgy@0: fazekasgy@6: //#define _DEBUG fazekasgy@0: fazekasgy@0: using std::string; fazekasgy@0: using std::vector; fazekasgy@0: using std::cerr; fazekasgy@0: using std::endl; fazekasgy@0: using std::map; fazekasgy@0: fazekasgy@31: Mutex PyPlugin::m_pythonInterpreterMutex; fazekasgy@0: fazekasgy@31: PyPlugin::PyPlugin(std::string pluginKey, float inputSampleRate, PyObject *pyClass, int &instcount) : cannam@24: Plugin(inputSampleRate), cannam@24: m_pyClass(pyClass), fazekasgy@31: m_instcount(instcount), fazekasgy@0: m_stepSize(0), fazekasgy@6: m_blockSize(0), cannam@24: m_channels(0), fazekasgy@0: m_plugin(pluginKey), fazekasgy@0: m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)), fazekasgy@31: m_path((pluginKey.substr(0,pluginKey.rfind(PATHSEP)))), fazekasgy@6: m_processType(0), fazekasgy@6: m_pyProcess(NULL), fazekasgy@31: m_inputDomain(TimeDomain), fazekasgy@31: m_quitOnErrorFlag(false), fazekasgy@31: m_debugFlag(false) fazekasgy@0: { fazekasgy@31: m_ti.setInputSampleRate(inputSampleRate); fazekasgy@31: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: cerr << "Creating instance " << m_instcount << " of " << pluginKey << endl; fazekasgy@31: fazekasgy@31: if (m_instcount == 0) initvampy(); fazekasgy@31: m_instcount++; fazekasgy@31: fazekasgy@31: // if (!PyImport_ImportModule("vampy")) fazekasgy@31: // cerr << "Could not import extension." << endl; fazekasgy@31: cannam@24: // Create an instance fazekasgy@27: Py_INCREF(m_pyClass); cannam@24: PyObject *pyInputSampleRate = PyFloat_FromDouble(inputSampleRate); cannam@24: PyObject *args = PyTuple_Pack(1, pyInputSampleRate); fazekasgy@27: m_pyInstance = PyObject_Call(m_pyClass, args, NULL); fazekasgy@27: fazekasgy@27: if (!m_pyInstance || PyErr_Occurred()) { fazekasgy@27: if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } fazekasgy@28: Py_DECREF(m_pyClass); fazekasgy@27: Py_CLEAR(args); fazekasgy@27: Py_CLEAR(pyInputSampleRate); fazekasgy@31: cerr << "PyPlugin::PyPlugin: Failed to create Python plugin instance for key \"" fazekasgy@31: << pluginKey << "\" (is the 1-arg class constructor from sample rate correctly provided?)" << endl; cannam@24: throw std::string("Constructor failed"); cannam@24: } fazekasgy@27: Py_INCREF(m_pyInstance); cannam@24: Py_DECREF(args); cannam@24: Py_DECREF(pyInputSampleRate); fazekasgy@31: fazekasgy@31: //query the debug flag fazekasgy@31: m_debugFlag = getBooleanFlag("vampy_debug_messages",true); fazekasgy@31: if (m_debugFlag) cerr << "Debug messages ON for Vampy plugin: " << m_class << endl; fazekasgy@31: else cerr << "Debug messages OFF for Vampy plugin: " << m_class << endl; fazekasgy@31: fazekasgy@31: //query the quit on error flag fazekasgy@31: m_quitOnErrorFlag = getBooleanFlag("quit_on_type_error",false); fazekasgy@31: if (m_debugFlag && m_quitOnErrorFlag) cerr << "Quit on type error ON for: " << m_class << endl; fazekasgy@31: fazekasgy@31: //query the type conversion mode flag fazekasgy@31: bool st_flag = getBooleanFlag("use_strict_type_conversion",false); fazekasgy@31: if (m_debugFlag && st_flag) cerr << "Strict type conversion ON for: " << m_class << endl; fazekasgy@31: m_ti.setStrictTypingFlag(st_flag); fazekasgy@0: } fazekasgy@0: fazekasgy@0: PyPlugin::~PyPlugin() fazekasgy@0: { fazekasgy@31: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: m_instcount--; fazekasgy@31: cerr << "Deleting plugin instance. Count: " << m_instcount << endl; fazekasgy@31: cannam@24: if (m_pyInstance) Py_DECREF(m_pyInstance); fazekasgy@31: //we increase the class refcount before creating an instance fazekasgy@31: if (m_pyClass) Py_DECREF(m_pyClass); fazekasgy@27: if (m_pyProcess) Py_CLEAR(m_pyProcess); fazekasgy@31: if (m_instcount == 0) cleanModule(); cannam@24: fazekasgy@6: #ifdef _DEBUG fazekasgy@31: cerr << "PyPlugin::PyPlugin:" << m_class << " instance " << m_instcount << " deleted." << endl; fazekasgy@6: #endif fazekasgy@0: } fazekasgy@0: fazekasgy@0: fazekasgy@0: string fazekasgy@0: PyPlugin::getIdentifier() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: string rString="vampy-xxx"; fazekasgy@31: if (!m_debugFlag) return genericMethodCall("getIdentifier",rString); cannam@3: fazekasgy@31: rString = genericMethodCall("getIdentifier",rString); fazekasgy@31: if (rString == "vampy-xxx") fazekasgy@31: cerr << "Warning: Plugin must return a unique identifier." << endl; fazekasgy@0: return rString; fazekasgy@0: } fazekasgy@0: fazekasgy@0: string fazekasgy@0: PyPlugin::getName() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@0: string rString="VamPy Plugin (Noname)"; fazekasgy@31: return genericMethodCall("getName",rString); fazekasgy@0: } fazekasgy@0: fazekasgy@0: string fazekasgy@0: PyPlugin::getDescription() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: string rString="Not given. (Hint: Implement getDescription method.)"; fazekasgy@31: return genericMethodCall("getDescription",rString); fazekasgy@31: } cannam@3: fazekasgy@0: fazekasgy@0: string fazekasgy@0: PyPlugin::getMaker() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: string rString="VamPy Plugin."; fazekasgy@31: return genericMethodCall("getMaker",rString); fazekasgy@0: } fazekasgy@0: fazekasgy@0: int fazekasgy@0: PyPlugin::getPluginVersion() const fazekasgy@0: { fazekasgy@31: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: size_t rValue=2; fazekasgy@31: return genericMethodCall("getPluginVersion",rValue); fazekasgy@0: } fazekasgy@0: fazekasgy@0: string fazekasgy@0: PyPlugin::getCopyright() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: string rString="Licence information not available."; fazekasgy@31: return genericMethodCall("getCopyright",rString); fazekasgy@0: } fazekasgy@0: fazekasgy@0: fazekasgy@0: bool fazekasgy@0: PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) fazekasgy@0: { fazekasgy@31: cannam@24: if (channels < getMinChannelCount() || cannam@24: channels > getMaxChannelCount()) return false; fazekasgy@31: fazekasgy@6: m_inputDomain = getInputDomain(); fazekasgy@6: fazekasgy@31: //Note: placing Mutex before the calls above causes deadlock !! cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); cannam@3: fazekasgy@6: m_stepSize = stepSize; fazekasgy@6: m_blockSize = blockSize; fazekasgy@6: m_channels = channels; fazekasgy@6: fazekasgy@31: //query the process implementation type fazekasgy@31: //two optional flags can be used: 'use_numpy_interface' or 'use_legacy_interface' fazekasgy@31: //if they are not provided, we fall back to the original method fazekasgy@31: setProcessType(); fazekasgy@6: fazekasgy@31: return genericMethodCallArgs("initialise",channels,stepSize,blockSize); fazekasgy@0: } fazekasgy@0: fazekasgy@0: void fazekasgy@0: PyPlugin::reset() fazekasgy@0: { fazekasgy@6: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: genericMethodCall("reset"); fazekasgy@0: } fazekasgy@0: fazekasgy@31: PyPlugin::InputDomain fazekasgy@31: PyPlugin::getInputDomain() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: // Note: Vamp enum type is mapped to Python string !! fazekasgy@31: // Is there a better way? (Enums are not native to Python) fazekasgy@31: string rValue = "TimeDomain"; fazekasgy@31: genericMethodCall("getInputDomain",rValue); fazekasgy@31: return (rValue == "FrequencyDomain")?FrequencyDomain:TimeDomain; fazekasgy@0: } fazekasgy@0: fazekasgy@31: size_t fazekasgy@31: PyPlugin::getPreferredBlockSize() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: size_t rValue = 0; fazekasgy@31: return genericMethodCall("getPreferredBlockSize",rValue); fazekasgy@0: } fazekasgy@0: fazekasgy@31: size_t fazekasgy@31: PyPlugin::getPreferredStepSize() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: size_t rValue = 0; fazekasgy@31: return genericMethodCall("getPreferredStepSize",rValue); fazekasgy@0: } fazekasgy@0: fazekasgy@31: size_t fazekasgy@31: PyPlugin::getMinChannelCount() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: size_t rValue = 1; fazekasgy@31: return genericMethodCall("getMinChannelCount",rValue); fazekasgy@0: } fazekasgy@0: fazekasgy@31: size_t fazekasgy@31: PyPlugin::getMaxChannelCount() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: size_t rValue = 1; fazekasgy@31: return genericMethodCall("getMaxChannelCount",rValue); fazekasgy@31: } fazekasgy@0: fazekasgy@0: PyPlugin::OutputList fazekasgy@0: PyPlugin::getOutputDescriptors() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@0: OutputList list; fazekasgy@31: return genericMethodCall("getOutputDescriptors",list); fazekasgy@0: } fazekasgy@0: fazekasgy@0: PyPlugin::ParameterList fazekasgy@0: PyPlugin::getParameterDescriptors() const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@0: ParameterList list; fazekasgy@31: ///Note: This function is often called first by the host. fazekasgy@27: if (!m_pyInstance) {cerr << "Error: pyInstance is NULL" << endl; return list;} fazekasgy@31: return genericMethodCall("getParameterDescriptors",list); fazekasgy@0: } fazekasgy@0: fazekasgy@0: void PyPlugin::setParameter(std::string paramid, float newval) fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: genericMethodCallArgs("setParameter",paramid,newval); fazekasgy@0: } fazekasgy@0: fazekasgy@0: float PyPlugin::getParameter(std::string paramid) const fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: return genericMethodCallArgs("getParameter",paramid); fazekasgy@0: } fazekasgy@0: fazekasgy@0: #ifdef _DEBUG fazekasgy@0: static int proccounter = 0; fazekasgy@0: #endif fazekasgy@0: fazekasgy@0: PyPlugin::FeatureSet fazekasgy@31: PyPlugin::process(const float *const *inputBuffers,Vamp::RealTime timestamp) fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); cannam@3: fazekasgy@6: #ifdef _DEBUG fazekasgy@6: cerr << "[call] process, frame:" << proccounter << endl; fazekasgy@6: proccounter++; fazekasgy@6: #endif fazekasgy@6: fazekasgy@8: if (m_blockSize == 0 || m_channels == 0) { fazekasgy@0: cerr << "ERROR: PyPlugin::process: " fazekasgy@0: << "Plugin has not been initialised" << endl; fazekasgy@0: return FeatureSet(); fazekasgy@0: } fazekasgy@0: fazekasgy@6: if (m_processType == not_implemented) { fazekasgy@6: cerr << "ERROR: In Python plugin [" << m_class fazekasgy@6: << "] No process implementation found. Returning empty feature set." << endl; fazekasgy@6: return FeatureSet(); fazekasgy@6: } fazekasgy@0: fazekasgy@31: // string method=PyString_AsString(m_pyProcess); fazekasgy@6: fazekasgy@6: PyObject *pyOutputList = NULL; fazekasgy@0: fazekasgy@6: if (m_processType == numpyProcess) { fazekasgy@31: pyOutputList = numpyProcessCall(inputBuffers,timestamp); fazekasgy@6: } fazekasgy@6: fazekasgy@6: if (m_processType == legacyProcess) { fazekasgy@31: pyOutputList = legacyProcessCall(inputBuffers,timestamp); fazekasgy@0: } fazekasgy@6: fazekasgy@31: FeatureSet rFeatureset; fazekasgy@31: rFeatureset = m_ti.PyValue_To_FeatureSet(pyOutputList); fazekasgy@0: Py_CLEAR(pyOutputList); fazekasgy@31: return rFeatureset; fazekasgy@31: fazekasgy@0: } fazekasgy@0: fazekasgy@31: PyObject* fazekasgy@31: PyPlugin::numpyProcessCall(const float *const *inputBuffers,Vamp::RealTime timestamp) fazekasgy@31: { fazekasgy@31: PyObject *pyOutputList = NULL; fazekasgy@31: fazekasgy@31: //create a list of buffers fazekasgy@31: PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels); fazekasgy@31: for (size_t i=0; i < m_channels; ++i) { fazekasgy@31: //Expose memory using the Buffer Interface of C/API fazekasgy@32: //This will pass a pointer which can be recasted fazekasgy@32: //in Python code as float or complex array fazekasgy@31: PyObject *pyBuffer = PyBuffer_FromMemory fazekasgy@31: ((void *) (float *) inputBuffers[i], fazekasgy@31: (Py_ssize_t) sizeof(float) * m_blockSize); fazekasgy@0: fazekasgy@31: PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyBuffer); fazekasgy@31: } fazekasgy@31: /* fazekasgy@31: //(1) pass RealTime as frameCount fazekasgy@31: PyObject *pyLongSample = PyLong_FromLong ( fazekasgy@31: Vamp::RealTime::realTime2Frame fazekasgy@31: (timestamp, (unsigned int) m_inputSampleRate)); fazekasgy@31: fazekasgy@31: //Call python process (returns new reference) fazekasgy@31: pyOutputList = PyObject_CallMethodObjArgs fazekasgy@31: (m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL); fazekasgy@31: */ fazekasgy@31: //(2) pass RealTime as PyRealTime fazekasgy@31: PyObject *pyRealTime = PyRealTime_FromRealTime(timestamp); fazekasgy@31: fazekasgy@31: //Call python process (returns new reference) fazekasgy@31: pyOutputList = PyObject_CallMethodObjArgs fazekasgy@31: (m_pyInstance,m_pyProcess,pyChannelList,pyRealTime,NULL); fazekasgy@31: fazekasgy@31: Py_DECREF(pyChannelList); fazekasgy@31: // Py_DECREF(pyLongSample); fazekasgy@31: Py_DECREF(pyRealTime); fazekasgy@31: return pyOutputList; fazekasgy@31: } fazekasgy@31: fazekasgy@31: PyObject* fazekasgy@31: PyPlugin::legacyProcessCall(const float *const *inputBuffers,Vamp::RealTime timestamp) fazekasgy@31: { fazekasgy@31: PyObject *pyOutputList = NULL; fazekasgy@31: fazekasgy@31: //create a list of lists fazekasgy@31: PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels); fazekasgy@31: for (size_t i=0; i < m_channels; ++i) { fazekasgy@31: //New list object fazekasgy@31: PyObject *pyFloat, *pyList; fazekasgy@31: pyList = PyList_New((Py_ssize_t) m_blockSize); fazekasgy@31: fazekasgy@31: //Pack samples into a Python List Object fazekasgy@31: //pyFloat types will always be new references, fazekasgy@31: //these will be discarded when the list is deallocated fazekasgy@31: for (size_t j = 0; j < m_blockSize; ++j) { fazekasgy@31: pyFloat=PyFloat_FromDouble( fazekasgy@31: (double) inputBuffers[i][j]); fazekasgy@31: PyList_SET_ITEM(pyList, (Py_ssize_t) j, pyFloat); fazekasgy@31: } fazekasgy@31: PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyList); fazekasgy@31: } fazekasgy@31: fazekasgy@31: //pass RealTime as frameCount fazekasgy@31: PyObject *pyLongSample = PyLong_FromLong ( fazekasgy@31: Vamp::RealTime::realTime2Frame fazekasgy@31: (timestamp, (unsigned int) m_inputSampleRate)); fazekasgy@31: fazekasgy@31: //Call python process (returns new reference) fazekasgy@31: pyOutputList = PyObject_CallMethodObjArgs fazekasgy@31: (m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL); fazekasgy@31: fazekasgy@31: Py_DECREF(pyChannelList); fazekasgy@31: Py_DECREF(pyLongSample); fazekasgy@31: return pyOutputList; fazekasgy@31: } fazekasgy@0: fazekasgy@0: PyPlugin::FeatureSet fazekasgy@0: PyPlugin::getRemainingFeatures() fazekasgy@0: { cannam@3: MutexLocker locker(&m_pythonInterpreterMutex); fazekasgy@31: FeatureSet rValue; fazekasgy@31: return genericMethodCall("getRemainingFeatures",rValue); fazekasgy@0: } fazekasgy@0: fazekasgy@31: fazekasgy@6: bool fazekasgy@31: PyPlugin::getBooleanFlag(char flagName[], bool defValue = false) const fazekasgy@6: { fazekasgy@31: bool rValue = defValue; fazekasgy@31: if (PyObject_HasAttrString(m_pyInstance,flagName)) fazekasgy@31: { fazekasgy@31: PyObject *pyValue = PyObject_GetAttrString(m_pyInstance,flagName); fazekasgy@31: if (!pyValue) fazekasgy@31: { fazekasgy@31: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@31: } else { fazekasgy@31: rValue = m_ti.PyValue_To_Bool(pyValue); fazekasgy@31: if (m_ti.error) { fazekasgy@31: cerr << m_ti.lastError().message << endl; fazekasgy@31: Py_CLEAR(pyValue); fazekasgy@31: rValue = defValue; fazekasgy@31: } else Py_DECREF(pyValue); fazekasgy@31: } fazekasgy@31: } fazekasgy@31: if (m_debugFlag) cerr << FLAG_VALUE << endl; fazekasgy@31: return rValue; fazekasgy@6: } fazekasgy@6: fazekasgy@31: void fazekasgy@31: PyPlugin::setProcessType() fazekasgy@31: { fazekasgy@31: //quering process implementation type fazekasgy@31: char legacyMethod[]="process"; fazekasgy@31: char numpyMethod[]="processN"; fazekasgy@6: fazekasgy@31: if (PyObject_HasAttrString(m_pyInstance,legacyMethod) && fazekasgy@31: m_processType == 0) fazekasgy@31: { fazekasgy@31: m_processType = legacyProcess; fazekasgy@31: m_pyProcess = PyString_FromString(legacyMethod); fazekasgy@31: } fazekasgy@31: fazekasgy@31: if (PyObject_HasAttrString(m_pyInstance,numpyMethod) && fazekasgy@31: m_processType == 0) fazekasgy@31: { fazekasgy@31: m_processType = numpyProcess; fazekasgy@31: m_pyProcess = PyString_FromString(numpyMethod); fazekasgy@31: } fazekasgy@31: fazekasgy@31: // These flags are optional. If provided, they override the fazekasgy@31: // implementation type making the use of the odd processN() fazekasgy@31: // function redundant. fazekasgy@31: // However, the code above provides backwards compatibility. fazekasgy@31: if (getBooleanFlag("use_numpy_interface",false)) fazekasgy@31: m_processType = numpyProcess; fazekasgy@31: if (getBooleanFlag("use_legacy_interface",false)) fazekasgy@31: m_processType = legacyProcess; fazekasgy@31: if (m_debugFlag && m_processType) fazekasgy@31: cerr << "Process type: " << ((m_processType==numpyProcess)?"numpy process":"legacy process") << endl; fazekasgy@6: fazekasgy@31: if (!m_processType) fazekasgy@31: { fazekasgy@31: m_processType = not_implemented; fazekasgy@31: m_pyProcess = NULL; fazekasgy@31: char method[]="initialise::setProcessType"; fazekasgy@31: cerr << PLUGIN_ERROR << " No process implementation found. Plugin will do nothing." << endl; fazekasgy@6: } fazekasgy@6: } fazekasgy@6: