cmake_minimum_required(VERSION 3.0)
project(LinkExamples)

#     _    ____ ___ ___
#    / \  / ___|_ _/ _ \
#   / _ \ \___ \| | | | |
#  / ___ \ ___) | | |_| |
# /_/   \_\____/___\___/
#

if(WIN32)
  function(configure_asio asio_sdk_path_OUT)
    # ASIO-related path/file variables
    set(asio_download_root "https://www.steinberg.net/sdk_downloads")
    set(asio_file_name "asiosdk2.3.zip")
    set(asio_dir_name "ASIOSDK2.3")
    set(asio_working_dir "${CMAKE_BINARY_DIR}/modules")
    set(asio_output_path "${asio_working_dir}/${asio_file_name}")

    message(STATUS "Downloading ASIO SDK")
    file(DOWNLOAD "${asio_download_root}/${asio_file_name}" ${asio_output_path})
    file(SHA1 ${asio_output_path} asio_zip_hash)
    message("   ASIO SDK SHA1: ${asio_zip_hash}")

    message("   Extracting ASIO SDK")
    execute_process(COMMAND ${CMAKE_COMMAND} -E tar "xf" ${asio_output_path} --format=zip
      WORKING_DIRECTORY ${asio_working_dir}
      INPUT_FILE ${asio_output_path}
    )

    # Set the ASIO SDK path for the caller
    set(${asio_sdk_path_OUT} "${asio_working_dir}/${asio_dir_name}" PARENT_SCOPE)
  endfunction()
endif()

#     _             _ _
#    / \  _   _  __| (_) ___
#   / _ \| | | |/ _` | |/ _ \
#  / ___ \ |_| | (_| | | (_) |
# /_/   \_\__,_|\__,_|_|\___/
#

set(linkhut_audio_SOURCES)

if(APPLE)
  set(linkhut_audio_SOURCES
    linkaudio/AudioPlatform_CoreAudio.hpp
    linkaudio/AudioPlatform_CoreAudio.cpp
  )
elseif(WIN32)
  if(LINK_BUILD_ASIO)
    configure_asio(asio_sdk_path)

    include_directories(${asio_sdk_path}/common)
    include_directories(${asio_sdk_path}/host)
    include_directories(${asio_sdk_path}/host/pc)

    set(linkhut_audio_SOURCES
      ${asio_sdk_path}/common/asio.cpp
      ${asio_sdk_path}/host/asiodrivers.cpp
      ${asio_sdk_path}/host/pc/asiolist.cpp
      linkaudio/AudioPlatform_Asio.hpp
      linkaudio/AudioPlatform_Asio.cpp
    )
  else()
    message(WARNING "LinkHut has been configured to be built with the WASAPI audio "
      "driver. This driver is considered experimental and has problems with low-latency "
      "playback. Please consider using the ASIO driver instead.")
    set(linkhut_audio_SOURCES
      linkaudio/AudioPlatform_Wasapi.hpp
      linkaudio/AudioPlatform_Wasapi.cpp
    )
  endif()
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
  set(linkhut_audio_SOURCES
    linkaudio/AudioPlatform_Portaudio.hpp
    linkaudio/AudioPlatform_Portaudio.cpp
  )
endif()

include_directories(linkaudio)
source_group("Audio Sources" FILES ${linkhut_audio_SOURCES})

#   ____
#  / ___|___  _ __ ___  _ __ ___   ___  _ __
# | |   / _ \| '_ ` _ \| '_ ` _ \ / _ \| '_ \
# | |__| (_) | | | | | | | | | | | (_) | | | |
#  \____\___/|_| |_| |_|_| |_| |_|\___/|_| |_|
#

function(configure_linkhut_executable target)
  if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
    target_link_libraries(${target} pthread)
  endif()

  target_link_libraries(${target} Ableton::Link)

  target_set_word_size(${target})
endfunction()

function(configure_linkhut_audio_sources target)
  if(APPLE)
    target_link_libraries(${target} "-framework AudioUnit")
    target_compile_definitions(${target} PRIVATE
      -DLINKHUT_AUDIO_PLATFORM_COREAUDIO=1
    )
  elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
    target_link_libraries(${target} asound portaudio)
    target_compile_definitions(${target} PRIVATE
      -DLINKHUT_AUDIO_PLATFORM_PORTAUDIO=1
    )
  elseif(WIN32)
    if(LINK_BUILD_ASIO)
      # ASIO uses lots of old-school string APIs from the C stdlib
      add_definitions("/D_CRT_SECURE_NO_WARNINGS")
      target_compile_definitions(${target} PRIVATE
        -DLINKHUT_AUDIO_PLATFORM_ASIO=1
      )
    else()
      target_compile_definitions(${target} PRIVATE
        -DLINKHUT_AUDIO_PLATFORM_WASAPI=1
      )
      endif()

    target_link_libraries(${target} winmm)
  endif()

endfunction()

if(WIN32)
  # When building LinkHut, additional warnings are generated from third-party frameworks
  set(extra_ignored_warnings_LIST
    "/wd4127" # conditional expression is constant
    "/wd4702" # unreachable code
  )
  if(LINK_BUILD_ASIO)
    set(extra_ignored_warnings_LIST
      ${extra_ignored_warnings_LIST}
      "/wd4267" # 'argument': conversion from '?' to '?', possible loss of data
      "/wd4477" # 'printf': format string '%?' requires an argument of type '?'
    )
  endif()
  string(REPLACE ";" " " extra_ignored_warnings "${extra_ignored_warnings_LIST}")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${extra_ignored_warnings}")
endif()

#  _     _       _    _   _       _
# | |   (_)_ __ | | _| | | |_   _| |_
# | |   | | '_ \| |/ / |_| | | | | __|
# | |___| | | | |   <|  _  | |_| | |_
# |_____|_|_| |_|_|\_\_| |_|\__,_|\__|
#

set(linkhut_HEADERS
  linkaudio/AudioEngine.hpp
  linkaudio/AudioPlatform.hpp
  ${link_HEADERS}
)

set(linkhut_SOURCES
  linkaudio/AudioEngine.cpp
  linkhut/main.cpp
)

add_executable(LinkHut
  ${linkhut_HEADERS}
  ${linkhut_SOURCES}
  ${linkhut_audio_SOURCES}
)
configure_linkhut_audio_sources(LinkHut)
configure_linkhut_executable(LinkHut)
source_group("LinkHut" FILES ${linkhut_HEADERS} ${linkhut_SOURCES})

#   ___  _     _       _    _   _       _
#  / _ \| |   (_)_ __ | | _| | | |_   _| |_
# | | | | |   | | '_ \| |/ / |_| | | | | __|
# | |_| | |___| | | | |   <|  _  | |_| | |_
#  \__\_\_____|_|_| |_|_|\_\_| |_|\__,_|\__|
#

if(LINK_BUILD_QT_EXAMPLES)

  set(CMAKE_AUTOMOC ON)
  set(CMAKE_INCLUDE_CURRENT_DIR ON)

  find_package(Qt5Quick REQUIRED)

  set(qlinkhut_HEADERS
    linkaudio/AudioEngine.hpp
    linkaudio/AudioPlatform.hpp
    qlinkhut/Controller.hpp
    ${link_HEADERS}
  )

  set(qlinkhut_SOURCES
    linkaudio/AudioEngine.cpp
    qlinkhut/Controller.cpp
    qlinkhut/main.cpp
    ${link_SOURCES}
  )
  source_group("QLinkHut" FILES ${qlinkhut_HEADERS} ${qlinkhut_SOURCES})
  qt5_add_resources(UI_RESOURCES qlinkhut/resources.qrc)

  add_executable(QLinkHut
    ${qlinkhut_HEADERS}
    ${qlinkhut_SOURCES}
    ${linkhut_audio_SOURCES}
    ${UI_RESOURCES}
  )
  target_link_libraries(QLinkHut Qt5::Quick)
  configure_linkhut_audio_sources(QLinkHut)
  configure_linkhut_executable(QLinkHut)

  # A silent version of QLinkHut that uses the Link application context instead of
  # the audio buffer context. It is the same as QLinkHut except that it doesn't
  # generate sound.

  add_executable(QLinkHutSilent
    ${qlinkhut_HEADERS}
    ${qlinkhut_SOURCES}
    linkaudio/AudioPlatform_Dummy.hpp
    ${UI_RESOURCES}
  )
  target_link_libraries(QLinkHutSilent Qt5::Quick)

  target_compile_definitions(QLinkHutSilent PRIVATE
    -DLINKHUT_AUDIO_PLATFORM_DUMMY=1
  )
  if(UNIX)
    set_target_properties(QLinkHutSilent
      PROPERTIES
      COMPILE_FLAGS "-Wno-unused"
    )
  endif()

  configure_linkhut_executable(QLinkHutSilent)
endif()
