comparison pyvamp-main.cpp @ 24:7d28bed0864e

* Rearrange Python plugin construction. Formerly, the PyPluginAdapter has retained a single plugin instance pointer for each plugin found, and its createPlugin method has simply returned a new PyPlugin object wrapping the same instance pointer. This has a couple of negative consequences: - Because construction of the actual Python instance occurred before the wrapper was constructed, it was not possible to pass arguments (i.e. the sample rate) from the wrapper constructor to the Python plugin instance constructor -- they had to be passed later, to initialise, disadvantaging those plugins that would like to use the sample rate for parameter & step/block size calculations etc - Because there was only a single Python plugin instance, it was not possible to run more than one instance at once with any isolation This rework instead stores the Python class pointer (rather than instance pointer) in the PyPluginAdapter, and each PyPlugin wrapper instance creates its own Python plugin instance. What could possibly go wrong?
author cannam
date Mon, 17 Aug 2009 15:22:06 +0000
parents 812fbde7eca5
children 7648f3f2fa14
comparison
equal deleted inserted replaced
23:535d559300dc 24:7d28bed0864e
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 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 2
37 /** 3 /**
38 * This Vamp plugin is a wrapper for Python Scripts. (VamPy) 4 * This Vamp plugin is a wrapper for Python Scripts. (VamPy)
39 * Centre for Digital Music, Queen Mary, University of London. 5 * Centre for Digital Music, Queen Mary, University of London.
40 * Copyright 2008, George Fazekas. 6 * Copyright 2008, George Fazekas.
41 */ 7 */
42 8
43 #include <Python.h> 9 #include <Python.h>
44 #include "vamp/vamp.h" 10 #include "vamp/vamp.h"
45 #include "vamp-sdk/PluginAdapter.h" 11 #include "vamp-sdk/PluginAdapter.h"
46 #include "PyPlugScanner.h" 12 #include "PyPlugScanner.h"
65 static int adinstcount; 31 static int adinstcount;
66 32
67 class PyPluginAdapter : public Vamp::PluginAdapterBase 33 class PyPluginAdapter : public Vamp::PluginAdapterBase
68 { 34 {
69 public: 35 public:
70 PyPluginAdapter(std::string pyPlugId, PyObject* pyInstance) : 36 PyPluginAdapter(std::string pyPlugId, PyObject* pyClass) :
71 PluginAdapterBase(), 37 PluginAdapterBase(),
72 m_plug(pyPlugId), 38 m_plug(pyPlugId),
73 m_pyInstance(pyInstance) 39 m_pyClass(pyClass)
74 { 40 {
75 cerr << "PyPluginAdapter:ctor:"<< adinstcount << ": " << m_plug << endl; 41 cerr << "PyPluginAdapter:ctor:"<< adinstcount << ": " << m_plug << endl;
76 adinstcount++; 42 adinstcount++;
77 m_instanceCount = 0; 43 m_instanceCount = 0;
78 } 44 }
79 45
80 ~PyPluginAdapter() 46 ~PyPluginAdapter()
81 { 47 {
82 } 48 }
83 49
84 protected: 50 protected:
85 Vamp::Plugin *createPlugin(float inputSampleRate) { 51 Vamp::Plugin *createPlugin(float inputSampleRate)
86 52 {
87 std::string pclass = m_plug.substr(m_plug.rfind(':')+1,m_plug.size()-1); 53 try {
88 std::string ppath = m_plug.substr(0,m_plug.rfind(pathsep)); 54 PyPlugin *plugin = new PyPlugin(m_plug, inputSampleRate, m_pyClass);
89 PyPlugin *plugin = new PyPlugin(m_plug,inputSampleRate,m_pyInstance); 55 m_instanceCount++;
90 m_instanceCount++; 56 return plugin;
91 cerr << "PyPluginAdapter::createPlugin:" << pclass << " (instance: " << m_instanceCount << ")" << endl; 57 } catch (...) {
92 return plugin; 58 cerr << "PyPluginAdapter::createPlugin: Failed to construct PyPlugin" << endl;
93 59 return 0;
94 } 60 }
95 61 }
96 std::string m_plug; 62
97 bool m_haveInitialized; 63 std::string m_plug;
98 PyObject *m_pyInstance; 64 bool m_haveInitialized;
99 int m_instanceCount; 65 PyObject *m_pyClass;
100 66 int m_instanceCount;
101 }; 67 };
102 68
103 69
104 static std::vector<PyPluginAdapter *> adapters; 70 static std::vector<PyPluginAdapter *> adapters;
105 static bool haveScannedPlugins = false; 71 static bool haveScannedPlugins = false;
181 *vampGetPluginDescriptor(unsigned int version,unsigned int index) 147 *vampGetPluginDescriptor(unsigned int version,unsigned int index)
182 { 148 {
183 if (version < 1) return 0; 149 if (version < 1) return 0;
184 150
185 int isPythonInitialized = Py_IsInitialized(); 151 int isPythonInitialized = Py_IsInitialized();
186 //cerr << "# isPythonInitialized: " << isPythonInitialized << endl; 152 cerr << "# isPythonInitialized: " << isPythonInitialized << endl;
187 //cerr << "# haveScannedPlugins: " << haveScannedPlugins << endl; 153 cerr << "# haveScannedPlugins: " << haveScannedPlugins << endl;
188 154
189 if (!haveScannedPlugins) { 155 if (!haveScannedPlugins) {
190 156
191 if (!isPythonInitialized) { 157 if (!isPythonInitialized) {
192 158
208 #endif 174 #endif
209 if (!pylib) cerr << "Warning: Could not preload Python." 175 if (!pylib) cerr << "Warning: Could not preload Python."
210 << " Dynamic loading in scripts will fail." << endl; 176 << " Dynamic loading in scripts will fail." << endl;
211 */ 177 */
212 Py_Initialize(); 178 Py_Initialize();
179 cerr << "# isPythonInitialized after initialize: " << Py_IsInitialized() << endl;
213 PyEval_InitThreads(); 180 PyEval_InitThreads();
214 } else { 181 } else {
215 //Py_InitializeEx(1); 182 //Py_InitializeEx(1);
216 } 183 }
217 184
218 vector<string> pyPlugs; 185 vector<string> pyPlugs;
219 vector<string> pyPath; 186 vector<string> pyPath;
220 vector<PyObject *> pyInstances; 187 vector<PyObject *> pyClasses;
221 static PyPlugScanner *scanner; 188 static PyPlugScanner *scanner;
222 189
223 //Scanning Plugins 190 //Scanning Plugins
224 cerr << "Scanning PyPlugins" << endl; 191 cerr << "Scanning PyPlugins" << endl;
225 scanner = PyPlugScanner::getInstance(); 192 scanner = PyPlugScanner::getInstance();
228 //pyPath.push_back("/Users/Shared/Development/vamp-experiments"); 195 //pyPath.push_back("/Users/Shared/Development/vamp-experiments");
229 scanner->setPath(pyPath); 196 scanner->setPath(pyPath);
230 pyPlugs = scanner->getPyPlugs(); 197 pyPlugs = scanner->getPyPlugs();
231 cerr << "Found " << pyPlugs.size() << " Scripts ...OK" << endl; 198 cerr << "Found " << pyPlugs.size() << " Scripts ...OK" << endl;
232 //TODO: this will support multiple classes per script 199 //TODO: this will support multiple classes per script
233 pyInstances = scanner->getPyInstances(); 200 pyClasses = scanner->getPyClasses();
234 cerr << "Found " << pyInstances.size() << " Instances ...OK" << endl; 201 cerr << "Found " << pyClasses.size() << " Classes ...OK" << endl;
235 202
236 for (size_t i = 0; i < pyPlugs.size(); ++i) { 203 for (size_t i = 0; i < pyPlugs.size(); ++i) {
237 adapters.push_back( new PyPluginAdapter(pyPlugs[i],pyInstances[i])); 204 adapters.push_back( new PyPluginAdapter(pyPlugs[i],pyClasses[i]));
238 } 205 }
239 haveScannedPlugins=true; 206 haveScannedPlugins=true;
240 207
241 } 208 }
242 209