# Max/MSP port and modifications: Copyright (C) 2026 沁墨蓝汐
# Modified 2026-10-12. SPDX-License-Identifier: AGPL-3.0-or-later

cmake_minimum_required(VERSION 3.25)
set(CMAKE_OSX_DEPLOYMENT_TARGET "15.0" CACHE STRING "Minimum macOS version")
project(MolluskVoiceChangerMax VERSION 1.1.1 LANGUAGES C CXX OBJCXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(MOLLUSK_UPSTREAM "${CMAKE_CURRENT_SOURCE_DIR}/vendor/MolluskVoiceChanger" CACHE PATH "Pinned upstream MolluskVoiceChanger checkout")
set(MAXSDK_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor/max-sdk-base")
list(PREPEND CMAKE_MODULE_PATH "${MAXSDK_SOURCE_DIR}/cmake")
find_package(MaxSDK REQUIRED COMPONENTS Max MSP)
add_subdirectory("${MOLLUSK_UPSTREAM}/JUCE" "${CMAKE_CURRENT_BINARY_DIR}/JUCE" EXCLUDE_FROM_ALL)

juce_add_binary_data(MolluskFonts SOURCES
    "${MOLLUSK_UPSTREAM}/assets/fonts/Bungee-Regular.ttf"
    "${MOLLUSK_UPSTREAM}/assets/fonts/RocknRollOne-Regular.ttf"
    "${MOLLUSK_UPSTREAM}/assets/fonts/AlfaSlabOne-Regular.ttf"
    "${MOLLUSK_UPSTREAM}/assets/fonts/RubikGlitch-Regular.ttf"
    "${MOLLUSK_UPSTREAM}/assets/icons/squid2.svg"
    "${MOLLUSK_UPSTREAM}/assets/icons/octopus.svg")

juce_add_binary_data(MolluskLegal NAMESPACE MolluskLegalData HEADER_NAME MolluskLegalData.h
    SOURCES package/NOTICE.txt package/LICENSE)

set(CORE_RELATIVE_SOURCES
    PluginProcessor.cpp PresetManager.cpp
    ui/AdvancedPanel.cpp ui/BasicPanel.cpp ui/MolluskLookAndFeel.cpp
    dsp/HighPassFilter.cpp dsp/BandPassFilter.cpp dsp/PhaserProcessor.cpp
    dsp/PitchShifter.cpp dsp/NoiseGate.cpp dsp/FormantShifter.cpp
    dsp/LFOFilter.cpp dsp/EffectChain.cpp dsp/OutputGain.cpp)

# Compile unchanged upstream sources plus narrowly scoped Max-only overrides.
set(MOLLUSK_MAX_SRC "${CMAKE_CURRENT_BINARY_DIR}/upstream-max/src")
file(GLOB_RECURSE UPSTREAM_FILES CONFIGURE_DEPENDS RELATIVE "${MOLLUSK_UPSTREAM}/src" "${MOLLUSK_UPSTREAM}/src/*")
foreach(path IN LISTS UPSTREAM_FILES)
    configure_file("${MOLLUSK_UPSTREAM}/src/${path}" "${MOLLUSK_MAX_SRC}/${path}" COPYONLY)
endforeach()
configure_file(source/overrides/LFOFilter.h "${MOLLUSK_MAX_SRC}/dsp/LFOFilter.h" COPYONLY)
configure_file(source/overrides/LFOFilter.cpp "${MOLLUSK_MAX_SRC}/dsp/LFOFilter.cpp" COPYONLY)
configure_file(source/overrides/BandPassFilter.h "${MOLLUSK_MAX_SRC}/dsp/BandPassFilter.h" COPYONLY)
configure_file(source/overrides/BandPassFilter.cpp "${MOLLUSK_MAX_SRC}/dsp/BandPassFilter.cpp" COPYONLY)
configure_file(source/MolluskLookAndFeelMax.cpp "${MOLLUSK_MAX_SRC}/ui/MolluskLookAndFeel.cpp" COPYONLY)

add_library(mollusk_runtime STATIC)
set_target_properties(mollusk_runtime PROPERTIES POSITION_INDEPENDENT_CODE ON CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON)
target_include_directories(mollusk_runtime PUBLIC source "${MOLLUSK_UPSTREAM}/JUCE/modules")
target_compile_definitions(mollusk_runtime PUBLIC
    JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 JUCE_WEB_BROWSER=0 JUCE_USE_CURL=0
    JUCE_STANDALONE_APPLICATION=0 JUCE_DISPLAY_SPLASH_SCREEN=0)
target_link_libraries(mollusk_runtime PRIVATE juce::juce_audio_utils juce::juce_dsp juce::juce_gui_extra)

set(MAX_CORE_SOURCES ${CORE_RELATIVE_SOURCES})
list(TRANSFORM MAX_CORE_SOURCES PREPEND "${MOLLUSK_MAX_SRC}/")
add_library(mollusk_core STATIC ${MAX_CORE_SOURCES} source/MolluskEngine.cpp source/MolluskTranslations.cpp)
set_target_properties(mollusk_core PROPERTIES POSITION_INDEPENDENT_CODE ON CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON)
target_include_directories(mollusk_core PUBLIC source "${MOLLUSK_MAX_SRC}")
target_link_libraries(mollusk_core PUBLIC mollusk_runtime PRIVATE MolluskFonts)

option(MOLLUSK_BUILD_EXTERNAL "Build the Max external and original editor adapter" ON)
if(MOLLUSK_BUILD_EXTERNAL)
add_library(mollusk MODULE source/MolluskMax.cpp source/MolluskUI.cpp source/MolluskAbout.cpp source/PluginEditorMax.cpp)
target_link_libraries(mollusk PRIVATE mollusk_core MolluskLegal Max::Max Max::MSP)
set_target_properties(mollusk PROPERTIES
    OUTPUT_NAME "mollusk~" PREFIX "" BUNDLE TRUE BUNDLE_EXTENSION "mxo"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/package/externals"
    CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON)
get_property(MAX_LINK_FLAGS_FILE TARGET Max::Max PROPERTY _MAX_LINKER_FLAGS_FILE)
file(STRINGS "${MAX_LINK_FLAGS_FILE}" MAX_RAW_LINK_FLAGS)
separate_arguments(MAX_LINK_FLAGS UNIX_COMMAND "${MAX_RAW_LINK_FLAGS}")
target_link_options(mollusk PRIVATE ${MAX_LINK_FLAGS})

set(MACOSX_BUNDLE_EXECUTABLE_NAME "mollusk~")
set(AUTHOR_DOMAIN "com.mollusk")
set(BUNDLE_IDENTIFIER "max.external")
set(PACKAGE_VERSION "1.1.1")
set(COPYRIGHT_STRING "Copyright 2026 Ito Hyakkei; Max/MSP port Copyright 2026 沁墨蓝汐")
configure_file("${MAXSDK_SOURCE_DIR}/cmake/Info.plist.in" "${CMAKE_CURRENT_BINARY_DIR}/Mollusk-Info.plist" @ONLY)
# File-provider folders may recreate FinderInfo while signing. Sign a clean copy.
add_custom_command(TARGET mollusk POST_BUILD
    COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_BINARY_DIR}/Mollusk-Info.plist" "$<TARGET_BUNDLE_DIR:mollusk>/Contents/Info.plist"
    COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${MAXSDK_SOURCE_DIR}/script/PkgInfo" "$<TARGET_BUNDLE_DIR:mollusk>/Contents/PkgInfo"
    COMMAND "${CMAKE_COMMAND}" "-DMOLLUSK_BUNDLE_PATH=$<TARGET_BUNDLE_DIR:mollusk>" -P "${CMAKE_CURRENT_SOURCE_DIR}/source/SignExternal.cmake"
    COMMAND "${CMAKE_COMMAND}" -E create_symlink "mollusk~.mxo" "${CMAKE_CURRENT_SOURCE_DIR}/package/externals/mollusk.ui.mxo"
    VERBATIM)
endif()

option(MOLLUSK_BUILD_VERIFICATION "Build separate upstream and Max-adapter comparison runners" ON)
if(MOLLUSK_BUILD_VERIFICATION)
    set(REFERENCE_CORE_SOURCES ${CORE_RELATIVE_SOURCES})
    list(TRANSFORM REFERENCE_CORE_SOURCES PREPEND "${MOLLUSK_UPSTREAM}/src/")
    add_library(mollusk_reference_core STATIC ${REFERENCE_CORE_SOURCES})
    target_include_directories(mollusk_reference_core PUBLIC source "${MOLLUSK_UPSTREAM}/src")
    target_link_libraries(mollusk_reference_core PUBLIC mollusk_runtime PRIVATE MolluskFonts)
    add_executable(mollusk_reference source/ReferenceDSP.cpp "${MOLLUSK_UPSTREAM}/src/PluginEditor.cpp")
    target_link_libraries(mollusk_reference PRIVATE mollusk_reference_core)
    add_executable(mollusk_verify source/VerifyDSP.cpp "${MOLLUSK_MAX_SRC}/PluginEditor.cpp")
    target_link_libraries(mollusk_verify PRIVATE mollusk_core)
    add_executable(mollusk_instance_verify source/VerifyInstances.cpp "${MOLLUSK_MAX_SRC}/PluginEditor.cpp")
    target_link_libraries(mollusk_instance_verify PRIVATE mollusk_core)
    add_executable(mollusk_original_instance_probe source/VerifyInstances.cpp "${MOLLUSK_UPSTREAM}/src/PluginEditor.cpp")
    target_compile_definitions(mollusk_original_instance_probe PRIVATE MOLLUSK_REFERENCE_TEST=1)
    target_link_libraries(mollusk_original_instance_probe PRIVATE mollusk_reference_core)
    add_executable(mollusk_ui_probe source/MolluskUI.cpp source/MolluskAbout.cpp source/PluginEditorMax.cpp)
    target_compile_definitions(mollusk_ui_probe PRIVATE MOLLUSK_UI_PROBE=1)
    target_link_libraries(mollusk_ui_probe PRIVATE mollusk_core MolluskLegal)
endif()
