annotate vampy-main.cpp @ 32:a8231788216c vampy2

Vampy2: accept numpy array return types.
author fazekasgy
date Mon, 21 Sep 2009 13:56:28 +0000
parents 4f1894c7591b
children c905122f79e7
rev   line source
fazekasgy@31 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
fazekasgy@31 2
fazekasgy@31 3 /**
fazekasgy@31 4 * This Vamp plugin is a wrapper for Python Scripts. (VamPy)
fazekasgy@31 5 * Centre for Digital Music, Queen Mary, University of London.
fazekasgy@31 6 * Copyright 2008, George Fazekas.
fazekasgy@31 7 */
fazekasgy@31 8
fazekasgy@31 9 #include <Python.h>
fazekasgy@31 10 #include "vamp/vamp.h"
fazekasgy@31 11 #include "vamp-sdk/PluginAdapter.h"
fazekasgy@31 12 #include "PyPlugScanner.h"
fazekasgy@31 13 #include "PyPlugin.h"
fazekasgy@31 14 // #include "host/pyRealTime.h"
fazekasgy@31 15 #include "PyExtensionModule.h"
fazekasgy@31 16
fazekasgy@31 17
fazekasgy@31 18 #ifdef _WIN32
fazekasgy@31 19 #define pathsep ('\\')
fazekasgy@31 20 #include <windows.h>
fazekasgy@31 21 #include <tchar.h>
fazekasgy@31 22 #else
fazekasgy@31 23 #define pathsep ('/')
fazekasgy@31 24 #include <dirent.h>
fazekasgy@31 25 #include <dlfcn.h>
fazekasgy@31 26 #endif
fazekasgy@31 27
fazekasgy@31 28 using std::cerr;
fazekasgy@31 29 using std::endl;
fazekasgy@31 30 using std::string;
fazekasgy@31 31 using std::vector;
fazekasgy@31 32
fazekasgy@31 33
fazekasgy@31 34 //volatile bool mutex = false;
fazekasgy@31 35 static int adinstcount;
fazekasgy@31 36 static int totinstcount;
fazekasgy@31 37
fazekasgy@31 38 class PyPluginAdapter : public Vamp::PluginAdapterBase
fazekasgy@31 39 {
fazekasgy@31 40 public:
fazekasgy@31 41 PyPluginAdapter(std::string pyPlugId, PyObject* pyClass) :
fazekasgy@31 42 PluginAdapterBase(),
fazekasgy@31 43 m_plug(pyPlugId),
fazekasgy@31 44 m_pyClass(pyClass)
fazekasgy@31 45 {
fazekasgy@31 46 cerr << "PyPluginAdapter:ctor:"<< adinstcount << ": " << m_plug << endl;
fazekasgy@31 47 adinstcount++;
fazekasgy@31 48 m_instanceCount = 0;
fazekasgy@31 49 }
fazekasgy@31 50
fazekasgy@31 51 ~PyPluginAdapter()
fazekasgy@31 52 {
fazekasgy@31 53 }
fazekasgy@31 54
fazekasgy@31 55 protected:
fazekasgy@31 56 Vamp::Plugin *createPlugin(float inputSampleRate)
fazekasgy@31 57 {
fazekasgy@31 58 try {
fazekasgy@31 59 PyPlugin *plugin = new PyPlugin(m_plug, inputSampleRate, m_pyClass, totinstcount);
fazekasgy@31 60 // m_instanceCount++; /// do this in the ctors
fazekasgy@31 61 return plugin;
fazekasgy@31 62 } catch (...) {
fazekasgy@31 63 cerr << "PyPluginAdapter::createPlugin: Failed to construct PyPlugin" << endl;
fazekasgy@31 64 return 0;
fazekasgy@31 65 }
fazekasgy@31 66 }
fazekasgy@31 67
fazekasgy@31 68 std::string m_plug;
fazekasgy@31 69 bool m_haveInitialized;
fazekasgy@31 70 PyObject *m_pyClass;
fazekasgy@31 71 int m_instanceCount;
fazekasgy@31 72 };
fazekasgy@31 73
fazekasgy@31 74
fazekasgy@31 75 static std::vector<PyPluginAdapter *> adapters;
fazekasgy@31 76 static bool haveScannedPlugins = false;
fazekasgy@31 77 static bool haveVampyInitialised = false;
fazekasgy@31 78
fazekasgy@31 79 static bool tryPreload(string name)
fazekasgy@31 80 {
fazekasgy@31 81 cerr << "Trying to load Python interpreter library \"" << name << "\"...";
fazekasgy@31 82 #ifdef _WIN32
fazekasgy@31 83 void *lib = LoadLibrary(name.c_str());
fazekasgy@31 84 if (!lib) {
fazekasgy@31 85 cerr << " failed" << endl;
fazekasgy@31 86 return false;
fazekasgy@31 87 }
fazekasgy@31 88 #else
fazekasgy@31 89 void *lib = dlopen(name.c_str(), RTLD_NOW | RTLD_GLOBAL);
fazekasgy@31 90 if (!lib) {
fazekasgy@31 91 cerr << " failed" << endl;
fazekasgy@31 92 return false;
fazekasgy@31 93 }
fazekasgy@31 94 #endif
fazekasgy@31 95 cerr << " succeeded" << endl;
fazekasgy@31 96 return true;
fazekasgy@31 97 }
fazekasgy@31 98
fazekasgy@31 99 static bool preloadPython()
fazekasgy@31 100 {
fazekasgy@31 101 #ifdef _WIN32
fazekasgy@31 102 // this doesn't seem to be necessary at all on Windows
fazekasgy@31 103 return true;
fazekasgy@31 104 #endif
fazekasgy@31 105
fazekasgy@31 106 string pyver = Py_GetVersion();
fazekasgy@31 107 int dots = 2;
fazekasgy@31 108 string shortver;
fazekasgy@31 109 for (size_t i = 0; i < pyver.length(); ++i) {
fazekasgy@31 110 if (pyver[i] == '.') {
fazekasgy@31 111 if (--dots == 0) {
fazekasgy@31 112 shortver = pyver.substr(0, i);
fazekasgy@31 113 break;
fazekasgy@31 114 }
fazekasgy@31 115 }
fazekasgy@31 116 }
fazekasgy@31 117 cerr << "Short version: " << shortver << endl;
fazekasgy@31 118
fazekasgy@31 119 vector<string> pfxs;
fazekasgy@31 120 pfxs.push_back("");
fazekasgy@31 121 pfxs.push_back(string(Py_GetExecPrefix()) + "/lib/");
fazekasgy@31 122 pfxs.push_back(string(Py_GetExecPrefix()) + "/");
fazekasgy@31 123 pfxs.push_back("/usr/lib/");
fazekasgy@31 124 pfxs.push_back("/usr/local/lib/");
fazekasgy@31 125 char buffer[5];
fazekasgy@31 126
fazekasgy@31 127 // hahaha! grossness is like a brother to us
fazekasgy@31 128 #ifdef __APPLE__
fazekasgy@31 129 for (size_t pfxidx = 0; pfxidx < pfxs.size(); ++pfxidx) {
fazekasgy@31 130 for (int minor = 8; minor >= 0; --minor) {
fazekasgy@31 131 sprintf(buffer, "%d", minor);
fazekasgy@31 132 if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".dylib." + buffer)) return true;
fazekasgy@31 133 }
fazekasgy@31 134 if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".dylib")) return true;
fazekasgy@31 135 if (tryPreload(pfxs[pfxidx] + string("libpython.dylib"))) return true;
fazekasgy@31 136 }
fazekasgy@31 137 #else
fazekasgy@31 138 for (size_t pfxidx = 0; pfxidx < pfxs.size(); ++pfxidx) {
fazekasgy@31 139 for (int minor = 8; minor >= 0; --minor) {
fazekasgy@31 140 sprintf(buffer, "%d", minor);
fazekasgy@31 141 if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".so." + buffer)) return true;
fazekasgy@31 142 }
fazekasgy@31 143 if (tryPreload(pfxs[pfxidx] + string("libpython") + shortver + ".so")) return true;
fazekasgy@31 144 if (tryPreload(pfxs[pfxidx] + string("libpython.so"))) return true;
fazekasgy@31 145 }
fazekasgy@31 146 #endif
fazekasgy@31 147
fazekasgy@31 148 return false;
fazekasgy@31 149 }
fazekasgy@31 150
fazekasgy@31 151 /* This doesn't work: don't try it again.
fazekasgy@31 152 static bool initPython()
fazekasgy@31 153 {
fazekasgy@31 154 // preloadPython();
fazekasgy@31 155 Py_Initialize();
fazekasgy@31 156 #ifndef _WIN32
fazekasgy@31 157 //set dlopen flags form Python
fazekasgy@31 158 string pyCmd = "from sys import setdlopenflags\nimport dl\nsetdlopenflags(dl.RTLD_NOW|dl.RTLD_GLOBAL)\n";
fazekasgy@31 159 if (PyRun_SimpleString(pyCmd.c_str()) == -1)
fazekasgy@31 160 {
fazekasgy@31 161 cerr << "Warning: Could not set dlopen flasgs. Dynamic loading in scripts will fail." << endl;
fazekasgy@31 162 return false;
fazekasgy@31 163 }
fazekasgy@31 164 #endif
fazekasgy@31 165 PyEval_InitThreads();
fazekasgy@31 166 return Py_IsInitialized();
fazekasgy@31 167 }
fazekasgy@31 168 */
fazekasgy@31 169
fazekasgy@31 170 const VampPluginDescriptor
fazekasgy@31 171 *vampGetPluginDescriptor(unsigned int version,unsigned int index)
fazekasgy@31 172 {
fazekasgy@31 173 if (version < 1) return 0;
fazekasgy@31 174
fazekasgy@31 175 int isPythonInitialized = Py_IsInitialized();
fazekasgy@31 176 cerr << "# isPythonInitialized: " << isPythonInitialized << endl;
fazekasgy@31 177 cerr << "# haveScannedPlugins: " << haveScannedPlugins << endl;
fazekasgy@31 178
fazekasgy@31 179 if (!haveScannedPlugins) {
fazekasgy@31 180
fazekasgy@31 181 if (!isPythonInitialized){
fazekasgy@31 182
fazekasgy@31 183 if (!preloadPython())
fazekasgy@31 184 cerr << "Warning: Could not preload Python. Dynamic loading in scripts will fail." << endl;
fazekasgy@31 185
fazekasgy@31 186 int ext = PyImport_AppendInittab("vampy",initvampy);
fazekasgy@31 187 if (ext == -1) cerr << "Extension unsuccessful." << endl;
fazekasgy@31 188 else cerr << "Extension successful." << endl;
fazekasgy@31 189 Py_Initialize();
fazekasgy@31 190 initvampy();
fazekasgy@31 191 // if (!PyImport_ImportModule("vampy"))
fazekasgy@31 192 // cerr << "Could not import extension." << endl;
fazekasgy@31 193
fazekasgy@31 194 // Py_InitModule("vampy", VampyMethods);
fazekasgy@31 195
fazekasgy@31 196 // initpyRealTime();
fazekasgy@31 197 cerr << "# isPythonInitialized after initialize: " << Py_IsInitialized() << endl;
fazekasgy@31 198 // PyEval_InitThreads(); //not sure why this was needed
fazekasgy@31 199 }
fazekasgy@31 200
fazekasgy@31 201 vector<string> pyPlugs;
fazekasgy@31 202 vector<string> pyPath;
fazekasgy@31 203 vector<PyObject *> pyClasses;
fazekasgy@31 204 static PyPlugScanner *scanner;
fazekasgy@31 205
fazekasgy@31 206 //Scanning Plugins
fazekasgy@31 207 cerr << "Scanning PyPlugins" << endl;
fazekasgy@31 208 scanner = PyPlugScanner::getInstance();
fazekasgy@31 209 pyPath=scanner->getAllValidPath();
fazekasgy@31 210 //add this as extra path for development
fazekasgy@31 211 //pyPath.push_back("/Users/Shared/Development/vamp-experiments");
fazekasgy@31 212 scanner->setPath(pyPath);
fazekasgy@31 213 pyPlugs = scanner->getPyPlugs();
fazekasgy@31 214 cerr << "Found " << pyPlugs.size() << " Scripts ...OK" << endl;
fazekasgy@31 215 //TODO: this should support multiple classes per script (?)
fazekasgy@31 216 pyClasses = scanner->getPyClasses();
fazekasgy@31 217 cerr << "Found " << pyClasses.size() << " Classes ...OK" << endl;
fazekasgy@31 218
fazekasgy@31 219 for (size_t i = 0; i < pyPlugs.size(); ++i) {
fazekasgy@31 220 adapters.push_back( new PyPluginAdapter(pyPlugs[i],pyClasses[i]));
fazekasgy@31 221 }
fazekasgy@31 222 haveScannedPlugins=true;
fazekasgy@31 223 // if (!haveVampyInitialised) {
fazekasgy@31 224 // // PyImport_AddModule("vampy");
fazekasgy@31 225 // // if (!PyImport_ImportModule("vampy"))
fazekasgy@31 226 // cerr << "Could not import extension." << endl;
fazekasgy@31 227 // initvampy();
fazekasgy@31 228 // haveVampyInitialised = true;
fazekasgy@31 229 // cerr << "Extension initialised from main." << endl;
fazekasgy@31 230 // }
fazekasgy@31 231 }
fazekasgy@31 232
fazekasgy@31 233 cerr << "Accessing adapter index: " << index << " (adapters: " << adapters.size() << ")" << endl;
fazekasgy@31 234 if (index<adapters.size()) {
fazekasgy@31 235 const VampPluginDescriptor *tmp = adapters[index]->getDescriptor();
fazekasgy@31 236 return tmp;
fazekasgy@31 237 } else return 0;
fazekasgy@31 238
fazekasgy@31 239
fazekasgy@31 240 }
fazekasgy@31 241
fazekasgy@31 242
fazekasgy@31 243
fazekasgy@31 244
fazekasgy@31 245
fazekasgy@31 246
fazekasgy@31 247
fazekasgy@31 248