Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@
[submodule "external/clap-sdk"]
path = external/clap-sdk
url = https://github.com/free-audio/clap.git
[submodule "external/efsw"]
path = external/efsw
url = https://github.com/SpartanJ/efsw
118 changes: 69 additions & 49 deletions architecture/clap/Makefile.simple
Original file line number Diff line number Diff line change
Expand Up @@ -13,75 +13,95 @@
# - CLAP SDK and helpers in ../../external/
# - C++17 compatible compiler

CXX = g++
CXXFLAGS = -std=c++17 -fPIC -O2 -Wall -Wextra
INCLUDES = -I../../architecture \
-I../../external/clap-sdk/include \
-I../../external/clap-helpers/include \
-I/usr/local/include \
-I/opt/homebrew/include \
-Iefsw/include \
-Iefsw/src

LIBS = -L/usr/local/lib -L/opt/homebrew/lib -lfaust -ldl -framework CoreServices -framework CoreFoundation

TARGET = FaustDynamic.clap
SOURCE = simple-faust.cpp
HELPER_OBJS = clap-helpers-impl.o interpreter-clap.o
MAIN_OBJ = faust-dynamic.o
EFSW_LIB = efsw/build/libefsw-static.a
CXX := /usr/bin/clang++
CXXFLAGS := -std=c++17 -fPIC -O2 -Wall -Wextra -fvisibility=default

# Detect whether we're inside an installed faust2clap tree or building in-repo
SCRIPT_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
TOP_DIR := $(abspath $(SCRIPT_DIR)/../..)

# Allow override via env, useful for installed tree
FAUST2CLAP_ROOT ?= $(TOP_DIR)

# External dependencies
CLAP_SDK_INC := $(FAUST2CLAP_ROOT)/external/clap-sdk/include
CLAP_HELPERS_INC := $(FAUST2CLAP_ROOT)/external/clap-helpers/include
EFSW_INC := $(FAUST2CLAP_ROOT)/external/efsw/include
EFSW_SRC := $(FAUST2CLAP_ROOT)/external/efsw/src
EFSW_LIB := $(FAUST2CLAP_ROOT)/external/efsw/build/libefsw-static.a

INCLUDES = \
-I$(FAUST2CLAP_ROOT)/architecture \
-I$(FAUST2CLAP_ROOT)/external/clap-sdk/include \
-I$(FAUST2CLAP_ROOT)/external/clap-helpers/include \
-I$(FAUST2CLAP_ROOT)/external/efsw/include \
-I$(FAUST2CLAP_ROOT)/external/efsw/src \
-I/usr/local/include \
-I/opt/homebrew/include

LIBS := -L$(FAUST2CLAP_ROOT)/external/efsw/build \
-lfaust -ldl \
-framework CoreServices -framework CoreFoundation

# Output target
TARGET := FaustDynamic.clap

# Source files
SOURCE := simple-faust.cpp
MAIN_OBJ := faust-dynamic.o
HELPER_OBJS := clap-helpers-impl.o interpreter-clap.o

all: $(TARGET)

$(TARGET): $(MAIN_OBJ) $(HELPER_OBJS) $(EFSW_LIB)
@echo "🔗 Linking $(TARGET)..."
$(CXX) -shared $(MAIN_OBJ) $(HELPER_OBJS) $(EFSW_LIB) $(LIBS) -o $@
$(CXX) -bundle -undefined dynamic_lookup \
$(MAIN_OBJ) $(HELPER_OBJS) $(EFSW_LIB) $(LIBS) \
-Wl,-headerpad_max_install_names \
-Wl,-exported_symbol,_clap_entry \
-Wl,-rpath,/usr/local/lib \
-o $@
@echo "✅ Built $(TARGET) successfully"

$(MAIN_OBJ): $(SOURCE)
@echo "🔨 Compiling main plugin source..."
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $(SOURCE) -o $@
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@

clap-helpers-impl.o: clap-helpers-impl.cpp
@echo "🔨 Compiling CLAP helpers..."
$(CXX) $(CXXFLAGS) $(INCLUDES) -c clap-helpers-impl.cpp -o $@
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@

interpreter-clap.o: interpreter-clap.cpp interpreter-clap.h
@echo "🔨 Compiling Faust interpreter interface..."
$(CXX) $(CXXFLAGS) $(INCLUDES) -c interpreter-clap.cpp -o $@


# Build efsw automatically if missing
ifeq ("$(wildcard $(EFSW_LIB))","")
$(info ⚠️ efsw not built yet – will build it now)
NEED_EFSW := 1
endif


$(EFSW_LIB):
@echo "🔨 Building efsw library..."
@cd efsw && mkdir -p build && cd build && cmake .. && make efsw-static
@echo "🔨 Building efsw..."
cd $(FAUST2CLAP_ROOT)/external/efsw && \
mkdir -p build && \
cd build && \
cmake .. && \
make efsw-static

install: $(TARGET)
@echo "📦 Installing $(TARGET)..."
mkdir -p $(HOME)/Library/Audio/Plug-Ins/CLAP/
mkdir -p $(HOME)/.clap/plugins/
cp -f $(TARGET) $(HOME)/Library/Audio/Plug-Ins/CLAP/
cp -f $(TARGET) $(HOME)/.clap/plugins/
@echo "✅ Plugin installed to user plugin directories"

clean:
@echo "🧹 Cleaning build artifacts..."
rm -f $(MAIN_OBJ) $(HELPER_OBJS) $(TARGET)
rm -f *.o $(TARGET)
@echo "✅ Clean complete"

install: $(TARGET)
@echo "📦 Installing $(TARGET)..."
@mkdir -p $(HOME)/Library/Audio/Plug-Ins/CLAP/
@mkdir -p $(HOME)/.clap/plugins/
cp $(TARGET) $(HOME)/Library/Audio/Plug-Ins/CLAP/
cp $(TARGET) $(HOME)/.clap/plugins/
@echo "✅ Installed $(TARGET) to system plugin directories"

# Development targets
test: $(TARGET)
@echo "🧪 Testing plugin load..."
@if [ -n "$(CLAP_VALIDATOR)" ]; then \
$(CLAP_VALIDATOR) $(TARGET); \
else \
echo "⚠️ CLAP_VALIDATOR not set, skipping validation"; \
fi

# Show build info
info:
@echo "🛠️ Faust Dynamic CLAP Plugin Build Configuration:"
@echo " Compiler: $(CXX)"
@echo " Flags: $(CXXFLAGS)"
@echo " Target: $(TARGET)"
@echo " Dependencies: libfaust (with interpreter), CLAP SDK"

