annotate PyExtensionManager.cpp @ 70:6c755f3e1173

More fixes
author Chris Cannam
date Mon, 17 Nov 2014 14:07:00 +0000
parents 146d14ab15e7
children f92587bedb2c
rev   line source
Chris@67 1 /* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */
fazekasgy@37 2 /*
fazekasgy@37 3
fazekasgy@37 4 * Vampy : This plugin is a wrapper around the Vamp plugin API.
fazekasgy@37 5 * It allows for writing Vamp plugins in Python.
fazekasgy@37 6
fazekasgy@37 7 * Centre for Digital Music, Queen Mary University of London.
fazekasgy@37 8 * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources
fazekasgy@37 9 * for licence information.)
fazekasgy@37 10
fazekasgy@37 11 */
fazekasgy@37 12
fazekasgy@37 13 #include <Python.h>
fazekasgy@37 14 #include "vamp/vamp.h"
fazekasgy@37 15 #include "PyExtensionModule.h"
fazekasgy@37 16 #include "PyExtensionManager.h"
fazekasgy@37 17 #include <algorithm>
Chris@67 18 #include "Debug.h"
fazekasgy@37 19
fazekasgy@37 20 using std::cerr;
fazekasgy@37 21 using std::endl;
fazekasgy@37 22 using std::string;
fazekasgy@37 23 using std::vector;
fazekasgy@37 24 using std::find;
fazekasgy@37 25
fazekasgy@37 26 //static
Chris@66 27 const char* PyExtensionManager::m_exposedNames[] = {
fazekasgy@37 28 "ParameterDescriptor",
fazekasgy@37 29 "OutputDescriptor",
fazekasgy@37 30 "ParameterList",
fazekasgy@37 31 "OutputList",
fazekasgy@37 32 "FeatureList",
fazekasgy@37 33 "FeatureSet",
fazekasgy@37 34 "Feature",
fazekasgy@37 35 "RealTime",
fazekasgy@37 36 "frame2RealTime",
fazekasgy@37 37 /* //using builtin objects:
fazekasgy@37 38 "OneSamplePerStep",
fazekasgy@37 39 "FixedSampleRate",
fazekasgy@37 40 "VariableSampleRate",
fazekasgy@37 41 "TimeDomain",
fazekasgy@37 42 "FrequencyDomain",
fazekasgy@37 43 */
fazekasgy@37 44 NULL
fazekasgy@37 45 };
fazekasgy@37 46
fazekasgy@37 47 PyExtensionManager::PyExtensionManager()
fazekasgy@37 48 {
Chris@67 49 DSTREAM << "Creating extension manager." << endl;
fazekasgy@37 50 }
fazekasgy@37 51
fazekasgy@37 52 bool
fazekasgy@37 53 PyExtensionManager::initExtension()
fazekasgy@37 54 {
Chris@67 55 DSTREAM << "Initialising extension module." << endl;
fazekasgy@37 56
fazekasgy@37 57 /// call the module initialiser first
fazekasgy@37 58 initvampy();
fazekasgy@37 59
fazekasgy@37 60 /// these references are all borrowed
fazekasgy@37 61 m_pyGlobalNamespace = PyImport_GetModuleDict();
fazekasgy@37 62 if (!m_pyGlobalNamespace)
fazekasgy@37 63 {cerr << "Vampy::PyExtensionManager::initExtension: GlobalNamespace failed." << endl; return false;}
fazekasgy@37 64 PyObject *pyVampyModule = PyDict_GetItemString(m_pyGlobalNamespace,"vampy");
fazekasgy@37 65 if (!pyVampyModule)
fazekasgy@37 66 {cerr << "Vampy::PyExtensionManager::initExtension: VampyModule failed." << endl; return false;}
fazekasgy@37 67 m_pyVampyNamespace = PyModule_GetDict(pyVampyModule);
fazekasgy@37 68 if (!m_pyVampyNamespace)
fazekasgy@37 69 {cerr << "Vampy::PyExtensionManager::initExtension: VampyNamespace failed." << endl; return false;}
fazekasgy@37 70
fazekasgy@37 71 /// initialise local namespaces
fazekasgy@37 72 updateAllLocals();
Chris@67 73
Chris@67 74 DSTREAM << "Vampy: Extension namespaces updated." << endl;
Chris@67 75
fazekasgy@37 76 return true;
fazekasgy@37 77 }
fazekasgy@37 78
fazekasgy@37 79
fazekasgy@37 80 PyExtensionManager::~PyExtensionManager()
fazekasgy@37 81 {
Chris@67 82 DSTREAM << "Cleaning locals..." << endl;
fazekasgy@37 83
fazekasgy@37 84 cleanAllLocals();
fazekasgy@37 85
Chris@67 86 DSTREAM << "Cleaning module..." << endl;
fazekasgy@37 87
fazekasgy@37 88 if (!cleanModule())
fazekasgy@37 89 cerr << "Vampy::~PyExtensionManager: failed to clean extension module." << endl;
Chris@67 90 DSTREAM << "Vampy::~PyExtensionManager: Extension module cleaned." << endl;
fazekasgy@37 91 }
fazekasgy@37 92
fazekasgy@37 93
fazekasgy@37 94
fazekasgy@37 95 void
fazekasgy@37 96 PyExtensionManager::setPlugModuleNames(vector<string> pyPlugs)
fazekasgy@37 97 {
fazekasgy@37 98 for (size_t i = 0; i < pyPlugs.size(); ++i) {
fazekasgy@37 99 string modName = pyPlugs[i];
fazekasgy@37 100 string tmp = modName.substr(modName.rfind(':')+1,modName.size()-1);
fazekasgy@37 101 m_plugModuleNames.push_back(tmp);
fazekasgy@37 102
Chris@67 103 DSTREAM << "Inserted module name: " << tmp << endl;
fazekasgy@37 104 }
fazekasgy@37 105 }
fazekasgy@37 106
fazekasgy@37 107 void
fazekasgy@37 108 PyExtensionManager::deleteModuleName(string plugKey)
fazekasgy@37 109 {
fazekasgy@37 110 string name = plugKey.substr(plugKey.rfind(':')+1,plugKey.size()-1);
fazekasgy@37 111 vector<string>::iterator it =
fazekasgy@37 112 find (m_plugModuleNames.begin(), m_plugModuleNames.end(), name);
fazekasgy@37 113 if (it != m_plugModuleNames.end()) m_plugModuleNames.erase(it);
Chris@67 114
Chris@67 115 DSTREAM << "PyExtensionManager::deleteModuleName: Deleted module name: " << name << endl;
fazekasgy@37 116 }
fazekasgy@37 117
fazekasgy@37 118
fazekasgy@37 119 void
fazekasgy@37 120 PyExtensionManager::cleanAllLocals() const
fazekasgy@37 121 {
fazekasgy@37 122 for (size_t i = 0; i < m_plugModuleNames.size(); ++i) {
fazekasgy@37 123 cleanLocalNamespace(m_plugModuleNames[i].c_str());
fazekasgy@37 124 }
fazekasgy@37 125 }
fazekasgy@37 126
fazekasgy@37 127 void
fazekasgy@37 128 PyExtensionManager::updateAllLocals() const
fazekasgy@37 129 {
fazekasgy@37 130 for (size_t i = 0; i < m_plugModuleNames.size(); ++i) {
fazekasgy@37 131 updateLocalNamespace(m_plugModuleNames[i].c_str());
fazekasgy@37 132 }
fazekasgy@37 133 }
fazekasgy@37 134
fazekasgy@37 135 void
fazekasgy@37 136 PyExtensionManager::cleanLocalNamespace(const char* plugModuleName) const
fazekasgy@37 137 {
fazekasgy@37 138
fazekasgy@37 139 /// these references are all borrowed
fazekasgy@37 140 PyObject *pyPlugModule = PyDict_GetItemString(m_pyGlobalNamespace,plugModuleName);
fazekasgy@37 141 if (!pyPlugModule) return;
fazekasgy@37 142 PyObject *pyPlugDict = PyModule_GetDict(pyPlugModule);
fazekasgy@37 143 if (!pyPlugDict) return;
fazekasgy@37 144
fazekasgy@37 145 int i = 0;
fazekasgy@37 146 while (PyExtensionManager::m_exposedNames[i]) {
Chris@66 147 const char* name = PyExtensionManager::m_exposedNames[i];
fazekasgy@37 148 i++;
fazekasgy@37 149 PyObject *key = PyString_FromString(name);
fazekasgy@37 150 if (!key) break;
fazekasgy@37 151 if (PyDict_Contains(pyPlugDict,key)) {
fazekasgy@37 152 if (PyDict_SetItem(pyPlugDict,key,Py_None) != 0)
fazekasgy@37 153 cerr << "Vampy::PyExtensionManager::cleanLocalNamespace: Failed: "
fazekasgy@37 154 << name << " of "<< plugModuleName << endl;
Chris@67 155 else DSTREAM << "Cleaned local name: " << name << endl;
fazekasgy@37 156 }
fazekasgy@37 157 Py_DECREF(key);
fazekasgy@37 158 }
fazekasgy@37 159 }
fazekasgy@37 160
fazekasgy@37 161 void
fazekasgy@37 162 PyExtensionManager::updateLocalNamespace(const char* plugModuleName) const
fazekasgy@37 163 {
fazekasgy@37 164 /// this allows the use of common syntax like:
fazekasgy@37 165 /// from vampy import *
fazekasgy@37 166 /// even after several unload/reload cycles
fazekasgy@37 167
fazekasgy@37 168 /// these references are all borrowed
fazekasgy@37 169 PyObject *pyPlugModule = PyDict_GetItemString(m_pyGlobalNamespace,plugModuleName);
fazekasgy@37 170 if (!pyPlugModule) return;
fazekasgy@37 171 PyObject *pyPlugDict = PyModule_GetDict(pyPlugModule);
fazekasgy@37 172 if (!pyPlugDict) return;
fazekasgy@37 173
fazekasgy@37 174 int i = 0;
fazekasgy@37 175 while (PyExtensionManager::m_exposedNames[i]) {
fazekasgy@37 176 const char* name = PyExtensionManager::m_exposedNames[i];
fazekasgy@37 177 i++;
fazekasgy@37 178 PyObject *key = PyString_FromString(name);
fazekasgy@37 179 if (!key) break;
fazekasgy@37 180 if (PyDict_Contains(pyPlugDict,key)) {
fazekasgy@37 181 PyObject* item = PyDict_GetItem(m_pyVampyNamespace,key);
fazekasgy@37 182 if (PyDict_SetItem(pyPlugDict,key,item) != 0)
fazekasgy@37 183 cerr << "Vampy::PyExtensionManager::updateLocalNamespace: Failed: "
fazekasgy@37 184 << name << " of "<< plugModuleName << endl;
Chris@67 185 else DSTREAM << "Updated local name: " << name << endl;
fazekasgy@37 186 }
fazekasgy@37 187 Py_DECREF(key);
fazekasgy@37 188 }
fazekasgy@37 189 }
fazekasgy@37 190
fazekasgy@37 191
fazekasgy@37 192 bool
fazekasgy@37 193 PyExtensionManager::cleanModule(void) const
fazekasgy@37 194 {
fazekasgy@37 195
fazekasgy@37 196 PyObject *m = PyImport_AddModule("vampy");
fazekasgy@37 197 if (!m) {
fazekasgy@37 198 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@37 199 cerr << "Vampy::PyExtensionManager::cleanModule: PyImport_AddModule returned NULL!" << endl;
fazekasgy@37 200 return false;
fazekasgy@37 201 } else {
fazekasgy@37 202 PyObject *dict = PyModule_GetDict(m);
fazekasgy@37 203 #ifdef _DEBUG
fazekasgy@37 204 Py_ssize_t ln = PyDict_Size(dict);
Chris@67 205 DSTREAM << "Vampy::PyExtensionManager::cleanModule: Size of module dict = " << (int) ln << endl;
fazekasgy@37 206 #endif
fazekasgy@37 207 /// Clean the module dictionary.
fazekasgy@37 208 // printDict(dict);
fazekasgy@37 209 PyDict_Clear(dict);
fazekasgy@37 210 if (PyErr_Occurred())
fazekasgy@37 211 { PyErr_Print(); PyErr_Clear(); return false; }
fazekasgy@37 212 PyObject *name = PyString_FromString("vampy");
fazekasgy@37 213 if (name) PyDict_SetItemString(dict,"__name__",name);
fazekasgy@37 214 Py_XDECREF(name);
fazekasgy@37 215 #ifdef _DEBUG
fazekasgy@37 216 ln = PyDict_Size(dict);
Chris@67 217 DSTREAM << "Vampy::PyExtensionManager::cleanModule: Size of module dict (cleaned) = " << (int) ln << endl;
fazekasgy@37 218 #endif
fazekasgy@37 219 return true;
fazekasgy@37 220 }
fazekasgy@37 221 }
fazekasgy@37 222
fazekasgy@37 223 void
fazekasgy@37 224 PyExtensionManager::printDict(PyObject* inDict) const
fazekasgy@37 225 {
fazekasgy@37 226 Py_ssize_t pyPos = 0;
fazekasgy@37 227 PyObject *pyKey, *pyDictValue;
fazekasgy@37 228 cerr << endl << endl << "Module dictionary contents: " << endl;
fazekasgy@37 229 while (PyDict_Next(inDict, &pyPos, &pyKey, &pyDictValue))
fazekasgy@37 230 {
fazekasgy@37 231 char *key = PyString_AS_STRING(pyKey);
fazekasgy@37 232 char *val = PyString_AS_STRING(PyObject_Str(pyDictValue));
fazekasgy@37 233 cerr << "key: [ '" << key << "' ] value: " << val << endl;
fazekasgy@37 234 }
fazekasgy@37 235 }
fazekasgy@37 236