Mercurial > hg > vampy
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 |