SynthLab SDK
Creating SynthLab-DM Modules

What is a DM Module?

SynthLab-DM modules are plugins within a plugin and are separate DLLs that you write, compile, and that the SynthLab-DM synths will load at runtime. You place the DLL (Windows) or dylib (MacOS) into a special folder in the same directory with your plugins, whether they are AU, VST3 or RAFX. You only need to compile a single DLL or dylib for each OS. The same dylib will load into AU or VST synths on MacOS and the x64 DLL will load into VST3 and the x86 DLL into RAFX synths in Windows. In the image below, you can see the choice of cores for the wavetable synth. Each object may expose up to 4 module cores. You may design and replace one, two, or every core in the synth, making a very personalized version for yourself. This gives you the flexibility of modular synth programming and the nearly instant reward in testing - each of the SynthLab-DM variants is a hybrid modular/semi-modular synth (or a demi-modular synth).


SL_Promo_DM2.png


In order to use the SynthLab products in DM-mode, you will need to build the initial set of DM modules on your target system. I have made this as simple as I can by providing you with Visual Studio and Xcode projects that have all 18 module sub-projects aggregated into them. This lets you build all the modules, in debug or release mode, with a single "build solution" operation. Details are below.

NOTE: the DM modules built in Debug mode will run significantly slower than their Release configuration counterparts. This is by design and how debug configurations operate due to added overhead used at runtime. When you build the initial set of DM modules, you should use the Release configuration (Visual Studio) or Product -> Build For -> Profiling in Xcode in order to achieve the intended CPU efficiency, which is between 0.7% and 2.3% per note event, depending on the algorithm and modulation. You will easily acheive 16 notes of polyphony without maxing out the CPU thread slice in Release mode, but only 4-8 notes in Debug mode!

DM Modules are DLL-Packaged ModuleCore Objects

The best part about this is that if you've followed the tutorial and have learned to write a ModuleCore object, then you already know everything you need to know and better yet – the exact same code you wrote for the ModuleCores is used in the SynthLab-DM modules, verbatim. The only difference is that these ModuleCore objects are compiled as a separate project and loaded dynamically into the SynthLab-DM synths. You can use the DM synths as the testing clients and actively debug your code. This lets you design, build and test your module ideas with ultra-lean ultra-tiny compiler projects.

In these sections, you will learn how to setup the Visual Studio and Xcode projects to genrate the dynamic libraries. Each project will generate one ModuleCore DLL or dylib and will use one set of source files for each ModuleCore project. You can create new ModuleCores within the new project, or you can re-package existing ModuleCore objects; remember there is no difference in the code. So there is no new theory here regarding the modules or cores since this is a simple re-packaging of the ModuleCore requiring zero integration code.

SynthLab-DM SDK Folders

The SDK has a dedicated folder just for DM development shown below. It includes a subfolder named sdk_files that contains duplicates of some (but not all) of the files from the SDK's source folder. The reason for the duplicates is that when you code DM modules, you must adhere to the same C++ objects and interfaces that the DM synths were built with – this is part of the contract that all plugin APIs require and the DM modules are actually tiny plugins that are loaded at run-time. Since it is highly likely you will want to modify some (or many) of the SynthLab source objects to match your own design paradigms (or your company's), these are isolated from the others and should not be modified. The example Visual Studio and Xcode projects all reference these files.


dmdev_0.png


There are six subfolders:
dll_support_files: contains a pair of files that implement the DLL's exported entry point functions; these are used identically across the projects, but need to be paired with their corresponding synthlabcore.h and .cpp files for each project; these two files contain both MacOS and Windows code together.


dmdev_1.png


dm_modules: this is where the DLLs/dylibs for all 18 modules for Windows and MacOS will be built when you use either the individual or aggregate projects(these are all x64); note that the x86 folder is only for RackAFX users who want to use that software for development and testing; these are combined in the SynthLabModules folder that will be copied into your plugin binaries folder (the location of your VST3 and AU plugins). See Installing the SynthLab Plugins for the details.


dmdev_2.png


Notice the two folders, one for Windows and the other for MacOS; these contain subfolders, one for each type of module, and inside of these are where your DLLs (Windows) and dylib (MacOS) files will be deposited after building. There is another folder named spare_modules where you may stash modules while you play with the different combinations. The DrumWT DLL/dylib files are in stashed away in here and are preset with a preferred index of 3 (last of the set). This is what your folders will look like after you have build the initial set of DM modules.


dmdev_3.png


dm_projects: contains DM projects for every module core in the SynthLab SDK, each with its own folder


