I have to break this bad habit.
This was supposed be a post about MojoAL 2.0, where I tell you how I rewrote a bunch of it and added all sorts of things. And I did rewrite a bunch of it! All the crazy lock-free stuff that causes nightmares on platforms with cooperative multitasking that just can't tolerate a tiny little spinlock is gone, taking a new approach that balances maintainable code against my wilder YOLO programming instincts.
And once I did that, I went to drop it into all sorts of OpenAL-based games, and naturally it didn't work on any of them. So I started trying to debug one of them, and I'm sitting here running some binary I don't have source code to under a debugger trying to piece together what on earth it's trying to do, with pointers and object numbers flying around without any real clarity about what is going where and why.
And here's where the bad habit kicked in.
I thought: grr, I wish there was something like ApiTrace for OpenAL.
And to be perfectly clear, people think this sort of thing all the time. "I wish I could visualize thread usage," "I wish I could see memory fragmentation over time," "I wish I could watch Batman wrestle a bear," but you can usually carry on without these things, so the idle thought passes and life goes on in its bearless way. But not for me.
For me, I spent months working towards that idle wish. I'll just hack on this for a few hours, maybe I'll get it to write out a list of OpenAL calls to stdout! And I did that. But then I thought, hey, maybe I can make it push this back through the real OpenAL to reproduce things exactly but without the game underneath it. And I did that. But then I thought...you know, it'd be nice to have a full GUI so you can wander around in the data, and now I was getting in stupid deep.
So I present it to you. I call it alTrace. It lets you explore a stream of OpenAL calls the same way ApiTrace lets you wander around in OpenGL.
The basic idea is you run your program against a magic shared library that looks like OpenAL, but actually just proxies between the app and a real AL implementation, making notes to a tracefile as it goes. Then when the program is done, you can use those notes in various tools: dump info to stdout, re-run the tracefile with OpenAL, or get into a full GUI debugging tool. You can have an end-user send it to you to see what went wrong on his machine, or you can use it to reproduce a problem precisely without the game at all, to debug an OpenAL implementation.
In this sense, it's not unreasonable to call it an ApiTrace-like for audio.
Something that's always bothered me in ApiTrace, though, is that you have to find a specific function call and let it rerun the entire call stream to that point to find out the exact GL state (which can be a lengthy process, especially if you have to do it more than once). I took a different approach in alTrace: all important details are logged to the tracefile and tracked in the tools, so you don't even need to have OpenAL installed on the system to examine it later.
Keeping track of everything that's changed from call to call is managed by my new favorite data structure, the Persistent Hash-Array-Mapped Trie, which makes it efficient to have large amounts of arbitrary data that changes often and take snapshots of that data often as well. You can have literally thousands of copies of your data tree that all change a handful of things, and each copy only takes a few more bytes. Reading and writing is fast, too, so we just build up a snapshot for every function call and keep the entire AL state at any moment at our fingertips. Now looking a few functions further in any direction isn't a matter of reprocessing everything again (which, unlike ApiTrace running the GL as fast as possible, has to match the wall clock time for audio to work right). It's super nice.
There's lots of neat features in alTrace already--I encourage you to watch the intro video above if you're interested--and there are several cool features I hope to add to it in the future, to make it a more robust debugging tool.
For now, though, I'm going to break my bad habit of running off to build new things, and instead I'm going to finish porting a very old thing to Linux for the next project. That's almost done!