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
|