diff PyPlugScanner.cpp @ 0:e20e214bdfb5

Added VAMP-Python binding project vampy
author fazekasgy
date Tue, 11 Mar 2008 19:47:34 +0000
parents
children 134313c59d82
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PyPlugScanner.cpp	Tue Mar 11 19:47:34 2008 +0000
@@ -0,0 +1,255 @@
+/**
+ * This VAMP plugin is a wrapper for Python Scripts. (VamPy)
+ * Centre for Digital Music, Queen Mary, University of London.
+ * Copyright 2008, George Fazekas.
+
+*/
+
+
+#include "/usr/include/python/Python.h"
+#include "PyPlugScanner.h"
+
+//#include <fstream>
+//#include <cctype>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <tchar.h>
+#define pathsep ("\\")
+#else 
+#include <dirent.h>
+#include <dlfcn.h>
+#define pathsep ("/")
+#endif 
+#define joinPath(a,b) ( (a)+pathsep+(b) )
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+
+PyPlugScanner::PyPlugScanner()
+{
+
+} 
+
+PyPlugScanner *PyPlugScanner::m_instance = NULL;
+bool PyPlugScanner::m_hasInstance = false;
+
+PyPlugScanner*
+PyPlugScanner::getInstance()
+{
+	if (!m_hasInstance) {
+		m_instance = new PyPlugScanner();
+		m_hasInstance = true;
+	}
+	return m_instance;
+}
+
+void
+PyPlugScanner::setPath(vector<string> path)
+{
+	m_path=path;
+}
+
+// TODO: This should return all scripts for all valid paths
+// Validate python classes here?
+// For now, we assume that each script on the path has one valid class
+vector<string> 
+PyPlugScanner::getPyPlugs()
+{
+	//foreach m_path listFiles then return vector<pyPlugs>
+	//format: FullPathString/FileName.py:ClassName
+	
+	vector<string> pyPlugs;
+	string pluginKey;
+	PyObject *pyClassInstance;
+	
+    for (size_t i = 0; i < m_path.size(); ++i) {
+        
+        vector<string> files = listFiles(m_path[i],"py");
+
+        for (vector<string>::iterator fi = files.begin();
+             fi != files.end(); ++fi) {
+				string script = *fi;
+				if (!script.empty()) {					
+					string classname=script.substr(0,script.rfind('.'));
+					pluginKey=joinPath(m_path[i],script)+":"+classname;
+					pyClassInstance = getScriptInstance(m_path[i],classname);
+					if (pyClassInstance == NULL) 
+					cerr << "Warning: Syntax error in VamPy plugin:  " 
+					<< classname << ". Avoiding plugin." << endl;
+					else { 
+							pyPlugs.push_back(pluginKey);
+							m_pyInstances.push_back(pyClassInstance);
+						}
+					//pyPlugs.push_back(pluginKey);
+				}
+		}		
+	}
+		
+return pyPlugs;	
+
+}
+
+
+//For now return one class instance found in each script
+vector<PyObject*> 
+PyPlugScanner::getPyInstances()
+{
+return m_pyInstances;	
+
+}
+
+
+//Validate
+//This should not be called more than once!
+PyObject* 
+PyPlugScanner::getScriptInstance(string path, string classname)
+{
+
+	//Add plugin path to active Python Path 
+	string pyCmd = "import sys\nsys.path.append('" + path + "')\n";
+	PyRun_SimpleString(pyCmd.c_str());				
+
+	//Assign an object to the source code
+	PyObject *pySource = PyString_FromString(classname.c_str());
+
+	//Import it as a module into the py interpreter
+	PyObject *pyModule = PyImport_Import(pySource);
+	PyObject* pyError = PyErr_Occurred();
+	if (! pyError == 0) { 
+		cerr << "ERROR: error importing source: " << classname << endl; 
+		PyErr_Print(); 
+		Py_DECREF(pySource); 
+		Py_CLEAR(pyModule);  // safer if pyModule==NULL
+		return NULL; 
+	}
+	Py_DECREF(pySource);
+
+	//Read the namespace of the module into a dictionary object (borrowed reference)
+	PyObject *pyDict = PyModule_GetDict(pyModule);
+	Py_DECREF(pyModule);
+
+	//Get the PluginClass from the module (borrowed reference)
+	PyObject *pyClass = PyDict_GetItemString(pyDict, classname.c_str());
+
+	//Check if class is present and a callable method is implemented
+	if (pyClass && PyCallable_Check(pyClass)) {
+
+		//Create an instance
+		PyObject *pyInstance = PyObject_CallObject(pyClass, NULL);
+		//cerr << "__(getInstance) PyPlugin Class: " << m_class << " successfully created.__" << endl;
+		return pyInstance; 
+	}	else return NULL;
+}
+
+
+
+// Return a list of files in dir with given extension
+// Code taken from hostext/PluginLoader.cpp
+vector<string>
+PyPlugScanner::listFiles(string dir, string extension)
+{
+    vector<string> files;
+
+#ifdef _WIN32
+
+    string expression = dir + "\\*." + extension;
+    WIN32_FIND_DATA data;
+    HANDLE fh = FindFirstFile(expression.c_str(), &data);
+    if (fh == INVALID_HANDLE_VALUE) return files;
+
+    bool ok = true;
+    while (ok) {
+        files.push_back(data.cFileName);
+        ok = FindNextFile(fh, &data);
+    }
+
+    FindClose(fh);
+
+#else
+
+    size_t extlen = extension.length();
+    DIR *d = opendir(dir.c_str());
+    if (!d) return files;
+            
+    struct dirent *e = 0;
+    while ((e = readdir(d))) {
+ 
+        if (!(e->d_type & DT_REG) && (e->d_type != DT_UNKNOWN)) continue;
+        
+        if (!e->d_name) continue;
+       
+        size_t len = strlen(e->d_name);
+        if (len < extlen + 2 ||
+            e->d_name + len - extlen - 1 != "." + extension) {
+            continue;
+        }
+		//cerr << "pyscripts: " << e->d_name <<  endl;
+        files.push_back(e->d_name);
+    }
+
+    closedir(d);
+#endif
+
+    return files;
+}
+
+//Return correct plugin directories as per platform
+//Code taken from vamp-sdk/PluginHostAdapter.cpp
+std::vector<std::string>
+PyPlugScanner::getAllValidPath()
+{
+    std::vector<std::string> path;
+    std::string envPath;
+
+    char *cpath = getenv("VAMP_PATH");
+    if (cpath) envPath = cpath;
+
+#ifdef _WIN32
+#define PATH_SEPARATOR ';'
+#define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins"
+#else
+#define PATH_SEPARATOR ':'
+#ifdef __APPLE__
+#define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"
+#else
+#define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"
+#endif
+#endif
+
+    if (envPath == "") {
+        envPath = DEFAULT_VAMP_PATH;
+        char *chome = getenv("HOME");
+        if (chome) {
+            std::string home(chome);
+            std::string::size_type f;
+            while ((f = envPath.find("$HOME")) != std::string::npos &&
+                    f < envPath.length()) {
+                envPath.replace(f, 5, home);
+            }
+        }
+#ifdef _WIN32
+        char *cpfiles = getenv("ProgramFiles");
+        if (!cpfiles) cpfiles = "C:\\Program Files";
+        std::string pfiles(cpfiles);
+        std::string::size_type f;
+        while ((f = envPath.find("%ProgramFiles%")) != std::string::npos &&
+               f < envPath.length()) {
+            envPath.replace(f, 14, pfiles);
+        }
+#endif
+    }
+
+    std::string::size_type index = 0, newindex = 0;
+
+    while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) {
+	path.push_back(envPath.substr(index, newindex - index));
+	index = newindex + 1;
+    }
+    
+    path.push_back(envPath.substr(index));
+
+    return path;
+}