Blog

Why we wrote our own plugin framework

Sonorie generates audio plugins. That turns out to be an unusual thing to want to do, licence-wise, and it is why there is a plugin framework underneath it that nobody else uses.

The clause

The dominant C++ audio framework’s EULA contains a sentence to the effect that you may not create, make available as a service, nor distribute products that create other products. A service that generates plugins is precisely that. No standard tier covers it; the answer is a bespoke negotiation.

The open-source alternative for that framework is AGPL, which is worse for this case rather than better. The WebAssembly previews we serve and the binaries our farm compiles would become copyleft works, and people selling closed plugins built on top could not do so. The exported project was always fine — it fetches the framework itself, so the seller is their own licensee — but the preview and the build farm are ours, and those are the parts that bind.

So the framework had to be ours.

What that means concretely

Header-only C++17, no framework dependency. One SonoreDspstruct becomes a CLAP, a VST3, an AUv2 component, an LV2 bundle and a standalone application, because every wrapper sits on the same instance. The only vendored third-party code is the format headers themselves — CLAP (MIT), LV2 (ISC), and Steinberg’s VST3 C API, which is BSD-3 and, crucially, not the dual-GPL C++ SDK.

The DSP toolkit is written from published mathematics — the RBJ cookbook, TPT and zero-delay-feedback topologies, polyBLEP oscillators, Schroeder and Jot reverb structures, BS.1770 loudness — and never adapted from anybody’s implementation, which would re-contaminate exactly what this exists to remove.

The interface is a webview showing the same HTML the browser preview shows, so a faceplate approved in the studio opens unchanged in a DAW.

The rule that made it survivable

Writing a DSP library is easy. Writing one you can trust is not, and the difference is a rule: every claim is measured. A filter documented as −3 dB at its cutoff is driven with a sine at that frequency and asserted to read −3.01 dB. A compressor documented as 4:1 is measured at 4.00:1. A reverb’s T60 is checked against a Schroeder integral.

These are the bugs that found, none of which reading would have:

  • A one-pole filter using the naive Euler form: “6 kHz” measured 4.5 kHz. It sat underneath every damping control in the library — comb filters, feedback delay networks, spring reverbs, Karplus-Strong.
  • A ladder filter that documented a zero-delay-feedback topology and fed back the previous sample’s state: 17% flat at 8 kHz.
  • A reverb whose allpass delay times were computed and never applied. The array was dead and the filters ran at their defaults at every sample rate. It still sounded like a reverb, which is why nobody heard it.
  • A loudness meter that agreed perfectly with our own reference implementation and disagreed with the ITU’s published table by 0.26 LU. Agreeing with your own reference is worth nothing.

The parts that only a real host can tell you

Our own tests prove our reading of a specification. The industry validators prove the industry’s, and that gap was real: clap-validator failed three state-reproducibility tests because loading a state changed parameter values without telling the host to rescan them. Legal by our reading, wrong by theirs, and now asserted in our own suite so it cannot come back.

Apple’s auvalwas worse and more instructive. The first green macOS build was the start of the work, not the end: each fix let the validator reach one layer deeper, and none of the later defects were visible until the earlier ones were gone. A wrapper that has never been run is not “probably fine”; it is unmeasured.

What it is now

VST3, AU, CLAP, LV2 and standalone, on Windows, macOS and Linux. Validator-clean on all of them: pluginval at strictness 10, clap-validator, lv2lint, auval with zero warnings. Artifacts are small — a CLAP around 20 KB for a simple effect — because there is no framework runtime inside them.

It is Apache-2.0 and public, and the plugins you export from Sonorie carry no third-party framework licence, because there is no third-party framework.

Would we recommend this to anyone else? Only if a licence leaves you no choice, as it did here. It cost far more than the chat interface everybody sees. What it bought is that nobody has to ask permission to sell what they make.

Questions

Why not just use JUCE?

Its licence does not permit creating products that create other products, which is exactly what a plugin-generating service does. The AGPL option is worse for this case: the WebAssembly previews we serve and the binaries our build farm ships would become copyleft works, and buyers could not then sell closed plugins built with it.

Is it hard to implement VST3, AU, CLAP and LV2 yourself?

CLAP is easy — one C header and an entry point. VST3 against the BSD-licensed C API is straightforward but unforgiving about threading and normalised parameter ranges. LV2 is fine once you accept that the metadata is read before your code runs. AU is the hard one: its failures are silent, and Apple's auval is the only honest verdict.

What does 'every claim is measured' mean in a DSP library?

That a filter documented as -3 dB at its cutoff is driven with a sine at that frequency and asserted to read -3.01 dB, rather than being eyeballed. Doing this found a one-pole filter that was 25% off in frequency and sat under every damping control in the library, and a ladder filter that claimed a zero-delay-feedback topology while feeding back last sample's state.

Sonorie turns a description into a real plugin: VST3, AU, CLAP, LV2 and a standalone app, built for Windows, macOS and Linux.

Build one