comparison pyvamp-main.cpp @ 0:e20e214bdfb5

Added VAMP-Python binding project vampy
author fazekasgy
date Tue, 11 Mar 2008 19:47:34 +0000
parents
children dc88002ce687
comparison
equal deleted inserted replaced
-1:000000000000 0:e20e214bdfb5
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Vamp
5
6 An API for audio analysis and feature extraction plugins.
7
8 Centre for Digital Music, Queen Mary, University of London.
9 Copyright 2006 Chris Cannam.
10
11 Permission is hereby granted, free of charge, to any person
12 obtaining a copy of this software and associated documentation
13 files (the "Software"), to deal in the Software without
14 restriction, including without limitation the rights to use, copy,
15 modify, merge, publish, distribute, sublicense, and/or sell copies
16 of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be
20 included in all copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 Except as contained in this notice, the names of the Centre for
31 Digital Music; Queen Mary, University of London; and Chris Cannam
32 shall not be used in advertising or otherwise to promote the sale,
33 use or other dealings in this Software without prior written
34 authorization.
35 */
36
37 /**
38 * This VAMP plugin is a wrapper for Python Scripts. (VamPy)
39 * Centre for Digital Music, Queen Mary, University of London.
40 * Copyright 2008, George Fazekas.
41
42 TODO: needs more complete error checking
43 needs correct implementation of Python threading
44 more efficient data conversion using the buffering interface or ctypes
45 VAMP 'programs' not implemented
46 support multiple plugins per script in scanner
47 ensure proper cleanup, (host do a good job though)
48
49 COMPILING AND LINKING:
50 (1) include Python.h wherever it is on your machine
51 (2) this plugin needs to be linked against the Python binary:
52
53 example on on MacOSX:
54 g++ -O2 -Wall -I. -fPIC -c -o pyvamp-main.o pyvamp-main.cpp
55 g++ -dynamiclib -o vamp-pyvamp-plugin.dylib ./PyPlugScanner.o ./PyPlugin.o ./pyvamp-main.o sdk/vamp-sdk/libvamp-sdk.a
56 ... -u _PyMac_Error /Library/Frameworks/Python.framework/Versions/2.5/Python
57 */
58
59 //#include "Python.h"
60 #include "/usr/include/python/Python.h"
61 #include "vamp/vamp.h"
62 #include "vamp-sdk/PluginAdapter.h"
63 #include "PyPlugScanner.h"
64 #include "PyPlugin.h"
65
66 #ifdef _WIN32
67 #define pathsep ('\\')
68 #include <windows.h>
69 #include <tchar.h>
70 #else
71 #define pathsep ('/')
72 #include <dirent.h>
73 #include <dlfcn.h>
74 #endif
75
76 using std::cerr;
77 using std::endl;
78 using std::string;
79 using std::vector;
80
81 volatile bool mutex = false;
82 static int adinstcount;
83
84 class PyPluginAdapter : public Vamp::PluginAdapterBase
85 {
86 public:
87 PyPluginAdapter(std::string pyPlugId, PyObject* pyInstance) :
88 PluginAdapterBase(),
89 m_plug(pyPlugId),
90 m_pyInstance(pyInstance)
91 {
92 cerr << "PyPluginAdapter:ctor:"<< adinstcount << ": " << m_plug << endl;
93 adinstcount++;
94 m_instanceCount = 0;
95 }
96
97 ~PyPluginAdapter()
98 {
99 }
100
101 protected:
102 Vamp::Plugin *createPlugin(float inputSampleRate) {
103
104 std::string pclass = m_plug.substr(m_plug.rfind(':')+1,m_plug.size()-1);
105 std::string ppath = m_plug.substr(0,m_plug.rfind(pathsep));
106 PyPlugin *plugin = new PyPlugin(m_plug,inputSampleRate,m_pyInstance);
107 m_instanceCount++;
108 cerr << "PyPluginAdapter::createPlugin:" << pclass << " (instance: " << m_instanceCount << ")" << endl;
109 return plugin;
110
111 }
112
113 std::string m_plug;
114 bool m_haveInitialized;
115 PyObject *m_pyInstance;
116 int m_instanceCount;
117
118 };
119
120
121 static std::vector<PyPluginAdapter *> adapters;
122 static bool haveScannedPlugins = false;
123
124 const VampPluginDescriptor
125 *vampGetPluginDescriptor(unsigned int version,unsigned int index)
126 {
127 if (version < 1) return 0;
128
129 int isPythonInitialized = Py_IsInitialized();
130 //cerr << "# isPythonInitialized: " << isPythonInitialized << endl;
131 //cerr << "# haveScannedPlugins: " << haveScannedPlugins << endl;
132
133 if (!haveScannedPlugins) {
134
135 if (!isPythonInitialized) {
136
137 string pythonPath =
138 (string) Py_GetExecPrefix() + pathsep +
139 (string) Py_GetProgramName();
140
141 void *pylib = 0;
142
143 cerr << "Loading Python Interpreter at: " << pythonPath << endl;
144 //Preloading the binary allows the load of shared libs //dlopen("/Library/Frameworks/Python.framework/Versions/2.5/Python", RTLD_NOW|RTLD_GLOBAL);
145 #ifdef _WIN32
146 //TODO: check how to do RTLD_NOW on Windows
147 pylib = LoadLibrary(pythonPath.c_str());
148 #else
149 pylib = dlopen(pythonPath.c_str(), RTLD_NOW|RTLD_GLOBAL);
150 #endif
151 if (!pylib) cerr << "Warning: Could not preload Python."
152 << " Dynamic lodading in scripts will fail." << endl;
153 Py_Initialize();
154 PyEval_InitThreads();
155 } else {
156 //Py_InitializeEx(1);
157 }
158
159 vector<string> pyPlugs;
160 vector<string> pyPath;
161 vector<PyObject *> pyInstances;
162 static PyPlugScanner *scanner;
163
164 //Scanning Plugins
165 cerr << "Scanning PyPlugins" << endl;
166 scanner = PyPlugScanner::getInstance();
167 pyPath=scanner->getAllValidPath();
168 //add this as extra path for development
169 pyPath.push_back("/Users/Shared/Development/vamp-experiments");
170 scanner->setPath(pyPath);
171 pyPlugs = scanner->getPyPlugs();
172 cerr << "Found " << pyPlugs.size() << " Scripts ...OK" << endl;
173 //TODO: this will support multiple classes per script
174 pyInstances = scanner->getPyInstances();
175 cerr << "Found " << pyInstances.size() << " Instances ...OK" << endl;
176
177 for (size_t i = 0; i < pyPlugs.size(); ++i) {
178 adapters.push_back( new PyPluginAdapter(pyPlugs[i],pyInstances[i]));
179 }
180 haveScannedPlugins=true;
181 }
182
183 cerr << "Accessing adapter index: " << index << " (adapters: " << adapters.size() << ")" << endl;
184 if (index<adapters.size()) {
185 const VampPluginDescriptor *tmp = adapters[index]->getDescriptor();
186 return tmp;
187 } else return 0;
188
189
190 }
191
192
193
194
195
196
197
198