Mercurial > hg > vampy
comparison vampy-main.cpp @ 37:27bab3a16c9a vampy2final
new branch Vampy2final
author | fazekasgy |
---|---|
date | Mon, 05 Oct 2009 11:28:00 +0000 |
parents | |
children | c1e4f706ca9a |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 37:27bab3a16c9a |
---|---|
1 /* | |
2 | |
3 * Vampy : This plugin is a wrapper around the Vamp plugin API. | |
4 * It allows for writing Vamp plugins in Python. | |
5 | |
6 * Centre for Digital Music, Queen Mary University of London. | |
7 * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources | |
8 * for licence information.) | |
9 | |
10 */ | |
11 | |
12 #include <Python.h> | |
13 | |
14 #ifdef HAVE_NUMPY | |
15 #define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API | |
16 #include "numpy/arrayobject.h" | |
17 #endif | |
18 | |
19 #include "vamp/vamp.h" | |
20 #include "vamp-sdk/PluginAdapter.h" | |
21 #include "PyPlugScanner.h" | |
22 #include "PyPlugin.h" | |
23 #include "PyExtensionModule.h" | |
24 #include "PyExtensionManager.h" | |
25 | |
26 | |
27 #ifdef _WIN32 | |
28 #define pathsep ('\\') | |
29 #include <windows.h> | |
30 #include <tchar.h> | |
31 #else | |
32 #define pathsep ('/') | |
33 #include <dirent.h> | |
34 #include <dlfcn.h> | |
35 #endif | |
36 | |
37 using std::cerr; | |
38 using std::endl; | |
39 using std::string; | |
40 using std::vector; | |
41 | |
42 static int adinstcount; | |
43 static int totinstcount; | |
44 | |
45 class PyPluginAdapter : public Vamp::PluginAdapterBase | |
46 { | |
47 public: | |
48 PyPluginAdapter(std::string pyPlugId, PyObject* pyClass) : | |
49 PluginAdapterBase(), | |
50 m_plug(pyPlugId), | |
51 m_pyClass(pyClass), | |
52 m_failed(false) | |
53 { | |
54 cerr << "PyPluginAdapter:ctor:"<< adinstcount << ": " << m_plug << endl; | |
55 adinstcount++; | |
56 } | |
57 | |
58 ~PyPluginAdapter() | |
59 { | |
60 } | |
61 | |
62 bool failed() { return m_failed; } | |
63 std::string getPlugKey() { return m_plug; } | |
64 | |
65 protected: | |
66 Vamp::Plugin *createPlugin(float inputSampleRate) | |
67 { | |
68 try { | |
69 PyPlugin *plugin = new PyPlugin(m_plug, inputSampleRate, m_pyClass, totinstcount); | |
70 return plugin; | |
71 } catch (...) { | |
72 cerr << "PyPluginAdapter::createPlugin: Failed to construct PyPlugin" << endl; | |
73 // any plugin with syntax errors will fail to construct | |
74 m_failed = true; | |
75 return 0; | |
76 } | |
77 } | |
78 | |
79 std::string m_plug; | |
80 PyObject *m_pyClass; | |
81 bool m_failed; | |
82 }; | |
83 | |
84 static void array_API_initialiser() | |
85 { | |
86 /// numpy C-API requirement | |
87 #ifdef HAVE_NUMPY | |
88 import_array(); | |
89 if(NPY_VERSION != PyArray_GetNDArrayCVersion()) | |
90 cerr << "Warning: Numpy ABI version mismatch. (Build version: " | |
91 << NPY_VERSION << " Runtime version: " << PyArray_GetNDArrayCVersion() << ")" << endl; | |
92 #endif | |
93 } | |
94 | |
95 | |
96 static std::vector<PyPluginAdapter *> adapters; | |
97 static bool haveScannedPlugins = false; | |
98 | |
99 static bool tryPreload(string name) | |
100 { | |
101 #ifdef _WIN32 | |
102 void *lib = LoadLibrary(name.c_str()); | |
103 if (!lib) { | |
104 return false; | |
105 } | |
106 #else | |
107 void *lib = dlopen(name.c_str(), RTLD_NOW | RTLD_GLOBAL); | |
108 if (!lib) { | |
109 return false; | |
110 } | |
111 #endif | |
112 return true; | |
113 } | |
114 | |
115 static bool preloadPython() | |
116 { | |
117 #ifdef _WIN32 | |
118 // this doesn't seem to be necessary at all on Windows | |
119 return true; | |
120 #endif | |
121 | |
122 string pyver = Py_GetVersion(); | |
123 int dots = 2; | |
124 string shortver; | |
125 for (size_t i = 0; i < pyver.length(); ++i) { | |
126 if (pyver[i] == '.') { | |
127 if (--dots == 0) { | |
128 shortver = pyver.substr(0, i); | |
129 break; | |
130 } | |
131 } | |
132 } | |
133 cerr << "Short version: " << shortver << endl; | |
134 // this is useful to find out where the loaded library might be loaded from | |
135 cerr << "Python exec prefix: " << Py_GetExecPrefix() << endl; | |
136 | |
137 vector<string> pfxs; | |
138 pfxs.push_back(""); | |
139 pfxs.push_back(string(Py_GetExecPrefix()) + "/lib/"); | |
140 pfxs.push_back(string(Py_GetExecPrefix()) + "/"); | |
141 pfxs.push_back("/usr/lib/"); | |
142 pfxs.push_back("/usr/local/lib/"); | |
143 char buffer[5]; | |
144 | |
145 // hahaha! grossness is like a brother to us | |
146 #ifdef __APPLE__ | |
147 for (size_t pfxidx = 0; pfxidx < pfxs.size(); ++pfxidx) { | |
148 for (int minor = 8; minor >= 0; --minor) { | |
149 sprintf(buffer, "%d", minor); | |
150 if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".dylib." + buffer)) return true; | |
151 } | |
152 if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".dylib")) return true; | |
153 if (tryPreload(pfxs[pfxidx] + string("libpython.dylib"))) return true; | |
154 } | |
155 #else | |
156 for (size_t pfxidx = 0; pfxidx < pfxs.size(); ++pfxidx) { | |
157 for (int minor = 8; minor >= 0; --minor) { | |
158 sprintf(buffer, "%d", minor); | |
159 if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".so." + buffer)) return true; | |
160 } | |
161 if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".so")) return true; | |
162 if (tryPreload(pfxs[pfxidx] + string("libpython.so"))) return true; | |
163 } | |
164 #endif | |
165 | |
166 return false; | |
167 } | |
168 | |
169 | |
170 static PyExtensionManager pyExtensionManager; | |
171 | |
172 const VampPluginDescriptor | |
173 *vampGetPluginDescriptor(unsigned int version,unsigned int index) | |
174 { | |
175 if (version < 1) return 0; | |
176 | |
177 int isPythonInitialized = Py_IsInitialized(); | |
178 cerr << "# isPythonInitialized: " << isPythonInitialized << endl; | |
179 cerr << "# haveScannedPlugins: " << haveScannedPlugins << endl; | |
180 | |
181 if (!haveScannedPlugins) { | |
182 | |
183 if (!isPythonInitialized){ | |
184 | |
185 if (!preloadPython()) | |
186 cerr << "Warning: Could not preload Python. Dynamic loading in scripts will fail." << endl; | |
187 if (PyImport_AppendInittab("vampy",initvampy) != 0) | |
188 cerr << "Warning: Extension module could not be added to module inittab." << endl; | |
189 Py_Initialize(); | |
190 initvampy(); | |
191 #ifdef _DEBUG | |
192 cerr << "# isPythonInitialized after initialize: " << Py_IsInitialized() << endl; | |
193 #endif | |
194 } | |
195 | |
196 vector<string> pyPlugs; | |
197 vector<string> pyPath; | |
198 vector<PyObject *> pyClasses; | |
199 static PyPlugScanner *scanner; | |
200 | |
201 //Scanning Plugins | |
202 cerr << "Scanning Vampy Plugins" << endl; | |
203 scanner = PyPlugScanner::getInstance(); | |
204 | |
205 // added env. varable support VAMPY_EXTPATH | |
206 pyPath=scanner->getAllValidPath(); | |
207 scanner->setPath(pyPath); | |
208 | |
209 // added env. variable support: | |
210 // VAMPY_COMPILED=1 to recognise .pyc files (default is 1) | |
211 pyPlugs = scanner->getPyPlugs(); | |
212 | |
213 cerr << "Found " << pyPlugs.size() << " Scripts." << endl; | |
214 //TODO: should this support multiple classes per script (?) | |
215 pyClasses = scanner->getPyClasses(); | |
216 cerr << "Found " << pyClasses.size() << " Classes." << endl; | |
217 | |
218 for (size_t i = 0; i < pyPlugs.size(); ++i) { | |
219 adapters.push_back( new PyPluginAdapter(pyPlugs[i],pyClasses[i])); | |
220 } | |
221 pyExtensionManager.setPlugModuleNames(pyPlugs); | |
222 pyExtensionManager.initExtension(); | |
223 array_API_initialiser(); | |
224 haveScannedPlugins=true; | |
225 } | |
226 | |
227 #ifdef _DEBUG | |
228 cerr << "Accessing adapter index: " << index << " (adapters: " << adapters.size() << ")" << endl; | |
229 #endif | |
230 | |
231 if (index<adapters.size()) { | |
232 | |
233 const VampPluginDescriptor *tmp = adapters[index]->getDescriptor(); | |
234 | |
235 if (adapters[index]->failed()) { | |
236 cerr << "\nERROR: [in vampGetPluginDescriptor] Removing adapter of: \n'" | |
237 << adapters[index]->getPlugKey() << "'\n" | |
238 << "The plugin has failed to construct. Hint: Check __init__() function." << endl; | |
239 pyExtensionManager.deleteModuleName(adapters[index]->getPlugKey()); | |
240 delete adapters[index]; | |
241 adapters.erase(adapters.begin()+index); | |
242 return 0; | |
243 } | |
244 | |
245 return tmp; | |
246 | |
247 } else return 0; | |
248 } | |
249 | |
250 | |
251 | |
252 | |
253 | |
254 | |
255 | |
256 |