As native as possible Python bindings

For a while I have been a big fan of the CLI tools now and have used them fairly extensively across Lua, Python and some other environments. More than I’d like to count I’ve written the same functions, classes and code plumbing to wrap up the command line calls which is obviously sub-optimal. I had a look at writing my own Python to C++ bindings using pybind11 or something fairly automatic with manual TLC applied afterwards or through configs but even then I think there are significant issues to overcome, particularly because Eigen complicates this problem. As such I’ve written what I think is the last set of loose bindings to the command line I’ll have to write. Yay!

So, here is me sharing it:

The interface is very Pythonic and the underlying code is fairly repetitious at the gain of not using any strange inheritance or multiple inheritance as I have done in some other side-ideas (https://github.com/jamesb93/FluidChain). This makes the code very readable and easy to understand.

From the README:

A basic call looks like this:

from flucoma import fluid
from flucoma.utils import get_slices
from pathlib import Path

source = Path("~/Desktop/ec1.wav").expanduser().resolve()

ns = fluid.noveltyslice(source, threshold=0.1)
idx = get_buffer(ns)

print(idx)

And a more complex one looks like this.

from flucoma import fluid
from flucoma.utils import get_slices

source = Path("~/Desktop/ec1.wav").expanduser().resolve()

mfcc = fluid.mfcc(source, 
    fftsettings = [2048, -1, -1],
    startframe = start,
    numframes = length
)

stats = get_buffer(
    fluid.stats(mfcc,
        numderivs = 1
    ), "numpy" # get_buffer() can return numpy arrays too
)

print(stats)

You can get it by pip installing it too:

pip install git+https://github.com/jamesb93/python-flucoma

Not all of the objects are implemented, I’m just doing them as I need them but hopefully people will find this useful in the future :slight_smile:

2 Likes

Nice work @jamesbradbury. ISTM compiled bindings should be possible w/ Eigen (isn’t that also what TensorFlow uses for its matrix ops?), but then again I speak from a position of cheerful ignorance about making python bindings for anything…

I think it is very feasible to use Eigen in Python, in fact there is a guide here which is quite nice but there are some limitations that mean adapting the code so that it is Python friendly. Again, I think there are some inefficiencies in binding, in that a copy is made for every matrix operation where you convert the matrix type unless you structure the C++ code in a certain way. I am super noob C++ coder so a lot of this is guess-work:

One major limitation of the above is that every data conversion implicitly involves a copy, which can be both expensive (for large matrices) and disallows binding functions that change their (Matrix) arguments. Pybind11 allows you to work around this by using Eigen’s Eigen::Ref<MatrixType> class much as you would when writing a function taking a generic type in Eigen itself (subject to some limitations discussed below).

I would be super up for writing a compiled module for Python if I understood the plumbing of the core codebase more, just to get around the friction of having to have the CLI present. Alas, I don’t, but I think that could be super cool to have as an option for scripting and wouldn’t feel like such a dirty hack.

OOPS: forgot the here part

https://pybind11.readthedocs.io/en/stable/advanced/cast/eigen.html

If there was a small example to work in the future from I would definitely be inclined to take it further and create bindings for all the objects :slight_smile: I had a go this afternoon shortly and found that working around CMAKE was a level of complexity that would take me a while to understand itself but binding some simple functions and classes was quite simple and readable.

Yeah, the CMake is a bit involved (but not as complex as it first seems). It’s mostly to do with managing the dependencies between repos, and avoiding too much repetition for the objects themselves.

If what you’re looking to do is make python versions of the objects you know and love, I’d perhaps hold off a bit until the code base has settled down a bit more: compared to what’s in Github, the internals have already shifted around somewhat for the current development stuff and are likely going to be refactored again before too long.

okay - it sounds like it would perfectly fit into a post-phd timeline then :wink:

The bindings are now complete and have their own test suite to make sure they don’t magically break.

They are also available by pip install python-flucoma

1 Like

This is amazing! The unit testing bit might be of interest to @francesco.cameli and @groma too!

1 Like

Happy to share my basic tests and talk about them! They mostly test pythonic things, like was a file created and are the dimensions of that file correct (channels * samples). I was able to catch that bug that I posted earlier with memory resets and some misnaming of parameters on my end.

1 Like

Just put some examples up for any interested people :slight_smile: