Chris@67: /* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */ 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: #include fazekasgy@37: #include "vamp/vamp.h" fazekasgy@37: #include "PyExtensionModule.h" fazekasgy@37: #include "PyExtensionManager.h" fazekasgy@37: #include Chris@67: #include "Debug.h" fazekasgy@37: fazekasgy@37: using std::cerr; fazekasgy@37: using std::endl; fazekasgy@37: using std::string; fazekasgy@37: using std::vector; fazekasgy@37: using std::find; fazekasgy@37: fazekasgy@37: //static Chris@66: const char* PyExtensionManager::m_exposedNames[] = { Chris@91: fazekasgy@37: "ParameterDescriptor", fazekasgy@37: "OutputDescriptor", fazekasgy@37: "FeatureSet", fazekasgy@37: "Feature", fazekasgy@37: "RealTime", fazekasgy@37: "frame2RealTime", Chris@91: Chris@91: /* // using builtin objects: Chris@91: "ParameterList", Chris@91: "OutputList", Chris@91: "FeatureList", fazekasgy@37: "OneSamplePerStep", fazekasgy@37: "FixedSampleRate", fazekasgy@37: "VariableSampleRate", fazekasgy@37: "TimeDomain", fazekasgy@37: "FrequencyDomain", fazekasgy@37: */ Chris@91: fazekasgy@37: NULL fazekasgy@37: }; fazekasgy@37: fazekasgy@37: PyExtensionManager::PyExtensionManager() fazekasgy@37: { Chris@67: DSTREAM << "Creating extension manager." << endl; fazekasgy@37: } fazekasgy@37: fazekasgy@37: bool fazekasgy@37: PyExtensionManager::initExtension() fazekasgy@37: { Chris@67: DSTREAM << "Initialising extension module." << endl; fazekasgy@37: fazekasgy@37: /// call the module initialiser first fazekasgy@37: initvampy(); fazekasgy@37: fazekasgy@37: /// these references are all borrowed fazekasgy@37: m_pyGlobalNamespace = PyImport_GetModuleDict(); fazekasgy@37: if (!m_pyGlobalNamespace) fazekasgy@37: {cerr << "Vampy::PyExtensionManager::initExtension: GlobalNamespace failed." << endl; return false;} fazekasgy@37: PyObject *pyVampyModule = PyDict_GetItemString(m_pyGlobalNamespace,"vampy"); fazekasgy@37: if (!pyVampyModule) fazekasgy@37: {cerr << "Vampy::PyExtensionManager::initExtension: VampyModule failed." << endl; return false;} fazekasgy@37: m_pyVampyNamespace = PyModule_GetDict(pyVampyModule); fazekasgy@37: if (!m_pyVampyNamespace) fazekasgy@37: {cerr << "Vampy::PyExtensionManager::initExtension: VampyNamespace failed." << endl; return false;} fazekasgy@37: fazekasgy@37: /// initialise local namespaces fazekasgy@37: updateAllLocals(); Chris@67: Chris@67: DSTREAM << "Vampy: Extension namespaces updated." << endl; Chris@67: fazekasgy@37: return true; fazekasgy@37: } fazekasgy@37: fazekasgy@37: fazekasgy@37: PyExtensionManager::~PyExtensionManager() fazekasgy@37: { Chris@67: DSTREAM << "Cleaning locals..." << endl; fazekasgy@37: fazekasgy@37: cleanAllLocals(); fazekasgy@37: Chris@67: DSTREAM << "Cleaning module..." << endl; fazekasgy@37: fazekasgy@37: if (!cleanModule()) fazekasgy@37: cerr << "Vampy::~PyExtensionManager: failed to clean extension module." << endl; Chris@67: DSTREAM << "Vampy::~PyExtensionManager: Extension module cleaned." << endl; fazekasgy@37: } fazekasgy@37: fazekasgy@37: fazekasgy@37: fazekasgy@37: void fazekasgy@37: PyExtensionManager::setPlugModuleNames(vector pyPlugs) fazekasgy@37: { fazekasgy@37: for (size_t i = 0; i < pyPlugs.size(); ++i) { fazekasgy@37: string modName = pyPlugs[i]; fazekasgy@37: string tmp = modName.substr(modName.rfind(':')+1,modName.size()-1); fazekasgy@37: m_plugModuleNames.push_back(tmp); fazekasgy@37: Chris@67: DSTREAM << "Inserted module name: " << tmp << endl; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: void fazekasgy@37: PyExtensionManager::deleteModuleName(string plugKey) fazekasgy@37: { fazekasgy@37: string name = plugKey.substr(plugKey.rfind(':')+1,plugKey.size()-1); fazekasgy@37: vector::iterator it = fazekasgy@37: find (m_plugModuleNames.begin(), m_plugModuleNames.end(), name); fazekasgy@37: if (it != m_plugModuleNames.end()) m_plugModuleNames.erase(it); Chris@67: Chris@67: DSTREAM << "PyExtensionManager::deleteModuleName: Deleted module name: " << name << endl; fazekasgy@37: } fazekasgy@37: fazekasgy@37: fazekasgy@37: void fazekasgy@37: PyExtensionManager::cleanAllLocals() const fazekasgy@37: { fazekasgy@37: for (size_t i = 0; i < m_plugModuleNames.size(); ++i) { fazekasgy@37: cleanLocalNamespace(m_plugModuleNames[i].c_str()); fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: void fazekasgy@37: PyExtensionManager::updateAllLocals() const fazekasgy@37: { fazekasgy@37: for (size_t i = 0; i < m_plugModuleNames.size(); ++i) { fazekasgy@37: updateLocalNamespace(m_plugModuleNames[i].c_str()); fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: void fazekasgy@37: PyExtensionManager::cleanLocalNamespace(const char* plugModuleName) const fazekasgy@37: { Chris@91: DSTREAM << "Cleaning local namespace: " << plugModuleName << endl; Chris@91: fazekasgy@37: /// these references are all borrowed fazekasgy@37: PyObject *pyPlugModule = PyDict_GetItemString(m_pyGlobalNamespace,plugModuleName); fazekasgy@37: if (!pyPlugModule) return; fazekasgy@37: PyObject *pyPlugDict = PyModule_GetDict(pyPlugModule); fazekasgy@37: if (!pyPlugDict) return; fazekasgy@37: fazekasgy@37: int i = 0; fazekasgy@37: while (PyExtensionManager::m_exposedNames[i]) { Chris@66: const char* name = PyExtensionManager::m_exposedNames[i]; fazekasgy@37: i++; fazekasgy@37: PyObject *key = PyString_FromString(name); fazekasgy@37: if (!key) break; fazekasgy@37: if (PyDict_Contains(pyPlugDict,key)) { fazekasgy@37: if (PyDict_SetItem(pyPlugDict,key,Py_None) != 0) fazekasgy@37: cerr << "Vampy::PyExtensionManager::cleanLocalNamespace: Failed: " fazekasgy@37: << name << " of "<< plugModuleName << endl; Chris@67: else DSTREAM << "Cleaned local name: " << name << endl; fazekasgy@37: } fazekasgy@37: Py_DECREF(key); fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: void fazekasgy@37: PyExtensionManager::updateLocalNamespace(const char* plugModuleName) const fazekasgy@37: { Chris@91: DSTREAM << "Updating local namespace: " << plugModuleName << endl; Chris@91: fazekasgy@37: /// this allows the use of common syntax like: fazekasgy@37: /// from vampy import * fazekasgy@37: /// even after several unload/reload cycles fazekasgy@37: fazekasgy@37: /// these references are all borrowed fazekasgy@37: PyObject *pyPlugModule = PyDict_GetItemString(m_pyGlobalNamespace,plugModuleName); fazekasgy@37: if (!pyPlugModule) return; fazekasgy@37: PyObject *pyPlugDict = PyModule_GetDict(pyPlugModule); fazekasgy@37: if (!pyPlugDict) return; fazekasgy@37: fazekasgy@37: int i = 0; fazekasgy@37: while (PyExtensionManager::m_exposedNames[i]) { fazekasgy@37: const char* name = PyExtensionManager::m_exposedNames[i]; fazekasgy@37: i++; fazekasgy@37: PyObject *key = PyString_FromString(name); fazekasgy@37: if (!key) break; fazekasgy@37: if (PyDict_Contains(pyPlugDict,key)) { fazekasgy@37: PyObject* item = PyDict_GetItem(m_pyVampyNamespace,key); fazekasgy@37: if (PyDict_SetItem(pyPlugDict,key,item) != 0) fazekasgy@37: cerr << "Vampy::PyExtensionManager::updateLocalNamespace: Failed: " fazekasgy@37: << name << " of "<< plugModuleName << endl; Chris@67: else DSTREAM << "Updated local name: " << name << endl; Chris@89: } else { Chris@89: DSTREAM << "Local namespace does not contain name: " << name << endl; fazekasgy@37: } fazekasgy@37: Py_DECREF(key); fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: fazekasgy@37: bool fazekasgy@37: PyExtensionManager::cleanModule(void) const fazekasgy@37: { fazekasgy@37: PyObject *m = PyImport_AddModule("vampy"); fazekasgy@37: if (!m) { fazekasgy@37: if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();} fazekasgy@37: cerr << "Vampy::PyExtensionManager::cleanModule: PyImport_AddModule returned NULL!" << endl; fazekasgy@37: return false; fazekasgy@37: } else { fazekasgy@37: PyObject *dict = PyModule_GetDict(m); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: Py_ssize_t ln = PyDict_Size(dict); Chris@67: DSTREAM << "Vampy::PyExtensionManager::cleanModule: Size of module dict = " << (int) ln << endl; fazekasgy@37: #endif fazekasgy@37: /// Clean the module dictionary. fazekasgy@37: // printDict(dict); fazekasgy@37: PyDict_Clear(dict); fazekasgy@37: if (PyErr_Occurred()) fazekasgy@37: { PyErr_Print(); PyErr_Clear(); return false; } fazekasgy@37: PyObject *name = PyString_FromString("vampy"); fazekasgy@37: if (name) PyDict_SetItemString(dict,"__name__",name); fazekasgy@37: Py_XDECREF(name); fazekasgy@37: #ifdef _DEBUG fazekasgy@37: ln = PyDict_Size(dict); Chris@67: DSTREAM << "Vampy::PyExtensionManager::cleanModule: Size of module dict (cleaned) = " << (int) ln << endl; fazekasgy@37: #endif fazekasgy@37: return true; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: fazekasgy@37: void fazekasgy@37: PyExtensionManager::printDict(PyObject* inDict) const fazekasgy@37: { fazekasgy@37: Py_ssize_t pyPos = 0; fazekasgy@37: PyObject *pyKey, *pyDictValue; fazekasgy@37: cerr << endl << endl << "Module dictionary contents: " << endl; fazekasgy@37: while (PyDict_Next(inDict, &pyPos, &pyKey, &pyDictValue)) fazekasgy@37: { fazekasgy@37: char *key = PyString_AS_STRING(pyKey); fazekasgy@37: char *val = PyString_AS_STRING(PyObject_Str(pyDictValue)); fazekasgy@37: cerr << "key: [ '" << key << "' ] value: " << val << endl; fazekasgy@37: } fazekasgy@37: } fazekasgy@37: