Skip to content

Commit

Permalink
Document expand and test new clap-first cmake api (#356)
Browse files Browse the repository at this point in the history
1. Move the test to new cmake api
2. DOcument the test, document the clap first cmake, and
   include a link to six sines for a more expansive implementation
3. Add an option for inline-auv2-config with make_clap_first if you don't want to implement the extension
  • Loading branch information
baconpaul committed Feb 22, 2025
1 parent e30349e commit 479dc15
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 167 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pullreq.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ jobs:
- name: Build project
run: |
cmake -S . -B ./build ${{ matrix.cmakeargs }} -DCMAKE_BUILD_TYPE=Debug -DCLAP_WRAPPER_DOWNLOAD_DEPENDENCIES=TRUE -DCLAP_WRAPPER_BUILD_TESTS=TRUE
cmake --build ./build --config Debug --target clap-first-distortion_all_plugins
cmake --build ./build --config Debug --target clap-first-distortion_all
- name: Show Build Results
shell: bash
Expand Down
80 changes: 59 additions & 21 deletions cmake/make_clapfirst.cmake
Original file line number Diff line number Diff line change
@@ -1,30 +1,54 @@
# This code is 'where we are going' but not 'where we are yet' way to make clap wrapped plugins
# easily. Right now we are developing it and it is subject to change. When this message is replaced
# with some basic documentation, you are probably safe, but until then, chat with baconpaul or timo
# on discord before you use it ok?
# The initial version of 'clap first' cmake support in a simple wrapper. This is subject
# to some syntactic change as we move the wrapper ahead, but the semantics and actions are
# stable.
#
# For examples see `tests/clap-first-example` or `https://github.com/baconpaul/six-sines`
#



# make_clapfirst_plugins assembles plugins in all formats - CLAP, VST3, AUv2, Standalone etc
# from two assets you provide. The first is a static library which contains symbols for the
# functions clap_init, clap_deinit, and clap_getfactory, named whatever you want. This is
# where 99.99% of your development will be. The second is a single c++ file which generates
# a clap_entry structure with the three functions provided in your static library.
#
# make_clap_first then assembles a clap, vst3, auv2 etc by recompiling the clap entry
# tiny file for each plugin format and introducing it to the plugin protocl, either by
# direct export with the clap or by other methods with the other formats. This assembled
# wrapper then links to your static library for your functions.
#
# This means in practice you just write a clap, but write it as a static lib not a dynamic
# lib, introduce a small fragment of c++ to make an export, and voila, you have all the formats
# in self contained standalone assembled items.

function(make_clapfirst_plugins)
set(oneValueArgs
TARGET_NAME
IMPL_TARGET
TARGET_NAME # name of the output target. It will be postpended _clap, _vst3, _all
IMPL_TARGET # name of the target you set up with your static library

OUTPUT_NAME
OUTPUT_NAME # output name of your CLAP, VST3, etc...

ENTRY_SOURCE
ENTRY_SOURCE # source file of the small cpp with the export directives and link to init

BUNDLE_IDENTIFIER
BUNDLE_IDENTIFIER # macos bundle identifier and builds
BUNDLE_VERSION

COPY_AFTER_BUILD
COPY_AFTER_BUILD # If true, on mac and lin the clap/vst3/etc... will install locally

STANDALONE_MACOS_ICON
STANDALONE_MACOS_ICON # Icons for standalone
STANDALONE_WINDOWS_ICON

ASSET_OUTPUT_DIRECTORY

AUV2_MANUFACTURER_NAME # The AUV2 info. If absent we will probe the CLAP for the
AUV2_MANUFACTURER_CODE # auv2 extension
AUV2_SUBTYPE_CODE
AUV2_INSTRUMENT_TYPE
)
set(multiValueArgs
PLUGIN_FORMATS
STANDALONE_CONFIGURATIONS
PLUGIN_FORMATS # A list of plugin formats, "CLAP" "VST3" "AUV2"
STANDALONE_CONFIGURATIONS # standalone configuration. This is a list of target names and clap ids
)
cmake_parse_arguments(C1ST "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )

Expand Down Expand Up @@ -130,14 +154,28 @@ function(make_clapfirst_plugins)
add_library(${AUV2_TARGET} MODULE)
target_sources(${AUV2_TARGET} PRIVATE ${C1ST_ENTRY_SOURCE})
target_link_libraries(${AUV2_TARGET} PRIVATE ${C1ST_IMPL_TARGET})
target_add_auv2_wrapper(
TARGET ${AUV2_TARGET}
OUTPUT_NAME "${C1ST_OUTPUT_NAME}"
BUNDLE_IDENTIFIER "${C1ST_BUNDLE_IDENTIFER}.auv2"
BUNDLE_VERSION "${C1ST_BUNDLE_VERSION}"

CLAP_TARGET_FOR_CONFIG "${CLAP_TARGET}"
)
if (DEFINED C1ST_AUV2_MANUFACTURER_CODE)
target_add_auv2_wrapper(
TARGET ${AUV2_TARGET}
OUTPUT_NAME "${C1ST_OUTPUT_NAME}"
BUNDLE_IDENTIFIER "${C1ST_BUNDLE_IDENTIFER}.auv2"
BUNDLE_VERSION "${C1ST_BUNDLE_VERSION}"

MANUFACTURER_NAME "${C1ST_AUV2_MANUFACTURER_NAME}"
MANUFACTURER_CODE "${C1ST_AUV2_MANUFACTURER_CODE}"
SUBTYPE_CODE "${C1ST_AUV2_SUBTYPE_CODE}"
INSTRUMENT_TYPE "${C1ST_AUV2_INSTRUMENT_TYPE}"
)
else()
target_add_auv2_wrapper(
TARGET ${AUV2_TARGET}
OUTPUT_NAME "${C1ST_OUTPUT_NAME}"
BUNDLE_IDENTIFIER "${C1ST_BUNDLE_IDENTIFER}.auv2"
BUNDLE_VERSION "${C1ST_BUNDLE_VERSION}"

CLAP_TARGET_FOR_CONFIG "${CLAP_TARGET}"
)
endif()

if (DEFINED C1ST_ASSET_OUTPUT_DIRECTORY)
set_target_properties(${AUV2_TARGET} PROPERTIES
Expand Down
128 changes: 39 additions & 89 deletions tests/clap-first-example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,103 +1,53 @@
project(clap-first-distortion)

# By A "Clap First" plugin, we mean a plugin which is *just* implmented as
# CLAP and uses this wrapper to project into the various other platforms.
#
# One special form of clap first plugin does that by creating a
# the platform plugins with the entire clap library built in. While there's
# a few ways to do this the pattern which eemse to work best is
#
# 1. Write the etnire DSP, handling, etc... of your clap as a library without
# the clap entry
# 2. Have a minimal clap entry c++ file which just exposes the entry points from
# that static library
# 3. Make each of the clap, vst3, auv2 etc... link the static library from 1 but
# recomile the entry from 2, so the resulting plugin has the entry point exposed.
# This is a test of our clap-first makefiles we use in CI, and as such serves as
# an example of doign this without helpers, with the absolute smalles cmake, and
# so forth. A more fulsome example, using C++, setting up compiler options for
# wider deployment, and so forth can be found at
#
# We show an example of that here with a slightly modified version of the
# basic c99 distortion plugin, here re-coded using a C++ compiler.
# https://github.com/baconpaul/six-sines

# So first make the actual plugin as a static library
add_library(${PROJECT_NAME}_base STATIC distortion_clap.cpp)
target_link_libraries(${PROJECT_NAME}_base PUBLIC clap)
project(clap-first-distortion)

set(PRODUCT_NAME "ClapFirst Bad Distortion")

# Now build and configure the CLAP.
add_library(${PROJECT_NAME}_clap MODULE
distortion_clap_entry.cpp
)
target_link_libraries(${PROJECT_NAME}_clap ${PROJECT_NAME}_base)
# Step one is to create a static 'impl' library which contains a static
# implementation of clap_init, clap_deinit and clap_get_factor. Here those
# are all in one cpp file, but a common idiom is to have an -entry-impl file
# separate from the rest of your clap, especially in multi-plugin claps.
add_library(${PROJECT_NAME}-impl STATIC distortion_clap.cpp)
target_link_libraries(${PROJECT_NAME}-impl PUBLIC clap)

if(APPLE)
set_target_properties(${PROJECT_NAME}_clap PROPERTIES
BUNDLE True
BUNDLE_EXTENSION clap
LIBRARY_OUTPUT_NAME ClapFirstDistortion
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_GUI_IDENTIFIER org.free-audio.clapfirst
MACOSX_BUNDLE_BUNDLE_NAME ClapFirstDistortion
MACOSX_BUNDLE_BUNDLE_VERSION "1"
MACOSX_BUNDLE_SHORT_VERSION_STRING "1"
XCODE_ATTRIBUTE_GENERATE_PKGINFO_FILE "YES"
)
elseif(UNIX)
set_target_properties(${PROJECT_NAME}_clap PROPERTIES OUTPUT_NAME ClapFirstDistortion SUFFIX ".clap" PREFIX "")
# Then we use make_clapfirst_plugin, provided by the wrappers, to create the
# project out of the impl and the cpp file which exports the entry
make_clapfirst_plugins(
TARGET_NAME ${PROJECT_NAME}
IMPL_TARGET ${PROJECT_NAME}-impl

else()
set_target_properties(${PROJECT_NAME}_clap
PROPERTIES
OUTPUT_NAME ClapFirstDistortion
SUFFIX ".clap" PREFIX ""
LIBRARY_OUTPUT_DIRECTORY CLAP
)
endif()
OUTPUT_NAME "${PRODUCT_NAME}"

# Building a VST3 is now easy. Make a MODULE library which compiles the entry code
# and links the base library, then use the wraper cmake code to expose it as a VST3
set(VST3_TARGET ${PROJECT_NAME}_vst3)
add_library(${VST3_TARGET} MODULE)
target_sources(${VST3_TARGET} PRIVATE distortion_clap_entry.cpp)
target_add_vst3_wrapper(TARGET ${VST3_TARGET}
OUTPUT_NAME "ClapFirstDistortion"
)
target_link_libraries(${VST3_TARGET} PRIVATE ${PROJECT_NAME}_base)
ENTRY_SOURCE "distortion_clap_entry.cpp"

BUNDLE_IDENTIFER "org.free-audio.clap-first-bad-distortion"
BUNDLE_VERSION ${PROJECT_VERSION}

# And the same for the standalone
set(SA_TARGET ${PROJECT_NAME}_standalone)
add_executable(${SA_TARGET})
target_sources(${SA_TARGET} PRIVATE distortion_clap_entry.cpp)
target_link_libraries(${SA_TARGET} PRIVATE ${PROJECT_NAME}_base)
target_add_standalone_wrapper(TARGET ${SA_TARGET}
OUTPUT_NAME "ClapFirstDistortion"
STATICALLY_LINKED_CLAP_ENTRY True
PLUGIN_ID "org.free-audio.clap-first-bad-distortion")
COPY_AFTER_BUILD FALSE

if (APPLE)
# And the same for the AUV2
set(AUV2_TARGET ${PROJECT_NAME}_auv2)
add_library(${AUV2_TARGET} MODULE)
target_sources(${AUV2_TARGET} PRIVATE distortion_clap_entry.cpp)
target_link_libraries(${AUV2_TARGET} PRIVATE ${PROJECT_NAME}_base)
target_add_auv2_wrapper(
TARGET ${AUV2_TARGET}
OUTPUT_NAME "ClapFirstDistortion"
BUNDLE_IDENTIFIER "org.freeaudio.bad-clap-first"
BUNDLE_VERSION "1"
PLUGIN_FORMATS CLAP VST3 AUV2

MANUFACTURER_NAME "FreeAudio Team"
MANUFACTURER_CODE "FrAU"
SUBTYPE_CODE "clDi"
INSTRUMENT_TYPE "aufx"
ASSET_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PROJECT_NAME}_assets

CLAP_TARGET_FOR_CONFIG ${PROJECT_NAME}_clap
)
endif()
# You can set up the AUv2 for a single plugin here, or you can
# set it up with the auv2 extension in your clap
AUV2_MANUFACTURER_NAME "Free Audio"
AUV2_MANUFACTURER_CODE "FrAD"
AUV2_SUBTYPE_CODE "BdDt"
AUV2_INSTRUMENT_TYPE "aufx"

# You can add a target-per-standalone you want. Syntax here is
# target-postfix output-name clap-id
# This allows you to make multiple standalones from a multi-plugin clap
# In this case, the standalone has no UI and is an audio to audio effect
# so it isn't very useful
# STANDALONE_CONFIGURATIONS
# standalone "${PRODUCT_NAME}" "org.free-audio.clap-first-bad-distortion"
)

# FInally collect those all in a utility target
add_custom_target(${PROJECT_NAME}_all_plugins)
add_dependencies(${PROJECT_NAME}_all_plugins ${PROJECT_NAME}_clap ${PROJECT_NAME}_vst3 ${PROJECT_NAME}_standalone)
if (APPLE)
add_dependencies(${PROJECT_NAME}_all_plugins ${PROJECT_NAME}_auv2)
endif()
Loading

0 comments on commit 479dc15

Please sign in to comment.