Hey Everyone!
I thought I’d post a quick update on what I’ve been working on. As I’ve mentioned elsewhere I’ve been working on an update to Cantabile’s real-time audio engine.
This has taken a lot longer than I originally anticipated - partly because I’ve been side tracked by some personal stuff, but more so because it’s a significant set of changes and I’ve switched approaches couple of times.
I’m also paying off some technical debt - some of the code I’m reworking is 15+ years old and has been patched a number times - those patches need to be made more permanent.
Since these changes are going to take quite a bit of testing, I’ve decided to take this opportunity to also clean up, fix, improve several other areas and then stabilize it all together.
After pulling everything apart, I’m now putting everything back together and things are slowly starting to work again. Audio and MIDI routes are working, input/output ports are working, plugins are working and media players are almost finished. I’m hoping to get media players and racks finished this week.
After that I’ll be doing more clean up and miscellaneous improvements followed by lots of testing and bug-fixing.
All that’s to say: I’ve been quiet, but busy (mostly). Stay tuned!
Brad
For the technically inclined, if you’re curious what these changes are:
-
Removed the Route Manager. The route manager was responsible for coordinating updates to routes and object whenever anything changed. It was a complicated sequence of 40+ steps across all racks and songs. This has been replaced with a cleaner, more focused asynchronous “invalidation model” where only objects that have actually changed need to be updated.
-
Previously the audio engine was synchronous, blocking and re-entrant. In the new approach, changes to the UI objects are synchronous but updates are pushed down the audio engine asynchronously. This should mean faster updates and cleaner code (not having to handle re-entrancy). It also fixes some obscure edge cases with bindings.
-
Removed all memory allocations from the audio thread. There used to be a lock-free heap used by the audio thread. I’m rearranging things so memory allocations are removed from the audio thread entirely. Also, switching to an amoritized, delayed free mechanism. Cleaner code, less chance for random stalls.
-
Improved UI thread/audio thread messaging including better support for collection management across threads, removal of blocking messages, everything async. Cleaner code, faster.
-
Replacing some inter-thread messaging with atomic (aka interlocked) operations.
-
Some reworking of the parallel execution thread pool, execution groups and execution nodes - should result in cleaner, simpler and leaner execution on each audio cycle.
-
Removing possibly problematic redundant code. There’s various pieces of code in the engine that are somewhat redundant but risky to remove. Now seems like a good time to remove them and deal with any consequences during the stabilization of all these other changes.
Plus, lots of other minor fixes, cleanup, etc…
One thing to note - these changes are all restricted to how the real-time object graph is constructed, updated and executed. The logic implemented by the objects themselves hasn’t changed. Similarly the actual layout of the graph hasn’t changed. This means any bugs (and there will be bugs) are almost certainly going to be order/timing related and not in the object’s themselves. (eg: this shouldn’t introduce bugs to the MIDI router, the audio mixer, the midi filters, plugin hosting etc…).