As such, this month worked out weirdly, but has a happy ending, as I convert crisis into open source software for a living.
For years, I've been ripping FMOD out of games. There's nothing technically wrong with FMOD--it's fast, has tons of features, and works on lots of platforms--but it also costs money for each platform you ship on, and often times the budget for the Linux port is zero dollars.
My usual strategy is to replace it with OpenAL, either outright or by making the game think it's still talking to FMOD, like this attempt from Aquaria. And this has worked great, until I started trying to move all these ported games to the Nintendo Switch. Being a locked down system, I couldn't just take the usual solution, OpenAL Soft, as it is offered under the LGPL license; since the user can't replace the library with a different build on the Switch, you literally can't ship the library there without violating its license.
It turns out other people I'm talking with were hitting the same roadblock; SDL2-based games up and running on the Switch quickly, but they didn't have OpenAL available for their existing audio code.
So, okay, how hard could it possibly be to implement OpenAL from scratch? I decided to find out. As an added bonus: I filmed myself doing it.
A simple script took a screenshot of my text editor every ten seconds, giving me a time-lapse of the work from start to finish. It's the future of revision control! At the end, a little cleanup and dirty dancing with ffmpeg got me the YouTube video on this post (make sure you set it to HD or 4K, and maybe play it at 0.25x speed). I have no idea if this is useful content, or even entertaining content, but it was worth a try in any case. Especially near the end you can watch me start to struggle with designing lock-free algorithms. Lock-free algorithms are haaaaaard.
OpenAL Soft is still the gold standard of OpenAL implementations, to be clear. Not only is it 5000+ commits into its Git repository, it has some pretty impressive, non-trivial features, like Ambisonics, HRTFs, surround sound, dozens of useful extensions, and portability. It's pretty sweet. My implementation isn't interested in overthrowing the king, but it does have a few unique qualities of its own:
- It's zlib-licensed.
- The entire OpenAL implementation is in a single C file you can drop into your project.
- It uses SDL for all the heavy lifting, which simplifies the code and keeps it easily portable.
- If you're on a locked down or embedded system, this might be a good option to reach for.
- Tested on Linux, macOS, and the Switch, but probably works anywhere SDL does.
- It offers all of core OpenAL 1.1. I set out to do a "mini-AL" type thing--the way we used to run "OpenGL" on our Voodoo1 cards for GLQuake on Windows 95--but it turns out implementing the entire 1.1 core API is not that hard! It even does capture devices if you need to record some audio.
- Almost the entire thing runs lock-free. There isn't a mutex protecting multiple threads calling into the API, or blocking the mixer thread. There doesn't need to be. This probably doubled the time it took to write the thing, but now you never run the risk of a simple state-setting call blocking for several milliseconds while the mixer runs, or the mixer not running fast enough because of bad luck between a mutex and the OS scheduler.
There is more work to be done on this still, but we're already at the point where I've dropped it into a few games and it works. Future effort on this will be adding some popular OpenAL extensions, fleshing out the correctness of the implementation, doing a little SIMD code, and unblocking a whole bunch of games that use OpenAL. :)