.PHONY: all clean install test info
.PHONY: all install clean
Binary file added architecture/clap/gui_stuff/grame.icns
Binary file not shown.
File renamed without changes.
2 changes: 1 addition & 1 deletion build/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ install (

####################################
# install faust2xxx tools
file (GLOB FAUST2XXX ${ROOT}/tools/faust2appls/faust2* ${ROOT}/tools/faust2appls/faustremote ${ROOT}/tools/faust2appls/encoderunitypackage ${ROOT}/tools/faust2appls/usage.sh ${ROOT}/tools/faust2appls/filename2ident ${ROOT}/tools/faust2sc-1.0.0/faust2sc ${ROOT}/tools/faust2clap/faust2clap.py )
file (GLOB FAUST2XXX ${ROOT}/tools/faust2appls/faust2* ${ROOT}/tools/faust2appls/faustremote ${ROOT}/tools/faust2appls/encoderunitypackage ${ROOT}/tools/faust2appls/usage.sh ${ROOT}/tools/faust2appls/filename2ident ${ROOT}/tools/faust2sc-1.0.0/faust2sc ${ROOT}/tools/faust2clap/faust2clap.py ${ROOT}/tools/faust2clap/faust2clap.sh ${ROOT}/tools/faust2clap/install-faust2clap.sh)
install (
FILES ${FAUST2XXX} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_EXECUTE WORLD_READ
Expand Down
1 change: 1 addition & 0 deletions external/efsw
Submodule efsw added at f94a66
104 changes: 57 additions & 47 deletions tools/faust2clap/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,88 +1,94 @@
#min required version of cmake for compatibility
cmake_minimum_required(VERSION 3.15)
#declaration of project and languages in use
project(faust2clap LANGUAGES C CXX)

#specify c++17 and macos deployment target
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.11" CACHE STRING "macOS target")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

#avoid installing clap sdk during build
set(CLAP_NO_INSTALL ON CACHE BOOL "" FORCE)

#enable post-build copying of plugin to standard location
set(COPY_AFTER_BUILD ON CACHE BOOL "Copy the CLAP plugin to system folder after build")

#include required external libraries
add_subdirectory(${CMAKE_SOURCE_DIR}/../../external/clap-sdk clap-sdk)
add_subdirectory(${CMAKE_SOURCE_DIR}/../../external/clap-helpers clap-helpers)
# Define root for local install
set(FAUST2CLAP_ROOT ${CMAKE_CURRENT_SOURCE_DIR})

#build a static lib to hold faust GUI glue (global symbols)
add_library(faust_gui_glue STATIC lib/faust_gui_glue.cpp)

#make sure it sees FAUST GUI headers (like faust/gui/GUI.h)
target_include_directories(faust_gui_glue PRIVATE
${CMAKE_SOURCE_DIR}/../../architecture
${CMAKE_SOURCE_DIR}/architecture/faust/gui
)
# --------------------------------------------------
# Locate Faust headers for global builds
# --------------------------------------------------
execute_process(COMMAND faust --includedir
OUTPUT_VARIABLE FAUST_INCLUDE_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "Faust include dir: ${FAUST_INCLUDE_DIR}")


#hardcode RtMidi paths for Homebrew on Apple Silicon
set(RTMIDI_LIBRARY /opt/homebrew/Cellar/rtmidi/6.0.0/lib/librtmidi.dylib CACHE FILEPATH "Hardcoded RtMidi lib path")
set(RTMIDI_INCLUDE_DIR /opt/homebrew/Cellar/rtmidi/6.0.0/include CACHE PATH "Hardcoded RtMidi include path")
message(STATUS "Final RtMidi include: ${RTMIDI_INCLUDE_DIR}")
# -------------------------------
# External Dependencies
# -------------------------------

# Clap SDK
add_subdirectory(${FAUST2CLAP_ROOT}/external/clap-sdk clap-sdk)
add_subdirectory(${FAUST2CLAP_ROOT}/external/clap-helpers clap-helpers)

# GUI glue lib
add_library(faust_gui_glue STATIC ${FAUST2CLAP_ROOT}/architecture/clap/faust_gui_glue.cpp)

target_include_directories(faust_gui_glue PRIVATE
${FAUST2CLAP_ROOT}/architecture
${FAUST2CLAP_ROOT}/architecture/faust/gui
${FAUST_INCLUDE_DIR}
)

# RtMidi (hardcoded Homebrew path)
set(RTMIDI_LIBRARY /opt/homebrew/Cellar/rtmidi/6.0.0/lib/librtmidi.dylib CACHE FILEPATH "RtMidi lib")
set(RTMIDI_INCLUDE_DIR /opt/homebrew/Cellar/rtmidi/6.0.0/include CACHE PATH "RtMidi include")
message(STATUS "Using hardcoded RtMidi:")
message(STATUS " Library: ${RTMIDI_LIBRARY}")
message(STATUS " Include: ${RTMIDI_INCLUDE_DIR}")


#search for all *_clap.cpp sources generated by Faust
file(GLOB_RECURSE FAUST_SOURCES "${CMAKE_SOURCE_DIR}/../../build/*_clap.cpp")

#loop through each generated file and add a CLAP plugin target


# -------------------------------
# Discover and Build Plugins
# -------------------------------

# This assumes that faust2clap.py puts sources in: <working_dir>/build/<plugin>/
file(GLOB_RECURSE FAUST_SOURCES "${CMAKE_BINARY_DIR}/*_clap.cpp")

foreach(FAUST_CPP ${FAUST_SOURCES})
get_filename_component(FILENAME ${FAUST_CPP} NAME_WE) # e.g. freeverb_clap
string(REPLACE "_clap" "" PLUGIN_NAME ${FILENAME}) # strip _clap
get_filename_component(FILENAME ${FAUST_CPP} NAME_WE)
string(REPLACE "_clap" "" PLUGIN_NAME ${FILENAME})

#declare the plugin module
add_library(${PLUGIN_NAME} MODULE ${FAUST_CPP})

#add plugin.cc to get full implementation of clap::helpers::Plugin<>
target_sources(${PLUGIN_NAME}
PRIVATE
${CMAKE_SOURCE_DIR}/lib/plugin.cc
)
target_sources(${PLUGIN_NAME} PRIVATE ${FAUST2CLAP_ROOT}/architecture/clap/plugin.cc)

#include necessary directories for compilation
target_include_directories(${PLUGIN_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/../../build
${CMAKE_SOURCE_DIR}/../../architecture
${CMAKE_SOURCE_DIR}/architecture/faust/gui
${CMAKE_SOURCE_DIR}/architecture/faust/midi
${CMAKE_SOURCE_DIR}/../../architecture/faust/dsp
${CMAKE_SOURCE_DIR}/../../external/clap-helpers/include
${CMAKE_SOURCE_DIR}/../../external/clap-sdk/include
${RTMIDI_INCLUDE_DIR} # RtMidi include path
${CMAKE_SOURCE_DIR}/../../build/${PLUGIN_NAME}
${CMAKE_BINARY_DIR}
${FAUST2CLAP_ROOT}/architecture
${FAUST2CLAP_ROOT}/architecture/faust/gui
${FAUST_INCLUDE_DIR}
${FAUST2CLAP_ROOT}/architecture/faust/midi
${FAUST2CLAP_ROOT}/architecture/faust/dsp
${FAUST2CLAP_ROOT}/external/clap-helpers/include
${FAUST2CLAP_ROOT}/external/clap-sdk/include
${RTMIDI_INCLUDE_DIR}
${CMAKE_BINARY_DIR}/${PLUGIN_NAME}
)

#link against the clap core library and clap helpers and GUI glue
target_link_libraries(${PLUGIN_NAME} PRIVATE
clap
clap-helpers
faust_gui_glue
${RTMIDI_LIBRARY} # RtMidi dynamic library
${RTMIDI_LIBRARY}
)

#use one shared plist template for all
configure_file(
${CMAKE_SOURCE_DIR}/cmake/generic.plist.in
${FAUST2CLAP_ROOT}/cmake/generic.plist.in
${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_NAME}.plist @ONLY
)

#set bundle properties for macOS
set_target_properties(${PLUGIN_NAME} PROPERTIES
OUTPUT_NAME ${PLUGIN_NAME}
BUNDLE TRUE
Expand All @@ -94,7 +100,6 @@ foreach(FAUST_CPP ${FAUST_SOURCES})
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_NAME}.plist
)

#copy plugin to user's system folder after build
if (APPLE AND COPY_AFTER_BUILD)
message(STATUS "Will copy plugin '${PLUGIN_NAME}' after build")
set(products_folder ${CMAKE_BINARY_DIR})
Expand All @@ -108,3 +113,8 @@ foreach(FAUST_CPP ${FAUST_SOURCES})
)
endif()
endforeach()

# Optional: install the faust2clap CLI
install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/faust2clap.sh
DESTINATION bin
RENAME faust2clap)
Loading