Blowing the dust off Python in Prototype

Hello module makers!

I’m writing to share my findings from the past week spent on getting Python to work in VCV-Prototype.

Disclaimer: I’m not trying to argue that any scripting language would be worth investigating for audio rate DSP, that is not what I think and not what I am trying to achieve. The only benefit I can see is for control rate operation, more specifically making scripting for MIDI controllers possible.
If there’s anything to debate about, it should be whether the community would need and use it or not.

Starting from the current issues noted here:

The issus is with numpy and is known (https://stackoverflow.com/a/56018713). It is related to loaded symbols from shared libraries, it seems to only happen on linux. The only workaround I found so far is to dlopen() right there and it fixes it:

static void initPython() {
...
    PyMem_RawFree(pythonPathW);
	// Workaround numpy linking bug when loading from C API, see: https://stackoverflow.com/a/56018713
	// TODO: disable workaround for Windows/Mac?
	std::string libPythonPath = rack::asset::plugin(pluginInstance, "dep/lib/libpython3.8.so.1.0");
	void *dlHandle = dlopen(libPythonPath.c_str(), RTLD_LAZY | RTLD_GLOBAL);
	// Initialize but don't register signal handlers
	Py_InitializeEx(0);
	assert(Py_IsInitialized());
...

Upgrading to Python 3.9, numpy to latest release or using system’s python results in the same bug.

The next issue I worked on is multiple instances. For that the Python C API provides us with sub-interpreters which I started testing and implementing. Doc: Initialization, Finalization, and Threads — Python 3.8.9 documentation
Sadly, there is another blocking issue along the path: some of numpy core components cannot be loaded into more that one interpreter per process: https://groups.google.com/g/cython-users/c/mmWEyUjpV6M (Cython but the same applies for CPython).
I should add that CPython and more notably numpy do not support nor advise a complete restart of the interpreter in embedded scenarios without restarting the host process which kind of defeats our purpose in Prototype.
At that point I think I can safely take a step back and turn to the dev community looking for suggestions. Should we throw away numpy, or even python, altogether?

I also spent some days looking at micropython, hoping to find something easy to embed in C++, only to face more frustration and lack of documentation/support.
I am certainly not giving up on scripting though, I am still convinced that it has a lot of potential for improving external control on patches and reducing patchcable clutter :slight_smile: Next I will see if Pypy can be an interesting replacement.

4 Likes

Thanks, this is useful research!

That’s unfortunate. That issue, and the difficulty itself of loading multiple interpreters suggest that we should make the Python interpreter a singleton instance, disallowing multiple Prototype modules to run Python simultaneously. That limits its flexibility, especially if you want to write many Python scripts intended to be used together moduarly.

And IMO Python without Numpy/Scipy is pointless and not worth pursuing. But with it, we’ll have immense MATLAB-like DSP power inside VCV Rack.

This reminds me of my favorite (and very true) joke about Python: https://i.imgflip.com/1xaidt.jpg

4 Likes

Great work on this, @FergusL!

It is not within my Python expertise at all, but I have been watching the dance away from per-process state for the past few years.

This is not a bad time to be running into this problem, since PEP 573 was adopted in 3.9. I don’t know if moving NumPy and SciPy over to that API (per PEP 630) is on the roadmap, but I’ll investigate. As PEP 630 itself discusses, PEP 573 doesn’t provide a complete replacement and I don’t know offhand if converting NumPy/SciPy would need any of the missing features. Might be worth checking/getting on the wish list. Could also be a good subject for a sprint, albiet a pretty advanced one.

I will (virtually) ask around at the 2021 PyCon and SciPyCon about this.

This is a tough call because some scripts are going to be provably safe, some scripts are going to be theoretically unstable but never actually cause problems, and some scripts (such as those loading NumPy or other Cython libraries, since Cython enforces single-interpreter-per-process right here at the moment) are going to tank immediately.

Users who are using vanilla Python to prototype sequencers, controllers, etc. are very unlikely to run into this as a problem (and my guess is that’s going to account for a lot of the use cases, although I agree that those aren’t nearly as interesting as having NumPy and SciPy, or Scikit-learn for that matter, at hand).

Maybe the second instantiation of a Python interpreter in Prototype could raise a warning message that essentially says “Keep it simple, or things might crash?”

2 Likes

I’d be grateful for a python environment in Prototype even without numpy/scipy!

I’d be manipulating control voltage or prototype sequencers well below audio rate with a couple lines of python, whenever I can’t find a module doing the thing. I can’t be arsed to pick up lua just for this purpose though. (;

https://learnxinyminutes.com/docs/lua/

If you change mind :slight_smile: . Lua is pretty quick to learn, i did some while coding small Pico 8 games and also in coding Uni. I dropped out of Uni now, but it’s the only language i’ve ever been somewhat actually good at XD. I haven’t practiced in a few months though…

2 Likes

Yah, you know I toyed with Lua in my Sonic Pi phase, and you’re right it’s easy to learn and all, but I’m lazy and I’m struggling to retain working knowledge of those languages I need for my day job so… (:

1 Like