diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..25b315a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,131 @@ +cmake_minimum_required(VERSION 3.22) + +project(SerumAlt VERSION 1.0.0 LANGUAGES CXX) + +# --------------------------------------------------------------------------- +# C++ standard +# --------------------------------------------------------------------------- +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +# --------------------------------------------------------------------------- +# JUCE +# --------------------------------------------------------------------------- +if(NOT DEFINED JUCE_ROOT) + set(JUCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/third_party/JUCE") +endif() +add_subdirectory("${JUCE_ROOT}") + +# --------------------------------------------------------------------------- +# Plugin target +# --------------------------------------------------------------------------- +# JUCE 7.0.12 builds its VST3 manifest helper (juce_vst3_helper) with the same +# toolchain as the plugin itself. When cross-compiling, that produces a Windows +# .exe which cannot run on the Linux build host, so we disable the automatic +# manifest step and inject a platform-independent moduleinfo.json afterwards +# (see build_windows.sh). Native builds keep the automatic step. +set(SERUMALT_VST3_AUTO_MANIFEST TRUE) +if(CMAKE_CROSSCOMPILING) + set(SERUMALT_VST3_AUTO_MANIFEST FALSE) +endif() + +juce_add_plugin(SerumAlt + VERSION 1.0.0 + COMPANY_NAME "SerumAlt Audio" + IS_SYNTH TRUE + NEEDS_MIDI_INPUT TRUE + NEEDS_MIDI_OUTPUT FALSE + IS_MIDI_EFFECT FALSE + EDITOR_WANTS_KEYBOARD_FOCUS FALSE + PLUGIN_MANUFACTURER_CODE Salt + PLUGIN_CODE Sera + BUNDLE_ID com.serumalt.SerumAlt + FORMATS VST3 AU Standalone + PRODUCT_NAME "SerumAlt" + VST3_AUTO_MANIFEST ${SERUMALT_VST3_AUTO_MANIFEST}) + +juce_generate_juce_header(SerumAlt) + +set(SERUMALT_SOURCES + Source/PluginProcessor.cpp + Source/PluginEditor.cpp + Source/Params.cpp + Source/Wavetable.cpp + Source/Oscillator.cpp + Source/SubOscillator.cpp + Source/NoiseOscillator.cpp + Source/Filter.cpp + Source/FilterBank.cpp + Source/Envelope.cpp + Source/LFO.cpp + Source/ModulationMatrix.cpp + Source/FXProcessor.cpp + Source/MacroControls.cpp + Source/RAVEButton.cpp + Source/SynthVoice.cpp + Source/Engine.cpp + Source/Resources.cpp + Source/EffectUnits/Hyper.cpp + Source/EffectUnits/Chorus.cpp + Source/EffectUnits/Flanger.cpp + Source/EffectUnits/Phaser.cpp + Source/EffectUnits/Distortion.cpp + Source/EffectUnits/EQ.cpp + Source/EffectUnits/Compressor.cpp + Source/EffectUnits/Delay.cpp + Source/EffectUnits/Reverb.cpp + Source/GUI/Knob.cpp + Source/GUI/Slider.cpp + Source/GUI/ToggleButton.cpp + Source/GUI/Display.cpp + Source/GUI/WaveformDisplay.cpp + Source/GUI/FilterDisplay.cpp + Source/GUI/EnvelopeDisplay.cpp + Source/GUI/LFODisplay.cpp + Source/GUI/Panel.cpp + Source/Presets/FactoryPresets.cpp) + +target_sources(SerumAlt PRIVATE ${SERUMALT_SOURCES}) + +target_compile_definitions(SerumAlt + PUBLIC + JUCE_WEB_BROWSER=0 + JUCE_USE_CURL=0 + JUCE_VST3_CAN_REPLACE_VST2=0) + +target_link_libraries(SerumAlt + PRIVATE + juce::juce_audio_utils + juce::juce_dsp + PUBLIC + juce::juce_recommended_config_flags + juce::juce_recommended_warning_flags) + +# --------------------------------------------------------------------------- +# Headless QA harness (console app that drives the processor and checks output) +# --------------------------------------------------------------------------- +option(SERUMALT_BUILD_TESTS "Build the headless QA harness" ON) + +if(SERUMALT_BUILD_TESTS) + juce_add_console_app(SerumAltTest) + juce_generate_juce_header(SerumAltTest) + target_sources(SerumAltTest PRIVATE ${SERUMALT_SOURCES} Source/Tests/TestMain.cpp) + target_compile_definitions(SerumAltTest + PUBLIC + JUCE_WEB_BROWSER=0 + JUCE_USE_CURL=0) + target_link_libraries(SerumAltTest + PRIVATE + juce::juce_audio_utils + juce::juce_dsp + PUBLIC + juce::juce_recommended_config_flags + juce::juce_recommended_warning_flags) +endif() + +if(MSVC) + target_compile_options(SerumAlt PRIVATE /W4) +else() + target_compile_options(SerumAlt PRIVATE -Wall -Wextra) +endif() diff --git a/build_windows.sh b/build_windows.sh new file mode 100755 index 0000000..f577d76 --- /dev/null +++ b/build_windows.sh @@ -0,0 +1,134 @@ +#!/usr/bin/env bash +# --------------------------------------------------------------------------- +# build_windows.sh — cross-compile SerumAlt VST3 for Windows using MinGW-w64 +# --------------------------------------------------------------------------- +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +TOOLCHAIN_FILE="mingw64-toolchain.cmake" +BUILD_DIR="build_windows" +OUTPUT_DIR="SerumAlt_Windows" +PLUGIN_NAME="SerumAlt" + +# 1. Check for the MinGW-w64 cross-compiler and exit if it is not found. +if ! command -v x86_64-w64-mingw32-g++ >/dev/null 2>&1; then + echo "ERROR: x86_64-w64-mingw32-g++ not found." >&2 + echo "Please install the MinGW-w64 cross-compiler first, e.g.:" >&2 + echo " sudo pacman -S mingw-w64-gcc" >&2 + exit 1 +fi + +echo "Found: $(command -v x86_64-w64-mingw32-g++)" + +# 2. Generate the CMake toolchain file. +cat > "$TOOLCHAIN_FILE" <<'EOF' +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) +set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) +set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) +set(CMAKE_AR x86_64-w64-mingw32-ar) +set(CMAKE_RANLIB x86_64-w64-mingw32-ranlib) +set(CMAKE_STRIP x86_64-w64-mingw32-strip) + +set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +EOF + +echo "Wrote toolchain file: $TOOLCHAIN_FILE" + +# 3. Configure with CMake + Ninja (VST3-only cross build, no test harness). +cmake -S . -B "$BUILD_DIR" -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN_FILE" \ + -DSERUMALT_BUILD_TESTS=OFF + +# 4. Build the VST3 target. +cmake --build "$BUILD_DIR" --target SerumAlt_VST3 + +# 5. Inject the VST3 moduleinfo.json. +# The automatic manifest step is disabled when cross-compiling (see +# CMakeLists.txt), because JUCE's manifest helper is a host tool that would +# otherwise be built as a Windows executable. The moduleinfo content is +# deterministic and platform-independent: it depends only on the plugin's +# name, manufacturer/plugin codes, and version, so we write the identical +# file that the native helper generates. Keep it in sync with the metadata +# in CMakeLists.txt (PLUGIN_CODE, PLUGIN_MANUFACTURER_CODE, VERSION). +VST3_BUNDLE="$BUILD_DIR/${PLUGIN_NAME}_artefacts/Release/VST3/$PLUGIN_NAME.vst3" +mkdir -p "$VST3_BUNDLE/Contents/Resources" +cat > "$VST3_BUNDLE/Contents/Resources/moduleinfo.json" <<'EOF' +{ + "Name": "SerumAlt", + "Version": "1.0.0", + "Factory Info": { + "Vendor": "SerumAlt Audio", + "URL": "", + "E-Mail": "", + "Flags": { + "Unicode": true, + "Classes Discardable": false, + "Component Non Discardable": false, + }, + }, + "Classes": [ + { + "CID": "ABCDEF019182FAEB53616C7453657261", + "Category": "Audio Module Class", + "Name": "SerumAlt", + "Vendor": "SerumAlt Audio", + "Version": "1.0.0", + "SDKVersion": "VST 3.7.8", + "Sub Categories": [ + "Instrument", + "Synth", + ], + "Class Flags": 2, + "Cardinality": 2147483647, + "Snapshots": [ + ], + }, + { + "CID": "ABCDEF011234ABCD53616C7453657261", + "Category": "Component Controller Class", + "Name": "SerumAlt", + "Vendor": "SerumAlt Audio", + "Version": "1.0.0", + "SDKVersion": "VST 3.7.8", + "Sub Categories": [ + "Instrument", + "Synth", + ], + "Class Flags": 2, + "Cardinality": 2147483647, + "Snapshots": [ + ], + }, + { + "CID": "ABCDEF01C0DEF00D53616C7453657261", + "Category": "Plugin Compatibility Class", + "Name": "SerumAlt", + "Vendor": "SerumAlt Audio", + "Version": "1.0.0", + "SDKVersion": "VST 3.7.8", + "Class Flags": 0, + "Cardinality": 2147483647, + "Snapshots": [ + ], + }, + ], +} +EOF + +# 6. Copy the resulting .vst3 bundle to SerumAlt_Windows/. +mkdir -p "$OUTPUT_DIR" +rm -rf "$OUTPUT_DIR/$PLUGIN_NAME.vst3" +cp -R "$BUILD_DIR/${PLUGIN_NAME}_artefacts/Release/VST3/$PLUGIN_NAME.vst3" "$OUTPUT_DIR/" + +echo +echo "Done. Windows VST3 plugin at: $SCRIPT_DIR/$OUTPUT_DIR/$PLUGIN_NAME.vst3" diff --git a/mingw64-toolchain.cmake b/mingw64-toolchain.cmake new file mode 100644 index 0000000..b0e08c7 --- /dev/null +++ b/mingw64-toolchain.cmake @@ -0,0 +1,15 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) +set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) +set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) +set(CMAKE_AR x86_64-w64-mingw32-ar) +set(CMAKE_RANLIB x86_64-w64-mingw32-ranlib) +set(CMAKE_STRIP x86_64-w64-mingw32-strip) + +set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)