Making a Windows VST plugin with D
In this tutorial, you'll learn how to make a VST plugin without UI using the D programming language, for Windows. The Mac OS X version would bring a bit more complexity and will be investigated in another blog post. Update: this tutorial is now obsolete.
dplug is a library that wraps plugin formats and manages the UI if needed. It's source code is available on Github.
It is most similar to IPlug and JUCE, two C++ alternatives you should absolutely consider when making plugins. Only a subset of JUCE and IPlug features are supported. If you need VST3 or AAX support, use them instead. AudioUnit support isn't there yet either, but will probably happen this year.
dplug also offers a way to render your plugin UI with a depth map and fancy lighting, but this is out-of-scope for this tutorial. We'll focus on getting something on the table as quickly as possible.
Setting up the environment
This tutorial assumes
gitis installed and ready-to-run. Get it here otherwise.
For 64-bit support, it is recommended to install Visual Studio before the D compiler (for example Visual Studio 2013 Community Edition). This is necessary because the DMD compiler uses the Microsoft's linker when building 64-bit binaries. You can skip this step if you don't want 64-bit support.
Install DMD: go to the D compiler downloads. The easiest way is to download and execute the installer. If you choose so, VisualD will also be installed. It allows to edit and debug D code from within Visual Studio. DMD should be in your PATH environment variable afterwards. Type
dmd --versionin a command prompt to check for correct setup.
Install DUB: go to the D package manager downloads. You will find releases there. DUB must be in your PATH environment variable. Type
dub helpin a command prompt to check for correct installation.
Build the M/S Encoder example
For the sake of brevity, the effect we'll create is a simple M/S encoder plugin.
You can find the full source code here. I recommend you copy this example to start creating your own plugins.
git clone https://github.com/p0nce/dplug.git
Go to the M/S encoder directory:
Build the plugin by typing:
This will create a DLL which can be used in a host as a VST2 plugin. Now let's get into details and see what files were necessary.
What is the file
DUB needs a project description file to work its magic.
Let's explain all of the JSON keys:
nameis necessary for every DUB project. In some cases it is even the only mandatory key.
importPaths: this list of paths is passed to the D compiler with the
-Iswitch, so that you can
sourcePaths: this list of paths is scanned for .d files to pass to the compiler. The D compilation model is similar to the C++ compilation model: there is a distinction between source files and import paths.
targetTypemust be set to
module.defto the linker, when on Windows. Without that exported symbol, the VST host wouldn't be able to load your plugin.
dependencieslists all dependencies needed by this project. Only
dplug:vstis needed here.
CFBundleIdentifierPrefixwill only be useful for the Mac version.
What is the file
This is the main source file for our M/S encoder. Like in JUCE or IPlug, it is a matter of subclassing a plugin client class and overloading some functions.
audio processing happens in the
processAudio()overload. This is pretty straightforward to understand, you get a number of input pointers, a number of ouput pointers, and a number of samples. The interesting things happen here!
reset()overload is called at initialization time or whenever the sampling rate changes. Since our M/S encoder has no state, this is left empty.
buildParams()is where you define plugin parameters. We have only one boolean parameter here, "On/Off". In
processAudio()this parameter is read with
buildLegalIO()overload is there to define which combination of input and output channels are allowed. In this example, stereo to stereo is the only legal combination.
buildPluginInfo()overload allows to define the plugin identity and some options.
How do I debug it?
If you have Visual Studio and VisualD installed, you can generate an IDE project using the command:
dub generate visuald.
This will create a solution able to build your project, and suitable for debugging (much like CMake or premake do).
Getting an optimized build
To build our M/S encoder with optimizations, you can do:
dub -b release-nobounds -f --combined
dub -b release-nobounds -f --combined -a x86_64 for a 64-bit plugin.
Speed-wise, this plugin should then be about 2500x real-time. Which is expected since it doesn't do much in the first place.
Why the D programming language?
Indeed. Why use D over the obvious alternative: C++?
This is a touchy topic that already has filled entire blog posts. Virtually everyone in real-time audio is using C++ and it's probably still the sanest choice to make.
We are a handful of people using D though. Prior work with VST and D include:
The Opossum synthesizer: http://bazaar.launchpad.net/~ace17/opossum/trunk/view/head:/README
I worked with both languages for years and felt qualified enough for the inevitable bullet point comparison. The most enabling thing is the D ecosystem and package management through DUB, which makes messing with dependencies basically a solved problem. Development seems to "flow" way more, and I tend to like the end result better in a way that is undoubtedly personal.
Isn't Garbage Collection at odds with real-time audio?
This will be counter-intuitive to many programmers, but the D GC isn't even given a chance to be a problem. The ways to avoid the dreaded GC pauses are well known within the community.
In our plugins the GC is used in the UI but not in audio processing. No collection happens after UI initialization. If there was some, the audio thread wouldn't get stopped thanks to being unregistered to the runtime.
The mere presence of a GC doesn't prevent you to do real-time audio, provided you are given the means to control it and avoid it as needed.
Making VST plugins with D isn't terribly involved. I hope you find the process enjoyable and most importantly, easy.