Mercurial > hg > vampy
comparison PyPlugScanner.cpp @ 0:e20e214bdfb5
Added VAMP-Python binding project vampy
author | fazekasgy |
---|---|
date | Tue, 11 Mar 2008 19:47:34 +0000 |
parents | |
children | 134313c59d82 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:e20e214bdfb5 |
---|---|
1 /** | |
2 * This VAMP plugin is a wrapper for Python Scripts. (VamPy) | |
3 * Centre for Digital Music, Queen Mary, University of London. | |
4 * Copyright 2008, George Fazekas. | |
5 | |
6 */ | |
7 | |
8 | |
9 #include "/usr/include/python/Python.h" | |
10 #include "PyPlugScanner.h" | |
11 | |
12 //#include <fstream> | |
13 //#include <cctype> | |
14 | |
15 #ifdef _WIN32 | |
16 #include <windows.h> | |
17 #include <tchar.h> | |
18 #define pathsep ("\\") | |
19 #else | |
20 #include <dirent.h> | |
21 #include <dlfcn.h> | |
22 #define pathsep ("/") | |
23 #endif | |
24 #define joinPath(a,b) ( (a)+pathsep+(b) ) | |
25 | |
26 using std::string; | |
27 using std::vector; | |
28 using std::cerr; | |
29 using std::endl; | |
30 | |
31 PyPlugScanner::PyPlugScanner() | |
32 { | |
33 | |
34 } | |
35 | |
36 PyPlugScanner *PyPlugScanner::m_instance = NULL; | |
37 bool PyPlugScanner::m_hasInstance = false; | |
38 | |
39 PyPlugScanner* | |
40 PyPlugScanner::getInstance() | |
41 { | |
42 if (!m_hasInstance) { | |
43 m_instance = new PyPlugScanner(); | |
44 m_hasInstance = true; | |
45 } | |
46 return m_instance; | |
47 } | |
48 | |
49 void | |
50 PyPlugScanner::setPath(vector<string> path) | |
51 { | |
52 m_path=path; | |
53 } | |
54 | |
55 // TODO: This should return all scripts for all valid paths | |
56 // Validate python classes here? | |
57 // For now, we assume that each script on the path has one valid class | |
58 vector<string> | |
59 PyPlugScanner::getPyPlugs() | |
60 { | |
61 //foreach m_path listFiles then return vector<pyPlugs> | |
62 //format: FullPathString/FileName.py:ClassName | |
63 | |
64 vector<string> pyPlugs; | |
65 string pluginKey; | |
66 PyObject *pyClassInstance; | |
67 | |
68 for (size_t i = 0; i < m_path.size(); ++i) { | |
69 | |
70 vector<string> files = listFiles(m_path[i],"py"); | |
71 | |
72 for (vector<string>::iterator fi = files.begin(); | |
73 fi != files.end(); ++fi) { | |
74 string script = *fi; | |
75 if (!script.empty()) { | |
76 string classname=script.substr(0,script.rfind('.')); | |
77 pluginKey=joinPath(m_path[i],script)+":"+classname; | |
78 pyClassInstance = getScriptInstance(m_path[i],classname); | |
79 if (pyClassInstance == NULL) | |
80 cerr << "Warning: Syntax error in VamPy plugin: " | |
81 << classname << ". Avoiding plugin." << endl; | |
82 else { | |
83 pyPlugs.push_back(pluginKey); | |
84 m_pyInstances.push_back(pyClassInstance); | |
85 } | |
86 //pyPlugs.push_back(pluginKey); | |
87 } | |
88 } | |
89 } | |
90 | |
91 return pyPlugs; | |
92 | |
93 } | |
94 | |
95 | |
96 //For now return one class instance found in each script | |
97 vector<PyObject*> | |
98 PyPlugScanner::getPyInstances() | |
99 { | |
100 return m_pyInstances; | |
101 | |
102 } | |
103 | |
104 | |
105 //Validate | |
106 //This should not be called more than once! | |
107 PyObject* | |
108 PyPlugScanner::getScriptInstance(string path, string classname) | |
109 { | |
110 | |
111 //Add plugin path to active Python Path | |
112 string pyCmd = "import sys\nsys.path.append('" + path + "')\n"; | |
113 PyRun_SimpleString(pyCmd.c_str()); | |
114 | |
115 //Assign an object to the source code | |
116 PyObject *pySource = PyString_FromString(classname.c_str()); | |
117 | |
118 //Import it as a module into the py interpreter | |
119 PyObject *pyModule = PyImport_Import(pySource); | |
120 PyObject* pyError = PyErr_Occurred(); | |
121 if (! pyError == 0) { | |
122 cerr << "ERROR: error importing source: " << classname << endl; | |
123 PyErr_Print(); | |
124 Py_DECREF(pySource); | |
125 Py_CLEAR(pyModule); // safer if pyModule==NULL | |
126 return NULL; | |
127 } | |
128 Py_DECREF(pySource); | |
129 | |
130 //Read the namespace of the module into a dictionary object (borrowed reference) | |
131 PyObject *pyDict = PyModule_GetDict(pyModule); | |
132 Py_DECREF(pyModule); | |
133 | |
134 //Get the PluginClass from the module (borrowed reference) | |
135 PyObject *pyClass = PyDict_GetItemString(pyDict, classname.c_str()); | |
136 | |
137 //Check if class is present and a callable method is implemented | |
138 if (pyClass && PyCallable_Check(pyClass)) { | |
139 | |
140 //Create an instance | |
141 PyObject *pyInstance = PyObject_CallObject(pyClass, NULL); | |
142 //cerr << "__(getInstance) PyPlugin Class: " << m_class << " successfully created.__" << endl; | |
143 return pyInstance; | |
144 } else return NULL; | |
145 } | |
146 | |
147 | |
148 | |
149 // Return a list of files in dir with given extension | |
150 // Code taken from hostext/PluginLoader.cpp | |
151 vector<string> | |
152 PyPlugScanner::listFiles(string dir, string extension) | |
153 { | |
154 vector<string> files; | |
155 | |
156 #ifdef _WIN32 | |
157 | |
158 string expression = dir + "\\*." + extension; | |
159 WIN32_FIND_DATA data; | |
160 HANDLE fh = FindFirstFile(expression.c_str(), &data); | |
161 if (fh == INVALID_HANDLE_VALUE) return files; | |
162 | |
163 bool ok = true; | |
164 while (ok) { | |
165 files.push_back(data.cFileName); | |
166 ok = FindNextFile(fh, &data); | |
167 } | |
168 | |
169 FindClose(fh); | |
170 | |
171 #else | |
172 | |
173 size_t extlen = extension.length(); | |
174 DIR *d = opendir(dir.c_str()); | |
175 if (!d) return files; | |
176 | |
177 struct dirent *e = 0; | |
178 while ((e = readdir(d))) { | |
179 | |
180 if (!(e->d_type & DT_REG) && (e->d_type != DT_UNKNOWN)) continue; | |
181 | |
182 if (!e->d_name) continue; | |
183 | |
184 size_t len = strlen(e->d_name); | |
185 if (len < extlen + 2 || | |
186 e->d_name + len - extlen - 1 != "." + extension) { | |
187 continue; | |
188 } | |
189 //cerr << "pyscripts: " << e->d_name << endl; | |
190 files.push_back(e->d_name); | |
191 } | |
192 | |
193 closedir(d); | |
194 #endif | |
195 | |
196 return files; | |
197 } | |
198 | |
199 //Return correct plugin directories as per platform | |
200 //Code taken from vamp-sdk/PluginHostAdapter.cpp | |
201 std::vector<std::string> | |
202 PyPlugScanner::getAllValidPath() | |
203 { | |
204 std::vector<std::string> path; | |
205 std::string envPath; | |
206 | |
207 char *cpath = getenv("VAMP_PATH"); | |
208 if (cpath) envPath = cpath; | |
209 | |
210 #ifdef _WIN32 | |
211 #define PATH_SEPARATOR ';' | |
212 #define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins" | |
213 #else | |
214 #define PATH_SEPARATOR ':' | |
215 #ifdef __APPLE__ | |
216 #define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp" | |
217 #else | |
218 #define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp" | |
219 #endif | |
220 #endif | |
221 | |
222 if (envPath == "") { | |
223 envPath = DEFAULT_VAMP_PATH; | |
224 char *chome = getenv("HOME"); | |
225 if (chome) { | |
226 std::string home(chome); | |
227 std::string::size_type f; | |
228 while ((f = envPath.find("$HOME")) != std::string::npos && | |
229 f < envPath.length()) { | |
230 envPath.replace(f, 5, home); | |
231 } | |
232 } | |
233 #ifdef _WIN32 | |
234 char *cpfiles = getenv("ProgramFiles"); | |
235 if (!cpfiles) cpfiles = "C:\\Program Files"; | |
236 std::string pfiles(cpfiles); | |
237 std::string::size_type f; | |
238 while ((f = envPath.find("%ProgramFiles%")) != std::string::npos && | |
239 f < envPath.length()) { | |
240 envPath.replace(f, 14, pfiles); | |
241 } | |
242 #endif | |
243 } | |
244 | |
245 std::string::size_type index = 0, newindex = 0; | |
246 | |
247 while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) { | |
248 path.push_back(envPath.substr(index, newindex - index)); | |
249 index = newindex + 1; | |
250 } | |
251 | |
252 path.push_back(envPath.substr(index)); | |
253 | |
254 return path; | |
255 } |