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[] = {
|
Chris@91
|
28
|
fazekasgy@37
|
29 "ParameterDescriptor",
|
fazekasgy@37
|
30 "OutputDescriptor",
|
fazekasgy@37
|
31 "FeatureSet",
|
fazekasgy@37
|
32 "Feature",
|
fazekasgy@37
|
33 "RealTime",
|
fazekasgy@37
|
34 "frame2RealTime",
|
Chris@91
|
35
|
Chris@91
|
36 /* // using builtin objects:
|
Chris@91
|
37 "ParameterList",
|
Chris@91
|
38 "OutputList",
|
Chris@91
|
39 "FeatureList",
|
fazekasgy@37
|
40 "OneSamplePerStep",
|
fazekasgy@37
|
41 "FixedSampleRate",
|
fazekasgy@37
|
42 "VariableSampleRate",
|
fazekasgy@37
|
43 "TimeDomain",
|
fazekasgy@37
|
44 "FrequencyDomain",
|
fazekasgy@37
|
45 */
|
Chris@91
|
46
|
fazekasgy@37
|
47 NULL
|
fazekasgy@37
|
48 };
|
fazekasgy@37
|
49
|
fazekasgy@37
|
50 PyExtensionManager::PyExtensionManager()
|
fazekasgy@37
|
51 {
|
Chris@67
|
52 DSTREAM << "Creating extension manager." << endl;
|
fazekasgy@37
|
53 }
|
fazekasgy@37
|
54
|
fazekasgy@37
|
55 bool
|
fazekasgy@37
|
56 PyExtensionManager::initExtension()
|
fazekasgy@37
|
57 {
|
Chris@67
|
58 DSTREAM << "Initialising extension module." << endl;
|
fazekasgy@37
|
59
|
fazekasgy@37
|
60 /// call the module initialiser first
|
fazekasgy@37
|
61 initvampy();
|
fazekasgy@37
|
62
|
fazekasgy@37
|
63 /// these references are all borrowed
|
fazekasgy@37
|
64 m_pyGlobalNamespace = PyImport_GetModuleDict();
|
fazekasgy@37
|
65 if (!m_pyGlobalNamespace)
|
fazekasgy@37
|
66 {cerr << "Vampy::PyExtensionManager::initExtension: GlobalNamespace failed." << endl; return false;}
|
fazekasgy@37
|
67 PyObject *pyVampyModule = PyDict_GetItemString(m_pyGlobalNamespace,"vampy");
|
fazekasgy@37
|
68 if (!pyVampyModule)
|
fazekasgy@37
|
69 {cerr << "Vampy::PyExtensionManager::initExtension: VampyModule failed." << endl; return false;}
|
fazekasgy@37
|
70 m_pyVampyNamespace = PyModule_GetDict(pyVampyModule);
|
fazekasgy@37
|
71 if (!m_pyVampyNamespace)
|
fazekasgy@37
|
72 {cerr << "Vampy::PyExtensionManager::initExtension: VampyNamespace failed." << endl; return false;}
|
fazekasgy@37
|
73
|
fazekasgy@37
|
74 /// initialise local namespaces
|
fazekasgy@37
|
75 updateAllLocals();
|
Chris@67
|
76
|
Chris@67
|
77 DSTREAM << "Vampy: Extension namespaces updated." << endl;
|
Chris@67
|
78
|
fazekasgy@37
|
79 return true;
|
fazekasgy@37
|
80 }
|
fazekasgy@37
|
81
|
fazekasgy@37
|
82
|
fazekasgy@37
|
83 PyExtensionManager::~PyExtensionManager()
|
fazekasgy@37
|
84 {
|
Chris@67
|
85 DSTREAM << "Cleaning locals..." << endl;
|
fazekasgy@37
|
86
|
fazekasgy@37
|
87 cleanAllLocals();
|
fazekasgy@37
|
88
|
Chris@67
|
89 DSTREAM << "Cleaning module..." << endl;
|
fazekasgy@37
|
90
|
fazekasgy@37
|
91 if (!cleanModule())
|
fazekasgy@37
|
92 cerr << "Vampy::~PyExtensionManager: failed to clean extension module." << endl;
|
Chris@67
|
93 DSTREAM << "Vampy::~PyExtensionManager: Extension module cleaned." << endl;
|
fazekasgy@37
|
94 }
|
fazekasgy@37
|
95
|
fazekasgy@37
|
96
|
fazekasgy@37
|
97
|
fazekasgy@37
|
98 void
|
fazekasgy@37
|
99 PyExtensionManager::setPlugModuleNames(vector<string> pyPlugs)
|
fazekasgy@37
|
100 {
|
fazekasgy@37
|
101 for (size_t i = 0; i < pyPlugs.size(); ++i) {
|
fazekasgy@37
|
102 string modName = pyPlugs[i];
|
fazekasgy@37
|
103 string tmp = modName.substr(modName.rfind(':')+1,modName.size()-1);
|
fazekasgy@37
|
104 m_plugModuleNames.push_back(tmp);
|
fazekasgy@37
|
105
|
Chris@67
|
106 DSTREAM << "Inserted module name: " << tmp << endl;
|
fazekasgy@37
|
107 }
|
fazekasgy@37
|
108 }
|
fazekasgy@37
|
109
|
fazekasgy@37
|
110 void
|
fazekasgy@37
|
111 PyExtensionManager::deleteModuleName(string plugKey)
|
fazekasgy@37
|
112 {
|
fazekasgy@37
|
113 string name = plugKey.substr(plugKey.rfind(':')+1,plugKey.size()-1);
|
fazekasgy@37
|
114 vector<string>::iterator it =
|
fazekasgy@37
|
115 find (m_plugModuleNames.begin(), m_plugModuleNames.end(), name);
|
fazekasgy@37
|
116 if (it != m_plugModuleNames.end()) m_plugModuleNames.erase(it);
|
Chris@67
|
117
|
Chris@67
|
118 DSTREAM << "PyExtensionManager::deleteModuleName: Deleted module name: " << name << endl;
|
fazekasgy@37
|
119 }
|
fazekasgy@37
|
120
|
fazekasgy@37
|
121
|
fazekasgy@37
|
122 void
|
fazekasgy@37
|
123 PyExtensionManager::cleanAllLocals() const
|
fazekasgy@37
|
124 {
|
fazekasgy@37
|
125 for (size_t i = 0; i < m_plugModuleNames.size(); ++i) {
|
fazekasgy@37
|
126 cleanLocalNamespace(m_plugModuleNames[i].c_str());
|
fazekasgy@37
|
127 }
|
fazekasgy@37
|
128 }
|
fazekasgy@37
|
129
|
fazekasgy@37
|
130 void
|
fazekasgy@37
|
131 PyExtensionManager::updateAllLocals() const
|
fazekasgy@37
|
132 {
|
fazekasgy@37
|
133 for (size_t i = 0; i < m_plugModuleNames.size(); ++i) {
|
fazekasgy@37
|
134 updateLocalNamespace(m_plugModuleNames[i].c_str());
|
fazekasgy@37
|
135 }
|
fazekasgy@37
|
136 }
|
fazekasgy@37
|
137
|
fazekasgy@37
|
138 void
|
fazekasgy@37
|
139 PyExtensionManager::cleanLocalNamespace(const char* plugModuleName) const
|
fazekasgy@37
|
140 {
|
Chris@91
|
141 DSTREAM << "Cleaning local namespace: " << plugModuleName << endl;
|
Chris@91
|
142
|
fazekasgy@37
|
143 /// these references are all borrowed
|
fazekasgy@37
|
144 PyObject *pyPlugModule = PyDict_GetItemString(m_pyGlobalNamespace,plugModuleName);
|
fazekasgy@37
|
145 if (!pyPlugModule) return;
|
fazekasgy@37
|
146 PyObject *pyPlugDict = PyModule_GetDict(pyPlugModule);
|
fazekasgy@37
|
147 if (!pyPlugDict) return;
|
fazekasgy@37
|
148
|
fazekasgy@37
|
149 int i = 0;
|
fazekasgy@37
|
150 while (PyExtensionManager::m_exposedNames[i]) {
|
Chris@66
|
151 const char* name = PyExtensionManager::m_exposedNames[i];
|
fazekasgy@37
|
152 i++;
|
fazekasgy@37
|
153 PyObject *key = PyString_FromString(name);
|
fazekasgy@37
|
154 if (!key) break;
|
fazekasgy@37
|
155 if (PyDict_Contains(pyPlugDict,key)) {
|
fazekasgy@37
|
156 if (PyDict_SetItem(pyPlugDict,key,Py_None) != 0)
|
fazekasgy@37
|
157 cerr << "Vampy::PyExtensionManager::cleanLocalNamespace: Failed: "
|
fazekasgy@37
|
158 << name << " of "<< plugModuleName << endl;
|
Chris@67
|
159 else DSTREAM << "Cleaned local name: " << name << endl;
|
fazekasgy@37
|
160 }
|
fazekasgy@37
|
161 Py_DECREF(key);
|
fazekasgy@37
|
162 }
|
fazekasgy@37
|
163 }
|
fazekasgy@37
|
164
|
fazekasgy@37
|
165 void
|
fazekasgy@37
|
166 PyExtensionManager::updateLocalNamespace(const char* plugModuleName) const
|
fazekasgy@37
|
167 {
|
Chris@91
|
168 DSTREAM << "Updating local namespace: " << plugModuleName << endl;
|
Chris@91
|
169
|
fazekasgy@37
|
170 /// this allows the use of common syntax like:
|
fazekasgy@37
|
171 /// from vampy import *
|
fazekasgy@37
|
172 /// even after several unload/reload cycles
|
fazekasgy@37
|
173
|
fazekasgy@37
|
174 /// these references are all borrowed
|
fazekasgy@37
|
175 PyObject *pyPlugModule = PyDict_GetItemString(m_pyGlobalNamespace,plugModuleName);
|
fazekasgy@37
|
176 if (!pyPlugModule) return;
|
fazekasgy@37
|
177 PyObject *pyPlugDict = PyModule_GetDict(pyPlugModule);
|
fazekasgy@37
|
178 if (!pyPlugDict) return;
|
fazekasgy@37
|
179
|
fazekasgy@37
|
180 int i = 0;
|
fazekasgy@37
|
181 while (PyExtensionManager::m_exposedNames[i]) {
|
fazekasgy@37
|
182 const char* name = PyExtensionManager::m_exposedNames[i];
|
fazekasgy@37
|
183 i++;
|
fazekasgy@37
|
184 PyObject *key = PyString_FromString(name);
|
fazekasgy@37
|
185 if (!key) break;
|
fazekasgy@37
|
186 if (PyDict_Contains(pyPlugDict,key)) {
|
fazekasgy@37
|
187 PyObject* item = PyDict_GetItem(m_pyVampyNamespace,key);
|
fazekasgy@37
|
188 if (PyDict_SetItem(pyPlugDict,key,item) != 0)
|
fazekasgy@37
|
189 cerr << "Vampy::PyExtensionManager::updateLocalNamespace: Failed: "
|
fazekasgy@37
|
190 << name << " of "<< plugModuleName << endl;
|
Chris@67
|
191 else DSTREAM << "Updated local name: " << name << endl;
|
Chris@89
|
192 } else {
|
Chris@89
|
193 DSTREAM << "Local namespace does not contain name: " << name << endl;
|
fazekasgy@37
|
194 }
|
fazekasgy@37
|
195 Py_DECREF(key);
|
fazekasgy@37
|
196 }
|
fazekasgy@37
|
197 }
|
fazekasgy@37
|
198
|
fazekasgy@37
|
199
|
fazekasgy@37
|
200 bool
|
fazekasgy@37
|
201 PyExtensionManager::cleanModule(void) const
|
fazekasgy@37
|
202 {
|
fazekasgy@37
|
203 PyObject *m = PyImport_AddModule("vampy");
|
fazekasgy@37
|
204 if (!m) {
|
fazekasgy@37
|
205 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
|
fazekasgy@37
|
206 cerr << "Vampy::PyExtensionManager::cleanModule: PyImport_AddModule returned NULL!" << endl;
|
fazekasgy@37
|
207 return false;
|
fazekasgy@37
|
208 } else {
|
fazekasgy@37
|
209 PyObject *dict = PyModule_GetDict(m);
|
fazekasgy@37
|
210 #ifdef _DEBUG
|
fazekasgy@37
|
211 Py_ssize_t ln = PyDict_Size(dict);
|
Chris@67
|
212 DSTREAM << "Vampy::PyExtensionManager::cleanModule: Size of module dict = " << (int) ln << endl;
|
fazekasgy@37
|
213 #endif
|
fazekasgy@37
|
214 /// Clean the module dictionary.
|
fazekasgy@37
|
215 // printDict(dict);
|
fazekasgy@37
|
216 PyDict_Clear(dict);
|
fazekasgy@37
|
217 if (PyErr_Occurred())
|
fazekasgy@37
|
218 { PyErr_Print(); PyErr_Clear(); return false; }
|
fazekasgy@37
|
219 PyObject *name = PyString_FromString("vampy");
|
fazekasgy@37
|
220 if (name) PyDict_SetItemString(dict,"__name__",name);
|
fazekasgy@37
|
221 Py_XDECREF(name);
|
fazekasgy@37
|
222 #ifdef _DEBUG
|
fazekasgy@37
|
223 ln = PyDict_Size(dict);
|
Chris@67
|
224 DSTREAM << "Vampy::PyExtensionManager::cleanModule: Size of module dict (cleaned) = " << (int) ln << endl;
|
fazekasgy@37
|
225 #endif
|
fazekasgy@37
|
226 return true;
|
fazekasgy@37
|
227 }
|
fazekasgy@37
|
228 }
|
fazekasgy@37
|
229
|
fazekasgy@37
|
230 void
|
fazekasgy@37
|
231 PyExtensionManager::printDict(PyObject* inDict) const
|
fazekasgy@37
|
232 {
|
fazekasgy@37
|
233 Py_ssize_t pyPos = 0;
|
fazekasgy@37
|
234 PyObject *pyKey, *pyDictValue;
|
fazekasgy@37
|
235 cerr << endl << endl << "Module dictionary contents: " << endl;
|
fazekasgy@37
|
236 while (PyDict_Next(inDict, &pyPos, &pyKey, &pyDictValue))
|
fazekasgy@37
|
237 {
|
fazekasgy@37
|
238 char *key = PyString_AS_STRING(pyKey);
|
fazekasgy@37
|
239 char *val = PyString_AS_STRING(PyObject_Str(pyDictValue));
|
fazekasgy@37
|
240 cerr << "key: [ '" << key << "' ] value: " << val << endl;
|
fazekasgy@37
|
241 }
|
fazekasgy@37
|
242 }
|
fazekasgy@37
|
243
|