Mercurial > hg > vampy
view PyPlugScanner.cpp @ 8:3af6b5990ad8
more examples and some bug fixes
author | fazekasgy |
---|---|
date | Fri, 13 Jun 2008 16:50:00 +0000 |
parents | a4c955e9a70b |
children | 7d28bed0864e |
line wrap: on
line source
/** * This Vamp plugin is a wrapper for Python Scripts. (VamPy) * Centre for Digital Music, Queen Mary, University of London. * Copyright 2008, George Fazekas. */ #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 { cerr << "ERROR: callable plugin class could not be found in source: " << classname << endl << "Hint: plugin source filename and plugin class name must be the same." << endl; PyErr_Print(); 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 //!!! It would probably be better to actually call // PluginHostAdapter::getPluginPath. That would mean this "plugin" // needs to link against vamp-hostsdk, but that's probably acceptable // as it is sort of a host as well. 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; }