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