Simplifying the build process for vst3-rs

2025-12-26

VST 3 is an audio plugin interface which is developed by Steinberg and supported by a large number of host applications and plugins. The VST 3 API comprises a set of C++ header files which contain definitions for structs, constants, and abstract base classes (used in a similar way to COM). I maintain a set of Rust bindings for VST 3 which are automatically generated from the original C++ headers using libclang.

Earlier this month, I released version 0.3.0 of the vst3 crate. In previous versions of the crate, bindings were generated at build time, and users were required to supply both libclang and the VST 3 SDK as third-party dependencies. As of this latest version, the generated bindings are now published directly as part of the crate's source, and the build-time generation step and third-party dependencies are no longer necessary. This change both simplifies the setup process for downstream users of the crate and significantly improves build times.

These improvements were made possible by a recent change to the licensing situation around the VST 3 SDK, but they also required solving some technical problems regarding the output of the binding generator. I'll talk about both of these aspects below.

read more

LLQ: A wait-free SPSC linked-list queue with recyclable nodes

2022-12-04

Last year, I published a Rust library called basedrop, which implements a memory reclamation system tailored to the constraints of real-time audio scenarios. The purpose of basedrop is to make it easy to share dynamically allocated memory with a real-time audio thread while ensuring that no allocations or deallocations happen on that thread. This is accomplished by providing a set of smart pointers (analogous to Box and Arc from the Rust standard library) which do not directly free their associated allocation when dropped, but instead automatically push it onto a lock-free queue to be collected later on another thread.

Basedrop's design has some compelling benefits: it frees you from having to write code by hand every time you want to transfer an object to another thread to be freed, and if you restrict yourself to its vocabulary of smart pointers, it eliminates the possibility of accidentally dropping an allocation on the real-time thread (a mistake which can easily remain invisible if you don't have something like assert_no_alloc to catch it). However, after talking with some developers trying to make use of basedrop in real projects, it became clear to me that these benefits come at the cost of a somewhat opinionated API, making it difficult to integrate with certain program architectures. I decided that a stripped-down version of the core linked-list queue would probably have some value, and the end result of that was the llq crate.

read more

Basedrop: A garbage collector for real-time audio in Rust

2021-04-26

In real-time audio, deadlines are critical. Your code has on the order of several milliseconds to fill a buffer with samples to be shipped off to the DAC, milliseconds which it may be sharing with a number of other audio plugins. If your code takes too long to produce those samples, there are no second chances; they simply won't get played, and the user will hear an objectionable glitch or stutter instead.

In order to prevent this, real-time audio code must avoid performing any operations that can block the audio thread for an unbounded or unpredictable amount of time. Such operations include file and network I/O, memory allocation and deallocation, and the use of locks to synchronize with non-audio threads; these operations are not considered "real-time safe." Instead, operations like I/O and memory allocation should be performed on other threads, and synchronization should be performed using primitives that are wait-free for the audio thread. A more thorough overview of the subject can be found in Ross Bencina's now-classic blog post "Time Waits for Nothing".

Given that audio software generally does need to allocate memory and make use of it from the audio thread, the question becomes how to accomplish this in a manageable and efficient way while subject to the above constraints. Basedrop is my attempt at providing one answer to this question.

read more

The amplitwist, the conjugate transpose, and the complex derivative

2019-12-29

Complex numbers have a representation as matrices, which can serve to illuminate some initially non-obvious aspects of how they work. A real number can be represented as a multiple of the identity matrix:

with addition and multiplication given by the corresponding matrix operations. In order to extend this representation to the complex numbers, we need a matrix such that :

We can thus represent any complex number as:

It can be verified that addition and multiplication of these matrices is equivalent to addition and multiplication of the complex numbers they represent (meaning that matrices of this form comprise a field isomorphic to ).

read more

A rotated video of a cube

2019-01-07

The following is a video of a rotating cube:

This can be visualized as a plane sweeping through a cube of spacetime, or a flipbook:

read more