Draft. QPlug is in early development on the
qplug_2026branch. The API changes without notice and nothing here is production ready yet.
QPlug is a C++ framework for writing audio plugins. You write the DSP, the parameter logic and the user interface as three plain C++ classes; QPlug turns them into a native CLAP plugin and, through clap-wrapper, into VST3 and AudioUnit v2 as well, from the one implementation.
QPlug is built on two other Cycfi libraries. Q provides the DSP and the audio-stream vocabulary the processor speaks. Elements provides the GUI, and its model interface is what links controls to parameters.
Plugin code contains no CLAP, VST3 or AudioUnit types. The only translation unit that knows a plugin format is QPlug's own adapter.
The library is Open Source and released under the MIT License.
A QPlug plugin is composed of three parts, each an ordinary class you write:
-
processor: the DSP. Runs on the audio thread. Reads the controller's parameters and processes audio in
process(in, out). -
controller: the parameters and the logic that relates them, such as enabling a group of controls, units, tapering, and wiring between controls. Runs on the main thread. It is the hub the other two attach to and is unaware of both.
-
presenter: builds the user interface and links it to the controller's parameters. Owns the view, which exists only while the host has an editor open.
The processor and the presenter never see each other. Underneath sits
base_plugin, the host adapter, whose header is format-free and whose
implementation lives in one file per format. Today there is one: CLAP.
All dependencies are git submodules under lib/:
- q: DSP
- elements: GUI
- infra: shared utilities
- clap: the CLAP headers
- clap-wrapper: VST3 and AUv2
The last two are Cycfi forks of the upstream projects, so a fix QPlug needs can be carried until it is merged. They are used as they come: anything QPlug wants from them goes through their extensions, never by editing them.
The VST3 and AudioUnit SDKs are downloaded by clap-wrapper at configure time. C++20 is required, and macOS 11 or later.
macOS is the only platform exercised so far. On a fresh Mac you need four things; everything else is fetched by CMake at configure time.
- Xcode Command Line Tools,
xcode-select --install. Provides the C++20 compiler, the macOS SDK and frameworks, and git. Xcode 14 or later. - CMake 3.21 or later. Ninja as well if you use the presets below;
plain
cmake -B buildworks with CMake alone. - pkg-config,
brew install pkg-config. Artist, the graphics library under Elements, asks for it at configure time. - Network access at configure time. CMake fetches any missing
submodules, clap-wrapper downloads the VST3 SDK and Apple's AudioUnitSDK,
and the validators the tests need are downloaded, pinned and checksummed,
into
~/.cache/cycfi/qplug-validators. Building the VST3 means accepting Steinberg's VST3 SDK license, GPLv3 or the proprietary agreement; see clap-wrapper's README.
auval ships with macOS. To use your own validator installs instead of the
downloaded ones, pass -DCLAP_VALIDATOR=... and -DPLUGINVAL=..., or set
-DQPLUG_DOWNLOAD_VALIDATORS=OFF to have CMake look for installed copies. A
validator that cannot be found makes its test skip, not fail. See
scripts/README.md.
The GUI draws through Artist's Quartz2D backend, which is part of macOS, so there is no graphics toolchain to install: no Skia, no Cairo, and no fontconfig or freetype.
git clone https://github.com/cycfi/qplug.git
cd qplug
cmake --preset default
cmake --build cmake-build-debug
ctest --test-dir cmake-build-debug
Without Ninja, replace the preset line with
cmake -B cmake-build-debug -DCMAKE_BUILD_TYPE=Debug. A release preset
builds into cmake-build-release. The directory names are CLion's, so the
IDE and the command line share one build.
Always run cmake --build before ctest. A reconfigure on its own leaves
the AUv2 bundle without its AudioComponents entry until the next build, a
clap-wrapper quirk that QPlug works around at build time; the AU test
refuses to install such a bundle and says so.
This builds every example into cmake-build-debug/products/ in all three
formats and runs the format validators on them. Note that the AU test installs the
component into ~/Library/Audio/Plug-Ins/Components so that auval, and
any AU host, can see it. It also checks that the system's component
registry serves the version the bundle declares, and clears the
registration once if not: a rebuilt AU that a host still reads as the old
one is otherwise hard to recognise, since it looks like a plugin that
opens to an empty window.
The examples live under examples/. gain is the smallest: a mono gain
with one automatable parameter, a volume in decibels, and a fader with a
console taper for it.
A plugin declares one channel layout; a plugin that wants another is
another plugin. gain is mono, so a host offers it on mono tracks.
Not yet. The code is the record until the API settles.
Joel got into electronics and programming in the 80s because almost everything in music, his first love, is becoming electronic and digital. Since then, he builds his own guitars, effect boxes and synths. He enjoys playing distortion-laden rock guitar, composes and produces his own music in his home studio.
Joel de Guzman is the principal architect and engineer at Cycfi Research. He is a software engineer specializing in advanced C++ and an advocate of Open Source. He has authored a number of highly successful Open Source projects such as Boost.Spirit, Boost.Phoenix and Boost.Fusion. These libraries are all part of the Boost Libraries, a well respected, peer-reviewed, Open Source, collaborative development effort.
Feel free to join the discord channel for discussion and chat with the developer.
Copyright (c) 2019-2026 Joel de Guzman. All rights reserved. Distributed under the MIT License
