comparison PyPlugin.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 1ae350e97f93
children 046ba4183373
comparison
equal deleted inserted replaced
23:535d559300dc 24:7d28bed0864e
73 static std::map<std::string, p::eParmDescriptors> parmKeys; 73 static std::map<std::string, p::eParmDescriptors> parmKeys;
74 74
75 Mutex PyPlugin::m_pythonInterpreterMutex; 75 Mutex PyPlugin::m_pythonInterpreterMutex;
76 static bool isMapInitialised = false; 76 static bool isMapInitialised = false;
77 77
78 PyPlugin::PyPlugin(std::string pluginKey,float inputSampleRate, PyObject *pyInstance) : 78 PyPlugin::PyPlugin(std::string pluginKey, float inputSampleRate, PyObject *pyClass) :
79 Plugin(inputSampleRate), 79 Plugin(inputSampleRate),
80 m_pyInstance(pyInstance), 80 m_pyClass(pyClass),
81 m_stepSize(0), 81 m_stepSize(0),
82 m_blockSize(0), 82 m_blockSize(0),
83 m_channels(0), 83 m_channels(0),
84 m_plugin(pluginKey), 84 m_plugin(pluginKey),
85 m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)), 85 m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)),
86 m_path((pluginKey.substr(0,pluginKey.rfind(pathsep)))), 86 m_path((pluginKey.substr(0,pluginKey.rfind(pathsep)))),
87 m_processType(0), 87 m_processType(0),
88 m_pyProcess(NULL), 88 m_pyProcess(NULL),
89 m_inputDomain(TimeDomain) 89 m_inputDomain(TimeDomain)
90 { 90 {
91 // Create an instance
92 PyObject *pyInputSampleRate = PyFloat_FromDouble(inputSampleRate);
93 PyObject *args = PyTuple_Pack(1, pyInputSampleRate);
94
95 m_pyInstance = PyObject_CallObject(m_pyClass, args);
96
97 if (!m_pyInstance) {
98 cerr << "PyPlugin::PyPlugin: Failed to create Python plugin instance for key \"" << pluginKey << "\" (is the 1-arg class constructor from sample rate correctly provided?)" << endl;
99 throw std::string("Constructor failed");
100 }
101
102 Py_DECREF(args);
103 Py_DECREF(pyInputSampleRate);
91 } 104 }
92 105
93 PyPlugin::~PyPlugin() 106 PyPlugin::~PyPlugin()
94 { 107 {
108 if (m_pyInstance) Py_DECREF(m_pyInstance);
109
95 Py_CLEAR(m_pyProcess); 110 Py_CLEAR(m_pyProcess);
96 #ifdef _DEBUG 111 #ifdef _DEBUG
97 cerr << "PyPlugin::PyPlugin:" << m_class 112 cerr << "PyPlugin::PyPlugin:" << m_class
98 << " Instance deleted." << endl; 113 << " Instance deleted." << endl;
99 #endif 114 #endif
100 } 115 }
101 116
102 117
103 string 118 string
220 } 235 }
221 236
222 int 237 int
223 PyPlugin::getPluginVersion() const 238 PyPlugin::getPluginVersion() const
224 { 239 {
225 return 2; 240 //!!! implement
241
242 return 2;
226 } 243 }
227 244
228 string 245 string
229 PyPlugin::getCopyright() const 246 PyPlugin::getCopyright() const
230 { 247 {
250 267
251 268
252 rString=PyString_AsString(pyString); 269 rString=PyString_AsString(pyString);
253 Py_CLEAR(pyString); 270 Py_CLEAR(pyString);
254 } 271 }
255 return rString; 272
273 return rString;
256 } 274 }
257 275
258 276
259 bool 277 bool
260 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) 278 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
262 //useful for debugging Python plugins 280 //useful for debugging Python plugins
263 char method[]="initialise"; 281 char method[]="initialise";
264 cerr << "[call] " << method << endl; 282 cerr << "[call] " << method << endl;
265 283
266 //placing Mutex before these calls causes deadlock 284 //placing Mutex before these calls causes deadlock
267 if (channels < getMinChannelCount() || 285 if (channels < getMinChannelCount() ||
268 channels > getMaxChannelCount()) return false; 286 channels > getMaxChannelCount()) return false;
269 287
270 m_inputDomain = getInputDomain(); 288 m_inputDomain = getInputDomain();
271 289
272 MutexLocker locker(&m_pythonInterpreterMutex); 290 MutexLocker locker(&m_pythonInterpreterMutex);
273 291
298 if (!m_processType) 316 if (!m_processType)
299 { 317 {
300 m_processType = not_implemented; 318 m_processType = not_implemented;
301 m_pyProcess = NULL; 319 m_pyProcess = NULL;
302 cerr << "Warning: Python plugin [" << m_class << "::" << method 320 cerr << "Warning: Python plugin [" << m_class << "::" << method
303 << "] No process implementation found. Plugin will do nothing." << endl; 321 << "] No process implementation found. Plugin will do nothing." << endl;
304 } 322 }
305 323
306 324 //Check if the method is implemented in Python else return false
307 //Check if the method is implemented in Python else return false 325 if (PyObject_HasAttrString(m_pyInstance,method)) {
308 if (PyObject_HasAttrString(m_pyInstance,method)) {
309 326
310 PyObject *pyMethod = PyString_FromString(method); 327 PyObject *pyMethod = PyString_FromString(method);
311 PyObject *pyChannels = PyInt_FromSsize_t((Py_ssize_t)channels); 328 PyObject *pyChannels = PyInt_FromSsize_t((Py_ssize_t)channels);
312 PyObject *pyStepSize = PyInt_FromSsize_t((Py_ssize_t)m_stepSize); 329 PyObject *pyStepSize = PyInt_FromSsize_t((Py_ssize_t)m_stepSize);
313 PyObject *pyBlockSize = PyInt_FromSsize_t((Py_ssize_t)blockSize); 330 PyObject *pyBlockSize = PyInt_FromSsize_t((Py_ssize_t)blockSize);
314 PyObject *pyInputSampleRate = PyFloat_FromDouble((double)m_inputSampleRate); 331 //Call the method
315 332 PyObject *pyBool =
316 //Call the method 333 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyChannels,pyStepSize,pyBlockSize,NULL);
317 PyObject *pyBool =
318 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyChannels,pyStepSize,pyBlockSize,pyInputSampleRate,NULL);
319 334
320 Py_DECREF(pyMethod); 335 Py_DECREF(pyMethod);
321 Py_DECREF(pyChannels); 336 Py_DECREF(pyChannels);
322 Py_DECREF(pyStepSize); 337 Py_DECREF(pyStepSize);
323 Py_DECREF(pyBlockSize); 338 Py_DECREF(pyBlockSize);
324 Py_DECREF(pyInputSampleRate); 339
325 340 //Check return value
326 //Check return value 341 if (PyErr_Occurred() || !PyBool_Check(pyBool)) {
327 if (PyErr_Occurred() || !PyBool_Check(pyBool)) { 342 PyErr_Print(); PyErr_Clear();
328 PyErr_Print(); PyErr_Clear(); 343 Py_CLEAR(pyBool);
329 Py_CLEAR(pyBool); 344 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
330 cerr << "ERROR: In Python plugin [" << m_class << "::" << method 345 << "] Expected Bool return value." << endl;
331 << "] Expected Bool return value." << endl; 346 return false;
332 return false; 347 }
333 } 348
334 349 if (pyBool == Py_True) {
335 if (pyBool == Py_True) { 350 Py_CLEAR(pyBool);
336 Py_CLEAR(pyBool); 351 return true;
337 return true; 352 } else {
338 } else { 353 Py_CLEAR(pyBool);
339 Py_CLEAR(pyBool); 354 return false;
340 return false;} 355 }
341 } 356 }
342 return false; 357 return false;
343 } 358 }
344 359
345 void 360 void
346 PyPlugin::reset() 361 PyPlugin::reset()