comparison PyPlugin.cpp @ 51:c1e4f706ca9a

Fix numpy version incompatibility issues and updated some example plugins.
author fazekasgy
date Thu, 08 Oct 2009 08:47:28 +0000
parents 27bab3a16c9a
children 5664fe298af2
comparison
equal deleted inserted replaced
50:3868da185d73 51:c1e4f706ca9a
28 using std::endl; 28 using std::endl;
29 using std::map; 29 using std::map;
30 30
31 Mutex PyPlugin::m_pythonInterpreterMutex; 31 Mutex PyPlugin::m_pythonInterpreterMutex;
32 32
33 PyPlugin::PyPlugin(std::string pluginKey, float inputSampleRate, PyObject *pyClass, int &instcount) : 33 PyPlugin::PyPlugin(std::string pluginKey, float inputSampleRate, PyObject *pyClass, int &instcount, bool &numpyInstalled) :
34 Plugin(inputSampleRate), 34 Plugin(inputSampleRate),
35 m_pyClass(pyClass), 35 m_pyClass(pyClass),
36 m_instcount(instcount), 36 m_instcount(instcount),
37 m_stepSize(0), 37 m_stepSize(0),
38 m_blockSize(0), 38 m_blockSize(0),
42 m_path((pluginKey.substr(0,pluginKey.rfind(PATHSEP)))), 42 m_path((pluginKey.substr(0,pluginKey.rfind(PATHSEP)))),
43 m_processType(not_implemented), 43 m_processType(not_implemented),
44 m_pyProcess(NULL), 44 m_pyProcess(NULL),
45 m_inputDomain(TimeDomain), 45 m_inputDomain(TimeDomain),
46 m_quitOnErrorFlag(false), 46 m_quitOnErrorFlag(false),
47 m_debugFlag(false) 47 m_debugFlag(false),
48 m_numpyInstalled(numpyInstalled),
49 m_processFailure(false)
48 { 50 {
49 m_ti.setInputSampleRate(inputSampleRate); 51 m_ti.setInputSampleRate(inputSampleRate);
50 MutexLocker locker(&m_pythonInterpreterMutex); 52 MutexLocker locker(&m_pythonInterpreterMutex);
51 cerr << "Creating instance " << m_instcount << " of " << pluginKey << endl; 53 cerr << "Creating instance " << m_instcount << " of " << pluginKey << endl;
52 54
84 86
85 if (m_debugFlag && m_quitOnErrorFlag) cerr << "Quit on type error ON for: " << m_class << endl; 87 if (m_debugFlag && m_quitOnErrorFlag) cerr << "Quit on type error ON for: " << m_class << endl;
86 88
87 if (m_debugFlag && st_flag) cerr << "Strict type conversion ON for: " << m_class << endl; 89 if (m_debugFlag && st_flag) cerr << "Strict type conversion ON for: " << m_class << endl;
88 m_ti.setStrictTypingFlag(st_flag); 90 m_ti.setStrictTypingFlag(st_flag);
91 m_ti.setNumpyInstalled(m_numpyInstalled);
89 92
90 } 93 }
91 94
92 PyPlugin::~PyPlugin() 95 PyPlugin::~PyPlugin()
93 { 96 {
186 189
187 void 190 void
188 PyPlugin::reset() 191 PyPlugin::reset()
189 { 192 {
190 MutexLocker locker(&m_pythonInterpreterMutex); 193 MutexLocker locker(&m_pythonInterpreterMutex);
194 m_processFailure = false;
191 genericMethodCall("reset"); 195 genericMethodCall("reset");
192 } 196 }
193 197
194 PyPlugin::InputDomain 198 PyPlugin::InputDomain
195 PyPlugin::getInputDomain() const 199 PyPlugin::getInputDomain() const
288 cerr << "ERROR: In Python plugin [" << m_class 292 cerr << "ERROR: In Python plugin [" << m_class
289 << "] No process implementation found. Returning empty feature set." << endl; 293 << "] No process implementation found. Returning empty feature set." << endl;
290 return FeatureSet(); 294 return FeatureSet();
291 } 295 }
292 296
297 if (m_processFailure) return FeatureSet();
298
293 return processMethodCall(inputBuffers,timestamp); 299 return processMethodCall(inputBuffers,timestamp);
294 300
295 } 301 }
296 302
297 PyPlugin::FeatureSet 303 PyPlugin::FeatureSet
298 PyPlugin::getRemainingFeatures() 304 PyPlugin::getRemainingFeatures()
299 { 305 {
300 MutexLocker locker(&m_pythonInterpreterMutex); 306 MutexLocker locker(&m_pythonInterpreterMutex);
307 if (m_processFailure) return FeatureSet();
301 FeatureSet rValue; 308 FeatureSet rValue;
302 return genericMethodCall("getRemainingFeatures",rValue); 309 return genericMethodCall("getRemainingFeatures",rValue);
303 } 310 }
304 311
305 bool 312 bool
353 PyPlugin::setProcessType() 360 PyPlugin::setProcessType()
354 { 361 {
355 //quering process implementation type 362 //quering process implementation type
356 char legacyMethod[]="process"; 363 char legacyMethod[]="process";
357 char numpyMethod[]="processN"; 364 char numpyMethod[]="processN";
365 m_processFailure = false;
358 366
359 if (PyObject_HasAttrString(m_pyInstance,legacyMethod) && 367 if (PyObject_HasAttrString(m_pyInstance,legacyMethod) &&
360 m_processType == 0) 368 m_processType == 0)
361 { 369 {
362 m_processType = legacyProcess; 370 m_processType = legacyProcess;
382 if (m_debugFlag) cerr << "Process using (numpy) buffer interface." << endl; 390 if (m_debugFlag) cerr << "Process using (numpy) buffer interface." << endl;
383 } 391 }
384 392
385 if (m_vampyFlags & vf_ARRAY) { 393 if (m_vampyFlags & vf_ARRAY) {
386 #ifdef HAVE_NUMPY 394 #ifdef HAVE_NUMPY
387 m_processType = numpy_arrayProcess; 395 if (m_numpyInstalled) { m_processType = numpy_arrayProcess;
388 if (m_debugFlag) cerr << "Process using numpy array interface." << endl; 396 if (m_debugFlag)
397 cerr << "Process using numpy array interface." << endl;
398 }
399 else {
400 m_processFailure = true;
401 char method[]="initialise::setProcessType";
402 cerr << PLUGIN_ERROR
403 << "This plugin requests the Numpy array interface by setting "
404 << " the vf_ARRAY flag in its __init__() function." << endl
405 << "However, we could not found a version of Numpy compatible with this build of Vampy." << endl
406 << "If you have a numerical library installed that supports the buffer interface, " << endl
407 << "you can request this interface instead by setting the vf_BUFFER flag." << endl;
408 }
389 #else 409 #else
390 cerr << "Error: This version of vampy was compiled without numpy support, " 410 m_processFailure = true;
391 << "however the vf_ARRAY flag is set for plugin: " << m_class << endl 411 char method[]="initialise::setProcessType";
392 << "The default behaviour is: passing a python list of samples for each channel in process() " 412 cerr << PLUGIN_ERROR
393 << "or a list of memory buffers in processN(). " << endl 413 << "Error: This version of vampy was compiled without numpy support, "
394 << "This can be used create numpy arrays using the numpy.frombuffer() command." << endl; 414 << "however the vf_ARRAY flag is set for plugin: " << m_class << endl
415 << "The default behaviour is: passing a python list of samples for each channel in process() "
416 << "or a list of memory buffers in processN(). " << endl
417 << "This can be used create numpy arrays using the numpy.frombuffer() command." << endl;
395 #endif 418 #endif
396 } 419 }
397 420
398 if (!m_processType) 421 if (!m_pyProcessCallable)
399 { 422 {
400 m_processType = not_implemented; 423 m_processType = not_implemented;
401 m_pyProcess = NULL; 424 m_pyProcess = NULL;
402 m_pyProcessCallable = NULL;
403 char method[]="initialise::setProcessType"; 425 char method[]="initialise::setProcessType";
404 cerr << PLUGIN_ERROR << " No process implementation found. Plugin will do nothing." << endl; 426 cerr << PLUGIN_ERROR << " No process implementation found. Plugin will do nothing." << endl;
427 m_processFailure = true;
405 } 428 }
406 } 429 }
407 430
408 void 431 void
409 PyPlugin::typeErrorHandler(char *method) const 432 PyPlugin::typeErrorHandler(char *method, bool process) const
410 { 433 {
411 bool strict = false; 434 bool strict = false;
412 while (m_ti.error) { 435 while (m_ti.error) {
413 PyTypeInterface::ValueError e = m_ti.getError(); 436 PyTypeInterface::ValueError e = m_ti.getError();
437 #ifdef HAVE_NUMPY
438 // disable the process completely if numpy types are returned
439 // but a compatible version was not loaded.
440 // This is required because if an object is returned from
441 // the wrong build, malloc complains about its size
442 // (i.e. the interpreter doesn't free it properly)
443 // and the process may be leaking.
444 // Note: this only happens in the obscure situation when
445 // someone forces to return wrong numpy types from an
446 // incompatible version using the buffer interface.
447 // In this case the incampatible library is still usable,
448 // but manual conversion to python builtins is required.
449 // If the ARRAY interface is set but Numpy is not installed
450 // the process will be disabled already at initialisation.
451 if (process && !m_numpyInstalled && e.str().find("numpy")!=std::string::npos)
452 {
453 m_processFailure = true;
454 cerr << "Warning: incompatible numpy type encountered. Disabling process." << endl;
455 }
456 #endif
414 cerr << PLUGIN_ERROR << e.str() << endl; 457 cerr << PLUGIN_ERROR << e.str() << endl;
415 if (e.strict) strict = true; 458 if (e.strict) strict = true;
416 // e.print(); 459 // e.print();
417 } 460 }
418 /// quit on hard errors like accessing NULL pointers or strict type conversion 461 /// quit on hard errors like accessing NULL pointers or strict type conversion
420 /// Otherwise most errors will go unnoticed apart from 463 /// Otherwise most errors will go unnoticed apart from
421 /// a messages in the terminal. 464 /// a messages in the terminal.
422 /// It would be best if hosts could catch an exception instead 465 /// It would be best if hosts could catch an exception instead
423 /// and display something meaningful to the user. 466 /// and display something meaningful to the user.
424 if (strict && m_quitOnErrorFlag) exit(EXIT_FAILURE); 467 if (strict && m_quitOnErrorFlag) exit(EXIT_FAILURE);
425 } 468
426 469 // this would disable all outputs even if some are valid
470 // if (process) m_processFailure = true;
471
472 }
473