fazekasgy@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ fazekasgy@0: fazekasgy@0: /* fazekasgy@0: Vamp fazekasgy@0: fazekasgy@0: An API for audio analysis and feature extraction plugins. fazekasgy@0: fazekasgy@0: Centre for Digital Music, Queen Mary, University of London. fazekasgy@0: Copyright 2006 Chris Cannam. fazekasgy@0: fazekasgy@0: Permission is hereby granted, free of charge, to any person fazekasgy@0: obtaining a copy of this software and associated documentation fazekasgy@0: files (the "Software"), to deal in the Software without fazekasgy@0: restriction, including without limitation the rights to use, copy, fazekasgy@0: modify, merge, publish, distribute, sublicense, and/or sell copies fazekasgy@0: of the Software, and to permit persons to whom the Software is fazekasgy@0: furnished to do so, subject to the following conditions: fazekasgy@0: fazekasgy@0: The above copyright notice and this permission notice shall be fazekasgy@0: included in all copies or substantial portions of the Software. fazekasgy@0: fazekasgy@0: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, fazekasgy@0: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF fazekasgy@0: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND fazekasgy@0: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR fazekasgy@0: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF fazekasgy@0: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION fazekasgy@0: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. fazekasgy@0: fazekasgy@0: Except as contained in this notice, the names of the Centre for fazekasgy@0: Digital Music; Queen Mary, University of London; and Chris Cannam fazekasgy@0: shall not be used in advertising or otherwise to promote the sale, fazekasgy@0: use or other dealings in this Software without prior written fazekasgy@0: authorization. fazekasgy@0: */ fazekasgy@0: fazekasgy@0: /** cannam@7: * This Vamp plugin is a wrapper for Python Scripts. (VamPy) fazekasgy@0: * Centre for Digital Music, Queen Mary, University of London. fazekasgy@0: * Copyright 2008, George Fazekas. fazekasgy@0: */ fazekasgy@0: cannam@3: #include fazekasgy@0: #include "vamp/vamp.h" fazekasgy@0: #include "vamp-sdk/PluginAdapter.h" fazekasgy@0: #include "PyPlugScanner.h" fazekasgy@0: #include "PyPlugin.h" fazekasgy@0: fazekasgy@0: #ifdef _WIN32 fazekasgy@0: #define pathsep ('\\') fazekasgy@0: #include fazekasgy@0: #include fazekasgy@0: #else fazekasgy@0: #define pathsep ('/') fazekasgy@0: #include fazekasgy@0: #include fazekasgy@0: #endif fazekasgy@0: fazekasgy@0: using std::cerr; fazekasgy@0: using std::endl; fazekasgy@0: using std::string; fazekasgy@0: using std::vector; fazekasgy@0: fazekasgy@6: //volatile bool mutex = false; fazekasgy@0: static int adinstcount; fazekasgy@0: fazekasgy@0: class PyPluginAdapter : public Vamp::PluginAdapterBase fazekasgy@0: { fazekasgy@0: public: fazekasgy@0: PyPluginAdapter(std::string pyPlugId, PyObject* pyInstance) : fazekasgy@0: PluginAdapterBase(), fazekasgy@0: m_plug(pyPlugId), fazekasgy@0: m_pyInstance(pyInstance) fazekasgy@0: { fazekasgy@0: cerr << "PyPluginAdapter:ctor:"<< adinstcount << ": " << m_plug << endl; fazekasgy@0: adinstcount++; fazekasgy@0: m_instanceCount = 0; fazekasgy@0: } fazekasgy@0: fazekasgy@0: ~PyPluginAdapter() fazekasgy@0: { fazekasgy@0: } fazekasgy@0: fazekasgy@0: protected: fazekasgy@0: Vamp::Plugin *createPlugin(float inputSampleRate) { fazekasgy@0: fazekasgy@0: std::string pclass = m_plug.substr(m_plug.rfind(':')+1,m_plug.size()-1); fazekasgy@0: std::string ppath = m_plug.substr(0,m_plug.rfind(pathsep)); fazekasgy@0: PyPlugin *plugin = new PyPlugin(m_plug,inputSampleRate,m_pyInstance); fazekasgy@0: m_instanceCount++; fazekasgy@0: cerr << "PyPluginAdapter::createPlugin:" << pclass << " (instance: " << m_instanceCount << ")" << endl; fazekasgy@0: return plugin; fazekasgy@0: fazekasgy@0: } fazekasgy@0: fazekasgy@0: std::string m_plug; fazekasgy@0: bool m_haveInitialized; fazekasgy@0: PyObject *m_pyInstance; fazekasgy@0: int m_instanceCount; fazekasgy@0: fazekasgy@0: }; fazekasgy@0: fazekasgy@0: fazekasgy@0: static std::vector adapters; fazekasgy@0: static bool haveScannedPlugins = false; fazekasgy@0: fazekasgy@0: const VampPluginDescriptor fazekasgy@0: *vampGetPluginDescriptor(unsigned int version,unsigned int index) fazekasgy@0: { fazekasgy@0: if (version < 1) return 0; fazekasgy@0: fazekasgy@0: int isPythonInitialized = Py_IsInitialized(); fazekasgy@0: //cerr << "# isPythonInitialized: " << isPythonInitialized << endl; fazekasgy@0: //cerr << "# haveScannedPlugins: " << haveScannedPlugins << endl; fazekasgy@0: fazekasgy@0: if (!haveScannedPlugins) { fazekasgy@8: fazekasgy@0: if (!isPythonInitialized) { fazekasgy@0: fazekasgy@0: string pythonPath = fazekasgy@0: (string) Py_GetExecPrefix() + pathsep + fazekasgy@0: (string) Py_GetProgramName(); fazekasgy@0: fazekasgy@0: void *pylib = 0; fazekasgy@0: fazekasgy@0: cerr << "Loading Python Interpreter at: " << pythonPath << endl; fazekasgy@1: //Preloading the binary allows the load of shared libs fazekasgy@0: //TODO: check how to do RTLD_NOW on Windows fazekasgy@2: #ifdef _WIN32 fazekasgy@0: pylib = LoadLibrary(pythonPath.c_str()); fazekasgy@0: #else fazekasgy@0: pylib = dlopen(pythonPath.c_str(), RTLD_NOW|RTLD_GLOBAL); fazekasgy@0: #endif fazekasgy@0: if (!pylib) cerr << "Warning: Could not preload Python." fazekasgy@1: << " Dynamic loading in scripts will fail." << endl; fazekasgy@0: Py_Initialize(); fazekasgy@0: PyEval_InitThreads(); fazekasgy@0: } else { fazekasgy@0: //Py_InitializeEx(1); fazekasgy@0: } fazekasgy@0: fazekasgy@0: vector pyPlugs; fazekasgy@0: vector pyPath; fazekasgy@0: vector pyInstances; fazekasgy@0: static PyPlugScanner *scanner; fazekasgy@0: fazekasgy@0: //Scanning Plugins fazekasgy@0: cerr << "Scanning PyPlugins" << endl; fazekasgy@0: scanner = PyPlugScanner::getInstance(); fazekasgy@0: pyPath=scanner->getAllValidPath(); fazekasgy@0: //add this as extra path for development fazekasgy@6: //pyPath.push_back("/Users/Shared/Development/vamp-experiments"); fazekasgy@0: scanner->setPath(pyPath); fazekasgy@0: pyPlugs = scanner->getPyPlugs(); fazekasgy@0: cerr << "Found " << pyPlugs.size() << " Scripts ...OK" << endl; fazekasgy@0: //TODO: this will support multiple classes per script fazekasgy@0: pyInstances = scanner->getPyInstances(); fazekasgy@0: cerr << "Found " << pyInstances.size() << " Instances ...OK" << endl; fazekasgy@0: fazekasgy@0: for (size_t i = 0; i < pyPlugs.size(); ++i) { fazekasgy@0: adapters.push_back( new PyPluginAdapter(pyPlugs[i],pyInstances[i])); fazekasgy@0: } fazekasgy@0: haveScannedPlugins=true; fazekasgy@6: fazekasgy@0: } fazekasgy@0: fazekasgy@0: cerr << "Accessing adapter index: " << index << " (adapters: " << adapters.size() << ")" << endl; fazekasgy@0: if (indexgetDescriptor(); fazekasgy@0: return tmp; fazekasgy@0: } else return 0; fazekasgy@0: fazekasgy@0: fazekasgy@0: } fazekasgy@0: fazekasgy@0: fazekasgy@0: fazekasgy@0: fazekasgy@0: fazekasgy@0: fazekasgy@0: fazekasgy@0: