# CMakeLists.txt cmake_minimum_required(VERSION 3.18) project(YrCrystals VERSION 1.0 LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) # --- FIX FOR WINDOWS MSVC ERRORS --- if(MSVC) add_compile_options($<$:/std:clatest>) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif() include(FetchContent) option(BUILD_ANDROID "Build for Android" OFF) option(BUILD_IOS "Build for iOS" OFF) find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Multimedia OpenGLWidgets) # --- FFTW3 Configuration (Double Precision) --- if(WIN32) # Windows: Expects FFTW3 to be installed/found via Config find_package(FFTW3 CONFIG REQUIRED) if(TARGET FFTW3::fftw3) add_library(fftw3 ALIAS FFTW3::fftw3) endif() elseif(APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" AND NOT BUILD_IOS) message(STATUS "Detected Apple Silicon Desktop. Using Homebrew FFTW3 (Double).") find_library(FFTW3_LIB NAMES fftw3 libfftw3 PATHS /opt/homebrew/lib NO_DEFAULT_PATH) find_path(FFTW3_INCLUDE_DIR fftw3.h PATHS /opt/homebrew/include NO_DEFAULT_PATH) if(NOT FFTW3_LIB OR NOT FFTW3_INCLUDE_DIR) message(FATAL_ERROR "FFTW3 not found in /opt/homebrew. Please run: brew install fftw") endif() add_library(fftw3 STATIC IMPORTED) set_target_properties(fftw3 PROPERTIES IMPORTED_LOCATION "${FFTW3_LIB}" INTERFACE_INCLUDE_DIRECTORIES "${FFTW3_INCLUDE_DIR}" ) else() message(STATUS "Building FFTW3 from source (Double Precision)...") set(ENABLE_FLOAT OFF CACHE BOOL "Build double precision" FORCE) set(ENABLE_SSE OFF CACHE BOOL "Disable SSE" FORCE) set(ENABLE_SSE2 OFF CACHE BOOL "Disable SSE2" FORCE) set(ENABLE_AVX OFF CACHE BOOL "Disable AVX" FORCE) set(ENABLE_AVX2 OFF CACHE BOOL "Disable AVX2" FORCE) set(ENABLE_THREADS OFF CACHE BOOL "Disable Threads" FORCE) set(ENABLE_OPENMP OFF CACHE BOOL "Disable OpenMP" FORCE) set(ENABLE_MPI OFF CACHE BOOL "Disable MPI" FORCE) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build Static Libs" FORCE) set(BUILD_TESTS OFF CACHE BOOL "Disable Tests" FORCE) # Enhanced NEON detection for Windows on Arm as well if(ANDROID_ABI STREQUAL "arm64-v8a") message(STATUS "Enabling NEON for Android ARM64") set(ENABLE_NEON ON CACHE BOOL "Enable NEON" FORCE) elseif(BUILD_IOS) set(ENABLE_NEON ON CACHE BOOL "Enable NEON" FORCE) elseif(MSVC AND CMAKE_SYSTEM_PROCESSOR MATCHES "(ARM64|arm64|aarch64)") set(ENABLE_NEON ON CACHE BOOL "Enable NEON" FORCE) endif() # Only apply sed patch on UNIX-like systems if(UNIX) set(PATCH_CMD sed -i.bak "s/cmake_minimum_required.*/cmake_minimum_required(VERSION 3.16)/" /CMakeLists.txt) else() set(PATCH_CMD "") endif() FetchContent_Declare( fftw3_source URL https://www.fftw.org/fftw-3.3.10.tar.gz DOWNLOAD_EXTRACT_TIMESTAMP TRUE PATCH_COMMAND ${PATCH_CMD} ) FetchContent_MakeAvailable(fftw3_source) endif() # --- Loop Tempo Estimator --- set(BUILD_TESTS OFF CACHE BOOL "Build tests" FORCE) set(BUILD_VAMP_PLUGIN OFF CACHE BOOL "Build Vamp plugin" FORCE) add_subdirectory(libraries/loop-tempo-estimator) # ========================================== # --- ICON GENERATION --- # ========================================== set(ICON_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/assets/icon_source.png") find_program(MAGICK_EXECUTABLE NAMES magick) if(NOT MAGICK_EXECUTABLE) message(WARNING "ImageMagick 'magick' not found. Icons will not be generated.") endif() if(EXISTS "${ICON_SOURCE}" AND MAGICK_EXECUTABLE) if(WIN32) # --- WINDOWS SPECIFIC --- # Generates into BINARY dir to keep source clean set(WINDOWS_ICON "${CMAKE_CURRENT_BINARY_DIR}/app_icon.ico") set(WINDOWS_RC "${CMAKE_CURRENT_BINARY_DIR}/app_icon.rc") set(ICON_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_icons.bat") # 1. Create the .rc file so the linker knows to include the icon file(WRITE "${WINDOWS_RC}" "IDI_ICON1 ICON \"app_icon.ico\"\n") # 2. Command to generate the actual .ico add_custom_command( OUTPUT "${WINDOWS_ICON}" COMMAND "${ICON_SCRIPT}" "${MAGICK_EXECUTABLE}" "${ICON_SOURCE}" "${WINDOWS_ICON}" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" DEPENDS "${ICON_SOURCE}" "${ICON_SCRIPT}" COMMENT "Generating Windows Icon (app_icon.ico)..." VERBATIM ) add_custom_target(GenerateIcons DEPENDS "${WINDOWS_ICON}") else() # --- MAC/LINUX/ANDROID/IOS SPECIFIC --- # Must generate into SOURCE dir so Android/iOS packaging tools find them set(MACOS_ICON "${CMAKE_CURRENT_SOURCE_DIR}/assets/icons/app_icon.icns") set(IOS_ASSETS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/ios/Assets.xcassets") set(IOS_CONTENTS_JSON "${IOS_ASSETS_PATH}/Contents.json") set(ANDROID_RES_PATH "${CMAKE_CURRENT_SOURCE_DIR}/android/res/mipmap-mdpi/ic_launcher.png") set(ICON_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_icons.sh") execute_process(COMMAND chmod +x "${ICON_SCRIPT}") add_custom_command( OUTPUT "${MACOS_ICON}" "${IOS_CONTENTS_JSON}" "${ANDROID_RES_PATH}" COMMAND "${ICON_SCRIPT}" "${MAGICK_EXECUTABLE}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" DEPENDS "${ICON_SOURCE}" "${ICON_SCRIPT}" COMMENT "Generating Cross-Platform Icons..." VERBATIM ) add_custom_target(GenerateIcons DEPENDS "${MACOS_ICON}" "${IOS_CONTENTS_JSON}" "${ANDROID_RES_PATH}") endif() endif() # --- Sources --- set(PROJECT_SOURCES src/main.cpp src/Utils.cpp src/Processor.cpp src/AudioEngine.cpp src/VisualizerWidget.cpp src/CommonWidgets.cpp src/PlayerControls.cpp src/MainWindow.cpp src/complex_block.cpp src/trig_interpolation.cpp ) # Add the generated icons AND the RC file to the source list if(EXISTS "${ICON_SOURCE}") if(WIN32) list(APPEND PROJECT_SOURCES ${WINDOWS_RC} ${WINDOWS_ICON}) elseif(APPLE AND NOT BUILD_IOS) list(APPEND PROJECT_SOURCES ${MACOS_ICON}) endif() endif() set(PROJECT_HEADERS src/Utils.h src/Processor.h src/AudioEngine.h src/VisualizerWidget.h src/CommonWidgets.h src/PlayerControls.h src/MainWindow.h src/complex_block.h src/trig_interpolation.h ) qt_add_executable(YrCrystals MANUAL_FINALIZATION ${PROJECT_SOURCES} ${PROJECT_HEADERS}) if(EXISTS "${ICON_SOURCE}" AND MAGICK_EXECUTABLE) add_dependencies(YrCrystals GenerateIcons) endif() # --- Mobile Definitions --- if(BUILD_ANDROID OR BUILD_IOS) target_compile_definitions(YrCrystals PRIVATE IS_MOBILE) endif() # --- Linking --- if(TARGET fftw3) set(FFTW_TARGET fftw3) # Fix: Only include source dirs if we actually built from source (FetchContent) if(DEFINED fftw3_source_SOURCE_DIR) target_include_directories(YrCrystals PRIVATE "${fftw3_source_SOURCE_DIR}/api" "${fftw3_source_BINARY_DIR}" ) endif() else() set(FFTW_TARGET fftw3) endif() target_link_libraries(YrCrystals PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Multimedia Qt6::OpenGLWidgets ${FFTW_TARGET} loop-tempo-estimator ) if(BUILD_ANDROID) target_link_libraries(YrCrystals PRIVATE log m) set_property(TARGET YrCrystals PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") endif() if(BUILD_IOS) if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/ios/Info.plist") message(FATAL_ERROR "Missing ios/Info.plist. Please create it before building.") endif() set_source_files_properties(src/Utils.cpp PROPERTIES LANGUAGE OBJCXX) set_target_properties(YrCrystals PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_BUNDLE_NAME "Yr Crystals" MACOSX_BUNDLE_GUI_IDENTIFIER "com.yrcrystals.app" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ios/Info.plist" XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon" RESOURCE "${IOS_ASSETS_PATH}" ) if(EXISTS "${ICON_SOURCE}") message(STATUS "Adding iOS Assets from: ${IOS_ASSETS_PATH}") file(MAKE_DIRECTORY "${IOS_ASSETS_PATH}") target_sources(YrCrystals PRIVATE "${IOS_ASSETS_PATH}") endif() qt_import_plugins(YrCrystals EXCLUDE Qt6::FFmpegMediaPlugin Qt6::QFFmpegMediaPlugin ) target_link_libraries(YrCrystals PRIVATE "-framework AudioToolbox" "-framework AVFoundation" "-framework CoreMedia" "-framework VideoToolbox" "-framework CoreVideo" "-framework CoreFoundation" "-framework UIKit" "-framework UniformTypeIdentifiers" "-lz" "-lbz2" "-liconv" ) endif() if(APPLE AND NOT BUILD_IOS) set_target_properties(YrCrystals PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_BUNDLE_NAME "Yr Crystals" MACOSX_BUNDLE_GUI_IDENTIFIER "com.yrcrystals.app" MACOSX_BUNDLE_ICON_FILE "app_icon.icns" RESOURCE "${MACOS_ICON}" ) elseif(WIN32) set_target_properties(YrCrystals PROPERTIES WIN32_EXECUTABLE TRUE ) endif() qt_finalize_executable(YrCrystals)