Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Building pure Python wheel for wasm

105 views
Skip to first unread message

Anirudh Thommandram

unread,
Jun 13, 2024, 3:11:03 PM6/13/24
to Parselmouth
I am working to (attempting to) build a pure Python wheel for the praat-parselmouth package. I am using Pyodide and Emscripten to do this. The thinking/hope is that if praat-parselmouth can be made available in a wasm wheel it could be used by Pyodide along with PyScript and can lead to some interesting in browser audio analysis use cases.

I am having some issues but I don't think it is parselmouth related (yet), its more just getting my pyodide environment working smoothly on my OS. But I will probably encounter some library-specific gotchas soon enough. wasm wheels have been built for many other big Python libraries that leverage C extensions such as numpy, scipy, scikit-learn, and pandas. So it should maybe technically be achievable.

Anyway, I was just wondering if anyone has had any experience building wheels for more...exotic?...platforms haha

Anirudh Thommandram

unread,
Jun 18, 2024, 3:55:51 PM6/18/24
to Parselmouth
I managed to compile this package to wasm with Emscripten and Pyodide for use with PyScript! I had to make some weird hacks that I don't really understand to build it but this works for the most part. A bunch of the praat files seem to be for the GUI parts of the program which technically don't need to be compiled for parselmouth I suppose, but I didn't go through the exercise of excluding them. But with this wasm wheel you can run Python Parselmouth code in the browser just by doing something like this in the HTML:
<py-config>
{
"packages": ["pandas", "scikit-learn", "praat_parselmouth-0.5.0.dev0-cp312-cp312-pyodide_2024_0_wasm32.whl"]
}
</py-config>
<div>
Hello Parselmouth! <br>
<py-script>
import parselmouth
from parselmouth.praat import call

sound = parselmouth.Sound("sound_file.wav")
</py-script>
</div>
Not sure how useful this will be to anyone but if there is interest, it's probably somewhat straightforward to add the pyodide build to pypi and then the package can be imported just by name like pandas and scikit-learn in the above code sample. Here is the hacky build here in case anyone wanted to try it out haha

Anirudh

yannick...@gmail.com

unread,
Jun 22, 2024, 1:50:58 PM6/22/24
to Parselmouth
Hi Anirudh!

I'm very sorry for the delay. I've had some very busy weeks at work, and wanted to take my time to not just quickly reply to you!

This is very cool though! A couple of years ago, I managed to get Parselmouth compiled to WASM as well, but I didn't follow up further on that. But now that Python is also turning more and more to WASM, it might be worth another look, indeed :-)

As far as I know, currently you can't upload pyoidide wheels to PyPI yet, can you? But I'd be happy to further investigate how to get this out, actually, when I find some time. It would be pretty cool for demos etc :-)
If there's anything in specific that you did, I'm of course curious to hear about it. But if not, then I'll try to see if I can compile myself. I do probably know better the parts of Praat and Parselmouth which are relevant.

Thank you!
Yannick

Anirudh Thommandram

unread,
Jun 24, 2024, 1:32:42 PM6/24/24
to Parselmouth
No worries!
And you are right, pyodide wheels or emscripten/wasm32 wheels cannot be uploaded to PyPi it seems. It is possible however to add a new package to the Pyodide distribution I think. (the current list of packages here https://github.com/pyodide/pyodide/tree/main/packages). That could be something?

In terms of what I had to do to compile, I feel like they were just amateur problems on my part haha. I had tried to follow the Pyodide docs about building a package out of tree, I kept running into issues with the emscripten compiler not finding the right Python modules on my system. I then tried to use the Docker image from Pyodide to see if I would fare any better. It is an x86_64 based image so it would run in emulation mode on my arm64, painfully slow haha. But it looked like it kind of worked! Until it crashed at file 1462/1463 with this function mismatch error
function_mismatch_error.jpeg
This was after it took a really long time so I started getting less interested in "learning" and more interested in hacking my way through lol. So for whatever reason this file, HyperPage.cpp, had a different function call signature than "what it was supposed to be" or something. I have no idea why or what it really means. It's used to enable some kind of menu item in the GUI it seemed like, something that was maybe irrelevant to my needs.

So I just changed that function signature and call in that file to add one more parameter so that it would match up with the definition the compiler was expecting. And because the parameter didn't actually matter, I decided to name it "wtf" and make it a boolean and call it true LOL
updated_function.jpeg

This totally worked and produced a pyodide wasm32 wheel! I then tried it out in PyScript and it was mostly working seamlessly. I ran into one issue for my purposes, which was this call:
intensity = call(sound, "To Intensity", 75, 0.0) # create a praat intensity object
Other "call" functions worked fine, like "To Pitch" and stuff, so I wasn't sure why this wasn't. BUT luckily, there was a function in Parselmouth called ".to_intensity" and then could do ".get_average" on that. I imagine it's something to do maybe with like creating temporary files underneath but file creating and accessing is a bit wonky when handled by Pyodide. This is purely a guess though, I've done little to no investigation.

With that, everything I needed for my current use case was working so I just decided to update this thread and move on. But it would be kind of cool to have this done "properly" haha - if you have any other questions about my experience, I'm happy to share. Thanks for your wonderful work on this library!

Ani
Reply all
Reply to author
Forward
0 new messages