dmdev_4.png


Each of the example modules includes pre-made Visual Studio and Xcode project solutions; use these if you want to examine or work on only one DM Module project at a time


dmdev_5.png


sdk_files: contains duplicates of some of the SDK files; the example Visual Studio and Xcode projects reference these files and not the SynthLab_SDK/source versions

vs_windows: contains a Visual Studio 2017 solution that aggregates all 18 module projects together into one VS solution; if you are using a newer version, just open and accept the message about retargeting the solution __SynthLab-DM modules may be built with any version of Visual Studio from VS2017 and upwards, and in any congifuration (debug or release)

xcode_mac: contains an Xcode project that aggregates all 18 module targets together into one combined project; if you are using a newer version, just open and accept the message about retargeting the solution __SynthLab-DM modules may be built with any version of Xcode from version 8.3 and upward, and in any congifuration (debug or release)

Here is what these aggregate solutions look like in Visual Studio and Xcode. Note that in both cases, they are accessing and working with the individual projects, so changes made in the aggregate solutions will propagate to the individual solutions as well.


dmdev_6.png


Remember: the DM modules built in Debug mode will run significantly slower than their Release configuration counterparts. This is by design and how debug configurations operate due to added overhead used at runtime. When you build the initial set of DM modules, you should use the Release configuration (Visual Studio) or Product -> Build For -> Profiling in Xcode in order to achieve the intended CPU efficiency, which is between 0.7% and 2.3% per note event, depending on the algorithm and modulation. You will easily acheive 16 notes of polyphony without maxing out the CPU thread slice in Release mode, but only 4-8 notes in Debug mode!

SynthLab-DM Examples

Each example core contains a source folder with the four files needed:

  • synthlabcore.h and .cpp: these are the C++ ModuleCore object that will be exported in the DLL
  • synthlabdll.h and .cpp: includes both Windows and MacOS code for exporting the creation function to the host DM synth

For every example, the synthlabcore.h and .cpp files are actually identical copies of their SDK ModuleCore counterparts, but with the C++ object renamed to SynthLabCore. This makes all of the core projects identical such that the DLL support files do not need to be modified unless you decide to change the object names or make deeper customizations – note that these changes won't affect the DLL itself and that the C++ class names have nothing to do with the module names, which are set in the constructor.


dmdev_7.png


SynthLab-DM DLL/dylib Locations

After you sucessfully compile a DM module you will have a tiny DLL or dylib file as a result. This file packages a single, dynamically loadable ModuleCore object and a pre-determined entry point function for the SynthLab-DM synth to load. To keep everything "in the SDK" the DM solutions create local output files, but then copy them into the SDK's appropriate folder inside of:

SynthLabModules/x64/<<OS>>/<<module type>="">>

For example, the oscillators will be copied into the OS-specific folder here:


dmdev_3.png


The copying is implelmented as a Post Build Rule in both VS and Xcode. It ensures that you have both a local version and a copied version into that folder. Your version has the same folder structure as the final version that will reside in your AU, VST3 or RAFX plugin folder along side the rest of the plugins. In the beginning, you will probably want to just copy the DLL or dylib file into the appropriate folder. And, using the aggregate solutions allows you to rebuild all the modules at once, setting you up with a fresh and new SynthLabModules folder. Once you've done this a few times you can modify your Visual Studio or Xcode project to copy the files into the "real" destinations in succession.

The location of your plugins and the acompanying SynthLabModules folder are based on the OS and plugin type, listed here and shown in relationship to their plugin binaries in the figure that follows:

  • AU MacOS: /Library/Audio/Plug-Ins/Components/
  • VST3 MacOS: /Library/Audio/Plug-Ins/VST3/
  • VST3 Windows: C:/Program Files/Common Files/VST3/
  • RAFX Windows: C:/Users/_your account_/AppData/Roaming/RackAFX 7.0/PlugIns/


dmdev_8.png


SynthLab-DM DLL Parsing
Synthlab-DM synths will find the SynthLabModules folder and itereate through each subfolder, instantiating the ModuleCores and adding them to their proper destinations; LFO_MODULE stamped modules will be added to the SynthLFO modules while FILTER_MODULES will be added to the SynthFilter modules, in each case as new member cores. Once all four cores have been filled for a given type, then it will reject any added cores. If you are developing a bunch of cores of the same kind, make sure you pick and choose only the cores you want to load and work with. You may need to temporarily re-locate some DM cores to the stash folder. Notice also that the pre-compiled cores have their own preferred index location. Since you have all the code and the same project I used, then you may change that index value. The file iterators go through the folders alphabetically, so if your module isn't showing up, or is in the wrong core slot, check the folders and make sure you have only the DLL or dylib files you need; you may always use the the spare_modules folder as a temporary location.

