diff --git a/CMakeLists.txt b/CMakeLists.txt index f31f64c24..4674a6309 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,12 @@ if(WIN32) - cmake_minimum_required(VERSION 3.15) + cmake_minimum_required(VERSION 3.19) cmake_policy(SET CMP0091 NEW) else() - # USE_LIBCPP requires add_link_options() in SfizzConfig.cmake - cmake_minimum_required(VERSION 3.13) + cmake_minimum_required(VERSION 3.19) endif() project(libsfizz - LANGUAGES CXX C + LANGUAGES CXX C ASM VERSION 1.2.3 ) set(PROJECT_DESCRIPTION "A library to load SFZ description files and use them to render music.") @@ -23,34 +22,34 @@ include(OptionEx) set(BUILD_TESTING OFF CACHE BOOL "Disable Abseil's tests [default: OFF]") -option_ex(ENABLE_LTO "Enable Link Time Optimization" ON) -option_ex(SFIZZ_JACK "Enable JACK stand-alone build" CMAKE_SYSTEM_NAME STREQUAL "Linux") -option_ex(SFIZZ_RENDER "Enable renderer of SMF files" ON) -option_ex(SFIZZ_BENCHMARKS "Enable benchmarks build" OFF) -option_ex(SFIZZ_TESTS "Enable tests build" OFF) -option_ex(SFIZZ_DEMOS "Enable feature demos build" OFF) -option_ex(SFIZZ_DEVTOOLS "Enable developer tools build" OFF) -option_ex(SFIZZ_SHARED "Enable shared library build" ON) -option_ex(SFIZZ_USE_SNDFILE "Enable use of the sndfile library" OFF) -option_ex(SFIZZ_USE_SYSTEM_ABSEIL "Use Abseil libraries preinstalled on system" OFF) -option_ex(SFIZZ_USE_SYSTEM_GHC_FS "Use GHC Filesystem libraries preinstalled on system" OFF) -option_ex(SFIZZ_USE_SYSTEM_SIMDE "Use SIMDe libraries preinstalled on system" OFF) -option_ex(SFIZZ_USE_SYSTEM_KISS_FFT "Use KISS FFT libraries preinstalled on system" OFF) -option_ex(SFIZZ_USE_SYSTEM_PUGIXML "Use pugixml libraries preinstalled on system" OFF) -option_ex(SFIZZ_USE_SYSTEM_CXXOPTS "Use CXXOPTS libraries preinstalled on system" OFF) -option_ex(SFIZZ_USE_SYSTEM_CATCH "Use Catch libraries preinstalled on system" OFF) -option_ex(SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds" OFF) -option_ex(SFIZZ_PROFILE_BUILD "Profile the build time" OFF) -option_ex(SFIZZ_SNDFILE_STATIC "Link the sndfile library statically" OFF) -option_ex(SFIZZ_ASAN "Use address sanitizer on all sfizz targets" OFF) -option_ex(SFIZZ_GIT_SUBMODULE_CHECK "Check Git submodules presence" ON) +option_ex(ENABLE_LTO "Enable Link Time Optimization" ON) +option_ex(SFIZZ_JACK "Enable JACK stand-alone build" CMAKE_SYSTEM_NAME STREQUAL "Linux") +option_ex(SFIZZ_RENDER "Enable renderer of SMF files" ON) +option_ex(SFIZZ_BENCHMARKS "Enable benchmarks build" OFF) +option_ex(SFIZZ_TESTS "Enable tests build" OFF) +option_ex(SFIZZ_DEMOS "Enable feature demos build" OFF) +option_ex(SFIZZ_DEVTOOLS "Enable developer tools build" OFF) +option_ex(SFIZZ_SHARED "Enable shared library build" ON) +option_ex(SFIZZ_DOWNLOAD_DEPENDENCIES_ONLY "Only download dependencies in the CPM cache if needed" OFF) +option_ex(SFIZZ_USE_SNDFILE "Enable use of the sndfile library" OFF) +option_ex(SFIZZ_USE_SYSTEM_ABSEIL "Use Abseil libraries preinstalled on system" OFF) +option_ex(SFIZZ_USE_SYSTEM_GHC_FS "Use GHC Filesystem libraries preinstalled on system" OFF) +option_ex(SFIZZ_USE_SYSTEM_SIMDE "Use SIMDe libraries preinstalled on system" OFF) +option_ex(SFIZZ_USE_SYSTEM_KISS_FFT "Use KISS FFT libraries preinstalled on system" OFF) +option_ex(SFIZZ_USE_SYSTEM_PUGIXML "Use pugixml libraries preinstalled on system" OFF) +option_ex(SFIZZ_USE_SYSTEM_CXXOPTS "Use CXXOPTS libraries preinstalled on system" OFF) +option_ex(SFIZZ_USE_SYSTEM_CATCH "Use Catch libraries preinstalled on system" OFF) +option_ex(SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds" OFF) +option_ex(SFIZZ_PROFILE_BUILD "Profile the build time" OFF) +option_ex(SFIZZ_SNDFILE_STATIC "Link the sndfile library statically" OFF) +option_ex(SFIZZ_ASAN "Use address sanitizer on all sfizz targets" OFF) +option_ex(SFIZZ_GIT_SUBMODULE_CHECK "Check Git submodules presence" ON) # Continuous Controller count (0 to 511) set(MIDI_CC_COUNT 512 CACHE STRING "Maximum number of managed Control Change messages") # Ensure presence of Git submodules (when not using the source tarball) -if(SFIZZ_GIT_SUBMODULE_CHECK AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git" - AND NOT CMAKE_VERSION VERSION_LESS "3.19.0") +if(SFIZZ_GIT_SUBMODULE_CHECK AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") include(GitSubmoduleCheck) git_submodule_check(external/abseil-cpp) git_submodule_check(external/filesystem) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 000000000..fe9a370a2 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,69 @@ +{ + "version": 6, + "cmakeMinimumRequired": { + "major": 3, + "minor": 23, + "patch": 0 + }, + "configurePresets": [ + { + "name": "base", + "hidden": true, + "displayName": "Base Configuration", + "description": "Default build using Ninja generator", + "generator": "Ninja Multi-Config", + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "SFIZZ_TESTS": "OFF", + "SFIZZ_JACK": "OFF", + "SFIZZ_RENDER": "ON" + } + }, + { + "name": "ci", + "hidden": true, + "displayName": "Base Configuration", + "description": "Common CI configurations", + "cacheVariables": { + "SFIZZ_USE_SYSTEM_ABSEIL": "ON" + } + }, + { + "name": "windows", + "displayName": "Windows", + "description": "Windows builds", + "inherits": "base", + "toolchainFile": "${sourceDir}/cmake/Windows.MSVC.toolchain.cmake" + }, + { + "name": "windows-test", + "displayName": "Windows Tests", + "description": "Windows builds with tests", + "inherits": "windows", + "cacheVariables": { + "SFIZZ_TESTS": "ON" + } + }, + { + "name": "linux", + "displayName": "Linux", + "description": "Linux builds", + "inherits": "base" + }, + { + "name": "linux-test", + "displayName": "Linux Tests", + "description": "Linux builds with tests", + "inherits": "linux", + "cacheVariables": { + "SFIZZ_TESTS": "ON" + } + }, + { + "name": "linux-ci", + "displayName": "Linux CI", + "description": "Linux CI builds", + "inherits": ["linux-test" , "ci"] + } + ] + } diff --git a/Testing/Temporary/CTestCostData.txt b/Testing/Temporary/CTestCostData.txt new file mode 100644 index 000000000..ed97d539c --- /dev/null +++ b/Testing/Temporary/CTestCostData.txt @@ -0,0 +1 @@ +--- diff --git a/Testing/Temporary/LastTest.log b/Testing/Temporary/LastTest.log new file mode 100644 index 000000000..03543b558 --- /dev/null +++ b/Testing/Temporary/LastTest.log @@ -0,0 +1,3 @@ +Start testing: Oct 29 13:32 Romance Standard Time +---------------------------------------------------------- +End testing: Oct 29 13:32 Romance Standard Time diff --git a/clients/CMakeLists.txt b/clients/CMakeLists.txt index 9346c29f6..33995e654 100644 --- a/clients/CMakeLists.txt +++ b/clients/CMakeLists.txt @@ -25,7 +25,7 @@ endif() if(SFIZZ_RENDER) add_executable(sfizz_render MidiHelpers.h sfizz_render.cpp) target_link_libraries(sfizz_render PRIVATE - sfizz::cxxopts + cxxopts::cxxopts sfizz::fmidi sfizz::internal st_audiofile_formats diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake new file mode 100644 index 000000000..e3453b577 --- /dev/null +++ b/cmake/CPM.cmake @@ -0,0 +1,1272 @@ +# CPM.cmake - CMake's missing package manager +# =========================================== +# See https://github.com/cpm-cmake/CPM.cmake for usage and update instructions. +# +# MIT License +# ----------- +#[[ + Copyright (c) 2019-2023 Lars Melchior and contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +]] + +cmake_minimum_required(VERSION 3.14 FATAL_ERROR) + +# Initialize logging prefix +if(NOT CPM_INDENT) + set(CPM_INDENT + "CPM:" + CACHE INTERNAL "" + ) +endif() + +if(NOT COMMAND cpm_message) + function(cpm_message) + message(${ARGV}) + endfunction() +endif() + +set(CURRENT_CPM_VERSION 0.40.2) + +get_filename_component(CPM_CURRENT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" REALPATH) +if(CPM_DIRECTORY) + if(NOT CPM_DIRECTORY STREQUAL CPM_CURRENT_DIRECTORY) + if(CPM_VERSION VERSION_LESS CURRENT_CPM_VERSION) + message( + AUTHOR_WARNING + "${CPM_INDENT} \ +A dependency is using a more recent CPM version (${CURRENT_CPM_VERSION}) than the current project (${CPM_VERSION}). \ +It is recommended to upgrade CPM to the most recent version. \ +See https://github.com/cpm-cmake/CPM.cmake for more information." + ) + endif() + if(${CMAKE_VERSION} VERSION_LESS "3.17.0") + include(FetchContent) + endif() + return() + endif() + + get_property( + CPM_INITIALIZED GLOBAL "" + PROPERTY CPM_INITIALIZED + SET + ) + if(CPM_INITIALIZED) + return() + endif() +endif() + +if(CURRENT_CPM_VERSION MATCHES "development-version") + message( + WARNING "${CPM_INDENT} Your project is using an unstable development version of CPM.cmake. \ +Please update to a recent release if possible. \ +See https://github.com/cpm-cmake/CPM.cmake for details." + ) +endif() + +set_property(GLOBAL PROPERTY CPM_INITIALIZED true) + +macro(cpm_set_policies) + # the policy allows us to change options without caching + cmake_policy(SET CMP0077 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + + # the policy allows us to change set(CACHE) without caching + if(POLICY CMP0126) + cmake_policy(SET CMP0126 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0126 NEW) + endif() + + # The policy uses the download time for timestamp, instead of the timestamp in the archive. This + # allows for proper rebuilds when a projects url changes + if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0135 NEW) + endif() + + # treat relative git repository paths as being relative to the parent project's remote + if(POLICY CMP0150) + cmake_policy(SET CMP0150 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0150 NEW) + endif() +endmacro() +cpm_set_policies() + +option(CPM_USE_LOCAL_PACKAGES "Always try to use `find_package` to get dependencies" + $ENV{CPM_USE_LOCAL_PACKAGES} +) +option(CPM_LOCAL_PACKAGES_ONLY "Only use `find_package` to get dependencies" + $ENV{CPM_LOCAL_PACKAGES_ONLY} +) +option(CPM_DOWNLOAD_ALL "Always download dependencies from source" $ENV{CPM_DOWNLOAD_ALL}) +option(CPM_DONT_UPDATE_MODULE_PATH "Don't update the module path to allow using find_package" + $ENV{CPM_DONT_UPDATE_MODULE_PATH} +) +option(CPM_DONT_CREATE_PACKAGE_LOCK "Don't create a package lock file in the binary path" + $ENV{CPM_DONT_CREATE_PACKAGE_LOCK} +) +option(CPM_INCLUDE_ALL_IN_PACKAGE_LOCK + "Add all packages added through CPM.cmake to the package lock" + $ENV{CPM_INCLUDE_ALL_IN_PACKAGE_LOCK} +) +option(CPM_USE_NAMED_CACHE_DIRECTORIES + "Use additional directory of package name in cache on the most nested level." + $ENV{CPM_USE_NAMED_CACHE_DIRECTORIES} +) + +set(CPM_VERSION + ${CURRENT_CPM_VERSION} + CACHE INTERNAL "" +) +set(CPM_DIRECTORY + ${CPM_CURRENT_DIRECTORY} + CACHE INTERNAL "" +) +set(CPM_FILE + ${CMAKE_CURRENT_LIST_FILE} + CACHE INTERNAL "" +) +set(CPM_PACKAGES + "" + CACHE INTERNAL "" +) +set(CPM_DRY_RUN + OFF + CACHE INTERNAL "Don't download or configure dependencies (for testing)" +) + +if(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE}) +else() + set(CPM_SOURCE_CACHE_DEFAULT OFF) +endif() + +set(CPM_SOURCE_CACHE + ${CPM_SOURCE_CACHE_DEFAULT} + CACHE PATH "Directory to download CPM dependencies" +) + +if(NOT CPM_DONT_UPDATE_MODULE_PATH) + set(CPM_MODULE_PATH + "${CMAKE_BINARY_DIR}/CPM_modules" + CACHE INTERNAL "" + ) + # remove old modules + file(REMOVE_RECURSE ${CPM_MODULE_PATH}) + file(MAKE_DIRECTORY ${CPM_MODULE_PATH}) + # locally added CPM modules should override global packages + set(CMAKE_MODULE_PATH "${CPM_MODULE_PATH};${CMAKE_MODULE_PATH}") +endif() + +if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + set(CPM_PACKAGE_LOCK_FILE + "${CMAKE_BINARY_DIR}/cpm-package-lock.cmake" + CACHE INTERNAL "" + ) + file(WRITE ${CPM_PACKAGE_LOCK_FILE} + "# CPM Package Lock\n# This file should be committed to version control\n\n" + ) +endif() + +include(FetchContent) + +# Try to infer package name from git repository uri (path or url) +function(cpm_package_name_from_git_uri URI RESULT) + if("${URI}" MATCHES "([^/:]+)/?.git/?$") + set(${RESULT} + ${CMAKE_MATCH_1} + PARENT_SCOPE + ) + else() + unset(${RESULT} PARENT_SCOPE) + endif() +endfunction() + +# Try to infer package name and version from a url +function(cpm_package_name_and_ver_from_url url outName outVer) + if(url MATCHES "[/\\?]([a-zA-Z0-9_\\.-]+)\\.(tar|tar\\.gz|tar\\.bz2|zip|ZIP)(\\?|/|$)") + # We matched an archive + set(filename "${CMAKE_MATCH_1}") + + if(filename MATCHES "([a-zA-Z0-9_\\.-]+)[_-]v?(([0-9]+\\.)*[0-9]+[a-zA-Z0-9]*)") + # We matched - (ie foo-1.2.3) + set(${outName} + "${CMAKE_MATCH_1}" + PARENT_SCOPE + ) + set(${outVer} + "${CMAKE_MATCH_2}" + PARENT_SCOPE + ) + elseif(filename MATCHES "(([0-9]+\\.)+[0-9]+[a-zA-Z0-9]*)") + # We couldn't find a name, but we found a version + # + # In many cases (which we don't handle here) the url would look something like + # `irrelevant/ACTUAL_PACKAGE_NAME/irrelevant/1.2.3.zip`. In such a case we can't possibly + # distinguish the package name from the irrelevant bits. Moreover if we try to match the + # package name from the filename, we'd get bogus at best. + unset(${outName} PARENT_SCOPE) + set(${outVer} + "${CMAKE_MATCH_1}" + PARENT_SCOPE + ) + else() + # Boldly assume that the file name is the package name. + # + # Yes, something like `irrelevant/ACTUAL_NAME/irrelevant/download.zip` will ruin our day, but + # such cases should be quite rare. No popular service does this... we think. + set(${outName} + "${filename}" + PARENT_SCOPE + ) + unset(${outVer} PARENT_SCOPE) + endif() + else() + # No ideas yet what to do with non-archives + unset(${outName} PARENT_SCOPE) + unset(${outVer} PARENT_SCOPE) + endif() +endfunction() + +function(cpm_find_package NAME VERSION) + string(REPLACE " " ";" EXTRA_ARGS "${ARGN}") + find_package(${NAME} ${VERSION} ${EXTRA_ARGS} QUIET) + if(${CPM_ARGS_NAME}_FOUND) + if(DEFINED ${CPM_ARGS_NAME}_VERSION) + set(VERSION ${${CPM_ARGS_NAME}_VERSION}) + endif() + cpm_message(STATUS "${CPM_INDENT} Using local package ${CPM_ARGS_NAME}@${VERSION}") + CPMRegisterPackage(${CPM_ARGS_NAME} "${VERSION}") + set(CPM_PACKAGE_FOUND + YES + PARENT_SCOPE + ) + else() + set(CPM_PACKAGE_FOUND + NO + PARENT_SCOPE + ) + endif() +endfunction() + +# Create a custom FindXXX.cmake module for a CPM package This prevents `find_package(NAME)` from +# finding the system library +function(cpm_create_module_file Name) + if(NOT CPM_DONT_UPDATE_MODULE_PATH) + # erase any previous modules + file(WRITE ${CPM_MODULE_PATH}/Find${Name}.cmake + "include(\"${CPM_FILE}\")\n${ARGN}\nset(${Name}_FOUND TRUE)" + ) + endif() +endfunction() + +# Find a package locally or fallback to CPMAddPackage +function(CPMFindPackage) + set(oneValueArgs NAME VERSION GIT_TAG FIND_PACKAGE_ARGUMENTS LOCAL_REQUIRED) + + cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "" ${ARGN}) + + if(NOT DEFINED CPM_ARGS_VERSION) + if(DEFINED CPM_ARGS_GIT_TAG) + cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION) + endif() + endif() + + set(downloadPackage ${CPM_DOWNLOAD_ALL}) + if(DEFINED CPM_DOWNLOAD_${CPM_ARGS_NAME}) + set(downloadPackage ${CPM_DOWNLOAD_${CPM_ARGS_NAME}}) + elseif(DEFINED ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}}) + set(downloadPackage $ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}}) + endif() + if(downloadPackage) + CPMAddPackage(${ARGN}) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS}) + + if(NOT CPM_PACKAGE_FOUND) + if(CPM_ARGS_LOCAL_REQUIRED) + message(FATAL_ERROR "Could not find required ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION} locally") + endif() + CPMAddPackage(${ARGN}) + cpm_export_variables(${CPM_ARGS_NAME}) + endif() + +endfunction() + +# checks if a package has been added before +function(cpm_check_if_package_already_added CPM_ARGS_NAME CPM_ARGS_VERSION) + if("${CPM_ARGS_NAME}" IN_LIST CPM_PACKAGES) + CPMGetPackageVersion(${CPM_ARGS_NAME} CPM_PACKAGE_VERSION) + if("${CPM_PACKAGE_VERSION}" VERSION_LESS "${CPM_ARGS_VERSION}") + message( + WARNING + "${CPM_INDENT} Requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION})." + ) + endif() + cpm_get_fetch_properties(${CPM_ARGS_NAME}) + set(${CPM_ARGS_NAME}_ADDED NO) + set(CPM_PACKAGE_ALREADY_ADDED + YES + PARENT_SCOPE + ) + cpm_export_variables(${CPM_ARGS_NAME}) + else() + set(CPM_PACKAGE_ALREADY_ADDED + NO + PARENT_SCOPE + ) + endif() +endfunction() + +# Parse the argument of CPMAddPackage in case a single one was provided and convert it to a list of +# arguments which can then be parsed idiomatically. For example gh:foo/bar@1.2.3 will be converted +# to: GITHUB_REPOSITORY;foo/bar;VERSION;1.2.3 +function(cpm_parse_add_package_single_arg arg outArgs) + # Look for a scheme + if("${arg}" MATCHES "^([a-zA-Z]+):(.+)$") + string(TOLOWER "${CMAKE_MATCH_1}" scheme) + set(uri "${CMAKE_MATCH_2}") + + # Check for CPM-specific schemes + if(scheme STREQUAL "gh") + set(out "GITHUB_REPOSITORY;${uri}") + set(packageType "git") + elseif(scheme STREQUAL "gl") + set(out "GITLAB_REPOSITORY;${uri}") + set(packageType "git") + elseif(scheme STREQUAL "bb") + set(out "BITBUCKET_REPOSITORY;${uri}") + set(packageType "git") + # A CPM-specific scheme was not found. Looks like this is a generic URL so try to determine + # type + elseif(arg MATCHES ".git/?(@|#|$)") + set(out "GIT_REPOSITORY;${arg}") + set(packageType "git") + else() + # Fall back to a URL + set(out "URL;${arg}") + set(packageType "archive") + + # We could also check for SVN since FetchContent supports it, but SVN is so rare these days. + # We just won't bother with the additional complexity it will induce in this function. SVN is + # done by multi-arg + endif() + else() + if(arg MATCHES ".git/?(@|#|$)") + set(out "GIT_REPOSITORY;${arg}") + set(packageType "git") + else() + # Give up + message(FATAL_ERROR "${CPM_INDENT} Can't determine package type of '${arg}'") + endif() + endif() + + # For all packages we interpret @... as version. Only replace the last occurrence. Thus URIs + # containing '@' can be used + string(REGEX REPLACE "@([^@]+)$" ";VERSION;\\1" out "${out}") + + # Parse the rest according to package type + if(packageType STREQUAL "git") + # For git repos we interpret #... as a tag or branch or commit hash + string(REGEX REPLACE "#([^#]+)$" ";GIT_TAG;\\1" out "${out}") + elseif(packageType STREQUAL "archive") + # For archives we interpret #... as a URL hash. + string(REGEX REPLACE "#([^#]+)$" ";URL_HASH;\\1" out "${out}") + # We don't try to parse the version if it's not provided explicitly. cpm_get_version_from_url + # should do this at a later point + else() + # We should never get here. This is an assertion and hitting it means there's a problem with the + # code above. A packageType was set, but not handled by this if-else. + message(FATAL_ERROR "${CPM_INDENT} Unsupported package type '${packageType}' of '${arg}'") + endif() + + set(${outArgs} + ${out} + PARENT_SCOPE + ) +endfunction() + +# Check that the working directory for a git repo is clean +function(cpm_check_git_working_dir_is_clean repoPath gitTag isClean) + + find_package(Git REQUIRED) + + if(NOT GIT_EXECUTABLE) + # No git executable, assume directory is clean + set(${isClean} + TRUE + PARENT_SCOPE + ) + return() + endif() + + # check for uncommitted changes + execute_process( + COMMAND ${GIT_EXECUTABLE} status --porcelain + RESULT_VARIABLE resultGitStatus + OUTPUT_VARIABLE repoStatus + OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET + WORKING_DIRECTORY ${repoPath} + ) + if(resultGitStatus) + # not supposed to happen, assume clean anyway + message(WARNING "${CPM_INDENT} Calling git status on folder ${repoPath} failed") + set(${isClean} + TRUE + PARENT_SCOPE + ) + return() + endif() + + if(NOT "${repoStatus}" STREQUAL "") + set(${isClean} + FALSE + PARENT_SCOPE + ) + return() + endif() + + # check for committed changes + execute_process( + COMMAND ${GIT_EXECUTABLE} diff -s --exit-code ${gitTag} + RESULT_VARIABLE resultGitDiff + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_QUIET + WORKING_DIRECTORY ${repoPath} + ) + + if(${resultGitDiff} EQUAL 0) + set(${isClean} + TRUE + PARENT_SCOPE + ) + else() + set(${isClean} + FALSE + PARENT_SCOPE + ) + endif() + +endfunction() + +# Add PATCH_COMMAND to CPM_ARGS_UNPARSED_ARGUMENTS. This method consumes a list of files in ARGN +# then generates a `PATCH_COMMAND` appropriate for `ExternalProject_Add()`. This command is appended +# to the parent scope's `CPM_ARGS_UNPARSED_ARGUMENTS`. +function(cpm_add_patches) + # Return if no patch files are supplied. + if(NOT ARGN) + return() + endif() + + # Find the patch program. + find_program(PATCH_EXECUTABLE patch) + if(WIN32 AND NOT PATCH_EXECUTABLE) + # The Windows git executable is distributed with patch.exe. Find the path to the executable, if + # it exists, then search `../usr/bin` and `../../usr/bin` for patch.exe. + find_package(Git QUIET) + if(GIT_EXECUTABLE) + get_filename_component(extra_search_path ${GIT_EXECUTABLE} DIRECTORY) + get_filename_component(extra_search_path_1up ${extra_search_path} DIRECTORY) + get_filename_component(extra_search_path_2up ${extra_search_path_1up} DIRECTORY) + find_program( + PATCH_EXECUTABLE patch HINTS "${extra_search_path_1up}/usr/bin" + "${extra_search_path_2up}/usr/bin" + ) + endif() + endif() + if(NOT PATCH_EXECUTABLE) + message(FATAL_ERROR "Couldn't find `patch` executable to use with PATCHES keyword.") + endif() + + # Create a temporary + set(temp_list ${CPM_ARGS_UNPARSED_ARGUMENTS}) + + # Ensure each file exists (or error out) and add it to the list. + set(first_item True) + foreach(PATCH_FILE ${ARGN}) + # Make sure the patch file exists, if we can't find it, try again in the current directory. + if(NOT EXISTS "${PATCH_FILE}") + if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${PATCH_FILE}") + message(FATAL_ERROR "Couldn't find patch file: '${PATCH_FILE}'") + endif() + set(PATCH_FILE "${CMAKE_CURRENT_LIST_DIR}/${PATCH_FILE}") + endif() + + # Convert to absolute path for use with patch file command. + get_filename_component(PATCH_FILE "${PATCH_FILE}" ABSOLUTE) + + # The first patch entry must be preceded by "PATCH_COMMAND" while the following items are + # preceded by "&&". + if(first_item) + set(first_item False) + list(APPEND temp_list "PATCH_COMMAND") + else() + list(APPEND temp_list "&&") + endif() + # Add the patch command to the list + list(APPEND temp_list "${PATCH_EXECUTABLE}" "-p1" "<" "${PATCH_FILE}") + endforeach() + + # Move temp out into parent scope. + set(CPM_ARGS_UNPARSED_ARGUMENTS + ${temp_list} + PARENT_SCOPE + ) + +endfunction() + +# method to overwrite internal FetchContent properties, to allow using CPM.cmake to overload +# FetchContent calls. As these are internal cmake properties, this method should be used carefully +# and may need modification in future CMake versions. Source: +# https://github.com/Kitware/CMake/blob/dc3d0b5a0a7d26d43d6cfeb511e224533b5d188f/Modules/FetchContent.cmake#L1152 +function(cpm_override_fetchcontent contentName) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "SOURCE_DIR;BINARY_DIR" "") + if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "${CPM_INDENT} Unsupported arguments: ${arg_UNPARSED_ARGUMENTS}") + endif() + + string(TOLOWER ${contentName} contentNameLower) + set(prefix "_FetchContent_${contentNameLower}") + + set(propertyName "${prefix}_sourceDir") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} "${arg_SOURCE_DIR}") + + set(propertyName "${prefix}_binaryDir") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} "${arg_BINARY_DIR}") + + set(propertyName "${prefix}_populated") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} TRUE) +endfunction() + +# Download and add a package from source +function(CPMAddPackage) + cpm_set_policies() + + list(LENGTH ARGN argnLength) + if(argnLength EQUAL 1) + cpm_parse_add_package_single_arg("${ARGN}" ARGN) + + # The shorthand syntax implies EXCLUDE_FROM_ALL and SYSTEM + set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;") + endif() + + set(oneValueArgs + NAME + FORCE + VERSION + GIT_TAG + DOWNLOAD_ONLY + GITHUB_REPOSITORY + GITLAB_REPOSITORY + BITBUCKET_REPOSITORY + GIT_REPOSITORY + SOURCE_DIR + FIND_PACKAGE_ARGUMENTS + NO_CACHE + SYSTEM + GIT_SHALLOW + EXCLUDE_FROM_ALL + SOURCE_SUBDIR + CUSTOM_CACHE_KEY + ) + + set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND PATCHES) + + cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}") + + # Set default values for arguments + + if(NOT DEFINED CPM_ARGS_VERSION) + if(DEFINED CPM_ARGS_GIT_TAG) + cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION) + endif() + endif() + + if(CPM_ARGS_DOWNLOAD_ONLY) + set(DOWNLOAD_ONLY ${CPM_ARGS_DOWNLOAD_ONLY}) + else() + set(DOWNLOAD_ONLY NO) + endif() + + if(DEFINED CPM_ARGS_GITHUB_REPOSITORY) + set(CPM_ARGS_GIT_REPOSITORY "https://github.com/${CPM_ARGS_GITHUB_REPOSITORY}.git") + elseif(DEFINED CPM_ARGS_GITLAB_REPOSITORY) + set(CPM_ARGS_GIT_REPOSITORY "https://gitlab.com/${CPM_ARGS_GITLAB_REPOSITORY}.git") + elseif(DEFINED CPM_ARGS_BITBUCKET_REPOSITORY) + set(CPM_ARGS_GIT_REPOSITORY "https://bitbucket.org/${CPM_ARGS_BITBUCKET_REPOSITORY}.git") + endif() + + if(DEFINED CPM_ARGS_GIT_REPOSITORY) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_REPOSITORY ${CPM_ARGS_GIT_REPOSITORY}) + if(NOT DEFINED CPM_ARGS_GIT_TAG) + set(CPM_ARGS_GIT_TAG v${CPM_ARGS_VERSION}) + endif() + + # If a name wasn't provided, try to infer it from the git repo + if(NOT DEFINED CPM_ARGS_NAME) + cpm_package_name_from_git_uri(${CPM_ARGS_GIT_REPOSITORY} CPM_ARGS_NAME) + endif() + endif() + + set(CPM_SKIP_FETCH FALSE) + + if(DEFINED CPM_ARGS_GIT_TAG) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_TAG ${CPM_ARGS_GIT_TAG}) + # If GIT_SHALLOW is explicitly specified, honor the value. + if(DEFINED CPM_ARGS_GIT_SHALLOW) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW ${CPM_ARGS_GIT_SHALLOW}) + endif() + endif() + + if(DEFINED CPM_ARGS_URL) + # If a name or version aren't provided, try to infer them from the URL + list(GET CPM_ARGS_URL 0 firstUrl) + cpm_package_name_and_ver_from_url(${firstUrl} nameFromUrl verFromUrl) + # If we fail to obtain name and version from the first URL, we could try other URLs if any. + # However multiple URLs are expected to be quite rare, so for now we won't bother. + + # If the caller provided their own name and version, they trump the inferred ones. + if(NOT DEFINED CPM_ARGS_NAME) + set(CPM_ARGS_NAME ${nameFromUrl}) + endif() + if(NOT DEFINED CPM_ARGS_VERSION) + set(CPM_ARGS_VERSION ${verFromUrl}) + endif() + + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS URL "${CPM_ARGS_URL}") + endif() + + # Check for required arguments + + if(NOT DEFINED CPM_ARGS_NAME) + message( + FATAL_ERROR + "${CPM_INDENT} 'NAME' was not provided and couldn't be automatically inferred for package added with arguments: '${ARGN}'" + ) + endif() + + # Check if package has been added before + cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}") + if(CPM_PACKAGE_ALREADY_ADDED) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + # Check for manual overrides + if(NOT CPM_ARGS_FORCE AND NOT "${CPM_${CPM_ARGS_NAME}_SOURCE}" STREQUAL "") + set(PACKAGE_SOURCE ${CPM_${CPM_ARGS_NAME}_SOURCE}) + set(CPM_${CPM_ARGS_NAME}_SOURCE "") + CPMAddPackage( + NAME "${CPM_ARGS_NAME}" + SOURCE_DIR "${PACKAGE_SOURCE}" + EXCLUDE_FROM_ALL "${CPM_ARGS_EXCLUDE_FROM_ALL}" + SYSTEM "${CPM_ARGS_SYSTEM}" + PATCHES "${CPM_ARGS_PATCHES}" + OPTIONS "${CPM_ARGS_OPTIONS}" + SOURCE_SUBDIR "${CPM_ARGS_SOURCE_SUBDIR}" + DOWNLOAD_ONLY "${DOWNLOAD_ONLY}" + FORCE True + ) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + # Check for available declaration + if(NOT CPM_ARGS_FORCE AND NOT "${CPM_DECLARATION_${CPM_ARGS_NAME}}" STREQUAL "") + set(declaration ${CPM_DECLARATION_${CPM_ARGS_NAME}}) + set(CPM_DECLARATION_${CPM_ARGS_NAME} "") + CPMAddPackage(${declaration}) + cpm_export_variables(${CPM_ARGS_NAME}) + # checking again to ensure version and option compatibility + cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}") + return() + endif() + + if(NOT CPM_ARGS_FORCE) + if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY) + cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS}) + + if(CPM_PACKAGE_FOUND) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + if(CPM_LOCAL_PACKAGES_ONLY) + message( + SEND_ERROR + "${CPM_INDENT} ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})" + ) + endif() + endif() + endif() + + CPMRegisterPackage("${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}") + + if(DEFINED CPM_ARGS_GIT_TAG) + set(PACKAGE_INFO "${CPM_ARGS_GIT_TAG}") + elseif(DEFINED CPM_ARGS_SOURCE_DIR) + set(PACKAGE_INFO "${CPM_ARGS_SOURCE_DIR}") + else() + set(PACKAGE_INFO "${CPM_ARGS_VERSION}") + endif() + + if(DEFINED FETCHCONTENT_BASE_DIR) + # respect user's FETCHCONTENT_BASE_DIR if set + set(CPM_FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR}) + else() + set(CPM_FETCHCONTENT_BASE_DIR ${CMAKE_BINARY_DIR}/_deps) + endif() + + cpm_add_patches(${CPM_ARGS_PATCHES}) + + if(DEFINED CPM_ARGS_DOWNLOAD_COMMAND) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND}) + elseif(DEFINED CPM_ARGS_SOURCE_DIR) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${CPM_ARGS_SOURCE_DIR}) + if(NOT IS_ABSOLUTE ${CPM_ARGS_SOURCE_DIR}) + # Expand `CPM_ARGS_SOURCE_DIR` relative path. This is important because EXISTS doesn't work + # for relative paths. + get_filename_component( + source_directory ${CPM_ARGS_SOURCE_DIR} REALPATH BASE_DIR ${CMAKE_CURRENT_BINARY_DIR} + ) + else() + set(source_directory ${CPM_ARGS_SOURCE_DIR}) + endif() + if(NOT EXISTS ${source_directory}) + string(TOLOWER ${CPM_ARGS_NAME} lower_case_name) + # remove timestamps so CMake will re-download the dependency + file(REMOVE_RECURSE "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild") + endif() + elseif(CPM_SOURCE_CACHE AND NOT CPM_ARGS_NO_CACHE) + string(TOLOWER ${CPM_ARGS_NAME} lower_case_name) + set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS}) + list(SORT origin_parameters) + if(CPM_ARGS_CUSTOM_CACHE_KEY) + # Application set a custom unique directory name + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${CPM_ARGS_CUSTOM_CACHE_KEY}) + elseif(CPM_USE_NAMED_CACHE_DIRECTORIES) + string(SHA1 origin_hash "${origin_parameters};NEW_CACHE_STRUCTURE_TAG") + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}/${CPM_ARGS_NAME}) + else() + string(SHA1 origin_hash "${origin_parameters}") + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}) + endif() + # Expand `download_directory` relative path. This is important because EXISTS doesn't work for + # relative paths. + get_filename_component(download_directory ${download_directory} ABSOLUTE) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${download_directory}) + + if(CPM_SOURCE_CACHE) + file(LOCK ${download_directory}/../cmake.lock) + endif() + + if(EXISTS ${download_directory}) + if(CPM_SOURCE_CACHE) + file(LOCK ${download_directory}/../cmake.lock RELEASE) + endif() + + cpm_store_fetch_properties( + ${CPM_ARGS_NAME} "${download_directory}" + "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build" + ) + cpm_get_fetch_properties("${CPM_ARGS_NAME}") + + if(DEFINED CPM_ARGS_GIT_TAG AND NOT (PATCH_COMMAND IN_LIST CPM_ARGS_UNPARSED_ARGUMENTS)) + # warn if cache has been changed since checkout + cpm_check_git_working_dir_is_clean(${download_directory} ${CPM_ARGS_GIT_TAG} IS_CLEAN) + if(NOT ${IS_CLEAN}) + message( + WARNING "${CPM_INDENT} Cache for ${CPM_ARGS_NAME} (${download_directory}) is dirty" + ) + endif() + endif() + + cpm_add_subdirectory( + "${CPM_ARGS_NAME}" + "${DOWNLOAD_ONLY}" + "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + "${${CPM_ARGS_NAME}_BINARY_DIR}" + "${CPM_ARGS_EXCLUDE_FROM_ALL}" + "${CPM_ARGS_SYSTEM}" + "${CPM_ARGS_OPTIONS}" + ) + set(PACKAGE_INFO "${PACKAGE_INFO} at ${download_directory}") + + # As the source dir is already cached/populated, we override the call to FetchContent. + set(CPM_SKIP_FETCH TRUE) + cpm_override_fetchcontent( + "${lower_case_name}" SOURCE_DIR "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + BINARY_DIR "${${CPM_ARGS_NAME}_BINARY_DIR}" + ) + + else() + # Enable shallow clone when GIT_TAG is not a commit hash. Our guess may not be accurate, but + # it should guarantee no commit hash get mis-detected. + if(NOT DEFINED CPM_ARGS_GIT_SHALLOW) + cpm_is_git_tag_commit_hash("${CPM_ARGS_GIT_TAG}" IS_HASH) + if(NOT ${IS_HASH}) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW TRUE) + endif() + endif() + + # remove timestamps so CMake will re-download the dependency + file(REMOVE_RECURSE ${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild) + set(PACKAGE_INFO "${PACKAGE_INFO} to ${download_directory}") + endif() + endif() + + cpm_create_module_file(${CPM_ARGS_NAME} "CPMAddPackage(\"${ARGN}\")") + + if(CPM_PACKAGE_LOCK_ENABLED) + if((CPM_ARGS_VERSION AND NOT CPM_ARGS_SOURCE_DIR) OR CPM_INCLUDE_ALL_IN_PACKAGE_LOCK) + cpm_add_to_package_lock(${CPM_ARGS_NAME} "${ARGN}") + elseif(CPM_ARGS_SOURCE_DIR) + cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "local directory") + else() + cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "${ARGN}") + endif() + endif() + + cpm_message( + STATUS "${CPM_INDENT} Adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION} (${PACKAGE_INFO})" + ) + + if(NOT CPM_SKIP_FETCH) + # CMake 3.28 added EXCLUDE, SYSTEM (3.25), and SOURCE_SUBDIR (3.18) to FetchContent_Declare. + # Calling FetchContent_MakeAvailable will then internally forward these options to + # add_subdirectory. Up until these changes, we had to call FetchContent_Populate and + # add_subdirectory separately, which is no longer necessary and has been deprecated as of 3.30. + set(fetchContentDeclareExtraArgs "") + if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.28.0") + if(${CPM_ARGS_EXCLUDE_FROM_ALL}) + list(APPEND fetchContentDeclareExtraArgs EXCLUDE_FROM_ALL) + endif() + if(${CPM_ARGS_SYSTEM}) + list(APPEND fetchContentDeclareExtraArgs SYSTEM) + endif() + if(DEFINED CPM_ARGS_SOURCE_SUBDIR) + list(APPEND fetchContentDeclareExtraArgs SOURCE_SUBDIR ${CPM_ARGS_SOURCE_SUBDIR}) + endif() + # For CMake version <3.28 OPTIONS are parsed in cpm_add_subdirectory + if(CPM_ARGS_OPTIONS AND NOT DOWNLOAD_ONLY) + foreach(OPTION ${CPM_ARGS_OPTIONS}) + cpm_parse_option("${OPTION}") + set(${OPTION_KEY} "${OPTION_VALUE}") + endforeach() + endif() + endif() + cpm_declare_fetch( + "${CPM_ARGS_NAME}" ${fetchContentDeclareExtraArgs} "${CPM_ARGS_UNPARSED_ARGUMENTS}" + ) + + cpm_fetch_package("${CPM_ARGS_NAME}" ${DOWNLOAD_ONLY} populated ${CPM_ARGS_UNPARSED_ARGUMENTS}) + if(CPM_SOURCE_CACHE AND download_directory) + file(LOCK ${download_directory}/../cmake.lock RELEASE) + endif() + if(${populated} AND ${CMAKE_VERSION} VERSION_LESS "3.28.0") + cpm_add_subdirectory( + "${CPM_ARGS_NAME}" + "${DOWNLOAD_ONLY}" + "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + "${${CPM_ARGS_NAME}_BINARY_DIR}" + "${CPM_ARGS_EXCLUDE_FROM_ALL}" + "${CPM_ARGS_SYSTEM}" + "${CPM_ARGS_OPTIONS}" + ) + endif() + cpm_get_fetch_properties("${CPM_ARGS_NAME}") + endif() + + set(${CPM_ARGS_NAME}_ADDED YES) + cpm_export_variables("${CPM_ARGS_NAME}") +endfunction() + +# Fetch a previously declared package +macro(CPMGetPackage Name) + if(DEFINED "CPM_DECLARATION_${Name}") + CPMAddPackage(NAME ${Name}) + else() + message(SEND_ERROR "${CPM_INDENT} Cannot retrieve package ${Name}: no declaration available") + endif() +endmacro() + +# export variables available to the caller to the parent scope expects ${CPM_ARGS_NAME} to be set +macro(cpm_export_variables name) + set(${name}_SOURCE_DIR + "${${name}_SOURCE_DIR}" + PARENT_SCOPE + ) + set(${name}_BINARY_DIR + "${${name}_BINARY_DIR}" + PARENT_SCOPE + ) + set(${name}_ADDED + "${${name}_ADDED}" + PARENT_SCOPE + ) + set(CPM_LAST_PACKAGE_NAME + "${name}" + PARENT_SCOPE + ) +endmacro() + +# declares a package, so that any call to CPMAddPackage for the package name will use these +# arguments instead. Previous declarations will not be overridden. +macro(CPMDeclarePackage Name) + if(NOT DEFINED "CPM_DECLARATION_${Name}") + set("CPM_DECLARATION_${Name}" "${ARGN}") + endif() +endmacro() + +function(cpm_add_to_package_lock Name) + if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + cpm_prettify_package_arguments(PRETTY_ARGN false ${ARGN}) + file(APPEND ${CPM_PACKAGE_LOCK_FILE} "# ${Name}\nCPMDeclarePackage(${Name}\n${PRETTY_ARGN})\n") + endif() +endfunction() + +function(cpm_add_comment_to_package_lock Name) + if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + cpm_prettify_package_arguments(PRETTY_ARGN true ${ARGN}) + file(APPEND ${CPM_PACKAGE_LOCK_FILE} + "# ${Name} (unversioned)\n# CPMDeclarePackage(${Name}\n${PRETTY_ARGN}#)\n" + ) + endif() +endfunction() + +# includes the package lock file if it exists and creates a target `cpm-update-package-lock` to +# update it +macro(CPMUsePackageLock file) + if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + get_filename_component(CPM_ABSOLUTE_PACKAGE_LOCK_PATH ${file} ABSOLUTE) + if(EXISTS ${CPM_ABSOLUTE_PACKAGE_LOCK_PATH}) + include(${CPM_ABSOLUTE_PACKAGE_LOCK_PATH}) + endif() + if(NOT TARGET cpm-update-package-lock) + add_custom_target( + cpm-update-package-lock COMMAND ${CMAKE_COMMAND} -E copy ${CPM_PACKAGE_LOCK_FILE} + ${CPM_ABSOLUTE_PACKAGE_LOCK_PATH} + ) + endif() + set(CPM_PACKAGE_LOCK_ENABLED true) + endif() +endmacro() + +# registers a package that has been added to CPM +function(CPMRegisterPackage PACKAGE VERSION) + list(APPEND CPM_PACKAGES ${PACKAGE}) + set(CPM_PACKAGES + ${CPM_PACKAGES} + CACHE INTERNAL "" + ) + set("CPM_PACKAGE_${PACKAGE}_VERSION" + ${VERSION} + CACHE INTERNAL "" + ) +endfunction() + +# retrieve the current version of the package to ${OUTPUT} +function(CPMGetPackageVersion PACKAGE OUTPUT) + set(${OUTPUT} + "${CPM_PACKAGE_${PACKAGE}_VERSION}" + PARENT_SCOPE + ) +endfunction() + +# declares a package in FetchContent_Declare +function(cpm_declare_fetch PACKAGE) + if(${CPM_DRY_RUN}) + cpm_message(STATUS "${CPM_INDENT} Package not declared (dry run)") + return() + endif() + + FetchContent_Declare(${PACKAGE} ${ARGN}) +endfunction() + +# returns properties for a package previously defined by cpm_declare_fetch +function(cpm_get_fetch_properties PACKAGE) + if(${CPM_DRY_RUN}) + return() + endif() + + set(${PACKAGE}_SOURCE_DIR + "${CPM_PACKAGE_${PACKAGE}_SOURCE_DIR}" + PARENT_SCOPE + ) + set(${PACKAGE}_BINARY_DIR + "${CPM_PACKAGE_${PACKAGE}_BINARY_DIR}" + PARENT_SCOPE + ) +endfunction() + +function(cpm_store_fetch_properties PACKAGE source_dir binary_dir) + if(${CPM_DRY_RUN}) + return() + endif() + + set(CPM_PACKAGE_${PACKAGE}_SOURCE_DIR + "${source_dir}" + CACHE INTERNAL "" + ) + set(CPM_PACKAGE_${PACKAGE}_BINARY_DIR + "${binary_dir}" + CACHE INTERNAL "" + ) +endfunction() + +# adds a package as a subdirectory if viable, according to provided options +function( + cpm_add_subdirectory + PACKAGE + DOWNLOAD_ONLY + SOURCE_DIR + BINARY_DIR + EXCLUDE + SYSTEM + OPTIONS +) + + if(NOT DOWNLOAD_ONLY AND EXISTS ${SOURCE_DIR}/CMakeLists.txt) + set(addSubdirectoryExtraArgs "") + if(EXCLUDE) + list(APPEND addSubdirectoryExtraArgs EXCLUDE_FROM_ALL) + endif() + if("${SYSTEM}" AND "${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.25") + # https://cmake.org/cmake/help/latest/prop_dir/SYSTEM.html#prop_dir:SYSTEM + list(APPEND addSubdirectoryExtraArgs SYSTEM) + endif() + if(OPTIONS) + foreach(OPTION ${OPTIONS}) + cpm_parse_option("${OPTION}") + set(${OPTION_KEY} "${OPTION_VALUE}") + endforeach() + endif() + set(CPM_OLD_INDENT "${CPM_INDENT}") + set(CPM_INDENT "${CPM_INDENT} ${PACKAGE}:") + add_subdirectory(${SOURCE_DIR} ${BINARY_DIR} ${addSubdirectoryExtraArgs}) + set(CPM_INDENT "${CPM_OLD_INDENT}") + endif() +endfunction() + +# downloads a previously declared package via FetchContent and exports the variables +# `${PACKAGE}_SOURCE_DIR` and `${PACKAGE}_BINARY_DIR` to the parent scope +function(cpm_fetch_package PACKAGE DOWNLOAD_ONLY populated) + set(${populated} + FALSE + PARENT_SCOPE + ) + if(${CPM_DRY_RUN}) + cpm_message(STATUS "${CPM_INDENT} Package ${PACKAGE} not fetched (dry run)") + return() + endif() + + FetchContent_GetProperties(${PACKAGE}) + + string(TOLOWER "${PACKAGE}" lower_case_name) + + if(NOT ${lower_case_name}_POPULATED) + if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.28.0") + if(DOWNLOAD_ONLY) + # MakeAvailable will call add_subdirectory internally which is not what we want when + # DOWNLOAD_ONLY is set. Populate will only download the dependency without adding it to the + # build + FetchContent_Populate( + ${PACKAGE} + SOURCE_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-src" + BINARY_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build" + SUBBUILD_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild" + ${ARGN} + ) + else() + FetchContent_MakeAvailable(${PACKAGE}) + endif() + else() + FetchContent_Populate(${PACKAGE}) + endif() + set(${populated} + TRUE + PARENT_SCOPE + ) + endif() + + cpm_store_fetch_properties( + ${CPM_ARGS_NAME} ${${lower_case_name}_SOURCE_DIR} ${${lower_case_name}_BINARY_DIR} + ) + + set(${PACKAGE}_SOURCE_DIR + ${${lower_case_name}_SOURCE_DIR} + PARENT_SCOPE + ) + set(${PACKAGE}_BINARY_DIR + ${${lower_case_name}_BINARY_DIR} + PARENT_SCOPE + ) +endfunction() + +# splits a package option +function(cpm_parse_option OPTION) + string(REGEX MATCH "^[^ ]+" OPTION_KEY "${OPTION}") + string(LENGTH "${OPTION}" OPTION_LENGTH) + string(LENGTH "${OPTION_KEY}" OPTION_KEY_LENGTH) + if(OPTION_KEY_LENGTH STREQUAL OPTION_LENGTH) + # no value for key provided, assume user wants to set option to "ON" + set(OPTION_VALUE "ON") + else() + math(EXPR OPTION_KEY_LENGTH "${OPTION_KEY_LENGTH}+1") + string(SUBSTRING "${OPTION}" "${OPTION_KEY_LENGTH}" "-1" OPTION_VALUE) + endif() + set(OPTION_KEY + "${OPTION_KEY}" + PARENT_SCOPE + ) + set(OPTION_VALUE + "${OPTION_VALUE}" + PARENT_SCOPE + ) +endfunction() + +# guesses the package version from a git tag +function(cpm_get_version_from_git_tag GIT_TAG RESULT) + string(LENGTH ${GIT_TAG} length) + if(length EQUAL 40) + # GIT_TAG is probably a git hash + set(${RESULT} + 0 + PARENT_SCOPE + ) + else() + string(REGEX MATCH "v?([0123456789.]*).*" _ ${GIT_TAG}) + set(${RESULT} + ${CMAKE_MATCH_1} + PARENT_SCOPE + ) + endif() +endfunction() + +# guesses if the git tag is a commit hash or an actual tag or a branch name. +function(cpm_is_git_tag_commit_hash GIT_TAG RESULT) + string(LENGTH "${GIT_TAG}" length) + # full hash has 40 characters, and short hash has at least 7 characters. + if(length LESS 7 OR length GREATER 40) + set(${RESULT} + 0 + PARENT_SCOPE + ) + else() + if(${GIT_TAG} MATCHES "^[a-fA-F0-9]+$") + set(${RESULT} + 1 + PARENT_SCOPE + ) + else() + set(${RESULT} + 0 + PARENT_SCOPE + ) + endif() + endif() +endfunction() + +function(cpm_prettify_package_arguments OUT_VAR IS_IN_COMMENT) + set(oneValueArgs + NAME + FORCE + VERSION + GIT_TAG + DOWNLOAD_ONLY + GITHUB_REPOSITORY + GITLAB_REPOSITORY + BITBUCKET_REPOSITORY + GIT_REPOSITORY + SOURCE_DIR + FIND_PACKAGE_ARGUMENTS + NO_CACHE + SYSTEM + GIT_SHALLOW + EXCLUDE_FROM_ALL + SOURCE_SUBDIR + ) + set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND) + cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + foreach(oneArgName ${oneValueArgs}) + if(DEFINED CPM_ARGS_${oneArgName}) + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + if(${oneArgName} STREQUAL "SOURCE_DIR") + string(REPLACE ${CMAKE_SOURCE_DIR} "\${CMAKE_SOURCE_DIR}" CPM_ARGS_${oneArgName} + ${CPM_ARGS_${oneArgName}} + ) + endif() + string(APPEND PRETTY_OUT_VAR " ${oneArgName} ${CPM_ARGS_${oneArgName}}\n") + endif() + endforeach() + foreach(multiArgName ${multiValueArgs}) + if(DEFINED CPM_ARGS_${multiArgName}) + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + string(APPEND PRETTY_OUT_VAR " ${multiArgName}\n") + foreach(singleOption ${CPM_ARGS_${multiArgName}}) + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + string(APPEND PRETTY_OUT_VAR " \"${singleOption}\"\n") + endforeach() + endif() + endforeach() + + if(NOT "${CPM_ARGS_UNPARSED_ARGUMENTS}" STREQUAL "") + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + string(APPEND PRETTY_OUT_VAR " ") + foreach(CPM_ARGS_UNPARSED_ARGUMENT ${CPM_ARGS_UNPARSED_ARGUMENTS}) + string(APPEND PRETTY_OUT_VAR " ${CPM_ARGS_UNPARSED_ARGUMENT}") + endforeach() + string(APPEND PRETTY_OUT_VAR "\n") + endif() + + set(${OUT_VAR} + ${PRETTY_OUT_VAR} + PARENT_SCOPE + ) + +endfunction() diff --git a/cmake/FindSIMDE.cmake b/cmake/FindSIMDE.cmake new file mode 100644 index 000000000..fa5b7a0d5 --- /dev/null +++ b/cmake/FindSIMDE.cmake @@ -0,0 +1,3 @@ +find_path(SIMDE_INCLUDE_DIR "simde/simde-features.h") +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(simde REQUIRED_VARS SIMDE_INCLUDE_DIR) diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 1b43ed78b..a8543a450 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -6,7 +6,7 @@ include(GNUWarnings) # C++14 is the minimum standard version required by Abseil LTS 20230125.1 and later, see # https://github.com/abseil/abseil-cpp/releases/tag/20230125.1 -set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ standard to be used") +set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to be used") set(CMAKE_C_STANDARD 99 CACHE STRING "C standard to be used") # Export the compile_commands.json file @@ -197,6 +197,7 @@ VST3 destination directory: ${VST3_PLUGIN_INSTALL_DIR}") endif() message(STATUS " Install prefix: ${CMAKE_INSTALL_PREFIX} +ASM includes: ${CMAKE_ASM_STANDARD_INCLUDE_DIRECTORIES} ") endif() endfunction() diff --git a/cmake/SfizzDeps.cmake b/cmake/SfizzDeps.cmake index 94e5418b6..abaec6e75 100644 --- a/cmake/SfizzDeps.cmake +++ b/cmake/SfizzDeps.cmake @@ -1,4 +1,5 @@ include(CheckCXXSourceCompiles) +include(cmake/CPM.cmake) # Find system threads find_package(Threads REQUIRED) @@ -98,16 +99,12 @@ if(SFIZZ_USE_SYSTEM_CXXOPTS) find_path(CXXOPTS_INCLUDE_DIR "cxxopts.hpp") if(NOT CXXOPTS_INCLUDE_DIR) message(FATAL_ERROR "Cannot find cxxopts") - else() - message(STATUS "Found system cxxopts") endif() - add_library(sfizz_cxxopts INTERFACE) - target_include_directories(sfizz_cxxopts INTERFACE "${CXXOPTS_INCLUDE_DIR}") else() - add_library(sfizz_cxxopts INTERFACE) - add_library(sfizz::cxxopts ALIAS sfizz_cxxopts) - target_include_directories(sfizz_cxxopts INTERFACE "external/cxxopts") + set(CXXOPTS_INCLUDE_DIR "external/cxxopts") endif() +add_library(sfizz_cxxopts INTERFACE) +target_include_directories(sfizz_cxxopts INTERFACE "${CXXOPTS_INCLUDE_DIR}") add_library(sfizz::cxxopts ALIAS sfizz_cxxopts) # The sndfile library @@ -145,13 +142,12 @@ add_subdirectory("external/st_audiofile" EXCLUDE_FROM_ALL) # The simde library add_library(sfizz_simde INTERFACE) add_library(sfizz::simde ALIAS sfizz_simde) -if(SFIZZ_USE_SYSTEM_SIMDE) - find_path(SIMDE_INCLUDE_DIR "simde/simde-features.h") - if(NOT SIMDE_INCLUDE_DIR) - message(FATAL_ERROR "Cannot find simde") - endif() - target_include_directories(sfizz_simde INTERFACE "${SIMDE_INCLUDE_DIR}") +if (SFIZZ_USE_SYSTEM_SIMDE) + find_package(SIMDE) + if (NOT SIMDE_FOUND) + message(FATAL_ERROR "Couldn't find SIMDE on the system") + endif() function(sfizz_ensure_simde_version result major minor micro) set(CMAKE_REQUIRED_INCLUDES "${SIMDE_INCLUDE_DIR}") check_cxx_source_compiles( @@ -166,10 +162,11 @@ int main() { return 0; }" sfizz_ensure_simde_version(SFIZZ_SIMDE_AT_LEAST_0_7_3 0 7 3) if(NOT SFIZZ_SIMDE_AT_LEAST_0_7_3) message(WARNING "The version of SIMDe on this system has known issues. \ -It is recommended to either update if a newer version is available, or use the \ -version bundled with this package. Refer to following issues: \ -simd-everywhere/simde#704, simd-everywhere/simde#706") + It is recommended to either update if a newer version is available, or use the \ + version bundled with this package. Refer to following issues: \ + simd-everywhere/simde#704, simd-everywhere/simde#706") endif() + target_include_directories(sfizz_simde INTERFACE "${SIMDE_INCLUDE_DIR}") else() target_include_directories(sfizz_simde INTERFACE "external/simde") endif() @@ -177,20 +174,11 @@ if(TARGET sfizz::openmp) target_link_libraries(sfizz_simde INTERFACE sfizz::openmp) endif() -# The pugixml library if(SFIZZ_USE_SYSTEM_PUGIXML) - find_package(PkgConfig REQUIRED) - pkg_check_modules(PUGIXML "pugixml" REQUIRED) - add_library(sfizz_pugixml INTERFACE) - target_include_directories(sfizz_pugixml INTERFACE ${PUGIXML_INCLUDE_DIRS}) - target_link_libraries(sfizz_pugixml INTERFACE ${PUGIXML_LIBRARIES}) - link_directories(${PUGIXML_LIBRARY_DIRS}) + find_package(pugixml REQUIRED) else() - add_library(sfizz_pugixml STATIC "src/external/pugixml/src/pugixml.cpp") - target_include_directories(sfizz_pugixml PUBLIC "src/external/pugixml/src") -endif() -add_library(sfizz::pugixml ALIAS sfizz_pugixml) - + add_subdirectory("src/external/pugixml" EXCLUDE_FROM_ALL) +end() # The spline library add_library(sfizz_spline STATIC "src/external/spline/spline/spline.cpp") add_library(sfizz::spline ALIAS sfizz_spline) diff --git a/cmake/VSWhere.cmake b/cmake/VSWhere.cmake new file mode 100644 index 000000000..c2ea310a9 --- /dev/null +++ b/cmake/VSWhere.cmake @@ -0,0 +1,132 @@ +#---------------------------------------------------------------------------------------------------------------------- +# MIT License +# +# Copyright (c) 2021 Mark Schofield +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +#---------------------------------------------------------------------------------------------------------------------- +include_guard() + +#[[==================================================================================================================== + toolchain_validate_vs_files + --------------------------- + + Note: Not supported for consumption outside of the toolchain files. + + Validates the the specified folder exists and contains the specified files. + + toolchain_validate_vs_files( + > + > + ...> + ) + + If the folder or files are missing, then a FATAL_ERROR is reported. +====================================================================================================================]]# +function(toolchain_validate_vs_files) + set(OPTIONS) + set(ONE_VALUE_KEYWORDS FOLDER DESCRIPTION) + set(MULTI_VALUE_KEYWORDS FILES) + + cmake_parse_arguments(PARSE_ARGV 0 VS "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") + + if(NOT EXISTS ${VS_FOLDER}) + message(FATAL_ERROR "Folder not present - ${VS_FOLDER} - ensure that the ${VS_DESCRIPTION} are installed with Visual Studio.") + endif() + + foreach(FILE ${VS_FILES}) + if(NOT EXISTS "${VS_FOLDER}/${FILE}") + message(FATAL_ERROR "File not present - ${VS_FOLDER}/${FILE} - ensure that the ${VS_DESCRIPTION} are installed with Visual Studio.") + endif() + endforeach() +endfunction() + +#[[==================================================================================================================== + findVisualStudio + ---------------- + + Finds a Visual Studio instance, and sets CMake variables based on properties of the found instance. + + findVisualStudio( + [VERSION ] + [PRERELEASE ] + [PRODUCTS ] + [REQUIRES ...] + PROPERTIES + < > + ) +====================================================================================================================]]# +function(findVisualStudio) + set(OPTIONS) + set(ONE_VALUE_KEYWORDS VERSION PRERELEASE PRODUCTS) + set(MULTI_VALUE_KEYWORDS REQUIRES PROPERTIES) + + cmake_parse_arguments(PARSE_ARGV 0 FIND_VS "${OPTIONS}" "${ONE_VALUE_KEYWORDS}" "${MULTI_VALUE_KEYWORDS}") + + find_program(VSWHERE_PATH + NAMES vswhere vswhere.exe + HINTS "$ENV{ProgramFiles\(x86\)}/Microsoft Visual Studio/Installer" + ) + + if(VSWHERE_PATH STREQUAL "VSWHERE_PATH-NOTFOUND") + message(FATAL_ERROR "'vswhere' isn't found.") + endif() + + set(VSWHERE_COMMAND ${VSWHERE_PATH} -latest) + + if(FIND_VS_PRERELEASE) + list(APPEND VSWHERE_COMMAND -prerelease) + endif() + + if(FIND_VS_PRODUCTS) + list(APPEND VSWHERE_COMMAND -products ${FIND_VS_PRODUCTS}) + endif() + + if(FIND_VS_REQUIRES) + list(APPEND VSWHERE_COMMAND -requires ${FIND_VS_REQUIRES}) + endif() + + if(FIND_VS_VERSION) + list(APPEND VSWHERE_COMMAND -version "${FIND_VS_VERSION}") + endif() + + message(VERBOSE "findVisualStudio: VSWHERE_COMMAND = ${VSWHERE_COMMAND}") + + execute_process( + COMMAND ${VSWHERE_COMMAND} + OUTPUT_VARIABLE VSWHERE_OUTPUT + ) + + message(VERBOSE "findVisualStudio: VSWHERE_OUTPUT = ${VSWHERE_OUTPUT}") + + # Matches `VSWHERE_PROPERTY` in the `VSWHERE_OUTPUT` text in the format written by vswhere. + # The matched value is assigned to the variable `VARIABLE_NAME` in the parent scope. + function(getVSWhereProperty VSWHERE_OUTPUT VSWHERE_PROPERTY VARIABLE_NAME) + string(REGEX MATCH "${VSWHERE_PROPERTY}: [^\r\n]*" VSWHERE_VALUE "${VSWHERE_OUTPUT}") + string(REPLACE "${VSWHERE_PROPERTY}: " "" VSWHERE_VALUE "${VSWHERE_VALUE}") + set(${VARIABLE_NAME} "${VSWHERE_VALUE}" PARENT_SCOPE) + endfunction() + + while(FIND_VS_PROPERTIES) + list(POP_FRONT FIND_VS_PROPERTIES VSWHERE_PROPERTY) + list(POP_FRONT FIND_VS_PROPERTIES VSWHERE_CMAKE_VARIABLE) + getVSWhereProperty("${VSWHERE_OUTPUT}" ${VSWHERE_PROPERTY} VSWHERE_VALUE) + set(${VSWHERE_CMAKE_VARIABLE} ${VSWHERE_VALUE} PARENT_SCOPE) + endwhile() +endfunction() diff --git a/cmake/Windows.Kits.cmake b/cmake/Windows.Kits.cmake new file mode 100644 index 000000000..fd3321487 --- /dev/null +++ b/cmake/Windows.Kits.cmake @@ -0,0 +1,153 @@ +#---------------------------------------------------------------------------------------------------------------------- +# MIT License +# +# Copyright (c) 2021 Mark Schofield +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +#---------------------------------------------------------------------------------------------------------------------- +# +# | CMake Variable | Description | +# |-----------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------| +# | CMAKE_SYSTEM_VERSION | The version of the operating system for which CMake is to build. Defaults to the host version. | +# | CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE | The architecture of the tooling to use. Defaults to 'arm64' on ARM64 systems, otherwise 'x64'. | +# | CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION | The version of the Windows SDK to use. Defaults to the highest installed, that is no higher than CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM | +# | CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM | The maximum version of the Windows SDK to use, for example '10.0.19041.0'. Defaults to nothing | +# | CMAKE_WINDOWS_KITS_10_DIR | The location of the root of the Windows Kits 10 directory. | +# +# The following variables will be set: +# +# | CMake Variable | Description | +# |---------------------------------------------|-------------------------------------------------------------------------------------------------------| +# | CMAKE_MT | The path to the 'mt' tool. | +# | CMAKE_RC_COMPILER | The path to the 'rc' tool. | +# | CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION | The version of the Windows SDK to be used. | +# | MDMERGE_TOOL | The path to the 'mdmerge' tool. | +# | MIDL_COMPILER | The path to the 'midl' compiler. | +# | WINDOWS_KITS_BIN_PATH | The path to the folder containing the Windows Kits binaries. | +# | WINDOWS_KITS_INCLUDE_PATH | The path to the folder containing the Windows Kits include files. | +# | WINDOWS_KITS_LIB_PATH | The path to the folder containing the Windows Kits library files. | +# | WINDOWS_KITS_REFERENCES_PATH | The path to the folder containing the Windows Kits references. | +# +include_guard() + +if(NOT CMAKE_SYSTEM_VERSION) + set(CMAKE_SYSTEM_VERSION ${CMAKE_HOST_SYSTEM_VERSION}) +endif() + +if(NOT CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE) + if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL ARM64) + set(CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE arm64) + else() + set(CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE x64) + endif() +endif() + +if(NOT CMAKE_WINDOWS_KITS_10_DIR) + get_filename_component(CMAKE_WINDOWS_KITS_10_DIR "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v10.0;InstallationFolder]" ABSOLUTE CACHE) + if ("${CMAKE_WINDOWS_KITS_10_DIR}" STREQUAL "/registry") + unset(CMAKE_WINDOWS_KITS_10_DIR) + endif() +endif() + +if(NOT CMAKE_WINDOWS_KITS_10_DIR) + message(FATAL_ERROR "Unable to find an installed Windows SDK, and one wasn't specified.") +endif() + +# If a CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION wasn't specified, find the highest installed version that is no higher +# than the host version +if(NOT CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION) + file(GLOB WINDOWS_KITS_VERSIONS RELATIVE "${CMAKE_WINDOWS_KITS_10_DIR}/lib" "${CMAKE_WINDOWS_KITS_10_DIR}/lib/*") + list(FILTER WINDOWS_KITS_VERSIONS INCLUDE REGEX "10\\.0\\.") + list(SORT WINDOWS_KITS_VERSIONS COMPARE NATURAL ORDER DESCENDING) + while(WINDOWS_KITS_VERSIONS) + list(POP_FRONT WINDOWS_KITS_VERSIONS CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION) + if(NOT CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM) + message(VERBOSE "Windows.Kits: Defaulting version: ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}") + break() + endif() + + if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION VERSION_LESS_EQUAL CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM) + message(VERBOSE "Windows.Kits: Choosing version: ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}") + break() + endif() + + message(VERBOSE "Windows.Kits: Not suitable: ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}") + set(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION) + endwhile() +endif() + +if(NOT CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION) + message(FATAL_ERROR "A Windows SDK could not be found.") +endif() + +set(WINDOWS_KITS_BIN_PATH "${CMAKE_WINDOWS_KITS_10_DIR}/bin/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}" CACHE PATH "" FORCE) +set(WINDOWS_KITS_INCLUDE_PATH "${CMAKE_WINDOWS_KITS_10_DIR}/include/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}" CACHE PATH "" FORCE) +set(WINDOWS_KITS_LIB_PATH "${CMAKE_WINDOWS_KITS_10_DIR}/lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}" CACHE PATH "" FORCE) +set(WINDOWS_KITS_REFERENCES_PATH "${CMAKE_WINDOWS_KITS_10_DIR}/References" CACHE PATH "" FORCE) +set(WINDOWS_KITS_PLATFORM_PATH "${CMAKE_WINDOWS_KITS_10_DIR}/Platforms/UAP/${CMAKE_SYSTEM_VERSION}/Platform.xml" CACHE PATH "" FORCE) + +if(NOT EXISTS ${WINDOWS_KITS_BIN_PATH}) + message(FATAL_ERROR "Windows SDK ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} cannot be found: Folder '${WINDOWS_KITS_BIN_PATH}' does not exist.") +endif() + +if(NOT EXISTS ${WINDOWS_KITS_INCLUDE_PATH}) + message(FATAL_ERROR "Windows SDK ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} cannot be found: Folder '${WINDOWS_KITS_INCLUDE_PATH}' does not exist.") +endif() + +if(NOT EXISTS ${WINDOWS_KITS_LIB_PATH}) + message(FATAL_ERROR "Windows SDK ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} cannot be found: Folder '${WINDOWS_KITS_LIB_PATH}' does not exist.") +endif() + +set(CMAKE_MT "${WINDOWS_KITS_BIN_PATH}/${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}/mt.exe") +set(CMAKE_RC_COMPILER_INIT "${WINDOWS_KITS_BIN_PATH}/${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}/rc.exe") +set(CMAKE_RC_FLAGS_INIT "/nologo") + +set(MIDL_COMPILER "${WINDOWS_KITS_BIN_PATH}/${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}/midl.exe") +set(MDMERGE_TOOL "${WINDOWS_KITS_BIN_PATH}/${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}/mdmerge.exe") + +# Windows SDK +if(CMAKE_SYSTEM_PROCESSOR STREQUAL AMD64) + set(WINDOWS_KITS_TARGET_ARCHITECTURE x64) +elseif((CMAKE_SYSTEM_PROCESSOR STREQUAL ARM) + OR (CMAKE_SYSTEM_PROCESSOR STREQUAL ARM64) + OR (CMAKE_SYSTEM_PROCESSOR STREQUAL X86)) + set(WINDOWS_KITS_TARGET_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) +elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL x64) + message(WARNING "CMAKE_SYSTEM_PROCESSOR should be 'AMD64', not 'x64'. WindowsToolchain will stop recognizing 'x64' in a future release.") + set(WINDOWS_KITS_TARGET_ARCHITECTURE x64) +elseif((CMAKE_SYSTEM_PROCESSOR STREQUAL arm) + OR (CMAKE_SYSTEM_PROCESSOR STREQUAL arm64) + OR (CMAKE_SYSTEM_PROCESSOR STREQUAL x86)) + message(WARNING "CMAKE_SYSTEM_PROCESSOR (${CMAKE_SYSTEM_PROCESSOR}) should be upper-case. WindowsToolchain will stop recognizing non-upper-case forms in a future release.") + set(WINDOWS_KITS_TARGET_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) +else() + message(FATAL_ERROR "Unable identify Windows Kits architecture for CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}") +endif() + +foreach(LANG C CXX RC ASM_MASM) + list(APPEND CMAKE_${LANG}_STANDARD_INCLUDE_DIRECTORIES "${WINDOWS_KITS_INCLUDE_PATH}/ucrt") + list(APPEND CMAKE_${LANG}_STANDARD_INCLUDE_DIRECTORIES "${WINDOWS_KITS_INCLUDE_PATH}/shared") + list(APPEND CMAKE_${LANG}_STANDARD_INCLUDE_DIRECTORIES "${WINDOWS_KITS_INCLUDE_PATH}/um") + list(APPEND CMAKE_${LANG}_STANDARD_INCLUDE_DIRECTORIES "${WINDOWS_KITS_INCLUDE_PATH}/winrt") + list(APPEND CMAKE_${LANG}_STANDARD_INCLUDE_DIRECTORIES "${WINDOWS_KITS_INCLUDE_PATH}/cppwinrt") +endforeach() + +link_directories("${WINDOWS_KITS_LIB_PATH}/ucrt/${WINDOWS_KITS_TARGET_ARCHITECTURE}") +link_directories("${WINDOWS_KITS_LIB_PATH}/um/${WINDOWS_KITS_TARGET_ARCHITECTURE}") +link_directories("${WINDOWS_KITS_REFERENCES_PATH}/${WINDOWS_KITS_TARGET_ARCHITECTURE}") diff --git a/cmake/Windows.MSVC.toolchain.cmake b/cmake/Windows.MSVC.toolchain.cmake new file mode 100644 index 000000000..7d979e202 --- /dev/null +++ b/cmake/Windows.MSVC.toolchain.cmake @@ -0,0 +1,247 @@ +#---------------------------------------------------------------------------------------------------------------------- +# MIT License +# +# Copyright (c) 2021 Mark Schofield +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +#---------------------------------------------------------------------------------------------------------------------- +# +# This CMake toolchain file configures a CMake, non-'Visual Studio Generator' build to use +# the MSVC compilers and tools. +# +# The following variables can be used to configure the behavior of this toolchain file: +# +# | CMake Variable | Description | +# |---------------------------------------------|--------------------------------------------------------------------------------------------------------------------------| +# | CMAKE_SYSTEM_PROCESSOR | The processor to compiler for. One of 'X86', 'AMD64', 'ARM', 'ARM64'. Defaults to ${CMAKE_HOST_SYSTEM_PROCESSOR}. | +# | CMAKE_SYSTEM_VERSION | The version of the operating system for which CMake is to build. Defaults to the host version. | +# | CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE | The architecture of the tooling to use. Defaults to 'arm64' on ARM64 systems, otherwise 'x64'. | +# | CMAKE_VS_PRODUCTS | One or more Visual Studio Product IDs to consider. Defaults to '*' | +# | CMAKE_VS_VERSION_PRERELEASE | Whether 'prerelease' versions of Visual Studio should be considered. Defaults to 'OFF' | +# | CMAKE_VS_VERSION_RANGE | A verson range for VS instances to find. For example, '[16.0,17.0)' will find versions '16.*'. Defaults to '[16.0,17.0)' | +# | CMAKE_WINDOWS_KITS_10_DIR | The location of the root of the Windows Kits 10 directory. | +# | VS_EXPERIMENTAL_MODULE | Whether experimental module support should be enabled. | +# | VS_INSTALLATION_PATH | The location of the root of the Visual Studio installation. If not specified VSWhere will be used to search for one. | +# | VS_PLATFORM_TOOLSET_VERSION | The version of the MSVC toolset to use. For example, 14.29.30133. Defaults to the highest available. | +# | VS_USE_SPECTRE_MITIGATION_ATLMFC_RUNTIME | Whether the compiler should link with the ATLMFC runtime that uses 'Spectre' mitigations. Defaults to 'OFF'. | +# | VS_USE_SPECTRE_MITIGATION_RUNTIME | Whether the compiler should link with a runtime that uses 'Spectre' mitigations. Defaults to 'OFF'. | +# +# The toolchain file will set the following variables: +# +# | CMake Variable | Description | +# |---------------------------------------------|-------------------------------------------------------------------------------------------------------| +# | CMAKE_C_COMPILER | The path to the C compiler to use. | +# | CMAKE_CXX_COMPILER | The path to the C++ compiler to use. | +# | CMAKE_MT | The path to the 'mt.exe' tool to use. | +# | CMAKE_RC_COMPILER | The path tp the 'rc.exe' tool to use. | +# | CMAKE_SYSTEM_NAME | Windows | +# | CMAKE_VS_PLATFORM_TOOLSET_VERSION | The version of the MSVC toolset being used - e.g. 14.29.30133. | +# | WIN32 | 1 | +# | MSVC | 1 | +# | MSVC_VERSION | The '' version of the C++ compiler being used. For example, '1929' | +# +# Other configuration: +# +# * If the 'CMAKE_CUDA_COMPILER' is set, and 'CMAKE_CUDA_HOST_COMPILER' is not set, and ENV{CUDAHOSTCXX} not defined +# then 'CMAKE_CUDA_HOST_COMPILER' is set to the value of 'CMAKE_CXX_COMPILER'. +# +# Resources: +# +# +cmake_minimum_required(VERSION 3.20) + +include_guard() + +if(NOT (CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)) + return() +endif() + +set(UNUSED ${CMAKE_TOOLCHAIN_FILE}) # Note: only to prevent cmake unused variable warninig +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + CMAKE_CROSSCOMPILING + CMAKE_SYSTEM_PROCESSOR + CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE + CMAKE_VS_PRODUCTS + CMAKE_VS_VERSION_PRERELEASE + CMAKE_VS_VERSION_RANGE + VS_INSTALLATION_PATH + VS_INSTALLATION_VERSION + VS_PLATFORM_TOOLSET_VERSION +) +set(CMAKE_CROSSCOMPILING TRUE) +set(WIN32 1) +set(MSVC 1) + +include("${CMAKE_CURRENT_LIST_DIR}/VSWhere.cmake") + +if(NOT CMAKE_SYSTEM_PROCESSOR) + set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR}) +endif() + +if(NOT CMAKE_VS_VERSION_RANGE) + set(CMAKE_VS_VERSION_RANGE "[16.0,)") +endif() + +if(NOT CMAKE_VS_VERSION_PRERELEASE) + set(CMAKE_VS_VERSION_PRERELEASE OFF) +endif() + +if(NOT CMAKE_VS_PRODUCTS) + set(CMAKE_VS_PRODUCTS "*") +endif() + +if(NOT CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE) + if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL ARM64) + set(CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE arm64) + else() + set(CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE x64) + endif() +endif() + +if(NOT VS_USE_SPECTRE_MITIGATION_RUNTIME) + set(VS_USE_SPECTRE_MITIGATION_RUNTIME OFF) +endif() + +# Find Visual Studio +# +if(NOT VS_INSTALLATION_PATH) + findVisualStudio( + VERSION ${CMAKE_VS_VERSION_RANGE} + PRERELEASE ${CMAKE_VS_VERSION_PRERELEASE} + PRODUCTS ${CMAKE_VS_PRODUCTS} + PROPERTIES + installationVersion VS_INSTALLATION_VERSION + installationPath VS_INSTALLATION_PATH + ) +endif() + +message(VERBOSE "VS_INSTALLATION_VERSION = ${VS_INSTALLATION_VERSION}") +message(VERBOSE "VS_INSTALLATION_PATH = ${VS_INSTALLATION_PATH}") + +if(NOT VS_INSTALLATION_PATH) + message(FATAL_ERROR "Unable to find Visual Studio") +endif() + +cmake_path(NORMAL_PATH VS_INSTALLATION_PATH) + +set(VS_MSVC_PATH "${VS_INSTALLATION_PATH}/VC/Tools/MSVC") + +# Use 'VS_PLATFORM_TOOLSET_VERSION' to resolve 'CMAKE_VS_PLATFORM_TOOLSET_VERSION' +# +if(NOT VS_PLATFORM_TOOLSET_VERSION) + if(VS_TOOLSET_VERSION) + message(WARNING "Old versions of WindowsToolchain incorrectly used 'VS_TOOLSET_VERSION' to specify the VS toolset version. This functionality is being deprecated - please use 'VS_PLATFORM_TOOLSET_VERSION' instead.") + set(VS_PLATFORM_TOOLSET_VERSION ${VS_TOOLSET_VERSION}) + else() + file(GLOB VS_PLATFORM_TOOLSET_VERSIONS RELATIVE ${VS_MSVC_PATH} ${VS_MSVC_PATH}/*) + list(SORT VS_PLATFORM_TOOLSET_VERSIONS COMPARE NATURAL ORDER DESCENDING) + list(POP_FRONT VS_PLATFORM_TOOLSET_VERSIONS VS_PLATFORM_TOOLSET_VERSION) + unset(VS_PLATFORM_TOOLSET_VERSIONS) + endif() +endif() + +set(CMAKE_VS_PLATFORM_TOOLSET_VERSION ${VS_PLATFORM_TOOLSET_VERSION}) +set(VS_TOOLSET_PATH "${VS_INSTALLATION_PATH}/VC/Tools/MSVC/${CMAKE_VS_PLATFORM_TOOLSET_VERSION}") + +# Set the tooling variables, include_directories and link_directories +# + +# Map CMAKE_SYSTEM_PROCESSOR values to CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE that identifies the tools that should +# be used to produce code for the CMAKE_SYSTEM_PROCESSOR. +if(CMAKE_SYSTEM_PROCESSOR STREQUAL AMD64) + set(CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE x64) +elseif((CMAKE_SYSTEM_PROCESSOR STREQUAL ARM) + OR (CMAKE_SYSTEM_PROCESSOR STREQUAL ARM64) + OR (CMAKE_SYSTEM_PROCESSOR STREQUAL X86)) + set(CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) +elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL x64) + message(WARNING "CMAKE_SYSTEM_PROCESSOR should be 'AMD64', not 'x64'. WindowsToolchain will stop recognizing 'x64' in a future release.") + set(CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE x64) +elseif((CMAKE_SYSTEM_PROCESSOR STREQUAL arm) + OR (CMAKE_SYSTEM_PROCESSOR STREQUAL arm64) + OR (CMAKE_SYSTEM_PROCESSOR STREQUAL x86)) + message(WARNING "CMAKE_SYSTEM_PROCESSOR (${CMAKE_SYSTEM_PROCESSOR}) should be upper-case. WindowsToolchain will stop recognizing non-upper-case forms in a future release.") + set(CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) +else() + message(FATAL_ERROR "Unable identify compiler architecture for CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}") +endif() + +set(CMAKE_CXX_COMPILER "${VS_TOOLSET_PATH}/bin/Host${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}/${CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE}/cl.exe") +set(CMAKE_C_COMPILER "${VS_TOOLSET_PATH}/bin/Host${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}/${CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE}/cl.exe") + +if(CMAKE_SYSTEM_PROCESSOR STREQUAL ARM) + set(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} /EHsc") +elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL arm) + message(WARNING "CMAKE_SYSTEM_PROCESSOR (${CMAKE_SYSTEM_PROCESSOR}) should be upper-case. WindowsToolchain will stop recognizing non-upper-case forms in a future release.") + set(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} /EHsc") +endif() + +# Compiler +foreach(LANG C CXX RC) + list(APPEND CMAKE_${LANG}_STANDARD_INCLUDE_DIRECTORIES "${VS_TOOLSET_PATH}/ATLMFC/include") + list(APPEND CMAKE_${LANG}_STANDARD_INCLUDE_DIRECTORIES "${VS_TOOLSET_PATH}/include") +endforeach() + +if(VS_USE_SPECTRE_MITIGATION_ATLMFC_RUNTIME) + # Ensure that the necessary folder and files are present before adding the 'link_directories' + toolchain_validate_vs_files( + DESCRIPTION "ATLMFC Spectre libraries" + FOLDER "${VS_TOOLSET_PATH}/ATLMFC/lib/spectre/${CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE}" + FILES + atls.lib + ) + link_directories("${VS_TOOLSET_PATH}/ATLMFC/lib/spectre/${CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE}") +else() + link_directories("${VS_TOOLSET_PATH}/ATLMFC/lib/${CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE}") +endif() + +if(VS_USE_SPECTRE_MITIGATION_RUNTIME) + # Ensure that the necessary folder and files are present before adding the 'link_directories' + toolchain_validate_vs_files( + DESCRIPTION "Spectre libraries" + FOLDER "${VS_TOOLSET_PATH}/lib/spectre/${CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE}" + FILES + msvcrt.lib vcruntime.lib vcruntimed.lib + ) + link_directories("${VS_TOOLSET_PATH}/lib/spectre/${CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE}") +else() + link_directories("${VS_TOOLSET_PATH}/lib/${CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE}") +endif() + +link_directories("${VS_TOOLSET_PATH}/lib/x86/store/references") + +# Module support +if(VS_EXPERIMENTAL_MODULE) + set(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} /experimental:module") + set(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} /stdIfcDir \"${VS_TOOLSET_PATH}/ifc/${CMAKE_VS_PLATFORM_TOOLSET_ARCHITECTURE}\"") +endif() + +# Windows Kits +include("${CMAKE_CURRENT_LIST_DIR}/Windows.Kits.cmake") + +# CUDA support +# +# If a CUDA compiler is specified, and a host compiler wasn't specified, set 'CMAKE_CXX_COMPILER' +# as the host compiler. +if(CMAKE_CUDA_COMPILER) + if((NOT CMAKE_CUDA_HOST_COMPILER) AND (NOT DEFINED ENV{CUDAHOSTCXX})) + set(CMAKE_CUDA_HOST_COMPILER "${CMAKE_CXX_COMPILER}") + endif() +endif() diff --git a/devtools/CMakeLists.txt b/devtools/CMakeLists.txt index b561045f2..678e6a3d0 100644 --- a/devtools/CMakeLists.txt +++ b/devtools/CMakeLists.txt @@ -9,7 +9,7 @@ if(TARGET sfizz::jack AND TARGET Qt5::Widgets) endif() add_executable(sfizz_preprocessor Preprocessor.cpp) -target_link_libraries(sfizz_preprocessor PRIVATE sfizz::parser sfizz::pugixml sfizz::cxxopts) +target_link_libraries(sfizz_preprocessor PRIVATE sfizz::parser pugixml::pugixml cxxopts::cxxopts) add_executable(sfizz_importer Importer.cpp) target_link_libraries(sfizz_importer PRIVATE sfizz::import) diff --git a/docker/arch.dockerfile b/docker/arch.dockerfile new file mode 100644 index 000000000..093f00f9e --- /dev/null +++ b/docker/arch.dockerfile @@ -0,0 +1,5 @@ +FROM archlinux:base-20241027.0.273886 AS base +RUN pacman -Sy --noconfirm cmake gcc gcc-libs ninja git pkg-config glibc + +FROM base as ci +RUN pacman -S --noconfirm abseil-cpp cxxopts ghc-filesystem jack pugixml simde diff --git a/docker/fedora.dockerfile b/docker/fedora.dockerfile new file mode 100644 index 000000000..9e919721d --- /dev/null +++ b/docker/fedora.dockerfile @@ -0,0 +1,5 @@ +FROM fedora:41 AS base +RUN dnf install -y cmake g++ git pkg-config ninja-build + +FROM base AS ci +RUN dnf install -y abseil-cpp-devel simde-devel diff --git a/docker/ubuntu.dockerfile b/docker/ubuntu.dockerfile new file mode 100644 index 000000000..35ac6a3d6 --- /dev/null +++ b/docker/ubuntu.dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:24.04 AS base +RUN apt update -y +RUN apt install -y cmake g++ git pkg-config ninja-build + +FROM base as ci +RUN apt install libabsl-dev + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f7aab0f7d..aa1256bb1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -271,7 +271,7 @@ target_sources(sfizz_import PRIVATE target_include_directories(sfizz_import PUBLIC ".") target_link_libraries(sfizz_import PUBLIC absl::strings absl::memory sfizz::filesystem - PRIVATE sfizz::internal sfizz::pugixml) + PRIVATE sfizz::internal pugixml::pugixml) # Sfizz spinlock mutex add_library(sfizz_spin_mutex STATIC @@ -295,7 +295,7 @@ target_sources(sfizz_internal PRIVATE ${SFIZZ_HEADERS} ${SFIZZ_SOURCES} ${FAUST_ target_include_directories(sfizz_internal PUBLIC "." "sfizz") target_link_libraries(sfizz_internal PUBLIC absl::strings absl::span sfizz::filesystem sfizz::atomic_queue sfizz::spin_mutex sfizz::bit_array sfizz::simde sfizz::hiir sfizz::jsl - PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile sfizz::pugixml sfizz::spline sfizz::tunings sfizz::kissfft sfizz::cephes sfizz::cpuid sfizz::threadpool sfizz::atomic invoke_hpp) + PRIVATE sfizz::parser sfizz::messaging absl::flat_hash_map Threads::Threads st_audiofile pugixml::pugixml sfizz::spline sfizz::tunings sfizz::kissfft sfizz::cephes sfizz::cpuid sfizz::threadpool sfizz::atomic invoke_hpp) if(SFIZZ_USE_SNDFILE) target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_USE_SNDFILE=1") target_link_libraries(sfizz_internal PUBLIC st_audiofile) diff --git a/tests/AudioFilesT.cpp b/tests/AudioFilesT.cpp index 55a10c9b7..5b8bed38a 100644 --- a/tests/AudioFilesT.cpp +++ b/tests/AudioFilesT.cpp @@ -36,15 +36,15 @@ void compareFiles(const fs::path& lFile, const fs::path& rFile) TEST_CASE("[AudioFiles] Compare Flac and WAV") { - compareFiles(fs::current_path() / "tests/TestFiles/kick.wav", - fs::current_path() / "tests/TestFiles/kick.flac"); + compareFiles(fs::path(SFIZZ_TEST_FILES) / "kick.wav", + fs::path(SFIZZ_TEST_FILES) / "kick.flac"); } #if !defined(SFIZZ_USE_SNDFILE) TEST_CASE("[AudioFiles] Compare WV and WAV") { - compareFiles(fs::current_path() / "tests/TestFiles/kick.wav", - fs::current_path() / "tests/TestFiles/kick.wv"); + compareFiles(fs::path(SFIZZ_TEST_FILES) / "kick.wav", + fs::path(SFIZZ_TEST_FILES) / "kick.wv"); } #endif @@ -78,8 +78,8 @@ void compareOutputs(const std::string& lFile, const std::string& rFile, CompareO sfz::AudioBuffer rBuffer { 2, static_cast(rSynth.getSamplesPerBlock()) }; sfz::AudioSpan lSpan { lBuffer }; sfz::AudioSpan rSpan { rBuffer }; - lSynth.loadSfzString(fs::current_path() / "tests/TestFiles/l.sfz", lFile); - rSynth.loadSfzString(fs::current_path() / "tests/TestFiles/r.sfz", rFile); + lSynth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "l.sfz", lFile); + rSynth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "r.sfz", rFile); lSynth.noteOn(opts.delay, opts.note, opts.velocity); rSynth.noteOn(opts.delay, opts.note, opts.velocity); lSynth.renderBlock(lSpan); @@ -159,8 +159,8 @@ TEST_CASE("[Files] Embedded sample data") synth1.setSamplesPerBlock(256); synth2.setSamplesPerBlock(256); - synth1.loadSfzFile(fs::current_path() / "tests/TestFiles/kick.sfz"); - synth2.loadSfzFile(fs::current_path() / "tests/TestFiles/kick_embedded.sfz"); + synth1.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "kick.sfz"); + synth2.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "kick_embedded.sfz"); REQUIRE(synth1.getNumPreloadedSamples() == 1); REQUIRE(synth2.getNumPreloadedSamples() == 1); diff --git a/tests/BindingsT.cpp b/tests/BindingsT.cpp index 5ce32011e..4c6297d80 100644 --- a/tests/BindingsT.cpp +++ b/tests/BindingsT.cpp @@ -12,7 +12,7 @@ TEST_CASE("[Bindings] Midnam C++") { sfz::Sfizz synth; - const auto path = fs::current_path() / "tests/TestFiles/labels.sfz"; + const auto path = fs::path(SFIZZ_TEST_FILES) / "labels.sfz"; synth.loadSfzFile(path.string()); const std::string xmlMidnam = synth.exportMidnam(""); REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); @@ -24,7 +24,7 @@ TEST_CASE("[Bindings] Midnam C++") TEST_CASE("[Bindings] Midnam C") { sfizz_synth_t* synth = sfizz_create_synth(); - const auto path = fs::current_path() / "tests/TestFiles/labels.sfz"; + const auto path = fs::path(SFIZZ_TEST_FILES) / "labels.sfz"; const auto strPath = path.string(); sfizz_load_file(synth, strPath.c_str()); char* midnamChar = sfizz_export_midnam(synth, ""); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3b6d10538..f015c9ac0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -64,6 +64,10 @@ set(SFIZZ_TEST_SOURCES ) add_executable(sfizz_tests ${SFIZZ_TEST_SOURCES}) +target_compile_definitions(sfizz_tests PUBLIC + "SFIZZ_TEST_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"" + "SFIZZ_TEST_FILES=\"${CMAKE_CURRENT_SOURCE_DIR}/Testfiles\"" +) target_link_libraries(sfizz_tests PRIVATE sfizz::internal sfizz::static sfizz::spin_mutex sfizz::jsl sfizz::filesystem st_audiofile) if(APPLE AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS "10.12") # workaround for incomplete C++17 runtime on macOS diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index dc26151b9..40d82b99b 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -24,7 +24,7 @@ using namespace sfz; TEST_CASE("[Files] Single region (regions_one.sfz)") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_one.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Regions/regions_one.sfz"); REQUIRE(synth.getNumRegions() == 1); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav"); } @@ -33,7 +33,7 @@ TEST_CASE("[Files] Single region (regions_one.sfz)") TEST_CASE("[Files] Multiple regions (regions_many.sfz)") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_many.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Regions/regions_many.sfz"); REQUIRE(synth.getNumRegions() == 3); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav"); REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy.1.wav"); @@ -43,7 +43,7 @@ TEST_CASE("[Files] Multiple regions (regions_many.sfz)") TEST_CASE("[Files] Basic opcodes (regions_opcodes.sfz)") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_opcodes.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Regions/regions_opcodes.sfz"); REQUIRE(synth.getNumRegions() == 1); REQUIRE(synth.getRegionView(0)->keyRange == Range(2, 14)); } @@ -51,7 +51,7 @@ TEST_CASE("[Files] Basic opcodes (regions_opcodes.sfz)") TEST_CASE("[Files] Underscore opcodes (underscore_opcodes.sfz)") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/underscore_opcodes.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Regions/underscore_opcodes.sfz"); REQUIRE(synth.getNumRegions() == 1); REQUIRE(synth.getRegionView(0)->loopMode == LoopMode::loop_sustain); } @@ -59,7 +59,7 @@ TEST_CASE("[Files] Underscore opcodes (underscore_opcodes.sfz)") TEST_CASE("[Files] (regions_bad.sfz)") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_bad.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Regions/regions_bad.sfz"); REQUIRE(synth.getNumRegions() == 2); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav"); REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy.wav"); @@ -68,7 +68,7 @@ TEST_CASE("[Files] (regions_bad.sfz)") TEST_CASE("[Files] Local include") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_local.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Includes/root_local.sfz"); REQUIRE(synth.getNumRegions() == 1); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav"); } @@ -76,7 +76,7 @@ TEST_CASE("[Files] Local include") TEST_CASE("[Files] Multiple includes") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/multiple_includes.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Includes/multiple_includes.sfz"); REQUIRE(synth.getNumRegions() == 2); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav"); REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy2.wav"); @@ -85,7 +85,7 @@ TEST_CASE("[Files] Multiple includes") TEST_CASE("[Files] Multiple includes with comments") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/multiple_includes_with_comments.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Includes/multiple_includes_with_comments.sfz"); REQUIRE(synth.getNumRegions() == 2); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy.wav"); REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy2.wav"); @@ -94,7 +94,7 @@ TEST_CASE("[Files] Multiple includes with comments") TEST_CASE("[Files] Subdir include") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_subdir.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Includes/root_subdir.sfz"); REQUIRE(synth.getNumRegions() == 1); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy_subdir.wav"); } @@ -102,7 +102,7 @@ TEST_CASE("[Files] Subdir include") TEST_CASE("[Files] Subdir include Win") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_subdir_win.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Includes/root_subdir_win.sfz"); REQUIRE(synth.getNumRegions() == 1); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy_subdir.wav"); } @@ -112,7 +112,7 @@ TEST_CASE("[Files] Recursive include (with include guard)") Synth synth; Parser& parser = synth.getParser(); parser.setRecursiveIncludeGuardEnabled(true); - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_recursive.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Includes/root_recursive.sfz"); REQUIRE(synth.getNumRegions() == 2); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy_recursive2.wav"); REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy_recursive1.wav"); @@ -123,7 +123,7 @@ TEST_CASE("[Files] Include loops (with include guard)") Synth synth; Parser& parser = synth.getParser(); parser.setRecursiveIncludeGuardEnabled(true); - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_loop.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "Includes/root_loop.sfz"); REQUIRE(synth.getNumRegions() == 2); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "dummy_loop2.wav"); REQUIRE(synth.getRegionView(1)->sampleId->filename() == "dummy_loop1.wav"); @@ -132,7 +132,7 @@ TEST_CASE("[Files] Include loops (with include guard)") TEST_CASE("[Files] Define test") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/defines.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "defines.sfz"); REQUIRE(synth.getNumRegions() == 4); REQUIRE(synth.getRegionView(0)->keyRange == Range(36, 36)); REQUIRE(synth.getRegionView(1)->keyRange == Range(38, 38)); @@ -143,7 +143,7 @@ TEST_CASE("[Files] Define test") TEST_CASE("[Files] Group from AVL") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/groups_avl.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "groups_avl.sfz"); REQUIRE(synth.getNumRegions() == 5); for (int i = 0; i < synth.getNumRegions(); ++i) { REQUIRE(synth.getRegionView(i)->volume == 6.0f); @@ -160,7 +160,7 @@ TEST_CASE("[Files] Group from AVL") TEST_CASE("[Files] Full hierarchy") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "basic_hierarchy.sfz"); REQUIRE(synth.getNumRegions() == 8); for (int i = 0; i < synth.getNumRegions(); ++i) { REQUIRE(synth.getRegionView(i)->width == 0.4_a); @@ -201,9 +201,9 @@ TEST_CASE("[Files] Full hierarchy") TEST_CASE("[Files] Reloading files") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "basic_hierarchy.sfz"); REQUIRE(synth.getNumRegions() == 8); - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "basic_hierarchy.sfz"); REQUIRE(synth.getNumRegions() == 8); } @@ -211,7 +211,7 @@ TEST_CASE("[Files] Full hierarchy with antislashes") { { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "basic_hierarchy.sfz"); REQUIRE(synth.getNumRegions() == 8); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "Regions/dummy.wav"); REQUIRE(synth.getRegionView(1)->sampleId->filename() == "Regions/dummy.1.wav"); @@ -225,7 +225,7 @@ TEST_CASE("[Files] Full hierarchy with antislashes") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy_antislash.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "basic_hierarchy_antislash.sfz"); REQUIRE(synth.getNumRegions() == 8); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "Regions/dummy.wav"); REQUIRE(synth.getRegionView(1)->sampleId->filename() == "Regions/dummy.1.wav"); @@ -241,7 +241,7 @@ TEST_CASE("[Files] Full hierarchy with antislashes") TEST_CASE("[Files] Pizz basic") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/SpecificBugs/MeatBassPizz/Programs/pizz.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "SpecificBugs/MeatBassPizz/Programs/pizz.sfz"); REQUIRE(synth.getNumRegions() == 4); for (int i = 0; i < synth.getNumRegions(); ++i) { REQUIRE(synth.getRegionView(i)->keyRange == Range(12, 22)); @@ -263,7 +263,7 @@ TEST_CASE("[Files] Pizz basic") TEST_CASE("[Files] Channels (channels.sfz)") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/channels.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "channels.sfz"); REQUIRE(synth.getNumRegions() == 2); REQUIRE(synth.getRegionView(0)->sampleId->filename() == "mono_sample.wav"); REQUIRE(!synth.getRegionView(0)->isStereo()); @@ -274,7 +274,7 @@ TEST_CASE("[Files] Channels (channels.sfz)") TEST_CASE("[Files] Generators and wavetables") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/wavetables.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "wavetables.sfz"); REQUIRE(synth.getNumRegions() == 12); int regionNumber = 0; @@ -377,7 +377,7 @@ TEST_CASE("[Files] Generators and wavetables") TEST_CASE("[Files] Embedded wavetables") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/wavetables_embedded.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "wavetables_embedded.sfz"); REQUIRE(synth.getNumRegions() == 7); int regionNumber = 0; @@ -440,7 +440,7 @@ TEST_CASE("[Files] Embedded wavetables") TEST_CASE("[Files] wrong (overlapping) replacement for defines") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/SpecificBugs/wrong-replacements.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "SpecificBugs/wrong-replacements.sfz"); REQUIRE( synth.getNumRegions() == 3 ); @@ -463,7 +463,7 @@ TEST_CASE("[Files] wrong (overlapping) replacement for defines") TEST_CASE("[Files] Specific bug: relative path with backslashes") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/SpecificBugs/win_backslashes.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "SpecificBugs/win_backslashes.sfz"); REQUIRE(synth.getNumRegions() == 1); REQUIRE(synth.getRegionView(0)->sampleId->filename() == R"(Xylo/Subfolder/closedhat.wav)"); } @@ -471,7 +471,7 @@ TEST_CASE("[Files] Specific bug: relative path with backslashes") TEST_CASE("[Files] Default path") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "default_path.sfz"); REQUIRE(synth.getNumRegions() == 4); REQUIRE(synth.getRegionView(0)->sampleId->filename() == R"(DefaultPath/SubPath1/sample1.wav)"); REQUIRE(synth.getRegionView(1)->sampleId->filename() == R"(DefaultPath/SubPath2/sample2.wav)"); @@ -482,9 +482,9 @@ TEST_CASE("[Files] Default path") TEST_CASE("[Files] Default path reset when calling loadSfzFile again") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "default_path.sfz"); REQUIRE(synth.getNumRegions() == 4); - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path_reset.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "default_path_reset.sfz"); REQUIRE(synth.getNumRegions() == 1); REQUIRE(synth.getRegionView(0)->sampleId->filename() == R"(DefaultPath/SubPath2/sample2.wav)"); } @@ -492,7 +492,7 @@ TEST_CASE("[Files] Default path reset when calling loadSfzFile again") TEST_CASE("[Files] Default path is ignored for generators") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path_generator.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "default_path_generator.sfz"); REQUIRE(synth.getNumRegions() == 1); REQUIRE(synth.getRegionView(0)->sampleId->filename() == R"(*sine)"); } @@ -501,7 +501,7 @@ TEST_CASE("[Files] Set CC applies properly") { Synth synth; const MidiState& midiState = synth.getResources().getMidiState(); - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_cc.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "set_cc.sfz"); REQUIRE(midiState.getCCValue(142) == 63_norm); REQUIRE(midiState.getCCValue(61) == 122_norm); } @@ -510,7 +510,7 @@ TEST_CASE("[Files] Set HDCC applies properly") { sfz::Synth synth; const MidiState& midiState = synth.getResources().getMidiState(); - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_hdcc.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "set_hdcc.sfz"); REQUIRE(midiState.getCCValue(142) == Approx(0.5678)); REQUIRE(midiState.getCCValue(61) == Approx(0.1234)); } @@ -519,7 +519,7 @@ TEST_CASE("[Files] Set RealCC applies properly") { sfz::Synth synth; const MidiState& midiState = synth.getResources().getMidiState(); - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_realcc.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "set_realcc.sfz"); REQUIRE(midiState.getCCValue(142) == Approx(0.5678)); REQUIRE(midiState.getCCValue(61) == Approx(0.1234)); } @@ -527,7 +527,7 @@ TEST_CASE("[Files] Set RealCC applies properly") TEST_CASE("[Files] Note and octave offsets") { Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/note_offset.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "note_offset.sfz", R"( note_offset=1 key=63 sample=*sine lokey=50 hikey=55 pitch_keycenter=50 sample=*sine @@ -582,7 +582,7 @@ TEST_CASE("[Files] Off modes") AudioBuffer buffer { 2, 256 }; synth.setSamplesPerBlock(256); - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/off_mode.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "off_mode.sfz"); REQUIRE( synth.getNumRegions() == 3 ); synth.noteOn(0, 64, 63); @@ -613,7 +613,7 @@ TEST_CASE("[Files] Looped regions taken from files and possibly overriden") Synth synth; synth.setSamplesPerBlock(256); synth.setSampleRate(44100); - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/looped_regions.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "looped_regions.sfz"); REQUIRE( synth.getNumRegions() == 3 ); REQUIRE( synth.getRegionView(0)->loopMode == LoopMode::loop_continuous ); REQUIRE( synth.getRegionView(1)->loopMode == LoopMode::no_loop ); @@ -627,7 +627,7 @@ TEST_CASE("[Files] Looped regions taken from files and possibly overriden") TEST_CASE("[Files] Looped regions can start at 0") { Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/loop_can_start_at_0.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "loop_can_start_at_0.sfz", R"( sample=wavetable_with_loop_at_endings.wav )"); REQUIRE( synth.getNumRegions() == 1 ); @@ -638,7 +638,7 @@ TEST_CASE("[Files] Looped regions can start at 0") TEST_CASE("[Synth] Release triggers automatically sets the loop mode") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/triggers_setting_loops.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "triggers_setting_loops.sfz", R"( sample=kick.wav pitch_keycenter=69 loop_mode=loop_sustain trigger=release sample=kick.wav pitch_keycenter=69 loop_mode=loop_sustain trigger=release_key sample=kick.wav pitch_keycenter=69 trigger=release loop_mode=loop_sustain @@ -659,14 +659,12 @@ TEST_CASE("[Synth] Release triggers automatically sets the loop mode") TEST_CASE("[Files] Case sentitiveness") { - const fs::path sfzFilePath = fs::current_path() / "tests/TestFiles/case_insensitive.sfz"; + const fs::path sfzFilePath = fs::path(SFIZZ_TEST_FILES) / "case_insensitive.sfz"; -#if defined(_WIN32) - const bool caseSensitiveFs = false; -#elif defined(__APPLE__) +#if defined(__APPLE__) const bool caseSensitiveFs = pathconf(sfzFilePath.string().c_str(), _PC_CASE_SENSITIVE) != 0; #else - const bool caseSensitiveFs = true; + const bool caseSensitiveFs = !fs::exists(fs::path(SFIZZ_TEST_FILES) / "CASE_INSENSITIVE.sfz"); #endif if (caseSensitiveFs) { @@ -693,7 +691,7 @@ TEST_CASE("[Files] Empty file") TEST_CASE("[Files] Labels") { sfz::Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/labels.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "labels.sfz"); auto keyLabels = synth.getKeyLabels(); auto ccLabels = synth.getCCLabels(); REQUIRE( keyLabels.size() == 2); @@ -714,7 +712,7 @@ TEST_CASE("[Files] Labels") TEST_CASE("[Files] Switch labels") { sfz::Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/labels_sw.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "labels_sw.sfz"); const std::string xmlMidnam = synth.exportMidnam(); REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); @@ -725,7 +723,7 @@ TEST_CASE("[Files] Duplicate labels") { sfz::Synth synth; synth.loadSfzString( - fs::current_path() / "tests/TestFiles/labels.sfz", + fs::path(SFIZZ_TEST_FILES) / "labels.sfz", R"( label_key60=Baz label_key60=Quux label_cc20=Foo label_cc20=Bar sample=*sine)"); @@ -745,7 +743,7 @@ TEST_CASE("[Files] Duplicate labels") TEST_CASE("[Files] Key center from audio file") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sample_keycenter.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sample_keycenter.sfz", R"( pitch_keycenter=sample oscillator=off sample=root_key_38.wav sample=root_key_62.wav @@ -767,14 +765,14 @@ TEST_CASE("[Files] Key center from audio file") TEST_CASE("[Files] Unused samples are cleared on reloading") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/unused_samples.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "unused_samples.sfz", R"( sample=*sine sample=kick.wav )"); REQUIRE(synth.getNumPreloadedSamples() == 1); // Same file path to reload - synth.loadSfzString(fs::current_path() / "tests/TestFiles/unused_samples.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "unused_samples.sfz", R"( sample=*sine )"); REQUIRE(synth.getNumPreloadedSamples() == 0); @@ -783,7 +781,7 @@ TEST_CASE("[Files] Unused samples are cleared on reloading") TEST_CASE("[Files] Key center from audio file, with embedded sample data") { sfz::Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/sample_keycenter_embedded.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "sample_keycenter_embedded.sfz"); REQUIRE(synth.getNumRegions() == 6); REQUIRE(synth.getRegionView(0)->pitchKeycenter == 38); @@ -797,7 +795,7 @@ TEST_CASE("[Files] Key center from audio file, with embedded sample data") TEST_CASE("[Files] NewDrums: disappearing CCs (#1077)") { sfz::Synth synth; - REQUIRE( synth.loadSfzFile(fs::current_path() / "tests/TestFiles/newdrums_flat.sfz") ); + REQUIRE( synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "newdrums_flat.sfz") ); REQUIRE( synth.getNumRegions() > 0 ); auto used_ccs = synth.getUsedCCs().span(); diff --git a/tests/LFOT.cpp b/tests/LFOT.cpp index 77776bafa..18ededdcc 100644 --- a/tests/LFOT.cpp +++ b/tests/LFOT.cpp @@ -77,10 +77,10 @@ static constexpr double mseThreshold = 1e-3; TEST_CASE("[LFO] Waves") { DataPoints ref; - REQUIRE(load_txt_file(ref, "tests/lfo/lfo_waves_reference.dat")); + REQUIRE(load_txt_file(ref, SFIZZ_TEST_DIR "/lfo/lfo_waves_reference.dat")); DataPoints cur; - REQUIRE(computeLFO(cur, "tests/lfo/lfo_waves.sfz", 100.0, ref.rows)); + REQUIRE(computeLFO(cur, SFIZZ_TEST_DIR "/lfo/lfo_waves.sfz", 100.0, ref.rows)); REQUIRE(ref.rows == cur.rows); REQUIRE(ref.cols == cur.cols); @@ -94,10 +94,10 @@ TEST_CASE("[LFO] Waves") TEST_CASE("[LFO] Subwave") { DataPoints ref; - REQUIRE(load_txt_file(ref, "tests/lfo/lfo_subwave_reference.dat")); + REQUIRE(load_txt_file(ref, SFIZZ_TEST_DIR "/lfo/lfo_subwave_reference.dat")); DataPoints cur; - REQUIRE(computeLFO(cur, "tests/lfo/lfo_subwave.sfz", 100.0, ref.rows)); + REQUIRE(computeLFO(cur, SFIZZ_TEST_DIR "/lfo/lfo_subwave.sfz", 100.0, ref.rows)); REQUIRE(ref.rows == cur.rows); REQUIRE(ref.cols == cur.cols); @@ -111,10 +111,10 @@ TEST_CASE("[LFO] Subwave") TEST_CASE("[LFO] Fade and delay") { DataPoints ref; - REQUIRE(load_txt_file(ref, "tests/lfo/lfo_fade_and_delay_reference.dat")); + REQUIRE(load_txt_file(ref, SFIZZ_TEST_DIR "/lfo/lfo_fade_and_delay_reference.dat")); DataPoints cur; - REQUIRE(computeLFO(cur, "tests/lfo/lfo_fade_and_delay.sfz", 100.0, ref.rows)); + REQUIRE(computeLFO(cur, SFIZZ_TEST_DIR "/lfo/lfo_fade_and_delay.sfz", 100.0, ref.rows)); REQUIRE(ref.rows == cur.rows); REQUIRE(ref.cols == cur.cols); diff --git a/tests/MainT.cpp b/tests/MainT.cpp index 156e3ac50..8b9432c81 100644 --- a/tests/MainT.cpp +++ b/tests/MainT.cpp @@ -5,26 +5,12 @@ #include -static bool moveToTestsDirectory(const fs::path& searchedPath); - int main(int argc, char* argv[]) { - if (!moveToTestsDirectory(fs::u8path("tests/TestFiles"))) { + if (!fs::exists(SFIZZ_TEST_FILES) || !fs::exists(SFIZZ_TEST_DIR)) { std::cerr << "Failed to locate test files\n"; return 1; } int result = Catch::Session().run(argc, argv); return result; } - -static bool moveToTestsDirectory(const fs::path& searchedPath) -{ - while (!fs::exists(searchedPath)) { - fs::path cwdPath = fs::current_path(); - fs::path newPath = cwdPath.parent_path(); - if (cwdPath == newPath) - return false; - fs::current_path(newPath); - } - return true; -} diff --git a/tests/MidiStateT.cpp b/tests/MidiStateT.cpp index 57080c14f..53081dc9f 100644 --- a/tests/MidiStateT.cpp +++ b/tests/MidiStateT.cpp @@ -143,7 +143,7 @@ TEST_CASE("[CC] Extended CCs on offset and delay") SECTION("CC131 - Note on velocity") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/extended_ccs.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "extended_ccs.sfz", R"( key=60 delay_cc131=1 sample=kick.wav key=61 offset_cc131=100 sample=snare.wav )"); @@ -166,7 +166,7 @@ TEST_CASE("[CC] Extended CCs on offset and delay") SECTION("CC132 - Note off velocity") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/extended_ccs.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "extended_ccs.sfz", R"( key=60 sample=*silence key=60 delay_cc132=1 sample=kick.wav trigger=release key=61 sample=snare.wav @@ -195,7 +195,7 @@ TEST_CASE("[CC] Extended CCs on offset and delay") SECTION("CC133 - Note number") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/extended_ccs.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "extended_ccs.sfz", R"( delay_cc133=1 offset_cc133=100 sample=kick.wav )"); synth.hdNoteOn(0, 0, 1.0f); @@ -215,7 +215,7 @@ TEST_CASE("[CC] Extended CCs on offset and delay") SECTION("CC134 - Note gate") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/extended_ccs.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "extended_ccs.sfz", R"( delay_cc134=1 offset_cc134=100 sample=kick.wav )"); synth.hdNoteOn(0, 60, 1.0f); @@ -247,7 +247,7 @@ TEST_CASE("[CC] Extended CCs on offset and delay") SECTION("CC137 - Alternate") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/extended_ccs.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "extended_ccs.sfz", R"( delay_cc137=1 offset_cc137=100 sample=kick.wav )"); synth.hdNoteOn(0, 60, 1.0f); @@ -277,7 +277,7 @@ TEST_CASE("[CC] Extended CCs on offset and delay") SECTION("CC140 - Keydelta") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/extended_ccs.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "extended_ccs.sfz", R"( delay=2 offset=200 delay_cc140=1 offset_cc140=100 sample=kick.wav )"); synth.hdNoteOn(0, 60, 1.0f); @@ -302,7 +302,7 @@ TEST_CASE("[CC] Extended CCs on offset and delay") SECTION("CC141 - Absolute Keydelta") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/extended_ccs.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "extended_ccs.sfz", R"( delay=2 offset=200 delay_cc141=1 offset_cc141=100 sample=kick.wav )"); synth.hdNoteOn(0, 60, 1.0f); diff --git a/tests/ParsingT.cpp b/tests/ParsingT.cpp index 6e3877641..7eee64bdc 100644 --- a/tests/ParsingT.cpp +++ b/tests/ParsingT.cpp @@ -651,7 +651,7 @@ TEST_CASE("[Parsing] Expanded value of #include") sfz::Parser parser; ParsingMocker mock; parser.setListener(&mock); - parser.parseFile(fs::current_path() / "tests/TestFiles/dollar_include_main.sfz"); + parser.parseFile(fs::path(SFIZZ_TEST_FILES) / "dollar_include_main.sfz"); std::vector> expectedMembers = { {{"sample", "*sine"}}, diff --git a/tests/PolyphonyT.cpp b/tests/PolyphonyT.cpp index e9eb6f4a3..184e7c622 100644 --- a/tests/PolyphonyT.cpp +++ b/tests/PolyphonyT.cpp @@ -20,7 +20,7 @@ using namespace sfz::literals; TEST_CASE("[Polyphony] Polyphony in hierarchy") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( key=61 sample=*sine polyphony=2 polyphony=2 key=62 sample=*sine @@ -47,7 +47,7 @@ TEST_CASE("[Polyphony] Polyphony in hierarchy") TEST_CASE("[Polyphony] Polyphony groups") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( polyphony=2 key=62 sample=*sine group=1 polyphony=3 @@ -75,7 +75,7 @@ TEST_CASE("[Polyphony] group polyphony limits") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( group=1 polyphony=2 sample=*sine key=65 )"); @@ -91,7 +91,7 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( polyphony=2 sample=*sine key=65 )"); @@ -107,7 +107,7 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (group)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( polyphony=2 sample=*sine key=65 )"); @@ -123,7 +123,7 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (master)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( polyphony=2 polyphony=5 sample=*sine key=65 @@ -140,7 +140,7 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (limit in another master)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( polyphony=2 sample=*saw key=65 @@ -162,7 +162,7 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (global)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( polyphony=2 polyphony=5 sample=*sine key=65 @@ -179,7 +179,7 @@ TEST_CASE("[Polyphony] Polyphony in master") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( polyphony=2 group=2 sample=*sine key=65 @@ -219,7 +219,7 @@ TEST_CASE("[Polyphony] Self-masking") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( sample=*sine key=64 note_polyphony=2 )"); synth.noteOn(0, 64, 63); @@ -240,7 +240,7 @@ TEST_CASE("[Polyphony] Not self-masking") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( sample=*sine key=66 note_polyphony=2 note_selfmask=off )"); synth.noteOn(0, 66, 63 ); @@ -282,7 +282,7 @@ TEST_CASE("[Polyphony] Self-masking only works from low to high") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( sample=*sine key=64 note_polyphony=1 )"); synth.noteOn(0, 64, 63 ); @@ -300,7 +300,7 @@ TEST_CASE("[Polyphony] Note polyphony checks works across regions in the same po { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( sample=*saw key=64 note_polyphony=1 sample=*sine key=64 note_polyphony=1 )"); @@ -322,7 +322,7 @@ TEST_CASE("[Polyphony] Note polyphony checks works across regions in the same po { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( sw_lokey=36 sw_hikey=37 sw_default=36 sw_last=36 key=48 note_polyphony=1 sample=*saw sw_last=37 key=48 transpose=12 note_polyphony=1 sample=*tri @@ -348,7 +348,7 @@ TEST_CASE("[Polyphony] Note polyphony do not operate across polyphony groups") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( group=1 sample=*saw key=64 note_polyphony=1 group=2 sample=*sine key=64 note_polyphony=1 )"); @@ -371,7 +371,7 @@ TEST_CASE("[Polyphony] Note polyphony do not operate across polyphony groups (wi { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( sw_lokey=36 sw_hikey=37 sw_default=36 group=1 sw_last=36 key=48 note_polyphony=1 sample=*saw group=2 sw_last=37 key=48 transpose=12 note_polyphony=1 sample=*tri @@ -396,7 +396,7 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( key=48 note_polyphony=1 sample=*saw trigger=release_key ampeg_attack=1 ampeg_decay=1 )"); synth.noteOn(0, 48, 63 ); @@ -418,7 +418,7 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices (masking works { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( key=48 note_polyphony=1 sample=*saw trigger=release_key ampeg_attack=1 ampeg_decay=1 )"); synth.noteOn(0, 48, 63 ); @@ -441,7 +441,7 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices and sustain ped { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( key=48 sample=*sine key=48 note_polyphony=1 sample=*saw trigger=release ampeg_attack=1 ampeg_decay=1 )"); @@ -467,7 +467,7 @@ TEST_CASE("[Polyphony] Note polyphony operates on release voices and sustain ped { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( key=48 sample=*sine key=48 note_polyphony=1 sample=*saw trigger=release ampeg_attack=1 ampeg_decay=1 )"); @@ -493,7 +493,7 @@ TEST_CASE("[Polyphony] Bi-directional choking (with polyphony)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( key=60 polyphony=1 sample=kick.wav loop_mode=one_shot sample=snare.wav trigger=release @@ -513,7 +513,7 @@ TEST_CASE("[Polyphony] Bi-directional choking (with note_polyphony)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( key=60 note_polyphony=1 sample=kick.wav loop_mode=one_shot sample=snare.wav trigger=release @@ -533,7 +533,7 @@ TEST_CASE("[Polyphony] Choke long release tails") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( sample=*saw ampeg_attack=0.1 ampeg_release=10 polyphony=1 )"); int attackBlocks = static_cast(0.1f / synth.getSamplesPerBlock() * 48000.0f) + 1; @@ -554,7 +554,7 @@ TEST_CASE("[Polyphony] Choke long release tails with note_polyphony") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( sample=*saw ampeg_attack=0.1 ampeg_release=10 note_polyphony=1 )"); int attackBlocks = static_cast(0.1f / synth.getSamplesPerBlock() * 48000.0f) + 1; @@ -575,7 +575,7 @@ TEST_CASE("[Polyphony] Choke same group and note if the region is switched off ( { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( group=1 off_by=1 locc1=0 hicc1=63 sample=*saw locc1=64 hicc1=127 sample=*sine @@ -593,7 +593,7 @@ TEST_CASE("[Polyphony] Choking on poly-aftertouch respects the note number") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyat_choke.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyat_choke.sfz", R"( key=55 group=1 off_by=2 sample=*saw key=55 group=2 on_locc130=127 on_hicc130=127 trigger=release sample=*sine )"); @@ -618,7 +618,7 @@ TEST_CASE("[Polyphony] A note coming at the same time as another can choke it") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( key=69 off_by=2 off_mode=normal tune=-3200 ampeg_release=1 sample=snare.wav key=81 group=2 sample=kick.wav )"); @@ -633,7 +633,7 @@ TEST_CASE("[Polyphony] A note coming one sample after another note can choke it" { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( key=69 off_by=2 off_mode=normal tune=-3200 ampeg_release=1 sample=snare.wav key=81 group=2 sample=kick.wav )"); @@ -648,7 +648,7 @@ TEST_CASE("[Polyphony] A note coming one sample before another note cannot choke { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( key=69 off_by=2 off_mode=normal tune=-3200 ampeg_release=1 sample=snare.wav key=81 group=2 sample=kick.wav )"); diff --git a/tests/RegionActivationT.cpp b/tests/RegionActivationT.cpp index 67389f85b..037eaaca9 100644 --- a/tests/RegionActivationT.cpp +++ b/tests/RegionActivationT.cpp @@ -192,7 +192,7 @@ TEST_CASE("[Keyswitches] Normal lastKeyswitch range") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "keyswitches.sfz", R"( sw_lokey=40 sw_hikey=42 sw_default=40 sw_last=40 key=60 sample=*sine sw_last=41 key=62 sample=*saw @@ -216,7 +216,7 @@ TEST_CASE("[Keyswitches] No lastKeyswitch range") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "keyswitches.sfz", R"( sw_last=40 key=60 sample=*sine sw_last=41 key=62 sample=*saw )"); @@ -246,7 +246,7 @@ TEST_CASE("[Keyswitches] Out of lastKeyswitch range") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "keyswitches.sfz", R"( sw_lokey=40 sw_hikey=42 sw_default=40 sw_last=40 key=60 sample=*sine sw_last=43 key=62 sample=*saw @@ -270,7 +270,7 @@ TEST_CASE("[Keyswitches] Overlapping key and lastKeyswitch range") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "keyswitches.sfz", R"( sw_lokey=1 sw_hikey=127 sw_default=40 sw_last=40 key=60 sample=*sine sw_last=41 key=62 sample=*saw @@ -301,7 +301,7 @@ TEST_CASE("[Keyswitches] sw_down, in range") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "keyswitches.sfz", R"( sw_lokey=1 sw_hikey=127 sw_default=40 sw_down=40 key=60 sample=*sine )"); @@ -322,7 +322,7 @@ TEST_CASE("[Keyswitches] sw_down, out of range") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "keyswitches.sfz", R"( sw_lokey=1 sw_hikey=10 sw_default=40 sw_down=40 key=60 sample=*sine )"); @@ -343,7 +343,7 @@ TEST_CASE("[Keyswitches] sw_up, in range") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "keyswitches.sfz", R"( sw_lokey=1 sw_hikey=127 sw_default=40 sw_up=40 key=60 sample=*sine )"); @@ -364,7 +364,7 @@ TEST_CASE("[Keyswitches] sw_up, out of range") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/keyswitches.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "keyswitches.sfz", R"( sw_lokey=1 sw_hikey=127 sw_default=40 sw_up=40 key=60 sample=*sine )"); @@ -385,7 +385,7 @@ TEST_CASE("[Keyswitches] sw_default") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_default.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_default.sfz", R"( sw_lokey=30 sw_hikey=50 sw_default=40 sw_last=41 key=51 sample=*sine sw_last=40 key=52 sample=*sine @@ -403,7 +403,7 @@ TEST_CASE("[Keyswitches] sw_default and playing with switches") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_default.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_default.sfz", R"( sw_lokey=30 sw_hikey=50 sw_default=40 sw_last=41 key=51 sample=*sine sw_last=40 key=52 sample=*sine @@ -435,7 +435,7 @@ TEST_CASE("[Keyswitches] sw_previous in range") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( sample=*saw sw_previous=60 lokey=50 hikey=70 )"); // Note: sforzando seems to activate by default if sw_previous is indeed 60, @@ -468,7 +468,7 @@ TEST_CASE("[Keyswitches] sw_previous out of range") // The behavior is the same in this case, regardless of the keyrange sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( sample=*saw sw_previous=60 lokey=50 hikey=55 )"); REQUIRE(!synth.getLayerView(0)->isSwitchedOn()); @@ -496,7 +496,7 @@ TEST_CASE("[Keyswitches] sw_lolast and sw_hilast") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( sw_lolast=57 sw_hilast=59 key=70 sample=*saw sw_lolast=60 sw_hilast=62 key=72 sample=*sine )"); @@ -536,7 +536,7 @@ TEST_CASE("[Keyswitches] sw_lolast and sw_hilast with sw_last") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( sw_last=40 sw_lolast=57 sw_hilast=59 key=70 sample=*saw sw_lolast=60 sw_hilast=62 sw_last=41 key=72 sample=*sine )"); @@ -572,7 +572,7 @@ TEST_CASE("[Keyswitches] sw_lolast and sw_hilast with sw_default") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( sw_default=58 sw_lolast=57 sw_hilast=59 key=70 sample=*saw sw_lolast=60 sw_hilast=62 key=72 sample=*sine @@ -585,7 +585,7 @@ TEST_CASE("[Keyswitches] Multiple sw_default") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( sw_default=60 sw_last=60 key=70 sample=*saw sw_default=58 @@ -603,7 +603,7 @@ TEST_CASE("[Keyswitches] Multiple sw_default, in region") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( sw_default=60 sw_last=58 key=70 sample=*saw sw_default=58 sw_last=59 key=72 sample=*saw @@ -617,7 +617,7 @@ TEST_CASE("[Region activation] Polyphonic aftertouch") sfz::Synth synth; SECTION("Basic sequence, note on") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyaft.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyaft.sfz", R"( sample=*saw lokey=48 hikey=60 lopolyaft=50 hipolyaft=100 sample=*sine lokey=36 hikey=47 )"); @@ -632,7 +632,7 @@ TEST_CASE("[Region activation] Polyphonic aftertouch") SECTION("Basic sequence, note off, no polyaft set") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyaft.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyaft.sfz", R"( sample=*saw lopolyaft=50 hipolyaft=100 sample=*sine trigger=release )"); @@ -644,7 +644,7 @@ TEST_CASE("[Region activation] Polyphonic aftertouch") SECTION("Basic sequence, note off") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyaft.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyaft.sfz", R"( sample=*saw lopolyaft=50 hipolyaft=100 sample=*sine trigger=release )"); @@ -668,7 +668,7 @@ TEST_CASE("[Keyswitches] sw_default with octave_offset") }; SECTION("In ") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( octave_offset=1 note_offset=-1 sw_default=48 sample=*sine @@ -678,7 +678,7 @@ TEST_CASE("[Keyswitches] sw_default with octave_offset") } SECTION("In ") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( octave_offset=1 note_offset=-1 sw_default=48 sample=*sine @@ -688,7 +688,7 @@ TEST_CASE("[Keyswitches] sw_default with octave_offset") } SECTION("In ") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( octave_offset=1 note_offset=-1 sw_default=48 sample=*sine @@ -698,7 +698,7 @@ TEST_CASE("[Keyswitches] sw_default with octave_offset") } SECTION("In ") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( octave_offset=1 note_offset=-1 sample=*sine sw_default=48 )"); @@ -713,7 +713,7 @@ TEST_CASE("[Region activation] Program change") sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; SECTION("Default value") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( sample=*saw )"); REQUIRE(synth.getLayerView(0)->isSwitchedOn()); @@ -728,7 +728,7 @@ TEST_CASE("[Region activation] Program change") } SECTION("Change range") { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_previous.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_previous.sfz", R"( sample=*saw hiprog=2 sample=*sine loprog=1 hiprog=126 sample=*tri loprog=-1 hiprog=200 diff --git a/tests/RegionTriggersT.cpp b/tests/RegionTriggersT.cpp index ec6d0cd8f..ae52b3993 100644 --- a/tests/RegionTriggersT.cpp +++ b/tests/RegionTriggersT.cpp @@ -249,7 +249,7 @@ TEST_CASE("[Triggers] sw_vel, basic") std::vector messageList; Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_vel.sfz", R"( key=60 sample=kick.wav key=62 sw_previous=60 sw_vel=previous sample=snare.wav )"); @@ -274,7 +274,7 @@ TEST_CASE("[Triggers] sw_vel, without sw_previous") std::vector messageList; Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_vel.sfz", R"( key=60 sample=kick.wav key=62 sw_vel=previous sample=snare.wav )"); @@ -299,7 +299,7 @@ TEST_CASE("[Triggers] sw_vel, with a note in between") std::vector messageList; Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_vel.sfz", R"( key=60 sample=kick.wav key=62 sw_vel=previous sample=snare.wav key=64 sample=closedhat.wav @@ -328,7 +328,7 @@ TEST_CASE("[Triggers] sw_vel, with a note in between and sw_previous") std::vector messageList; Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_vel.sfz", R"( key=60 sample=kick.wav key=62 sw_previous=60 sw_vel=previous sample=snare.wav key=64 sample=closedhat.wav @@ -355,7 +355,7 @@ TEST_CASE("[Triggers] sw_vel, consider the previous velocity for triggers") std::vector messageList; Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_vel.sfz", R"( key=60 sample=kick.wav key=62 sw_previous=60 sw_vel=previous sample=snare.wav lovel=63 )"); @@ -397,7 +397,7 @@ TEST_CASE("[Triggers] Honor lorand/hirand on CC triggers") std::vector messageList; Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_vel.sfz", R"( sample=*sine hikey=-1 start_locc64=63 start_hicc64=127 lorand=0 hirand=0.5 sample=*saw hikey=-1 start_locc64=63 start_hicc64=127 lorand=0.5 hirand=1 )"); @@ -415,7 +415,7 @@ TEST_CASE("[Triggers] Offed voices with CC triggers do not activate release trig std::vector messageList; Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_vel.sfz", R"( sample=*sine hikey=-1 start_locc64=63 start_hicc64=127 group=1 off_by=2 sample=*saw hikey=-1 start_locc64=0 start_hicc64=62 group=2 sample=*noise trigger=release_key @@ -433,7 +433,7 @@ TEST_CASE("[Triggers] lotimer") synth.setSampleRate(48000); synth.setSamplesPerBlock(480); sfz::AudioBuffer buffer { 2, 480 }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_vel.sfz", R"( key=40 lotimer=0.1 sample=kick.wav loop_mode=one_shot )"); @@ -472,7 +472,7 @@ TEST_CASE("[Triggers] lotimer on CC") synth.setSampleRate(48000); synth.setSamplesPerBlock(480); sfz::AudioBuffer buffer { 2, 480 }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_vel.sfz", R"( start_locc4=100 start_hicc4=100 lotimer=0.1 sample=kick.wav loop_mode=one_shot )"); @@ -512,7 +512,7 @@ TEST_CASE("[Triggers] hitimer (with group)") synth.setSampleRate(48000); synth.setSamplesPerBlock(480); sfz::AudioBuffer buffer { 2, 480 }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sw_vel.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sw_vel.sfz", R"( group=1 key=40 sample=snare.wav loop_mode=one_shot group=1 key=41 hitimer=0.1 sample=kick.wav loop_mode=one_shot )"); @@ -544,8 +544,8 @@ TEST_CASE("[Triggers] hitimer (with group)") // Advance time (it has to be 0.1s because playing the kick resets the timer) for (int i = 0; i < 10; ++i) synth.renderBlock(buffer); - - // t = 0.25s, not triggering a new kick + + // t = 0.25s, not triggering a new kick REQUIRE(playingSamples(synth) == std::vector { "snare.wav", "kick.wav", "kick.wav" }); synth.noteOn(0, 41, 100); REQUIRE(playingSamples(synth) == std::vector { "snare.wav", "kick.wav", "kick.wav" }); @@ -554,7 +554,7 @@ TEST_CASE("[Triggers] hitimer (with group)") TEST_CASE("[Triggers] Respect poly-aftertouch note values when triggering on cc130") { Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/poly_at_trigger.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "poly_at_trigger.sfz", R"( key=55 on_locc130=127 on_hicc130=127 sample=*saw key=57 on_locc130=127 on_hicc130=127 sample=*sine )"); diff --git a/tests/SynthDiscussion.h b/tests/SynthDiscussion.h index 0381a0089..7ac103b5d 100644 --- a/tests/SynthDiscussion.h +++ b/tests/SynthDiscussion.h @@ -65,7 +65,7 @@ struct SynthDiscussion void load(absl::string_view sfz) { - synth.loadSfzString(fs::current_path() / "tests/TestFiles/discussion.sfz", sfz); + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "discussion.sfz", sfz); } void send(absl::string_view path, int32_t value) diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index 311533ad7..26b271579 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -24,7 +24,7 @@ TEST_CASE("[Synth] Play and check active voices") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/groups_avl.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "groups_avl.sfz"); synth.noteOn(0, 36, 24); synth.noteOn(0, 36, 89); @@ -40,7 +40,7 @@ TEST_CASE("[Synth] All sound off") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/groups_avl.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "groups_avl.sfz"); synth.noteOn(0, 36, 24); synth.noteOn(0, 36, 89); synth.renderBlock(buffer); @@ -54,7 +54,7 @@ TEST_CASE("[Synth] Change the number of voice while playing") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/groups_avl.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "groups_avl.sfz"); synth.noteOn(0, 36, 24); synth.noteOn(0, 36, 89); @@ -101,7 +101,7 @@ TEST_CASE("[Synth] Check that we can change the size of the preload before and a sfz::Synth synth; synth.setPreloadSize(512); sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/groups_avl.sfz"); + synth.loadSfzFile(fs::path(SFIZZ_TEST_FILES) / "groups_avl.sfz"); synth.setPreloadSize(1024); synth.noteOn(0, 36, 24); @@ -116,7 +116,7 @@ TEST_CASE("[Synth] All notes offs/all sounds off") sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; synth.setNumVoices(8); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sound_off.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sound_off.sfz", R"( key=60 sample=*noise key=62 sample=*noise )"); @@ -155,7 +155,7 @@ TEST_CASE("[Synth] Releasing before the EG started smoothing (initial delay) kil sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; synth.setNumVoices(1); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/delay_release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "delay_release.sfz", R"( ampeg_delay=0.005 ampeg_release=1 sample=*noise )"); synth.noteOn(0, 60, 63); @@ -173,7 +173,7 @@ TEST_CASE("[Synth] Releasing after the initial and normal mode does not trigger sfz::Synth synth; sfz::AudioBuffer buffer{ 2, static_cast(synth.getSamplesPerBlock()) }; synth.setNumVoices(1); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/delay_release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "delay_release.sfz", R"( ampeg_delay=0.005 ampeg_release=1 sample=*noise )"); synth.noteOn(200, 60, 63); @@ -191,7 +191,7 @@ TEST_CASE("[Synth] Trigger=release and an envelope properly kills the voice at t synth.setSamplesPerBlock(480); sfz::AudioBuffer buffer(2, 480); synth.setNumVoices(1); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/envelope_trigger_release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "envelope_trigger_release.sfz", R"( lovel=0 hivel=127 sample=*silence trigger=release sample=*noise loop_mode=one_shot @@ -219,7 +219,7 @@ TEST_CASE("[Synth] Trigger=release_key and an envelope properly kills the voice synth.setSamplesPerBlock(480); sfz::AudioBuffer buffer(2, 480); synth.setNumVoices(1); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/envelope_trigger_release_key.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "envelope_trigger_release_key.sfz", R"( lovel=0 hivel=127 trigger=release_key sample=*noise loop_mode=one_shot ampeg_attack=0.02 ampeg_decay=0.02 ampeg_release=0.1 ampeg_sustain=0 @@ -246,7 +246,7 @@ TEST_CASE("[Synth] loopmode=one_shot and an envelope properly kills the voice at synth.setSamplesPerBlock(480); sfz::AudioBuffer buffer(2, 480); synth.setNumVoices(1); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/envelope_one_shot.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "envelope_one_shot.sfz", R"( lovel=0 hivel=127 sample=*noise loop_mode=one_shot ampeg_attack=0.02 ampeg_decay=0.02 ampeg_release=0.1 ampeg_sustain=0 @@ -271,7 +271,7 @@ TEST_CASE("[Synth] Number of effect buses and resetting behavior") sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/Effects/base.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "Effects/base.sfz", R"( lokey=0 hikey=127 sample=*sine )"); REQUIRE( synth.getEffectBusView(0) != nullptr); // We have a main bus @@ -279,7 +279,7 @@ TEST_CASE("[Synth] Number of effect buses and resetting behavior") for (int i = 0; i < 100; ++i) synth.renderBlock(buffer); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/Effects/bitcrusher_2.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "Effects/bitcrusher_2.sfz", R"( lokey=0 hikey=127 sample=*sine effect1=100 directtomain=50 fx1tomain=50 type=lofi bus=fx1 bitred=90 decim=10 )"); @@ -289,7 +289,7 @@ TEST_CASE("[Synth] Number of effect buses and resetting behavior") for (int i = 0; i < 100; ++i) synth.renderBlock(buffer); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/Effects/base.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "Effects/base.sfz", R"( lokey=0 hikey=127 sample=*sine )"); REQUIRE( synth.getEffectBusView(0) != nullptr); // We have a main bus @@ -298,7 +298,7 @@ TEST_CASE("[Synth] Number of effect buses and resetting behavior") for (int i = 0; i < 100; ++i) synth.renderBlock(buffer); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/Effects/bitcrusher_3.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "Effects/bitcrusher_3.sfz", R"( lokey=0 hikey=127 sample=*sine effect1=100 directtomain=50 fx3tomain=50 type=lofi bus=fx3 bitred=90 decim=10 )"); @@ -315,7 +315,7 @@ TEST_CASE("[Synth] Number of effect buses and resetting behavior") TEST_CASE("[Synth] No effect in the main bus") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/Effects/base.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "Effects/base.sfz", R"( lokey=0 hikey=127 sample=*sine )"); auto bus = synth.getEffectBusView(0); @@ -328,7 +328,7 @@ TEST_CASE("[Synth] No effect in the main bus") TEST_CASE("[Synth] One effect") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/Effects/bitcrusher_1.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "Effects/bitcrusher_1.sfz", R"( lokey=0 hikey=127 sample=*sine type=lofi bitred=90 decim=10 )"); @@ -342,7 +342,7 @@ TEST_CASE("[Synth] One effect") TEST_CASE("[Synth] Effect on a second bus") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/Effects/bitcrusher_2.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "Effects/bitcrusher_2.sfz", R"( lokey=0 hikey=127 sample=*sine effect1=100 directtomain=50 fx1tomain=50 type=lofi bus=fx1 bitred=90 decim=10 )"); @@ -362,7 +362,7 @@ TEST_CASE("[Synth] Effect on a second bus") TEST_CASE("[Synth] Effect on a third bus") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/Effects/bitcrusher_3.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "Effects/bitcrusher_3.sfz", R"( lokey=0 hikey=127 sample=*sine effect1=100 directtomain=50 fx3tomain=50 type=lofi bus=fx3 bitred=90 decim=10 )"); @@ -381,7 +381,7 @@ TEST_CASE("[Synth] Effect on a third bus") TEST_CASE("[Synth] Gain to mix") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/Effects/to_mix.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "Effects/to_mix.sfz", R"( lokey=0 hikey=127 sample=*sine effect1=100 fx1tomix=50 bus=fx1 type=lofi bitred=90 decim=10 )"); @@ -400,7 +400,7 @@ TEST_CASE("[Synth] Gain to mix") TEST_CASE("[Synth] Effect with two outputs") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/Effects/bitcrusher_2.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "Effects/bitcrusher_2.sfz", R"( lokey=0 hikey=127 sample=*sine effect1=100 lokey=0 hikey=127 sample=*sine effect1=100 output=1 directtomain=50 fx1tomain=50 type=lofi bus=fx1 bitred=90 decim=10 @@ -427,7 +427,7 @@ TEST_CASE("[Synth] Effect with two outputs") TEST_CASE("[Synth] Effect on the second output, with two outputs") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/Effects/bitcrusher_2.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "Effects/bitcrusher_2.sfz", R"( lokey=0 hikey=127 sample=*sine effect1=100 lokey=0 hikey=127 sample=*sine effect1=100 output=1 directtomain=50 fx1tomain=50 type=lofi bus=fx1 bitred=90 decim=10 output=1 @@ -455,7 +455,7 @@ TEST_CASE("[Synth] Basic curves") { sfz::Synth synth; const sfz::CurveSet& curves = synth.getResources().getCurves(); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/curves.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "curves.sfz", R"( sample=*sine curve_index=18 v000=0 v095=0.5 v127=1 curve_index=17 v000=0 v095=0.5 v100=1 @@ -472,7 +472,7 @@ TEST_CASE("[Synth] Basic curves") TEST_CASE("[Synth] Velocity points") { sfz::Synth synth; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/velocity_endpoints.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "velocity_endpoints.sfz", R"( amp_velcurve_064=1 sample=*sine amp_velcurve_064=1 amp_veltrack=-100 sample=*sine )"); @@ -512,7 +512,7 @@ TEST_CASE("[Synth] sample quality") sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString("tests/TestFiles/sampleQuality.sfz", R"( + synth.loadSfzString(SFIZZ_TEST_FILES "/sampleQuality.sfz", R"( sample=kick.wav key=60 sample=kick.wav key=61 sample_quality=5 )"); @@ -573,7 +573,7 @@ TEST_CASE("[Synth] Sister voices") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sister_voices.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sister_voices.sfz", R"( key=61 sample=*sine key=62 sample=*sine key=62 sample=*sine @@ -613,7 +613,7 @@ TEST_CASE("[Synth] Apply function on sisters") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sister_voices.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sister_voices.sfz", R"( key=63 sample=*saw key=63 sample=*saw key=63 sample=*saw @@ -632,7 +632,7 @@ TEST_CASE("[Synth] Sisters and off-by") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sister_voices.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sister_voices.sfz", R"( key=62 sample=*sine group=1 off_by=2 key=62 sample=*sine group=2 key=63 sample=*saw @@ -655,7 +655,7 @@ TEST_CASE("[Synth] Release (basic behavior with sample)") sfz::Synth synth; synth.setSamplesPerBlock(4096); sfz::AudioBuffer buffer { 2, 4096 }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release_key_sample.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release_key_sample.sfz", R"( key=62 sample=*sine key=62 sample=closedhat.wav trigger=release_key )"); @@ -671,7 +671,7 @@ TEST_CASE("[Synth] Release key (basic behavior with sample)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release_key_sample.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release_key_sample.sfz", R"( key=62 sample=closedhat.wav trigger=release_key )"); synth.noteOn(0, 62, 85); @@ -684,7 +684,7 @@ TEST_CASE("[Synth] Release key (pedal)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release_key_pedal.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release_key_pedal.sfz", R"( key=62 sample=*sine trigger=release_key )"); synth.noteOn(0, 62, 85); @@ -698,7 +698,7 @@ TEST_CASE("[Synth] Release") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( key=62 sample=*silence key=62 sample=*sine trigger=release )"); @@ -716,7 +716,7 @@ TEST_CASE("[Synth] Release (pedal was already down)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( key=62 sample=*silence key=62 sample=*sine trigger=release )"); @@ -734,7 +734,7 @@ TEST_CASE("[Synth] Release samples don't play unless there is another playing re { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( key=62 sample=*sine trigger=release )"); synth.noteOn(0, 62, 85); @@ -753,7 +753,7 @@ TEST_CASE("[Synth] Release key (Different sustain CC)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( sustain_cc=54 key=62 sample=*sine trigger=release_key )"); @@ -768,7 +768,7 @@ TEST_CASE("[Synth] Release (Different sustain CC)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( sustain_cc=54 key=62 sample=*silence key=62 sample=*sine trigger=release @@ -787,7 +787,7 @@ TEST_CASE("[Synth] Release (don't check sustain)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( sustain_cc=54 sustain_sw=off key=62 sample=*silence key=62 sample=*sine trigger=release @@ -803,7 +803,7 @@ TEST_CASE("[Synth] Release key (Different sostenuto CC)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( sostenuto_cc=54 key=62 sample=*sine trigger=release_key )"); @@ -818,7 +818,7 @@ TEST_CASE("[Synth] Release (don't check sostenuto)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( sostenuto_cc=54 sostenuto_sw=off key=62 sample=*silence key=62 sample=*sine trigger=release @@ -834,7 +834,7 @@ TEST_CASE("[Synth] Release (Different sostenuto CC)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( sostenuto_cc=54 key=62 sample=*silence key=62 sample=*sine trigger=release @@ -871,7 +871,7 @@ TEST_CASE("[Synth] Release (sustain + sostenuto)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( key=62 sample=*silence key=62 sample=*sine trigger=release key=64 sample=*silence @@ -913,7 +913,7 @@ TEST_CASE("[Synth] One shot regions with sustain + sostenuto") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/one_shot_sustain.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "one_shot_sustain.sfz", R"( key=60 sample=kick.wav loop_mode=one_shot )"); SECTION("Sustain") @@ -959,7 +959,7 @@ TEST_CASE("[Synth] Sustain threshold default") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( key=62 sample=*sine trigger=release )"); synth.noteOn(0, 62, 85); @@ -973,7 +973,7 @@ TEST_CASE("[Synth] Sustain threshold") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( sustain_lo=63 key=62 sample=*silence key=62 sample=*sine trigger=release @@ -1000,7 +1000,7 @@ TEST_CASE("[Synth] Sustain") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sostenuto.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sostenuto.sfz", R"( sample=*sine )"); @@ -1063,7 +1063,7 @@ TEST_CASE("[Synth] Sostenuto") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sostenuto.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sostenuto.sfz", R"( sample=*sine )"); @@ -1119,7 +1119,7 @@ TEST_CASE("[Synth] Release (Multiple notes, release_key ignores the pedal)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( lokey=62 hikey=64 sample=*sine trigger=release_key )"); synth.noteOn(0, 62, 85); @@ -1137,7 +1137,7 @@ TEST_CASE("[Synth] Release (Multiple notes, release, cleared the delayed voices { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( lokey=62 hikey=64 sample=*silence lokey=62 hikey=64 sample=*sine trigger=release loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1 @@ -1163,7 +1163,7 @@ TEST_CASE("[Synth] Release (Multiple notes after pedal is down, release, cleared { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( lokey=62 hikey=64 sample=*silence lokey=62 hikey=64 sample=*sine trigger=release loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1 @@ -1189,7 +1189,7 @@ TEST_CASE("[Synth] Release (Multiple note ons during pedal down)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( lokey=62 hikey=64 sample=*silence lokey=62 hikey=64 sample=*sine trigger=release loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1 @@ -1215,7 +1215,7 @@ TEST_CASE("[Synth] No release sample after the main sample stopped sounding by d synth.setSamplesPerBlock(4096); sfz::AudioBuffer buffer { 2, 4096 }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( lokey=62 hikey=64 sample=closedhat.wav loop_mode=one_shot lokey=62 hikey=64 sample=*sine trigger=release loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1 @@ -1255,7 +1255,7 @@ TEST_CASE("[Synth] If rt_dead is active the release sample can sound after the a synth.setSamplesPerBlock(4096); sfz::AudioBuffer buffer { 2, 4096 }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/release.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "release.sfz", R"( lokey=62 hikey=64 sample=closedhat.wav loop_mode=one_shot lokey=62 hikey=64 sample=*sine trigger=release loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1 @@ -1817,7 +1817,7 @@ TEST_CASE("[Keyswitches] Trigger from aftertouch extended CC") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/aftertouch_trigger.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "aftertouch_trigger.sfz", R"( start_locc129=100 start_hicc129=127 sample=*saw )"); synth.renderBlock(buffer); @@ -1840,7 +1840,7 @@ TEST_CASE("[Synth] Short empty files are turned into *silence") sfz::Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/aftertouch_trigger.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "aftertouch_trigger.sfz", R"( sample=silence.wav )"); synth.dispatchMessage(client, 0, "/region0/sample", "", nullptr); @@ -1854,7 +1854,7 @@ TEST_CASE("[Synth] Sustain cancels release (Flex EG)") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( hint_sustain_cancels_release=1 sample=*sine eg01_ampeg=1 eg01_sustain=2 @@ -1879,7 +1879,7 @@ TEST_CASE("[Synth] Sustain cancels release (Flex EG) is off by default") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( sample=*sine eg01_ampeg=1 eg01_sustain=2 eg01_time1=0 eg01_level1=0.00 @@ -1903,7 +1903,7 @@ TEST_CASE("[Synth] Sustain cancels release") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( hint_sustain_cancels_release=1 sample=*sine ampeg_release=10 )"); @@ -1924,7 +1924,7 @@ TEST_CASE("[Synth] Sustain cancels release is off by default") { sfz::Synth synth; sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( sample=*sine ampeg_release=10 )"); synth.noteOn(0, 60, 63 ); @@ -1947,7 +1947,7 @@ TEST_CASE("[Synth] Resets all controllers to default values") sfz::Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/default_cc.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "default_cc.sfz", R"( set_cc56=64 sample=*sine )"); @@ -1972,7 +1972,7 @@ TEST_CASE("[Synth] Sequences also work on cc triggers") sfz::Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sequence_cc_triggers.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sequence_cc_triggers.sfz", R"( seq_length=3 sample=*sine hikey=-1 start_locc61=0 start_hicc61=64 seq_position=1 sample=*saw hikey=-1 start_locc61=0 start_hicc61=64 seq_position=2 @@ -1998,13 +1998,13 @@ TEST_CASE("[Synth] Loading resets note and octave offsets") sfz::Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/octave_offset.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "octave_offset.sfz", R"( note_offset=1 octave_offset=-1 sample=*sine )"); synth.dispatchMessage(client, 0, "/note_offset", "", nullptr); synth.dispatchMessage(client, 0, "/octave_offset", "", nullptr); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/octave_offset.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "octave_offset.sfz", R"( sample=*sine )"); synth.dispatchMessage(client, 0, "/note_offset", "", nullptr); @@ -2026,7 +2026,7 @@ TEST_CASE("[Synth] Default CC values") sfz::Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/default.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "default.sfz", R"( sample=*sine )"); synth.renderBlock(buffer); @@ -2049,7 +2049,7 @@ TEST_CASE("[Synth] Loading a new file doesn't reset the midi state") sfz::Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sine.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sine.sfz", R"( sample=*sine )"); @@ -2069,7 +2069,7 @@ TEST_CASE("[Synth] Loading a new file doesn't reset the midi state") synth.dispatchMessage(client, 0, "/poly_aftertouch/64", "", nullptr); synth.dispatchMessage(client, 0, "/pitch_bend", "", nullptr); - synth.loadSfzString(fs::current_path() / "tests/TestFiles/saw.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "saw.sfz", R"( sample=*saw )"); synth.renderBlock(buffer); @@ -2107,7 +2107,7 @@ TEST_CASE("[Synth] Reloading a file ignores the `set_ccN` opcodes") sfz::Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sine.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sine.sfz", R"( set_cc1=0 sample=*sine )"); @@ -2117,7 +2117,7 @@ TEST_CASE("[Synth] Reloading a file ignores the `set_ccN` opcodes") synth.dispatchMessage(client, 0, "/cc1/value", "", nullptr); // Same file - synth.loadSfzString(fs::current_path() / "tests/TestFiles/sine.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "sine.sfz", R"( set_cc1=0 sample=*sine )"); @@ -2125,7 +2125,7 @@ TEST_CASE("[Synth] Reloading a file ignores the `set_ccN` opcodes") synth.dispatchMessage(client, 0, "/cc1/value", "", nullptr); // Different file - synth.loadSfzString(fs::current_path() / "tests/TestFiles/saw.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "saw.sfz", R"( set_cc1=0 sample=*saw )"); @@ -2146,7 +2146,7 @@ TEST_CASE("[Synth] Reuse offed voices in the last case scenario for new notes") sfz::Synth synth; synth.setNumVoices(2); sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "polyphony.sfz", R"( sample=*sine ampeg_release=10 )"); synth.noteOn(0, 60, 63); @@ -2167,7 +2167,7 @@ TEST_CASE("[Synth] Note on and off at the maximum delay") synth.setSampleRate(12800); synth.setSamplesPerBlock(128); sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/noteonoff.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "noteonoff.sfz", R"( loop_start=4 loop_end=124 ampeg_release=0.5 sample=looped_flute.wav )"); synth.setNumVoices(128); @@ -2187,7 +2187,7 @@ TEST_CASE("[Synth] Note on and off with delay") synth.setSampleRate(12800); synth.setSamplesPerBlock(128); sfz::AudioBuffer buffer { 2, static_cast(synth.getSamplesPerBlock()) }; - synth.loadSfzString(fs::current_path() / "tests/TestFiles/noteonoff.sfz", R"( + synth.loadSfzString(fs::path(SFIZZ_TEST_FILES) / "noteonoff.sfz", R"( loop_start=4 loop_end=124 ampeg_release=0.5 sample=looped_flute.wav )"); synth.setNumVoices(128); @@ -2202,4 +2202,4 @@ TEST_CASE("[Synth] Note on and off with delay") for (int i = 0; i < 100; ++i) synth.renderBlock(buffer); CHECK(synth.getNumActiveVoices() == 0); -} \ No newline at end of file +} diff --git a/tests/WavetablesT.cpp b/tests/WavetablesT.cpp index 0f8ca5ee8..ed502c40d 100644 --- a/tests/WavetablesT.cpp +++ b/tests/WavetablesT.cpp @@ -53,7 +53,7 @@ TEST_CASE("[Wavetables] Frequency ranges") TEST_CASE("[Wavetables] Wavetable sound files: Surge") { - sfz::FileMetadataReader reader { "tests/TestFiles/wavetables/surge.wav" }; + sfz::FileMetadataReader reader { SFIZZ_TEST_FILES "/wavetables/surge.wav" }; sfz::WavetableInfo wt; REQUIRE(reader.open()); @@ -64,7 +64,7 @@ TEST_CASE("[Wavetables] Wavetable sound files: Surge") TEST_CASE("[Wavetables] Wavetable sound files: Clm") { - sfz::FileMetadataReader reader { "tests/TestFiles/wavetables/clm.wav" }; + sfz::FileMetadataReader reader { SFIZZ_TEST_FILES "/wavetables/clm.wav" }; sfz::WavetableInfo wt; REQUIRE(reader.open()); @@ -75,7 +75,7 @@ TEST_CASE("[Wavetables] Wavetable sound files: Clm") TEST_CASE("[Wavetables] Non-wavetable sound files") { - sfz::FileMetadataReader reader { "tests/TestFiles/snare.wav" }; + sfz::FileMetadataReader reader { SFIZZ_TEST_FILES "/snare.wav" }; sfz::WavetableInfo wt; REQUIRE(reader.open()); @@ -98,7 +98,7 @@ std::vector readWholeFile(const fs::path& path) TEST_CASE("[Wavetables] Wavetable sound files: Surge, from memory") { - auto file = readWholeFile("tests/TestFiles/wavetables/surge.wav"); + auto file = readWholeFile(SFIZZ_TEST_FILES "/wavetables/surge.wav"); sfz::MemoryMetadataReader reader { file.data(), file.size() }; sfz::WavetableInfo wt; @@ -110,7 +110,7 @@ TEST_CASE("[Wavetables] Wavetable sound files: Surge, from memory") TEST_CASE("[Wavetables] Wavetable sound files: Clm, from memory") { - auto file = readWholeFile("tests/TestFiles/wavetables/clm.wav"); + auto file = readWholeFile(SFIZZ_TEST_FILES "/wavetables/clm.wav"); sfz::MemoryMetadataReader reader { file.data(), file.size() }; sfz::WavetableInfo wt; @@ -122,7 +122,7 @@ TEST_CASE("[Wavetables] Wavetable sound files: Clm, from memory") TEST_CASE("[Wavetables] Non-wavetable sound files, from memory") { - auto file = readWholeFile("tests/TestFiles/snare.wav"); + auto file = readWholeFile(SFIZZ_TEST_FILES "/snare.wav"); sfz::MemoryMetadataReader reader { file.data(), file.size() }; sfz::WavetableInfo wt;