russell mcclellan

russell.mcclellan@gmail.com

brinicle: a polyglot audio plug-in framework

Today I released brinicle, a toy framework for building audio effects using rust and react-native.

I've long been interested in better ways of writing audio software than the traditional method, which involves using C++ for both signal processing and user interface code. Since audio software usually has to work in real-time, certain language features like pausing garbage collection and locking thread synchronization (including dynamic memory allocation on most OSes) aren't available. This means languages that depend on these features for their basic functionality won't work. One of the few modern languages that's capable of working in a real time environment is Rust.

Rust has many of the niceties you'd expect from a language designed in the 21st century, such as native sum types and haskell-style polymorphism, but with a low-level focus and commitment to zero-cost abstractions that even exceeds that of C++ (for example, the recommended error handling mechanism in Rust is zero-cost, while that of C++ is not). Additionally, Rust has a novel borrow checker which saves you from common C/C++ headaches like use-after-free and race-conditions. I've been using Rust since 2015, but this is the first project I've shared outside of a small group of friends.

Most of the work of brinicle was completed in early 2017, but I spent a month or two of side-project time this year porting it to the newer versions of Rust and C++ that are currently available.

For the UI, brinicle uses react-native. In the current release, brinicle only supports audio plug-ins in macOS (although I have some hacked branches lying around which support iOS). This means it uses the somewhat half-baked react-native-macos port. While react-native is conceptually much clearer than other desktop UI libraries, it does have a lot of layers to it, which makes it complex to work with and debug.

The knobs in the example app created by the scaffolding script use lottie for smooth operation.

Demo app

Most of the work in this project was in the interfaces between the different pieces of technology. Rust is particularly difficult to interface with C++, since everything has to go through a C interop layer. For things like sum-types, I represented these as enums on the Rust side, and std::variant's on the C++-side, each wrapping a C interface. Once in C++, it was fairly easy to interface with react-native through Objective-C++.

Hopefully, this project inspires someone to dream about better ways to write audio software. While I'm not planning on investing in this project in the near future, I may well come back to it at some point. Obvious ways to extend it include: iOS support, virtual instrument support in addition to virtual effect support, and fleshing out the signal-processing library on the rust side.

All images and text are licensed under a Creative Commons Attribution 3.0 United States License, except as noted. Linked code, and embedded code examples are licensed separately.