# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2026 Nakildias <nakildiaspro@gmail.com>
cmake_minimum_required(VERSION 3.21)
project(waveline VERSION 0.1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
endif()

add_compile_options(-Wall -Wextra -Wpedantic)

# ------------------------------------------------------------- profile lib
# Which microphone this was installed for. Just a config file reader, so the
# GUI can link it without linking the USB transport -- see the note on the GUI
# target below, which that separation exists to keep true.
add_library(wavelineprofile STATIC
    src/device/deviceprofile.cpp
)
target_include_directories(wavelineprofile PUBLIC src)

# ---------------------------------------------------------------- device lib
# Deliberately free of Qt and PipeWire: the daemon links it and it is the one
# place the USB safety interlocks live. One .cpp per microphone that has a
# vendor protocol -- adding a device means adding a file here and a directory
# under devices/.
add_library(wavelinedevice STATIC
    src/device/wave3device.cpp
)
target_include_directories(wavelinedevice PUBLIC src)
target_link_libraries(wavelinedevice PUBLIC wavelineprofile)

# ------------------------------------------------------------------- probe
# Headless check that the device layer works, with no Qt involved. Useful on
# its own when the GUI will not start.
add_executable(waveline-probe src/tools/probe_main.cpp)
target_link_libraries(waveline-probe PRIVATE wavelinedevice)

# ------------------------------------------------------------------ engine
# The PipeWire graph: channels, dual mixes, routable software monitor. Also
# Qt-free, so the daemon can use it without dragging in a GUI toolkit.
find_package(PkgConfig REQUIRED)
pkg_check_modules(PIPEWIRE REQUIRED IMPORTED_TARGET libpipewire-0.3)

pkg_check_modules(RNNOISE REQUIRED IMPORTED_TARGET rnnoise)

# DeepFilterNet is the second noise suppression engine. It is deliberately NOT
# a build dependency: it ships no pkg-config file, is packaged under a
# different name everywhere it is packaged at all, and requiring it would mean
# needing a Rust toolchain to build this. src/engine/denoiser.cpp dlopen()s
# libdf.so at runtime instead, so all that is needed here is libdl.

add_library(wavelineengine STATIC
    src/engine/pwengine.cpp
    src/engine/mixergraph.cpp
    src/engine/denoiser.cpp
    src/engine/noisefilter.cpp
    src/engine/effectsfilter.cpp
    src/engine/gainfilter.cpp
    src/engine/channelinputmixer.cpp
    src/engine/approuter.cpp
    src/engine/soundsharerouter.cpp
    src/engine/levelprobe.cpp
)
target_include_directories(wavelineengine PUBLIC src)
target_link_libraries(wavelineengine PUBLIC PkgConfig::PIPEWIRE PkgConfig::RNNOISE
                                         ${CMAKE_DL_LIBS})

add_executable(waveline-graph src/tools/graph_main.cpp)
target_link_libraries(waveline-graph PRIVATE wavelineengine)

add_executable(waveline-nc src/tools/nc_main.cpp)
target_link_libraries(waveline-nc PRIVATE wavelineengine)

# --------------------------------------------------------------------- gui
# Svg is needed for the icons: they are recoloured at load time by substituting
# `currentColor`, then rendered with QSvgRenderer.
find_package(Qt6 6.4 REQUIRED COMPONENTS Core Widgets DBus Svg)
qt_standard_project_setup()

# ------------------------------------------------------------------ daemon
# QCoreApplication only: wavelined must run without a display, from a user unit.
qt_add_executable(wavelined
    src/daemon/main.cpp
    src/daemon/mixerservice.cpp
    src/daemon/configstore.cpp
    src/daemon/configstore.h
    src/daemon/mixerservice.h
)
target_link_libraries(wavelined PRIVATE
    wavelineengine wavelinedevice Qt6::Core Qt6::DBus)

# The GUI is a pure D-Bus client: it links neither the USB device layer nor
# PipeWire, so it cannot fight the daemon for the vendor interface. The profile
# library is the one exception and reads nothing but a config file -- the GUI
# needs the answer before the daemon is up, to know whether to show a hardware
# panel at all.
qt_add_executable(waveline-mixer
    src/main.cpp
    src/ui/mainwindow.cpp
    src/ui/mainwindow.h
    src/ui/theme.cpp
    src/ui/theme.h
    src/ui/widgets.cpp
    src/ui/widgets.h
    src/ui/levelmeter.cpp
    src/ui/levelmeter.h
    src/ui/channelstrip.cpp
    src/ui/channelstrip.h
    src/ui/mixerclient.cpp
    src/ui/mixerclient.h
    src/ui/appstab.cpp
    src/ui/appstab.h
    src/ui/soundsharingtab.cpp
    src/ui/soundsharingtab.h
    src/ui/effectswindow.cpp
    src/ui/effectswindow.h
)

# Compiled in rather than installed to a data directory: the mixer is a single
# binary users copy into ~/.local/bin, and an icon set that can go missing is a
# support problem for no benefit.
qt_add_resources(waveline-mixer "waveline-icons"
    PREFIX "/icons"
    BASE src/icons
    FILES
        src/icons/browser.svg
        src/icons/ear-off.svg
        src/icons/ear.svg
        src/icons/equal.svg
        src/icons/game.svg
        src/icons/gear.svg
        src/icons/headphones.svg
        src/icons/heartbeat.svg
        src/icons/microphone.svg
        src/icons/music.svg
        src/icons/speaker-high.svg
        src/icons/speaker-low.svg
        src/icons/speaker-muted.svg
        src/icons/stream.svg
        src/icons/system.svg
        src/icons/voice.svg
)
target_link_libraries(waveline-mixer PRIVATE
    wavelineprofile Qt6::Core Qt6::Widgets Qt6::DBus Qt6::Svg)

install(TARGETS wavelined waveline-mixer waveline-probe waveline-graph waveline-nc
        RUNTIME DESTINATION bin)