MacOS Gatekeeper
With each new OS, the MacOS Gatekeeper becomes more restrictive and prohibitive with regards to using products without the dreaded message telling you the product can't be opened because it is from an un-trusted source. I have code-signed the MacOS plugins and signed and notarized the installer so you should not have an issue with the synths. If you examine the DLL support files, you will see that I use the dlopen function to load the DM modules. According to the Apple documentation here: https://developer.apple.com/library/archive/technotes/tn2206/_index.html the Gatekeeper "does not apply to libraries the app loads itself using the dlopen function" so in theory you should not have issues. If you do (because Apple changes something in the future) then you may need to use the Security & Privacy firewall to manually accept opening these DLLs when you load a synth. This is one of the reasons you must build the DM modules yourself. I have never had an issue loading the DM DLLs on my own system (Catalina and Big Sur). However, Apple has as reputation of breaking existing OS paradigms on practically each new OS release so in the future, these dylib files may need to be relocated to a system folder, and the SynthLab DM products will need to be rebuilt on my end.

SynthLabCore Object
You already know that the DM module is just a special re-packaging of a ModuleCore object. To simplify the coding as much as possible, the two extra files that handle the DLL or dylib aspects will attempt to create a ModuleCore with the class name SynthLabCore that is packaged in the two DM core files named synthlabcore.h and synthlabcore.cpp which are identical to the same named files in the SDK. Notice that SynthLab-DM does not categorize your DM module based on its class name; not only can you name the class as you wish, but if you like you may use the same name for every class. The only thing that matter is that the actual DLL or dylib filename is unique so that you may plant them together in the same folder.

Starting a New Project

If you are beginning a brand new DM project from scratch, then you just need to make sure to code your ModuleCore into the two synthlabcore source files and with that object name. The DLL/dylib export code will instantiate and serve SynthLabCore objects to the DM host.

Re-Packaging an Existing ModuleCore
If you are going to re-package an existing ModuleCore as a DM module then you have three immediate options:

  1. take your ModuleCore and rename its class to SynthLabCore and package that in the existing synthlabcore.h and synthlabcore.cpp files
  2. take your ModuleCore and rename its class to SynthLabCore and package that in the whatever source code names you like, then add these files to your DM project to replace the existing synthlabcore.h and synthlabcore.cpp files
  3. leave the ModuleCore class name alone and modify the synthlabdll.cpp file to instantiate your new class name

If you are new to SynthLab or to DLL projects in general, you may want to use 1. or 2. above as they are guaranteed to produce the proper object at DM runtime. If you want to keep your ModuleCore with the same class name, regardless of how you package the source files, you will need to modify the DLL export code.

Modify DLL Export Code
You can modify the code for both Windows and MacOS at the same time since the edits are minimal.

If you are using ModuleCore source files that are NOT named synthlabcore.h and synthlabcore.cpp:

  • open the synthlab.cpp file
  • change the #include statement at the top to #include your ModuleCore.h file rather than synthlabcore.h

Inside of synthlabdll.cpp:

// --- function defs
#include "synthlabdll.h"
// --- this is the file containing your ModuleCore object for DM exporting
// #include "synthlabcore.h"
//
// --- changed to new file
#include "my_module_core.h"
// ---

Now you can change the two functions, one for Windows and one for MacOS, that instantiate and deliver the ModuleCore pointer.

  • alter the code to instantiate your object rather than the SynthLabCore object:
// --- Windows
DllExport SynthLab::ModuleCore* createModuleCore()
{
// --- removed SynthLabCore
// SynthLab::ModuleCore* module = new SynthLab::SynthLabCore();
// --- replaced with MyModuleCore
SynthLab::ModuleCore* module = new SynthLab::MyModuleCore();
return module;
}
// --- MacOS
SynthLab::ModuleCore* createModuleCore()
{
// --- removed SynthLabCore
// SynthLab::ModuleCore* module = new SynthLab::SynthLabCore();
// --- replaced with MyModuleCore
SynthLab::ModuleCore* module = new SynthLab::MyModuleCore();
return module;
}
// ---

At this point, gather your ModuleCore source files and pick the target OS. You will be creating Visual Studio and Xcode projects that are tiny and simple but be sure to follow the process exactly when you are starting out.

SynthLab-DM Programming Guide


synthlab_4.png