The CLAP API is neat and elegant, and can be used from C++ in a very bare-bones way. Over time, I've started to prefer using this directly instead of using a framework to abstract things. All this needs is a little template helper (pluginMethod()) which lets you make plain-C function pointers to C++ methods.
This repo contains some example plugins using this approach, as well as demonstrating the webview extension from CLAP 1.2.7.
There are also some additional helpers, and common dependencies which I use personally, so this repo can also be included in other project. These helpers are all independent (so you can pick-and-choose), and none of them are top-level classes you must inherit from.
The plugin-factory functions are defined in source/plugins.cpp. These are then collected into the clap_entry symbol in source/clap_entry.cpp. This two-part setup is used by the make_clapfirst_plugins() CMake function (see CMakeLists.txt) so it can hide all the symbols.
Each example plugin is in its own sub-directory, and they demonstrate slightly different things:
This synth has no dependencies aside from the CLAP headers, the clap-wrappers CMake tools (which can build VST3/others from the CLAP implementation), and the helpers in this repo.
It has note-in and audio in/out ports. It has no UI, so will show the host's default sliders. State is saved using a very basic string serialisation.
This uses dependencies from modules/.
It has audio in/out ports, processing the audio using the chorus from signalsmith-basics. It implements clap.gui to provide native UIs using webview-gui, and saves its state as CBOR.
This uses the CLAP webview helper from webview-gui. This helper lets your plugin implement the clap.webview/3 extension, and then it implements clap.gui for you by hooking up the plugin's webview extension to a native webview.
Using the webview extension means the plugin can still show a UI when compiled to WebAssembly, since platform-native UI pointers can't be used from inside the WASM sandbox. The resources for this webview UI are served from the plugin's memory (using clap_plugin_webview.get_resource().
This uses the same CLAP webview helper as the velocity randomiser, but with a more complex UI.
The webview resources are included in the plugin bundle, and referenced using file: URLs. This only works for targets which have bundles.
This project builds using CMake, using clap-wrapper to (optionally) produce VST3 plugins from the CLAP.
For WebAssembly/WASI, clap-wrapper supports both wasi-sdk and Emscripten, but I'd recommend wasi-sdk because it's just Clang plus some prebuilt system libraries. Emscripten is more opinionated and requires extra config to stop it generating JS stuff which we don't need.
mkdir -p out
# Generate (or update) the build project
cmake -B out/build # -G Xcode
# Build the project
cmake --build out/build --target example-plugins_clap --config ReleaseIf you're not familiar with CMake:
- The
example-plugins_claptarget will generateexample-plugins.clapinsidebuild/(orbuild/Release/) - When generating the project, you can specify a particular back-end, e.g.
-G Xcode. If you're using the default one, it might not support multiple build configs, so specify-DCMAKE_BUILD_TYPE=Releasewhen generating the build project - I personally add
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=..when generating as well, which puts the output inout/instead ofout/build
For personal convenience when developing on my Mac, I've included a Makefile which calls through to CMake. It assumes a Mac system with Xcode and REAPER installed, so if you run make dev-example-plugins it will build the plugins and open REAPER to test them.
With wasi-sdk, just point CMake at the appropriate toolchain when generating the project:
cmake . -B out/build-wasi -DCMAKE_TOOLCHAIN_FILE=wasi-sdk/share/cmake/wasi-sdk-pthread.cmake -DCMAKE_BUILD_TYPE=Release
cmake --build out/build-wasi --target example-plugins_wclap --config ReleaseThis will generate a directory including module.wasm (the actual binary) plus all the resources, To distribute this as a WCLAP bundle, pack it up into a .tar.gz:
pushd path/to/example-plugins.wclap/;
tar --exclude=".*" -vczf ../example-plugins.wclap.tar.gz *
popdI'd recommend using the wasi-sdk-pthread.cmake setup, but if your plugin doesn't spawn any threads of its own then it could use single-threaded configs.
To build with Emscripten, set up the environment, and then use the emcmake helper to create the build project:
. "$(EMSDK)/emsdk_env.sh"
emcmake cmake . -B out/build-emscripten -DCMAKE_BUILD_TYPE=Release
cmake --build out/build-emscripten --target example-plugins_wclap --config ReleaseEmscripten doesn't have proper WASI-threads support, so while plugins built like this can be used from multiple threads (main/audio/etc.), if you try to spawn your own threads it will throw an error.