mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-12-02 17:12:15 +00:00
Merge branch 'master' into refactor-and-fix-sffile-defsfont
This commit is contained in:
commit
d2754028b4
22 changed files with 39366 additions and 93 deletions
4
.github/workflows/linux.yml
vendored
4
.github/workflows/linux.yml
vendored
|
@ -1,6 +1,6 @@
|
|||
name: FluidSynth Linux
|
||||
|
||||
on: [push]
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
|
@ -17,7 +17,7 @@ jobs:
|
|||
matrix:
|
||||
CC: [""]
|
||||
CXX: [""]
|
||||
CMAKE_FLAGS: ["-Denable-profiling=1","-Denable-floats=1 -Denable-profiling=1","-Denable-floats=1","-Denable-trap-on-fpe=1","-Denable-fpe-check=1","-Denable-ipv6=0","-Denable-network=0","-Denable-aufile=0","-DBUILD_SHARED_LIBS=0","-Denable-ubsan=1"]
|
||||
CMAKE_FLAGS: ["-Denable-profiling=1","-Denable-floats=1 -Denable-profiling=1","-Denable-floats=1","-Denable-trap-on-fpe=1","-Denable-fpe-check=1","-Denable-ipv6=0","-Denable-network=0","-Denable-aufile=0","-DBUILD_SHARED_LIBS=0","-Denable-ubsan=1 -Denable-debug=1"]
|
||||
include:
|
||||
- CC: "gcc-7"
|
||||
CXX: "g++-7"
|
||||
|
|
17
.github/workflows/sonarcloud.yml
vendored
17
.github/workflows/sonarcloud.yml
vendored
|
@ -9,7 +9,8 @@ on:
|
|||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: RelWithDebInfo
|
||||
# Use Debug build for better code coverage results
|
||||
BUILD_TYPE: Debug
|
||||
|
||||
name: SonarCloud Workflow
|
||||
jobs:
|
||||
|
@ -29,7 +30,7 @@ jobs:
|
|||
run: sudo apt-get update -y
|
||||
|
||||
- name: Install Dependencies
|
||||
run: sudo -E apt-get -yq --no-install-suggests --no-install-recommends install cmake-data cmake libglib2.0-0 libsndfile-dev libasound2-dev libjack-dev portaudio19-dev libsdl2-dev libpulse-dev libdbus-1-dev libsystemd-dev libinstpatch-dev libreadline-dev
|
||||
run: sudo -E apt-get -yq --no-install-suggests --no-install-recommends install cmake-data cmake libglib2.0-0 libsndfile-dev libasound2-dev libjack-dev portaudio19-dev libsdl2-dev libpulse-dev libdbus-1-dev libsystemd-dev libinstpatch-dev libreadline-dev lcov gcovr ggcov
|
||||
|
||||
- name: Create Build Environment
|
||||
# Some projects don't allow in-source building, so create a separate build directory
|
||||
|
@ -52,26 +53,31 @@ jobs:
|
|||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -Werror=dev -Denable-portaudio=1 -Denable-ladspa=1 -DNO_GUI=1 $GITHUB_WORKSPACE
|
||||
run: cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -Werror=dev -Denable-portaudio=1 -Denable-ladspa=1 -Denable-coverage=1 -DNO_GUI=1 $GITHUB_WORKSPACE
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
shell: bash
|
||||
# Execute the build. You can specify a specific target with "--target <NAME>"
|
||||
run: |
|
||||
./build-wrapper-linux-x86-64 --out-dir bw-output make -j`nproc`
|
||||
./build-wrapper-linux-x86-64 --out-dir bw-output make
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{github.workspace}}/build
|
||||
shell: bash
|
||||
# Execute tests defined by the CMake configuration.
|
||||
run: |
|
||||
./build-wrapper-linux-x86-64 --out-dir bw-output make -j`nproc` check
|
||||
./build-wrapper-linux-x86-64 --out-dir bw-output make coverage
|
||||
|
||||
# sonar-scanner does not like utf8 filenames
|
||||
- name: Prepare for Sonar
|
||||
run: |
|
||||
rm -rf ${{ github.workspace }}/sf2
|
||||
gcovr --version
|
||||
gcovr --help
|
||||
ls -la ${{ github.workspace }}
|
||||
ls -la ${{ github.workspace }}/build
|
||||
ls -la ${{ github.workspace }}/build/coverage
|
||||
|
||||
# The offical sonarsource/sonarcloud-github-action@v1.5 action does not work properly.
|
||||
# It keeps complaining that the build-wrapper.json cannot be found.
|
||||
|
@ -86,5 +92,6 @@ jobs:
|
|||
run: sonar-scanner
|
||||
-Dsonar.login=${{ secrets.SONAR_TOKEN }}
|
||||
-Dsonar.cfamily.build-wrapper-output=${{ github.workspace }}/build/bw-output
|
||||
-Dsonar.coverageReportPaths=build/coverage/sonarqube.report
|
||||
-Dsonar.verbose=false
|
||||
-Dsonar.host.url=https://sonarcloud.io/
|
||||
|
|
2
AUTHORS
2
AUTHORS
|
@ -150,4 +150,4 @@ Bernat Arlandis i Mañó
|
|||
Sven Meier
|
||||
Marcus Weseloh
|
||||
Jean-jacques Ceresa
|
||||
|
||||
Vladimir Davidovich
|
||||
|
|
|
@ -49,6 +49,7 @@ set ( LIB_VERSION_INFO
|
|||
"${LIB_VERSION_CURRENT}.${LIB_VERSION_AGE}.${LIB_VERSION_REVISION}" )
|
||||
|
||||
# Options disabled by default
|
||||
option ( enable-coverage "enable gcov code coverage" off )
|
||||
option ( enable-debug "enable debugging (default=no)" off )
|
||||
option ( enable-floats "enable type float instead of double for DSP samples" off )
|
||||
option ( enable-fpe-check "enable Floating Point Exception checks and debug messages" off )
|
||||
|
@ -224,6 +225,22 @@ if ( CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_C
|
|||
set ( CMAKE_SHARED_LINKER_FLAGS "-fsanitize=address,undefined ${CMAKE_SHARED_LINKER_FLAGS}" )
|
||||
set ( ENABLE_UBSAN 1 )
|
||||
endif ( enable-ubsan )
|
||||
|
||||
if ( enable-coverage )
|
||||
if ( CMAKE_COMPILER_IS_GNUCXX )
|
||||
include ( CodeCoverage )
|
||||
set ( CODE_COVERAGE_VERBOSE TRUE )
|
||||
|
||||
append_coverage_compiler_flags()
|
||||
setup_target_for_coverage_gcovr_html (
|
||||
NAME coverage
|
||||
EXECUTABLE ${CMAKE_CTEST_COMMAND} -C $<CONFIG> --output-on-failure
|
||||
DEPENDENCIES check )
|
||||
set ( ENABLE_COVERAGE 1 )
|
||||
else()
|
||||
message ( SEND_ERROR "Code Coverage is currently only supported for GNU Compiler (GCC)" )
|
||||
endif()
|
||||
endif ()
|
||||
endif (CMAKE_C_COMPILER_ID STREQUAL "Intel" )
|
||||
endif ( CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "Intel" )
|
||||
|
||||
|
@ -743,6 +760,9 @@ link_directories (
|
|||
${LIBINSTPATCH_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
# required to allow ctest to be called from top-level build directory
|
||||
ENABLE_TESTING()
|
||||
|
||||
# Process subdirectories
|
||||
add_subdirectory ( src )
|
||||
add_subdirectory ( test )
|
||||
|
|
603
cmake_admin/CodeCoverage.cmake
Normal file
603
cmake_admin/CodeCoverage.cmake
Normal file
|
@ -0,0 +1,603 @@
|
|||
# Copyright (c) 2012 - 2017, Lars Bilke
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# CHANGES:
|
||||
#
|
||||
# 2012-01-31, Lars Bilke
|
||||
# - Enable Code Coverage
|
||||
#
|
||||
# 2013-09-17, Joakim Söderberg
|
||||
# - Added support for Clang.
|
||||
# - Some additional usage instructions.
|
||||
#
|
||||
# 2016-02-03, Lars Bilke
|
||||
# - Refactored functions to use named parameters
|
||||
#
|
||||
# 2017-06-02, Lars Bilke
|
||||
# - Merged with modified version from github.com/ufz/ogs
|
||||
#
|
||||
# 2019-05-06, Anatolii Kurotych
|
||||
# - Remove unnecessary --coverage flag
|
||||
#
|
||||
# 2019-12-13, FeRD (Frank Dana)
|
||||
# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
|
||||
# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments.
|
||||
# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY
|
||||
# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list
|
||||
# - Set lcov basedir with -b argument
|
||||
# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be
|
||||
# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().)
|
||||
# - Delete output dir, .info file on 'make clean'
|
||||
# - Remove Python detection, since version mismatches will break gcovr
|
||||
# - Minor cleanup (lowercase function names, update examples...)
|
||||
#
|
||||
# 2019-12-19, FeRD (Frank Dana)
|
||||
# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets
|
||||
#
|
||||
# 2020-01-19, Bob Apthorpe
|
||||
# - Added gfortran support
|
||||
#
|
||||
# 2020-02-17, FeRD (Frank Dana)
|
||||
# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters
|
||||
# in EXCLUDEs, and remove manual escaping from gcovr targets
|
||||
#
|
||||
# 2021-01-19, Robin Mueller
|
||||
# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run
|
||||
# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional
|
||||
# flags to the gcovr command
|
||||
#
|
||||
# 2020-05-04, Mihchael Davis
|
||||
# - Add -fprofile-abs-path to make gcno files contain absolute paths
|
||||
# - Fix BASE_DIRECTORY not working when defined
|
||||
# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines
|
||||
# USAGE:
|
||||
#
|
||||
# 1. Copy this file into your cmake modules path.
|
||||
#
|
||||
# 2. Add the following line to your CMakeLists.txt (best inside an if-condition
|
||||
# using a CMake option() to enable it just optionally):
|
||||
# include(CodeCoverage)
|
||||
#
|
||||
# 3. Append necessary compiler flags:
|
||||
# append_coverage_compiler_flags()
|
||||
#
|
||||
# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
|
||||
#
|
||||
# 4. If you need to exclude additional directories from the report, specify them
|
||||
# using full paths in the COVERAGE_EXCLUDES variable before calling
|
||||
# setup_target_for_coverage_*().
|
||||
# Example:
|
||||
# set(COVERAGE_EXCLUDES
|
||||
# '${PROJECT_SOURCE_DIR}/src/dir1/*'
|
||||
# '/path/to/my/src/dir2/*')
|
||||
# Or, use the EXCLUDE argument to setup_target_for_coverage_*().
|
||||
# Example:
|
||||
# setup_target_for_coverage_lcov(
|
||||
# NAME coverage
|
||||
# EXECUTABLE testrunner
|
||||
# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*")
|
||||
#
|
||||
# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set
|
||||
# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR)
|
||||
# Example:
|
||||
# set(COVERAGE_EXCLUDES "dir1/*")
|
||||
# setup_target_for_coverage_gcovr_html(
|
||||
# NAME coverage
|
||||
# EXECUTABLE testrunner
|
||||
# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
|
||||
# EXCLUDE "dir2/*")
|
||||
#
|
||||
# 5. Use the functions described below to create a custom make target which
|
||||
# runs your test executable and produces a code coverage report.
|
||||
#
|
||||
# 6. Build a Debug build:
|
||||
# cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
# make
|
||||
# make my_coverage_target
|
||||
#
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE)
|
||||
|
||||
# Check prereqs
|
||||
find_program( GCOV_PATH gcov )
|
||||
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
|
||||
find_program( FASTCOV_PATH NAMES fastcov fastcov.py )
|
||||
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
|
||||
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
|
||||
find_program( CPPFILT_PATH NAMES c++filt )
|
||||
|
||||
if(NOT GCOV_PATH)
|
||||
message(FATAL_ERROR "gcov not found! Aborting...")
|
||||
endif() # NOT GCOV_PATH
|
||||
|
||||
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||
list(GET LANGUAGES 0 LANG)
|
||||
|
||||
if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
|
||||
if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3)
|
||||
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
|
||||
endif()
|
||||
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
|
||||
if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang")
|
||||
# Do nothing; exit conditional without error if true
|
||||
elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
|
||||
# Do nothing; exit conditional without error if true
|
||||
else()
|
||||
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage"
|
||||
CACHE INTERNAL "")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag(-fprofile-abs-path HAVE_fprofile_abs_path)
|
||||
if(HAVE_fprofile_abs_path)
|
||||
set(COVERAGE_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_Fortran_FLAGS_COVERAGE
|
||||
${COVERAGE_COMPILER_FLAGS}
|
||||
CACHE STRING "Flags used by the Fortran compiler during coverage builds."
|
||||
FORCE )
|
||||
set(CMAKE_CXX_FLAGS_COVERAGE
|
||||
${COVERAGE_COMPILER_FLAGS}
|
||||
CACHE STRING "Flags used by the C++ compiler during coverage builds."
|
||||
FORCE )
|
||||
set(CMAKE_C_FLAGS_COVERAGE
|
||||
${COVERAGE_COMPILER_FLAGS}
|
||||
CACHE STRING "Flags used by the C compiler during coverage builds."
|
||||
FORCE )
|
||||
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||
""
|
||||
CACHE STRING "Flags used for linking binaries during coverage builds."
|
||||
FORCE )
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
|
||||
""
|
||||
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
|
||||
FORCE )
|
||||
mark_as_advanced(
|
||||
CMAKE_Fortran_FLAGS_COVERAGE
|
||||
CMAKE_CXX_FLAGS_COVERAGE
|
||||
CMAKE_C_FLAGS_COVERAGE
|
||||
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
|
||||
endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
|
||||
link_libraries(gcov)
|
||||
endif()
|
||||
|
||||
# Defines a target for running and collection code coverage information
|
||||
# Builds dependencies, runs the given executable and outputs reports.
|
||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||
# the coverage generation will not complete.
|
||||
#
|
||||
# setup_target_for_coverage_lcov(
|
||||
# NAME testrunner_coverage # New target name
|
||||
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||
# DEPENDENCIES testrunner # Dependencies to build first
|
||||
# BASE_DIRECTORY "../" # Base directory for report
|
||||
# # (defaults to PROJECT_SOURCE_DIR)
|
||||
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||
# NO_DEMANGLE # Don't demangle C++ symbols
|
||||
# # even if c++filt is found
|
||||
# )
|
||||
function(setup_target_for_coverage_lcov)
|
||||
|
||||
set(options NO_DEMANGLE)
|
||||
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
|
||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT LCOV_PATH)
|
||||
message(FATAL_ERROR "lcov not found! Aborting...")
|
||||
endif() # NOT LCOV_PATH
|
||||
|
||||
if(NOT GENHTML_PATH)
|
||||
message(FATAL_ERROR "genhtml not found! Aborting...")
|
||||
endif() # NOT GENHTML_PATH
|
||||
|
||||
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||
if(DEFINED Coverage_BASE_DIRECTORY)
|
||||
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||
else()
|
||||
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
||||
set(LCOV_EXCLUDES "")
|
||||
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
||||
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
||||
endif()
|
||||
list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
|
||||
endforeach()
|
||||
list(REMOVE_DUPLICATES LCOV_EXCLUDES)
|
||||
|
||||
# Conditional arguments
|
||||
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
|
||||
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
|
||||
endif()
|
||||
|
||||
# enable branch coverage
|
||||
set ( Coverage_LCOV_ARGS ${Coverage_LCOV_ARGS} --rc lcov_branch_coverage=1 )
|
||||
set ( Coverage_GENHTML_ARGS ${Coverage_GENHTML_ARGS} --branch-coverage )
|
||||
|
||||
# Setting up commands which will be run to generate coverage data.
|
||||
# Cleanup lcov
|
||||
set(LCOV_CLEAN_CMD
|
||||
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory .
|
||||
-b ${BASEDIR} --zerocounters
|
||||
)
|
||||
# Create baseline to make sure untouched files show up in the report
|
||||
set(LCOV_BASELINE_CMD
|
||||
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b
|
||||
${BASEDIR} -o ${Coverage_NAME}.base
|
||||
)
|
||||
# Run tests
|
||||
set(LCOV_EXEC_TESTS_CMD
|
||||
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
)
|
||||
# Capturing lcov counters and generating report
|
||||
set(LCOV_CAPTURE_CMD
|
||||
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b
|
||||
${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
|
||||
)
|
||||
# add baseline counters
|
||||
set(LCOV_BASELINE_COUNT_CMD
|
||||
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base
|
||||
-a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
|
||||
)
|
||||
# filter collected data to final coverage report
|
||||
set(LCOV_FILTER_CMD
|
||||
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove
|
||||
${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
|
||||
)
|
||||
# Generate HTML output
|
||||
set(LCOV_GEN_HTML_CMD
|
||||
${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o
|
||||
${Coverage_NAME} ${Coverage_NAME}.info
|
||||
)
|
||||
|
||||
|
||||
if(CODE_COVERAGE_VERBOSE)
|
||||
message(STATUS "Executed command report")
|
||||
message(STATUS "Command to clean up lcov: ")
|
||||
string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}")
|
||||
message(STATUS "${LCOV_CLEAN_CMD_SPACED}")
|
||||
|
||||
message(STATUS "Command to create baseline: ")
|
||||
string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}")
|
||||
message(STATUS "${LCOV_BASELINE_CMD_SPACED}")
|
||||
|
||||
message(STATUS "Command to run the tests: ")
|
||||
string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}")
|
||||
message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}")
|
||||
|
||||
message(STATUS "Command to capture counters and generate report: ")
|
||||
string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}")
|
||||
message(STATUS "${LCOV_CAPTURE_CMD_SPACED}")
|
||||
|
||||
message(STATUS "Command to add baseline counters: ")
|
||||
string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}")
|
||||
message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}")
|
||||
|
||||
message(STATUS "Command to filter collected data: ")
|
||||
string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}")
|
||||
message(STATUS "${LCOV_FILTER_CMD_SPACED}")
|
||||
|
||||
message(STATUS "Command to generate lcov HTML output: ")
|
||||
string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}")
|
||||
message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}")
|
||||
endif()
|
||||
|
||||
# Setup target
|
||||
add_custom_target(${Coverage_NAME}
|
||||
COMMAND ${LCOV_CLEAN_CMD}
|
||||
COMMAND ${LCOV_BASELINE_CMD}
|
||||
COMMAND ${LCOV_EXEC_TESTS_CMD}
|
||||
COMMAND ${LCOV_CAPTURE_CMD}
|
||||
COMMAND ${LCOV_BASELINE_COUNT_CMD}
|
||||
COMMAND ${LCOV_FILTER_CMD}
|
||||
COMMAND ${LCOV_GEN_HTML_CMD}
|
||||
|
||||
# Set output files as GENERATED (will be removed on 'make clean')
|
||||
BYPRODUCTS
|
||||
${Coverage_NAME}.base
|
||||
${Coverage_NAME}.capture
|
||||
${Coverage_NAME}.total
|
||||
${Coverage_NAME}.info
|
||||
${Coverage_NAME}/index.html
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
DEPENDS ${Coverage_DEPENDENCIES}
|
||||
VERBATIM # Protect arguments to commands
|
||||
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
|
||||
)
|
||||
|
||||
# Show where to find the lcov info report
|
||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||
COMMAND ;
|
||||
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
|
||||
)
|
||||
|
||||
# Show info where to find the report
|
||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||
COMMAND ;
|
||||
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
||||
)
|
||||
|
||||
endfunction() # setup_target_for_coverage_lcov
|
||||
|
||||
# Defines a target for running and collection code coverage information
|
||||
# Builds dependencies, runs the given executable and outputs reports.
|
||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||
# the coverage generation will not complete.
|
||||
#
|
||||
# setup_target_for_coverage_gcovr_html(
|
||||
# NAME ctest_coverage # New target name
|
||||
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||
# DEPENDENCIES executable_target # Dependencies to build first
|
||||
# BASE_DIRECTORY "../" # Base directory for report
|
||||
# # (defaults to PROJECT_SOURCE_DIR)
|
||||
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||
# )
|
||||
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
|
||||
# GCVOR command.
|
||||
function(setup_target_for_coverage_gcovr_html)
|
||||
|
||||
set(options NONE)
|
||||
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT GCOVR_PATH)
|
||||
message(FATAL_ERROR "gcovr not found! Aborting...")
|
||||
endif() # NOT GCOVR_PATH
|
||||
|
||||
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||
if(DEFINED Coverage_BASE_DIRECTORY)
|
||||
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||
else()
|
||||
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
||||
set(GCOVR_EXCLUDES "")
|
||||
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
||||
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
||||
endif()
|
||||
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
||||
endforeach()
|
||||
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
|
||||
|
||||
# Combine excludes to several -e arguments
|
||||
set(GCOVR_EXCLUDE_ARGS "")
|
||||
foreach(EXCLUDE ${GCOVR_EXCLUDES})
|
||||
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
|
||||
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
|
||||
endforeach()
|
||||
|
||||
# Set up commands which will be run to generate coverage data
|
||||
# Run tests
|
||||
set(GCOVR_HTML_EXEC_TESTS_CMD
|
||||
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
)
|
||||
# Create folder
|
||||
set(GCOVR_HTML_FOLDER_CMD
|
||||
${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
|
||||
)
|
||||
# Running gcovr
|
||||
set(GCOVR_HTML_CMD
|
||||
${GCOVR_PATH} --html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
||||
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
||||
-o ${Coverage_NAME}/index.html
|
||||
)
|
||||
|
||||
# The --keep option is broken since gcovr 4.0 all our gcov files are deleted before SonarQube
|
||||
# can use them. Hence create an additional sonarqube report, but do not fail if this fails.
|
||||
set(GCOVR_SONAR_CMD
|
||||
${GCOVR_PATH} --sonarqube -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
||||
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
||||
-o ${Coverage_NAME}/sonarqube.report || true
|
||||
)
|
||||
|
||||
if(CODE_COVERAGE_VERBOSE)
|
||||
message(STATUS "Executed command report")
|
||||
|
||||
message(STATUS "Command to run tests: ")
|
||||
string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}")
|
||||
message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}")
|
||||
|
||||
message(STATUS "Command to create a folder: ")
|
||||
string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}")
|
||||
message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}")
|
||||
|
||||
message(STATUS "Command to generate gcovr HTML coverage data: ")
|
||||
string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}")
|
||||
message(STATUS "${GCOVR_HTML_CMD_SPACED}")
|
||||
endif()
|
||||
|
||||
add_custom_target(${Coverage_NAME}
|
||||
COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD}
|
||||
COMMAND ${GCOVR_HTML_FOLDER_CMD}
|
||||
COMMAND ${GCOVR_HTML_CMD}
|
||||
COMMAND ${GCOVR_SONAR_CMD}
|
||||
|
||||
BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
DEPENDS ${Coverage_DEPENDENCIES}
|
||||
VERBATIM # Protect arguments to commands
|
||||
COMMENT "Running gcovr to produce HTML code coverage report."
|
||||
)
|
||||
|
||||
# Show info where to find the report
|
||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||
COMMAND ;
|
||||
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
||||
)
|
||||
|
||||
endfunction() # setup_target_for_coverage_gcovr_html
|
||||
|
||||
# Defines a target for running and collection code coverage information
|
||||
# Builds dependencies, runs the given executable and outputs reports.
|
||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||
# the coverage generation will not complete.
|
||||
#
|
||||
# setup_target_for_coverage_fastcov(
|
||||
# NAME testrunner_coverage # New target name
|
||||
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||
# DEPENDENCIES testrunner # Dependencies to build first
|
||||
# BASE_DIRECTORY "../" # Base directory for report
|
||||
# # (defaults to PROJECT_SOURCE_DIR)
|
||||
# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude.
|
||||
# NO_DEMANGLE # Don't demangle C++ symbols
|
||||
# # even if c++filt is found
|
||||
# SKIP_HTML # Don't create html report
|
||||
# )
|
||||
function(setup_target_for_coverage_fastcov)
|
||||
|
||||
set(options NO_DEMANGLE SKIP_HTML)
|
||||
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS)
|
||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT FASTCOV_PATH)
|
||||
message(FATAL_ERROR "fastcov not found! Aborting...")
|
||||
endif()
|
||||
|
||||
if(NOT GENHTML_PATH)
|
||||
message(FATAL_ERROR "genhtml not found! Aborting...")
|
||||
endif()
|
||||
|
||||
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||
if(Coverage_BASE_DIRECTORY)
|
||||
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||
else()
|
||||
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
# Collect excludes (Patterns, not paths, for fastcov)
|
||||
set(FASTCOV_EXCLUDES "")
|
||||
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES})
|
||||
list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}")
|
||||
endforeach()
|
||||
list(REMOVE_DUPLICATES FASTCOV_EXCLUDES)
|
||||
|
||||
# Conditional arguments
|
||||
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
|
||||
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
|
||||
endif()
|
||||
|
||||
# Set up commands which will be run to generate coverage data
|
||||
set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS})
|
||||
|
||||
set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
|
||||
--search-directory ${BASEDIR}
|
||||
--process-gcno
|
||||
--lcov
|
||||
--output ${Coverage_NAME}.info
|
||||
--exclude ${FASTCOV_EXCLUDES}
|
||||
--exclude ${FASTCOV_EXCLUDES}
|
||||
)
|
||||
|
||||
if(Coverage_SKIP_HTML)
|
||||
set(FASTCOV_HTML_CMD ";")
|
||||
else()
|
||||
set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS}
|
||||
-o ${Coverage_NAME} ${Coverage_NAME}.info
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CODE_COVERAGE_VERBOSE)
|
||||
message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):")
|
||||
|
||||
message(" Running tests:")
|
||||
string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}")
|
||||
message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}")
|
||||
|
||||
message(" Capturing fastcov counters and generating report:")
|
||||
string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}")
|
||||
message(" ${FASTCOV_CAPTURE_CMD_SPACED}")
|
||||
|
||||
if(NOT Coverage_SKIP_HTML)
|
||||
message(" Generating HTML report: ")
|
||||
string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}")
|
||||
message(" ${FASTCOV_HTML_CMD_SPACED}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Setup target
|
||||
add_custom_target(${Coverage_NAME}
|
||||
|
||||
# Cleanup fastcov
|
||||
COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
|
||||
--search-directory ${BASEDIR}
|
||||
--zerocounters
|
||||
|
||||
COMMAND ${FASTCOV_EXEC_TESTS_CMD}
|
||||
COMMAND ${FASTCOV_CAPTURE_CMD}
|
||||
COMMAND ${FASTCOV_HTML_CMD}
|
||||
|
||||
# Set output files as GENERATED (will be removed on 'make clean')
|
||||
BYPRODUCTS
|
||||
${Coverage_NAME}.info
|
||||
${Coverage_NAME}/index.html # report directory
|
||||
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
DEPENDS ${Coverage_DEPENDENCIES}
|
||||
VERBATIM # Protect arguments to commands
|
||||
COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report."
|
||||
)
|
||||
|
||||
set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info.")
|
||||
if(NOT Coverage_SKIP_HTML)
|
||||
string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.")
|
||||
endif()
|
||||
# Show where to find the fastcov info report
|
||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG}
|
||||
)
|
||||
|
||||
endfunction() # setup_target_for_coverage_fastcov
|
||||
|
||||
function(append_coverage_compiler_flags)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
|
||||
endfunction() # append_coverage_compiler_flags
|
|
@ -27,6 +27,53 @@ macro ( ADD_FLUID_TEST _test )
|
|||
|
||||
endmacro ( ADD_FLUID_TEST )
|
||||
|
||||
macro ( ADD_FLUID_TEST_UTIL _util )
|
||||
ADD_EXECUTABLE(${_util} ${_util}.c $<TARGET_OBJECTS:libfluidsynth-OBJ> )
|
||||
|
||||
# only build this unit test when explicitly requested by "make check"
|
||||
set_target_properties(${_util} PROPERTIES EXCLUDE_FROM_ALL TRUE)
|
||||
|
||||
# append no-op generator expression to avoid VS or XCode from adding per-config subdirectories
|
||||
set_target_properties(${_util} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/test/utils/$<0:>)
|
||||
|
||||
# import necessary compile flags and dependency libraries
|
||||
if ( FLUID_CPPFLAGS )
|
||||
set_target_properties ( ${_util} PROPERTIES COMPILE_FLAGS ${FLUID_CPPFLAGS} )
|
||||
endif ( FLUID_CPPFLAGS )
|
||||
TARGET_LINK_LIBRARIES(${_util} $<TARGET_PROPERTY:libfluidsynth,INTERFACE_LINK_LIBRARIES>)
|
||||
|
||||
# use the local include path to look for fluidsynth.h, as we cannot be sure fluidsynth is already installed
|
||||
target_include_directories(${_util}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include> # include auto generated headers
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include> # include "normal" public (sub-)headers
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src> # include private headers
|
||||
$<TARGET_PROPERTY:libfluidsynth,INCLUDE_DIRECTORIES> # include all other header search paths needed by libfluidsynth (esp. glib)
|
||||
)
|
||||
|
||||
# append the current unit test to check-target as dependency
|
||||
add_dependencies(check ${_util})
|
||||
|
||||
endmacro ( ADD_FLUID_TEST_UTIL )
|
||||
|
||||
# This macro adds a test that writes its output to a file called
|
||||
# <test>.output (in the current working dir) and then compares
|
||||
# the content with the file given in _expected_output
|
||||
macro ( ADD_FLUID_SF_DUMP_TEST _sfname)
|
||||
|
||||
set( test_args "${CMAKE_SOURCE_DIR}/sf2/${_sfname} ${_sfname}.yml" )
|
||||
|
||||
ADD_TEST(${_sfname}_dump_test
|
||||
${CMAKE_COMMAND}
|
||||
-Dtest_cmd=${CMAKE_BINARY_DIR}/test/utils/dump_sfont${CMAKE_EXECUTABLE_SUFFIX}
|
||||
-Dtest_args=${test_args}
|
||||
-Dtest_output=${_sfname}.yml
|
||||
-Dexpected_output=${CMAKE_SOURCE_DIR}/sf2/${_sfname}.yml
|
||||
-P ${CMAKE_SOURCE_DIR}/cmake_admin/RunOutputTest.cmake
|
||||
)
|
||||
|
||||
endmacro ( ADD_FLUID_SF_DUMP_TEST )
|
||||
|
||||
macro ( ADD_FLUID_DEMO _demo )
|
||||
ADD_EXECUTABLE(${_demo} ${_demo}.c )
|
||||
|
||||
|
|
31
cmake_admin/RunOutputTest.cmake
Normal file
31
cmake_admin/RunOutputTest.cmake
Normal file
|
@ -0,0 +1,31 @@
|
|||
if( NOT test_cmd )
|
||||
message( FATAL_ERROR "test_cmd not defined" )
|
||||
endif( NOT test_cmd )
|
||||
|
||||
if( NOT test_output )
|
||||
message( FATAL_ERROR "test_output not defined" )
|
||||
endif( NOT test_output )
|
||||
|
||||
if( NOT expected_output )
|
||||
message( FATAL_ERROR "expected_output not defined" )
|
||||
endif( NOT expected_output )
|
||||
|
||||
separate_arguments( test_args )
|
||||
|
||||
execute_process(
|
||||
COMMAND ${test_cmd} ${test_args}
|
||||
RESULT_VARIABLE test_not_successful
|
||||
)
|
||||
|
||||
if( test_not_successful )
|
||||
message( FATAL_ERROR "${test_cmd} ${test_args} returned error ${test_not_successful}!" )
|
||||
endif( test_not_successful )
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E compare_files ${expected_output} ${test_output}
|
||||
RESULT_VARIABLE compare_not_successful
|
||||
)
|
||||
|
||||
if( compare_not_successful )
|
||||
message( SEND_ERROR "${test_output} does not match ${expected_output}!" )
|
||||
endif( compare_not_successful )
|
|
@ -234,6 +234,12 @@ else ( ENABLE_UBSAN )
|
|||
set ( DEVEL_REPORT "${DEVEL_REPORT} UBSan (debug): no\n" )
|
||||
endif ( ENABLE_UBSAN )
|
||||
|
||||
if ( ENABLE_COVERAGE )
|
||||
set ( DEVEL_REPORT "${DEVEL_REPORT} Coverage: yes\n" )
|
||||
else ( ENABLE_COVERAGE )
|
||||
set ( DEVEL_REPORT "${DEVEL_REPORT} Coverage: no\n" )
|
||||
endif ( ENABLE_COVERAGE )
|
||||
|
||||
message( STATUS
|
||||
"\n**************************************************************\n"
|
||||
"Build Summary:\n"
|
||||
|
|
18805
sf2/VintageDreamsWaves-v2.sf2.yml
Normal file
18805
sf2/VintageDreamsWaves-v2.sf2.yml
Normal file
File diff suppressed because it is too large
Load diff
18805
sf2/VintageDreamsWaves-v2.sf3.yml
Normal file
18805
sf2/VintageDreamsWaves-v2.sf3.yml
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1241,7 +1241,10 @@ fluid_handle_reverb_command(void *data, int ac, char **av, fluid_ostream_t out,
|
|||
/* name and min/max values table */
|
||||
static struct value values[FLUID_REVERB_PARAM_LAST] =
|
||||
{
|
||||
{"room size"}, {"damp"}, {"width"}, {"level"}
|
||||
{"room size", 0, 0},
|
||||
{"damp", 0, 0},
|
||||
{"width", 0, 0},
|
||||
{"level", 0, 0}
|
||||
};
|
||||
|
||||
FLUID_ENTRY_COMMAND(data);
|
||||
|
@ -3553,7 +3556,7 @@ enum
|
|||
int fluid_handle_player_cde(void *data, int ac, char **av, fluid_ostream_t out, int cmd)
|
||||
{
|
||||
FLUID_ENTRY_COMMAND(data);
|
||||
int arg, was_running;
|
||||
int arg = 0, was_running;
|
||||
int seek = -1; /* current seek position in tick */
|
||||
|
||||
/* commands name table */
|
||||
|
|
|
@ -187,14 +187,14 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
|
|||
dev->data = data;
|
||||
|
||||
// Open the default output unit
|
||||
ComponentDescription desc;
|
||||
AudioComponentDescription desc;
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
desc.componentSubType = kAudioUnitSubType_HALOutput; //kAudioUnitSubType_DefaultOutput;
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
|
||||
Component comp = FindNextComponent(NULL, &desc);
|
||||
AudioComponent comp = AudioComponentFindNext(NULL, &desc);
|
||||
|
||||
if(comp == NULL)
|
||||
{
|
||||
|
@ -202,7 +202,7 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
|
|||
goto error_recovery;
|
||||
}
|
||||
|
||||
status = OpenAComponent(comp, &dev->outputUnit);
|
||||
status = AudioComponentInstanceNew(comp, &dev->outputUnit);
|
||||
|
||||
if(status != noErr)
|
||||
{
|
||||
|
@ -372,7 +372,7 @@ delete_fluid_core_audio_driver(fluid_audio_driver_t *p)
|
|||
fluid_core_audio_driver_t *dev = (fluid_core_audio_driver_t *) p;
|
||||
fluid_return_if_fail(dev != NULL);
|
||||
|
||||
CloseComponent(dev->outputUnit);
|
||||
AudioComponentInstanceDispose(dev->outputUnit);
|
||||
|
||||
if(dev->buffers[0])
|
||||
{
|
||||
|
|
|
@ -1203,10 +1203,6 @@ print_help(fluid_settings_t *settings)
|
|||
" Number of audio buffers\n");
|
||||
printf(" -C, --chorus\n"
|
||||
" Turn the chorus on or off [0|1|yes|no, default = on]\n");
|
||||
#ifdef WASAPI_SUPPORT
|
||||
printf(" -D, --query-audio-devices\n"
|
||||
" Probe all available soundcards for supported modes, sample-rates and sample-formats.\n");
|
||||
#endif
|
||||
printf(" -d, --dump\n"
|
||||
" Dump incoming and outgoing MIDI events to stdout\n");
|
||||
printf(" -E, --audio-file-endian\n"
|
||||
|
@ -1244,6 +1240,10 @@ print_help(fluid_settings_t *settings)
|
|||
" Audio file format for fast rendering or aufile driver (\"help\" for list)\n");
|
||||
printf(" -p, --portname=[label]\n"
|
||||
" Set MIDI port name (alsa_seq, coremidi drivers)\n");
|
||||
#ifdef WASAPI_SUPPORT
|
||||
printf(" -Q, --query-audio-devices\n"
|
||||
" Probe all available soundcards for supported modes, sample-rates and sample-formats.\n");
|
||||
#endif
|
||||
printf(" -q, --quiet\n"
|
||||
" Do not print welcome message or other informational output\n"
|
||||
" (Windows only: also suppress all log messages lower than PANIC\n");
|
||||
|
|
|
@ -233,11 +233,11 @@ static int process_pdta(SFData *sf, int size);
|
|||
static int load_phdr(SFData *sf, unsigned int size);
|
||||
static int load_pbag(SFData *sf, int size);
|
||||
static int load_pmod(SFData *sf, int size);
|
||||
static int load_pgen(SFData *sf, int size);
|
||||
extern int load_pgen(SFData *sf, int size);
|
||||
static int load_ihdr(SFData *sf, unsigned int size);
|
||||
static int load_ibag(SFData *sf, int size);
|
||||
static int load_imod(SFData *sf, int size);
|
||||
static int load_igen(SFData *sf, int size);
|
||||
extern int load_igen(SFData *sf, int size);
|
||||
static int load_shdr(SFData *sf, unsigned int size);
|
||||
|
||||
static int chunkid(uint32_t id);
|
||||
|
@ -248,11 +248,6 @@ static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist);
|
|||
static int valid_inst_genid(unsigned short genid);
|
||||
static int valid_preset_genid(unsigned short genid);
|
||||
|
||||
|
||||
static void delete_preset(SFPreset *preset);
|
||||
static void delete_inst(SFInst *inst);
|
||||
static void delete_zone(SFZone *zone);
|
||||
|
||||
static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data);
|
||||
static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24);
|
||||
|
||||
|
@ -1283,7 +1278,7 @@ static int load_pmod(SFData *sf, int size)
|
|||
* if a generator follows an instrument discard it
|
||||
* if a duplicate generator exists replace previous one
|
||||
* ------------------------------------------------------------------- */
|
||||
static int load_pgen(SFData *sf, int size)
|
||||
int load_pgen(SFData *sf, int size)
|
||||
{
|
||||
fluid_list_t *dup;
|
||||
fluid_list_t *preset_list;
|
||||
|
@ -1784,7 +1779,7 @@ static int load_imod(SFData *sf, int size)
|
|||
}
|
||||
|
||||
/* load instrument generators (see load_pgen for loading rules) */
|
||||
static int load_igen(SFData *sf, int size)
|
||||
int load_igen(SFData *sf, int size)
|
||||
{
|
||||
fluid_list_t *dup;
|
||||
fluid_list_t *inst_list;
|
||||
|
@ -2042,7 +2037,7 @@ static int load_shdr(SFData *sf, unsigned int size)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void delete_preset(SFPreset *preset)
|
||||
void delete_preset(SFPreset *preset)
|
||||
{
|
||||
fluid_list_t *entry;
|
||||
SFZone *zone;
|
||||
|
@ -2066,7 +2061,7 @@ static void delete_preset(SFPreset *preset)
|
|||
FLUID_FREE(preset);
|
||||
}
|
||||
|
||||
static void delete_inst(SFInst *inst)
|
||||
void delete_inst(SFInst *inst)
|
||||
{
|
||||
fluid_list_t *entry;
|
||||
SFZone *zone;
|
||||
|
@ -2092,7 +2087,7 @@ static void delete_inst(SFInst *inst)
|
|||
|
||||
|
||||
/* Free all elements of a zone (Preset or Instrument) */
|
||||
static void delete_zone(SFZone *zone)
|
||||
void delete_zone(SFZone *zone)
|
||||
{
|
||||
fluid_list_t *entry;
|
||||
|
||||
|
|
|
@ -183,4 +183,12 @@ int fluid_sffile_parse_presets(SFData *sf);
|
|||
int fluid_sffile_read_sample_data(SFData *sf, unsigned int sample_start, unsigned int sample_end,
|
||||
int sample_type, short **data, char **data24);
|
||||
|
||||
|
||||
/* extern only for unit test purposes */
|
||||
int load_igen(SFData *sf, int size);
|
||||
int load_pgen(SFData *sf, int size);
|
||||
void delete_preset(SFPreset *preset);
|
||||
void delete_inst(SFInst *inst);
|
||||
void delete_zone(SFZone *zone);
|
||||
|
||||
#endif /* _FLUID_SFFILE_H */
|
||||
|
|
|
@ -23,73 +23,76 @@
|
|||
#include "fluid_chan.h"
|
||||
|
||||
|
||||
#define _GEN(_name) GEN_ ## _name, #_name
|
||||
|
||||
|
||||
/* See SFSpec21 $8.1.3 */
|
||||
static const fluid_gen_info_t fluid_gen_info[] =
|
||||
{
|
||||
/* number/name init nrpn-scale min max def */
|
||||
{ GEN_STARTADDROFS, 1, 1, 0.0f, 1e10f, 0.0f },
|
||||
{ GEN_ENDADDROFS, 1, 1, -1e10f, 0.0f, 0.0f },
|
||||
{ GEN_STARTLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_ENDLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_STARTADDRCOARSEOFS, 0, 1, 0.0f, 1e10f, 0.0f },
|
||||
{ GEN_MODLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_VIBLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_MODENVTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_FILTERFC, 1, 2, 1500.0f, 13500.0f, 13500.0f },
|
||||
{ GEN_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f },
|
||||
{ GEN_MODLFOTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_MODENVTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_ENDADDRCOARSEOFS, 0, 1, -1e10f, 0.0f, 0.0f },
|
||||
{ GEN_MODLFOTOVOL, 1, 1, -960.0f, 960.0f, 0.0f },
|
||||
{ GEN_UNUSED1, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_CHORUSSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_REVERBSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_PAN, 1, 1, -500.0f, 500.0f, 0.0f },
|
||||
{ GEN_UNUSED2, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_UNUSED3, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_UNUSED4, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_MODLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
|
||||
{ GEN_VIBLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VIBLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
|
||||
{ GEN_MODENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_MODENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_MODENVSUSTAIN, 0, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_MODENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_KEYTOMODENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_KEYTOMODENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_VOLENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VOLENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_VOLENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VOLENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_VOLENVSUSTAIN, 0, 1, 0.0f, 1440.0f, 0.0f },
|
||||
{ GEN_VOLENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_KEYTOVOLENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_KEYTOVOLENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_INSTRUMENT, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_RESERVED1, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_KEYRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ GEN_VELRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ GEN_STARTLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_KEYNUM, 1, 0, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_VELOCITY, 1, 1, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_ATTENUATION, 1, 1, 0.0f, 1440.0f, 0.0f },
|
||||
{ GEN_RESERVED2, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_ENDLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_COARSETUNE, 0, 1, -120.0f, 120.0f, 0.0f },
|
||||
{ GEN_FINETUNE, 0, 1, -99.0f, 99.0f, 0.0f },
|
||||
{ GEN_SAMPLEID, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_SAMPLEMODE, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_RESERVED3, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_SCALETUNE, 0, 1, 0.0f, 1200.0f, 100.0f },
|
||||
{ GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ GEN_CUSTOM_BALANCE, 1, 0, -960.0f, 960.0f, 0.0f },
|
||||
{ GEN_CUSTOM_FILTERFC, 1, 2, 0.0f, 22050.0f, 0.0f },
|
||||
{ GEN_CUSTOM_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f }
|
||||
{ _GEN(STARTADDROFS), 1, 1, 0.0f, 1e10f, 0.0f },
|
||||
{ _GEN(ENDADDROFS), 1, 1, -1e10f, 0.0f, 0.0f },
|
||||
{ _GEN(STARTLOOPADDROFS), 1, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ _GEN(ENDLOOPADDROFS), 1, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ _GEN(STARTADDRCOARSEOFS), 0, 1, 0.0f, 1e10f, 0.0f },
|
||||
{ _GEN(MODLFOTOPITCH), 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ _GEN(VIBLFOTOPITCH), 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ _GEN(MODENVTOPITCH), 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ _GEN(FILTERFC), 1, 2, 1500.0f, 13500.0f, 13500.0f },
|
||||
{ _GEN(FILTERQ), 1, 1, 0.0f, 960.0f, 0.0f },
|
||||
{ _GEN(MODLFOTOFILTERFC), 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ _GEN(MODENVTOFILTERFC), 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ _GEN(ENDADDRCOARSEOFS), 0, 1, -1e10f, 0.0f, 0.0f },
|
||||
{ _GEN(MODLFOTOVOL), 1, 1, -960.0f, 960.0f, 0.0f },
|
||||
{ _GEN(UNUSED1), 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ _GEN(CHORUSSEND), 1, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ _GEN(REVERBSEND), 1, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ _GEN(PAN), 1, 1, -500.0f, 500.0f, 0.0f },
|
||||
{ _GEN(UNUSED2), 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ _GEN(UNUSED3), 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ _GEN(UNUSED4), 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ _GEN(MODLFODELAY), 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ _GEN(MODLFOFREQ), 1, 4, -16000.0f, 4500.0f, 0.0f },
|
||||
{ _GEN(VIBLFODELAY), 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ _GEN(VIBLFOFREQ), 1, 4, -16000.0f, 4500.0f, 0.0f },
|
||||
{ _GEN(MODENVDELAY), 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ _GEN(MODENVATTACK), 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ _GEN(MODENVHOLD), 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ _GEN(MODENVDECAY), 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ _GEN(MODENVSUSTAIN), 0, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ _GEN(MODENVRELEASE), 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ _GEN(KEYTOMODENVHOLD), 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ _GEN(KEYTOMODENVDECAY), 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ _GEN(VOLENVDELAY), 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ _GEN(VOLENVATTACK), 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ _GEN(VOLENVHOLD), 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ _GEN(VOLENVDECAY), 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ _GEN(VOLENVSUSTAIN), 0, 1, 0.0f, 1440.0f, 0.0f },
|
||||
{ _GEN(VOLENVRELEASE), 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ _GEN(KEYTOVOLENVHOLD), 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ _GEN(KEYTOVOLENVDECAY), 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ _GEN(INSTRUMENT), 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ _GEN(RESERVED1), 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ _GEN(KEYRANGE), 0, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ _GEN(VELRANGE), 0, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ _GEN(STARTLOOPADDRCOARSEOFS), 0, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ _GEN(KEYNUM), 1, 0, 0.0f, 127.0f, -1.0f },
|
||||
{ _GEN(VELOCITY), 1, 1, 0.0f, 127.0f, -1.0f },
|
||||
{ _GEN(ATTENUATION), 1, 1, 0.0f, 1440.0f, 0.0f },
|
||||
{ _GEN(RESERVED2), 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ _GEN(ENDLOOPADDRCOARSEOFS), 0, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ _GEN(COARSETUNE), 0, 1, -120.0f, 120.0f, 0.0f },
|
||||
{ _GEN(FINETUNE), 0, 1, -99.0f, 99.0f, 0.0f },
|
||||
{ _GEN(SAMPLEID), 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ _GEN(SAMPLEMODE), 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ _GEN(RESERVED3), 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ _GEN(SCALETUNE), 0, 1, 0.0f, 1200.0f, 100.0f },
|
||||
{ _GEN(EXCLUSIVECLASS), 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ _GEN(OVERRIDEROOTKEY), 1, 0, 0.0f, 127.0f, -1.0f },
|
||||
{ _GEN(PITCH), 1, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ _GEN(CUSTOM_BALANCE), 1, 0, -960.0f, 960.0f, 0.0f },
|
||||
{ _GEN(CUSTOM_FILTERFC), 1, 2, 0.0f, 22050.0f, 0.0f },
|
||||
{ _GEN(CUSTOM_FILTERQ), 1, 1, 0.0f, 960.0f, 0.0f }
|
||||
};
|
||||
|
||||
/* fluid_gen_init
|
||||
|
@ -122,3 +125,9 @@ fluid_real_t fluid_gen_scale_nrpn(int gen, int data)
|
|||
fluid_clip(data, -8192, 8192);
|
||||
return (fluid_real_t)(data * fluid_gen_info[gen].nrpn_scale);
|
||||
}
|
||||
|
||||
|
||||
const char *fluid_gen_name(int gen)
|
||||
{
|
||||
return fluid_gen_info[gen].name;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
typedef struct _fluid_gen_info_t
|
||||
{
|
||||
char num; /* Generator number */
|
||||
char *name;
|
||||
char init; /* Does the generator need to be initialized (not used) */
|
||||
char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */
|
||||
float min; /* The minimum value */
|
||||
|
@ -60,6 +61,7 @@ enum fluid_gen_flags
|
|||
fluid_real_t fluid_gen_scale(int gen, float value);
|
||||
fluid_real_t fluid_gen_scale_nrpn(int gen, int nrpn);
|
||||
void fluid_gen_init(fluid_gen_t *gen, fluid_channel_t *channel);
|
||||
const char *fluid_gen_name(int gen);
|
||||
|
||||
|
||||
#endif /* _FLUID_GEN_H */
|
||||
|
|
|
@ -319,3 +319,19 @@ fluid_list_str_compare_func(void *a, void *b)
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fluid_list_idx(fluid_list_t *list, void *data)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while(list)
|
||||
{
|
||||
if (list->data == data)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ fluid_list_t *fluid_list_remove_link(fluid_list_t *list, fluid_list_t *llink);
|
|||
fluid_list_t *fluid_list_nth(fluid_list_t *list, int n);
|
||||
fluid_list_t *fluid_list_last(fluid_list_t *list);
|
||||
fluid_list_t *fluid_list_insert_at(fluid_list_t *list, int n, void *data);
|
||||
int fluid_list_idx(fluid_list_t *list, void *data);
|
||||
int fluid_list_size(fluid_list_t *list);
|
||||
|
||||
#define fluid_list_next(slist) ((slist) ? (((fluid_list_t *)(slist))->next) : NULL)
|
||||
|
|
|
@ -22,6 +22,7 @@ ADD_FLUID_TEST(test_synth_process)
|
|||
ADD_FLUID_TEST(test_ct2hz)
|
||||
ADD_FLUID_TEST(test_sample_validate)
|
||||
ADD_FLUID_TEST(test_sfont_unloading)
|
||||
ADD_FLUID_TEST(test_sfont_zone)
|
||||
ADD_FLUID_TEST(test_seq_event_queue_sort)
|
||||
ADD_FLUID_TEST(test_seq_scale)
|
||||
ADD_FLUID_TEST(test_seq_evt_order)
|
||||
|
@ -29,6 +30,11 @@ ADD_FLUID_TEST(test_seq_event_queue_remove)
|
|||
ADD_FLUID_TEST(test_jack_obtaining_synth)
|
||||
ADD_FLUID_TEST(test_utf8_open)
|
||||
|
||||
ADD_FLUID_TEST_UTIL(dump_sfont)
|
||||
|
||||
ADD_FLUID_SF_DUMP_TEST(VintageDreamsWaves-v2.sf2)
|
||||
|
||||
if ( LIBSNDFILE_HASVORBIS )
|
||||
ADD_FLUID_TEST(test_sf3_sfont_loading)
|
||||
ADD_FLUID_SF_DUMP_TEST(VintageDreamsWaves-v2.sf3)
|
||||
endif ( LIBSNDFILE_HASVORBIS )
|
||||
|
|
430
test/dump_sfont.c
Normal file
430
test/dump_sfont.c
Normal file
|
@ -0,0 +1,430 @@
|
|||
#include "test.h"
|
||||
#include "fluidsynth.h"
|
||||
#include "fluid_sfont.h"
|
||||
#include "fluid_defsfont.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
static void dump_sample(fluid_sample_t *sample);
|
||||
static void dump_gens(const fluid_gen_t gen[]);
|
||||
static void dump_mod(const fluid_mod_t *mod);
|
||||
static void dump_preset_zone(fluid_preset_zone_t *zone);
|
||||
static void dump_preset(fluid_preset_t *preset);
|
||||
static void dump_inst_zone(fluid_inst_zone_t *zone);
|
||||
static void dump_inst(fluid_inst_t *inst);
|
||||
static void dump_defsfont(fluid_defsfont_t *defsfont);
|
||||
static int inst_compare_func(void *a, void *b);
|
||||
static fluid_list_t *collect_preset_insts(fluid_preset_t *preset, fluid_list_t *inst_list);
|
||||
|
||||
#define FMT_BUFSIZE (4096)
|
||||
static int indent_level = 0;
|
||||
static FILE *output = NULL;
|
||||
|
||||
static void fmt(const char *format, ...);
|
||||
static void indent(void);
|
||||
static void outdent(void);
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = FLUID_FAILED;
|
||||
int id;
|
||||
fluid_sfont_t *sfont;
|
||||
fluid_defsfont_t *defsfont;
|
||||
fluid_settings_t *settings;
|
||||
fluid_synth_t *synth;
|
||||
const char *adrivers[1] = { NULL };
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "Usage:\n");
|
||||
fprintf(stderr, " dump_sfont <input_soundfont> [output_file]\n");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
fluid_audio_driver_register(adrivers);
|
||||
|
||||
settings = new_fluid_settings();
|
||||
if (settings == NULL)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
synth = new_fluid_synth(settings);
|
||||
if (synth == NULL)
|
||||
{
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
id = fluid_synth_sfload(synth, argv[1], 1);
|
||||
if (id < 0)
|
||||
{
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
sfont = fluid_synth_get_sfont_by_id(synth, id);
|
||||
if (sfont == NULL)
|
||||
{
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
if (sfont->free != &fluid_defsfont_sfont_delete)
|
||||
{
|
||||
fprintf(stderr, "This tool only supports SoundFonts loaded by the default loader\n");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
defsfont = (fluid_defsfont_t *)fluid_sfont_get_data(sfont);
|
||||
if (defsfont == NULL)
|
||||
{
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
output = stdout;
|
||||
}
|
||||
else
|
||||
{
|
||||
output = fopen(argv[2], "w");
|
||||
if (output == NULL)
|
||||
{
|
||||
fprintf(stderr, "Unable to open output file %s", argv[2]);
|
||||
goto EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
dump_defsfont(defsfont);
|
||||
|
||||
ret = FLUID_OK;
|
||||
|
||||
EXIT:
|
||||
if (output && output != stdout)
|
||||
{
|
||||
fclose(output);
|
||||
}
|
||||
delete_fluid_synth(synth);
|
||||
delete_fluid_settings(settings);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dump_sample(fluid_sample_t *sample)
|
||||
{
|
||||
fmt("name: %s", sample->name);
|
||||
fmt("source_start: %u", sample->source_start);
|
||||
fmt("source_end: %u", sample->source_end);
|
||||
fmt("source_loopstart: %u", sample->source_loopstart);
|
||||
fmt("source_loopend: %u", sample->source_loopend);
|
||||
|
||||
fmt("start: %u", sample->start);
|
||||
fmt("end: %u", sample->end);
|
||||
fmt("loopstart: %u", sample->loopstart);
|
||||
fmt("loopend: %u", sample->loopend);
|
||||
|
||||
fmt("samplerate: %u", sample->samplerate);
|
||||
fmt("origpitch: %u", sample->origpitch);
|
||||
fmt("pitchadj: %u", sample->pitchadj);
|
||||
fmt("sampletype: %u", sample->sampletype);
|
||||
}
|
||||
|
||||
static void dump_gens(const fluid_gen_t gen[])
|
||||
{
|
||||
int i;
|
||||
|
||||
/* only dump generators if at least one is set */
|
||||
for (i = 0; i < GEN_LAST; i++)
|
||||
{
|
||||
if (gen[i].flags)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == GEN_LAST)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fmt("generators:");
|
||||
indent();
|
||||
for (i = 0; i < GEN_LAST; i++)
|
||||
{
|
||||
if (gen[i].flags)
|
||||
{
|
||||
fmt("%s: %.2f", fluid_gen_name(i), gen[i].val);
|
||||
}
|
||||
}
|
||||
outdent();
|
||||
}
|
||||
|
||||
static void dump_mod(const fluid_mod_t *mod)
|
||||
{
|
||||
fmt("dest: %s", fluid_gen_name(mod->dest));
|
||||
fmt("src1: %u", mod->src1);
|
||||
fmt("flags1: %u", mod->flags1);
|
||||
fmt("src2: %u", mod->src2);
|
||||
fmt("flags2: %u", mod->flags2);
|
||||
fmt("amount: %.2f", mod->amount);
|
||||
}
|
||||
|
||||
static void dump_preset_zone(fluid_preset_zone_t *zone)
|
||||
{
|
||||
int i;
|
||||
fluid_mod_t *mod;
|
||||
|
||||
fmt("name: %s", zone->name);
|
||||
if (zone->inst)
|
||||
{
|
||||
fmt("instrument: %s (index %d)", zone->inst->name, zone->inst->source_idx);
|
||||
}
|
||||
fmt("key_range: %d - %d", zone->range.keylo, zone->range.keyhi);
|
||||
fmt("vel_range: %d - %d", zone->range.vello, zone->range.velhi);
|
||||
dump_gens(zone->gen);
|
||||
|
||||
if (zone->mod)
|
||||
{
|
||||
fmt("modulators:");
|
||||
for (i = 0, mod = zone->mod; mod; mod = mod->next, i++)
|
||||
{
|
||||
fmt("- modulator: %d", i);
|
||||
indent();
|
||||
dump_mod(mod);
|
||||
outdent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_preset(fluid_preset_t *preset)
|
||||
{
|
||||
int i;
|
||||
fluid_preset_zone_t *zone;
|
||||
|
||||
fluid_defpreset_t *defpreset = fluid_preset_get_data(preset);
|
||||
if (defpreset == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fmt("name: %s", defpreset->name);
|
||||
fmt("bank: %u", defpreset->bank);
|
||||
fmt("num: %u", defpreset->num);
|
||||
|
||||
if (defpreset->global_zone)
|
||||
{
|
||||
fmt("global_zone:");
|
||||
indent();
|
||||
dump_preset_zone(defpreset->global_zone);
|
||||
outdent();
|
||||
}
|
||||
|
||||
fmt("zones:");
|
||||
for (i = 0, zone = defpreset->zone; zone; zone = fluid_preset_zone_next(zone), i++)
|
||||
{
|
||||
fmt("- zone: %d", i);
|
||||
if (zone == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
indent();
|
||||
dump_preset_zone(zone);
|
||||
outdent();
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_inst_zone(fluid_inst_zone_t *zone)
|
||||
{
|
||||
int i;
|
||||
fluid_mod_t *mod;
|
||||
|
||||
fmt("name: %s", zone->name);
|
||||
if (zone->sample)
|
||||
{
|
||||
fmt("sample: %s", zone->sample->name);
|
||||
}
|
||||
fmt("key_range: %d - %d", zone->range.keylo, zone->range.keyhi);
|
||||
fmt("vel_range: %d - %d", zone->range.vello, zone->range.velhi);
|
||||
dump_gens(zone->gen);
|
||||
if (zone->mod)
|
||||
{
|
||||
fmt("modulators:");
|
||||
for (i = 0, mod = zone->mod; mod; mod = mod->next, i++)
|
||||
{
|
||||
fmt("- modulator: %d", i);
|
||||
indent();
|
||||
dump_mod(mod);
|
||||
outdent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_inst(fluid_inst_t *inst)
|
||||
{
|
||||
int i;
|
||||
fluid_inst_zone_t *zone;
|
||||
|
||||
fmt("name: %s", inst->name);
|
||||
|
||||
if (inst->global_zone)
|
||||
{
|
||||
fmt("global_zone:");
|
||||
indent();
|
||||
dump_inst_zone(inst->global_zone);
|
||||
outdent();
|
||||
}
|
||||
|
||||
fmt("zones:");
|
||||
for (i = 0, zone = inst->zone; zone; zone = fluid_inst_zone_next(zone), i++)
|
||||
{
|
||||
fmt("- zone: %d", i);
|
||||
if (zone == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
indent();
|
||||
dump_inst_zone(zone);
|
||||
outdent();
|
||||
}
|
||||
}
|
||||
|
||||
static int inst_compare_func(void *a, void *b)
|
||||
{
|
||||
const fluid_inst_t *inst_a = a;
|
||||
const fluid_inst_t *inst_b = b;
|
||||
|
||||
return inst_a->source_idx - inst_b->source_idx;
|
||||
}
|
||||
|
||||
static fluid_list_t *collect_preset_insts(fluid_preset_t *preset, fluid_list_t *inst_list)
|
||||
{
|
||||
fluid_preset_zone_t *zone;
|
||||
fluid_defpreset_t *defpreset = fluid_preset_get_data(preset);
|
||||
if (defpreset == NULL)
|
||||
{
|
||||
return inst_list;
|
||||
}
|
||||
|
||||
if (defpreset->global_zone && defpreset->global_zone->inst &&
|
||||
fluid_list_idx(inst_list, defpreset->global_zone->inst) == -1)
|
||||
{
|
||||
inst_list = fluid_list_prepend(inst_list, defpreset->global_zone->inst);
|
||||
}
|
||||
|
||||
for (zone = defpreset->zone; zone; zone = fluid_preset_zone_next(zone))
|
||||
{
|
||||
if (zone->inst && (fluid_list_idx(inst_list, zone->inst) == -1))
|
||||
{
|
||||
inst_list = fluid_list_prepend(inst_list, zone->inst);
|
||||
}
|
||||
}
|
||||
|
||||
return inst_list;
|
||||
}
|
||||
|
||||
|
||||
static void dump_defsfont(fluid_defsfont_t *defsfont)
|
||||
{
|
||||
int i;
|
||||
fluid_list_t *list;
|
||||
fluid_sample_t *sample;
|
||||
fluid_preset_t *preset;
|
||||
fluid_inst_t *inst;
|
||||
fluid_list_t *inst_list = NULL;
|
||||
|
||||
fmt("samplepos: %u", defsfont->samplepos);
|
||||
fmt("samplesize: %u", defsfont->samplesize);
|
||||
fmt("sample24pos: %u", defsfont->sample24pos);
|
||||
fmt("sample24size: %u", defsfont->sample24size);
|
||||
|
||||
fmt("presets:");
|
||||
for (i = 0, list = defsfont->preset; list; list = fluid_list_next(list), i++)
|
||||
{
|
||||
preset = (fluid_preset_t *)fluid_list_get(list);
|
||||
fmt("- preset: %d", i);
|
||||
if (preset == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
indent();
|
||||
dump_preset(preset);
|
||||
outdent();
|
||||
fmt("");
|
||||
|
||||
inst_list = collect_preset_insts(preset, inst_list);
|
||||
}
|
||||
|
||||
inst_list = fluid_list_sort(inst_list, (fluid_compare_func_t)inst_compare_func);
|
||||
|
||||
fmt("instruments:");
|
||||
for (list = inst_list; list; list = fluid_list_next(list))
|
||||
{
|
||||
inst = (fluid_inst_t *)fluid_list_get(list);
|
||||
fmt("- instrument: %d", inst->source_idx);
|
||||
indent();
|
||||
dump_inst(inst);
|
||||
outdent();
|
||||
fmt("");
|
||||
}
|
||||
|
||||
delete_fluid_list(inst_list);
|
||||
|
||||
fmt("samples:");
|
||||
for (i = 0, list = defsfont->sample; list; list = fluid_list_next(list), i++)
|
||||
{
|
||||
sample = (fluid_sample_t *)fluid_list_get(list);
|
||||
fmt("- sample: %d", i);
|
||||
if (sample == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
indent();
|
||||
dump_sample(sample);
|
||||
outdent();
|
||||
fmt("");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void fmt(const char *format, ...)
|
||||
{
|
||||
char buf[FMT_BUFSIZE];
|
||||
va_list args;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
va_start(args, format);
|
||||
len = FLUID_VSNPRINTF(buf, FMT_BUFSIZE, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (len < 0)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "max buffer size exceeded");
|
||||
return;
|
||||
}
|
||||
|
||||
buf[FMT_BUFSIZE - 1] = '\0';
|
||||
|
||||
for (i = 0; i < indent_level; i++)
|
||||
{
|
||||
fprintf(output, " ");
|
||||
}
|
||||
|
||||
fwrite(buf, 1, FLUID_STRLEN(buf), output);
|
||||
fprintf(output, "\n");
|
||||
}
|
||||
|
||||
static void indent(void)
|
||||
{
|
||||
indent_level += 1;
|
||||
}
|
||||
|
||||
static void outdent(void)
|
||||
{
|
||||
if (indent_level > 0)
|
||||
{
|
||||
indent_level -= 1;
|
||||
}
|
||||
}
|
479
test/test_sfont_zone.c
Normal file
479
test/test_sfont_zone.c
Normal file
|
@ -0,0 +1,479 @@
|
|||
|
||||
#include "test.h"
|
||||
#include "fluidsynth.h"
|
||||
#include "sfloader/fluid_sfont.h"
|
||||
#include "sfloader/fluid_defsfont.h"
|
||||
#include "sfloader/fluid_sffile.h"
|
||||
#include "utils/fluid_sys.h"
|
||||
|
||||
|
||||
#define SET_BUF2(START, SIZE) \
|
||||
do \
|
||||
{ \
|
||||
file_buf = START; \
|
||||
file_end = (START) + (SIZE); \
|
||||
} while (0)
|
||||
#define SET_BUF(BUF) SET_BUF2(BUF, FLUID_N_ELEMENTS(BUF))
|
||||
#define UNSET_BUF \
|
||||
do \
|
||||
{ \
|
||||
file_buf = NULL; \
|
||||
file_end = NULL; \
|
||||
} while (0)
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// pointer to the start of the file_buf
|
||||
const unsigned char *start;
|
||||
// actual size of the buffer
|
||||
unsigned int size;
|
||||
// expected end address of the buffer
|
||||
const unsigned char *end;
|
||||
} buf_t;
|
||||
|
||||
static const unsigned char *file_buf = NULL;
|
||||
static const unsigned char *file_end = NULL;
|
||||
static int test_reader(void *buf, fluid_long_long_t count, void *h)
|
||||
{
|
||||
if (file_buf + count > file_end)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
FLUID_MEMCPY(buf, file_buf, count);
|
||||
file_buf += count;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
static int test_seek(void *handle, fluid_long_long_t offset, int origin)
|
||||
{
|
||||
if (origin == SEEK_CUR)
|
||||
{
|
||||
file_buf += offset;
|
||||
if (file_buf > file_end)
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
// shouldn't happen?
|
||||
TEST_ASSERT(0);
|
||||
}
|
||||
|
||||
static const fluid_file_callbacks_t fcb =
|
||||
{
|
||||
NULL, &test_reader, &test_seek, NULL, NULL
|
||||
};
|
||||
|
||||
static SFZone* new_test_zone(fluid_list_t** parent_list, int gen_count)
|
||||
{
|
||||
int i;
|
||||
SFZone *zone = FLUID_NEW(SFZone);
|
||||
TEST_ASSERT(zone != NULL);
|
||||
FLUID_MEMSET(zone, 0, sizeof(*zone));
|
||||
|
||||
for (i = 0; i < gen_count; i++)
|
||||
{
|
||||
zone->gen = fluid_list_prepend(zone->gen, NULL);
|
||||
}
|
||||
|
||||
if(parent_list != NULL)
|
||||
{
|
||||
*parent_list = fluid_list_append(*parent_list, zone);
|
||||
}
|
||||
|
||||
return zone;
|
||||
}
|
||||
|
||||
// test the good case first: one zone, with two generators and one terminal generator
|
||||
static void good_test_1zone_2gen_1termgen(int (*load_func)(SFData *sf, int size), SFData* sf, SFZone *zone)
|
||||
{
|
||||
const SFGen *gen;
|
||||
static const unsigned char buf[] =
|
||||
{
|
||||
GEN_KEYRANGE, 0, 60, 127, GEN_VELRANGE, 0, 60, 127, 0, 0, 0, 0
|
||||
};
|
||||
SET_BUF(buf);
|
||||
TEST_ASSERT(load_func(sf, FLUID_N_ELEMENTS(buf)));
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == GEN_KEYRANGE);
|
||||
TEST_ASSERT(gen->amount.range.lo == 60);
|
||||
TEST_ASSERT(gen->amount.range.hi == 127);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 1));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == GEN_VELRANGE);
|
||||
TEST_ASSERT(gen->amount.range.lo == 60);
|
||||
TEST_ASSERT(gen->amount.range.hi == 127);
|
||||
|
||||
TEST_ASSERT(file_buf == buf + sizeof(buf));
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
// bad case: too few generators in buffer, triggering a chunk size mismatch
|
||||
static void bad_test_too_short_gen_buffer(int (*load_func)(SFData *sf, int size), SFData *sf, SFZone *zone)
|
||||
{
|
||||
const unsigned char final_gen = (load_func == &load_pgen) ? GEN_INSTRUMENT : GEN_SAMPLEID;
|
||||
SFGen *gen;
|
||||
unsigned int i;
|
||||
static const unsigned char buf1[] = { GEN_KEYRANGE, 0, 0 };
|
||||
static const unsigned char buf2[] = { GEN_KEYRANGE, 0 };
|
||||
static const unsigned char buf3[] = { GEN_KEYRANGE };
|
||||
static const unsigned char buf8[] = { GEN_VELRANGE, 0, 0 };
|
||||
static const unsigned char buf9[] = { GEN_VELRANGE, 0 };
|
||||
static const unsigned char buf10[] = { GEN_VELRANGE };
|
||||
static const unsigned char buf4[] = { GEN_VELRANGE, 0, 0, 127, GEN_COARSETUNE, 0, 4 };
|
||||
static const unsigned char buf5[] = { GEN_VELRANGE, 0, 0, 127, GEN_COARSETUNE, 0 };
|
||||
static const unsigned char buf6[] = { GEN_VELRANGE, 0, 0, 127, GEN_COARSETUNE };
|
||||
const unsigned char buf11[] = { GEN_VELRANGE, 0, 0, 127, final_gen, 0, 4 };
|
||||
const unsigned char buf12[] = { GEN_VELRANGE, 0, 0, 127, final_gen, 0 };
|
||||
const unsigned char buf13[] = { GEN_VELRANGE, 0, 0, 127, final_gen };
|
||||
static const unsigned char buf7[] = { GEN_KEYRANGE, 0, 60, 127, GEN_OVERRIDEROOTKEY };
|
||||
|
||||
static const buf_t buf_with_one_gen[] =
|
||||
{
|
||||
{ buf1, sizeof(buf1), buf1 + sizeof(buf1) },
|
||||
{ buf2, sizeof(buf2),buf2 + sizeof(buf2) },
|
||||
{ buf3, sizeof(buf3), buf3 },
|
||||
{ buf8, sizeof(buf8), buf8 + sizeof(buf8) },
|
||||
{ buf9, sizeof(buf9), buf9 + sizeof(buf9) },
|
||||
{ buf10, sizeof(buf10), buf10 }
|
||||
};
|
||||
|
||||
const buf_t buf_with_two_gen[] =
|
||||
{
|
||||
{ buf4, sizeof(buf4), buf4 + sizeof(buf4) -1 },
|
||||
{ buf5, sizeof(buf5), buf5 + sizeof(buf5) },
|
||||
{ buf6, sizeof(buf6), buf6 + sizeof(buf6) - 1 },
|
||||
{ buf11, sizeof(buf11), buf11 + sizeof(buf11) - 1 },
|
||||
{ buf12, sizeof(buf12), buf12 + sizeof(buf12) },
|
||||
{ buf13, sizeof(buf13), buf13 + sizeof(buf13) -1}
|
||||
};
|
||||
|
||||
for (i = 0; i < FLUID_N_ELEMENTS(buf_with_one_gen); i++)
|
||||
{
|
||||
SET_BUF2(buf_with_one_gen[i].start, buf_with_one_gen[i].size);
|
||||
TEST_ASSERT(load_func(sf, 8 /* pretend that our input buffer is big enough, to make it fail in the fcbs later */) == FALSE);
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
TEST_ASSERT(file_buf == buf_with_one_gen[i].end);
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
for (i = 0; i < FLUID_N_ELEMENTS(buf_with_two_gen); i++)
|
||||
{
|
||||
SET_BUF2(buf_with_two_gen[i].start, buf_with_two_gen[i].size);
|
||||
TEST_ASSERT(load_func(sf, 8) == FALSE);
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
FLUID_FREE(gen);
|
||||
zone->gen->data = NULL;
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 1));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
TEST_ASSERT(file_buf == buf_with_two_gen[i].end);
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
SET_BUF(buf7);
|
||||
TEST_ASSERT(load_func(sf, FLUID_N_ELEMENTS(buf7)) == FALSE);
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == GEN_KEYRANGE);
|
||||
TEST_ASSERT(gen->amount.range.lo == 60);
|
||||
TEST_ASSERT(gen->amount.range.hi == 127);
|
||||
|
||||
TEST_ASSERT(file_buf == buf7 + sizeof(buf7) - 1);
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
// bad case: one zone, with two similar generators
|
||||
static void bad_test_duplicate_gen(int (*load_func)(SFData *sf, int size), SFData *sf, SFZone *zone)
|
||||
{
|
||||
const SFGen *gen;
|
||||
static const unsigned char buf[] = { GEN_COARSETUNE, 0, 5, 0, GEN_COARSETUNE, 0, 10, 0 };
|
||||
|
||||
SET_BUF(buf);
|
||||
TEST_ASSERT(load_func(sf, FLUID_N_ELEMENTS(buf)));
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == GEN_COARSETUNE);
|
||||
TEST_ASSERT(gen->amount.range.lo == 10);
|
||||
TEST_ASSERT(gen->amount.range.hi == 0);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 1));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
TEST_ASSERT(file_buf == buf + sizeof(buf));
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
// bad case: with one zone, generators in wrong order
|
||||
static void bad_test_gen_wrong_order(int (*load_func)(SFData *sf, int size), SFData *sf, SFZone *zone)
|
||||
{
|
||||
const SFGen *gen;
|
||||
static const unsigned char buf[] =
|
||||
{
|
||||
GEN_VELRANGE, 0, 60, 127,
|
||||
GEN_KEYRANGE, 0, 60, 127,
|
||||
GEN_INSTRUMENT, 0, 0xDD, 0xDD
|
||||
};
|
||||
SET_BUF(buf);
|
||||
TEST_ASSERT(load_func(sf, FLUID_N_ELEMENTS(buf)));
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == GEN_VELRANGE);
|
||||
TEST_ASSERT(gen->amount.range.lo == 60);
|
||||
TEST_ASSERT(gen->amount.range.hi == 127);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 1));
|
||||
if (load_func == &load_igen)
|
||||
{
|
||||
TEST_ASSERT(gen == NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == GEN_INSTRUMENT);
|
||||
TEST_ASSERT(gen->amount.uword == 0xDDDDu);
|
||||
}
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone->gen, 2));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
TEST_ASSERT(file_buf == buf + sizeof(buf));
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
// This test-case is derived from the invalid SoundFont provided in #808
|
||||
static void bad_test_issue_808(int (*load_func)(SFData *sf, int size), SFData *sf, SFZone *zone1)
|
||||
{
|
||||
const SFGen *gen;
|
||||
static const unsigned char buf[] =
|
||||
{
|
||||
// zone 1
|
||||
GEN_REVERBSEND, 0, 50, 0,
|
||||
GEN_VOLENVRELEASE, 0, 206, 249,
|
||||
// zone 2
|
||||
GEN_KEYRANGE, 0, 0, 35,
|
||||
GEN_OVERRIDEROOTKEY, 0, 43, 0,
|
||||
GEN_STARTADDRCOARSEOFS, 0, 0, 0,
|
||||
GEN_SAMPLEMODE, 0, 1, 0,
|
||||
GEN_STARTADDROFS, 0, 0, 0
|
||||
};
|
||||
|
||||
SET_BUF(buf);
|
||||
TEST_ASSERT(load_func(sf, FLUID_N_ELEMENTS(buf)));
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == GEN_REVERBSEND);
|
||||
TEST_ASSERT(gen->amount.range.lo == 50);
|
||||
TEST_ASSERT(gen->amount.range.hi == 0);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 1));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == GEN_VOLENVRELEASE);
|
||||
TEST_ASSERT(gen->amount.range.lo == 206);
|
||||
TEST_ASSERT(gen->amount.range.hi == 249);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 2));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
TEST_ASSERT(file_buf == buf + sizeof(buf));
|
||||
UNSET_BUF;
|
||||
}
|
||||
|
||||
// This test-case has a single zone which has additional generators after the final generator, while some of them are incomplete and others still have an extra (maybe incomplete) terminal gen.
|
||||
static void bad_test_additional_gens_after_final_gen(int (*load_func)(SFData *sf, int size), SFData *sf, SFZone *zone1)
|
||||
{
|
||||
unsigned int i;
|
||||
SFGen *gen;
|
||||
const unsigned char final_gen = (load_func == &load_pgen) ? GEN_INSTRUMENT : GEN_SAMPLEID;
|
||||
|
||||
const unsigned char buf1[] =
|
||||
{
|
||||
// zone 1
|
||||
GEN_KEYRANGE, 0, 60, 127,
|
||||
GEN_UNUSED1, 0, 0xFF, 0xFF,
|
||||
final_gen, 0, 0xDD, 0xDD,
|
||||
GEN_KEYRANGE, 0, 0, 35,
|
||||
GEN_OVERRIDEROOTKEY, 0, 43, 0,
|
||||
0, 0, 0, 0 // terminal generator
|
||||
};
|
||||
|
||||
const unsigned char buf2[] =
|
||||
{
|
||||
// zone 1
|
||||
GEN_KEYRANGE, 0, 60, 127,
|
||||
GEN_UNUSED1, 0, 0xFF, 0xFF,
|
||||
final_gen, 0, 0xDD, 0xDD,
|
||||
GEN_KEYRANGE, 0, 0, 35,
|
||||
GEN_OVERRIDEROOTKEY, 0, 43, 0,
|
||||
0, 0, 0 // incomplete terminal generator
|
||||
};
|
||||
|
||||
const unsigned char buf3[] =
|
||||
{
|
||||
// zone 1
|
||||
GEN_KEYRANGE, 0, 60, 127,
|
||||
GEN_UNUSED1, 0, 0xFF, 0xFF,
|
||||
final_gen, 0, 0xDD, 0xDD,
|
||||
GEN_KEYRANGE, 0, 0, 35,
|
||||
GEN_OVERRIDEROOTKEY, 0, 43
|
||||
};
|
||||
|
||||
const unsigned char buf4[] =
|
||||
{
|
||||
// zone 1
|
||||
GEN_KEYRANGE, 0, 60, 127,
|
||||
GEN_UNUSED1, 0, 0xFF, 0xFF,
|
||||
final_gen, 0, 0xDD, 0xDD,
|
||||
GEN_KEYRANGE, 0, 0, 35,
|
||||
GEN_OVERRIDEROOTKEY, 0
|
||||
};
|
||||
|
||||
const buf_t buf[] =
|
||||
{
|
||||
{ buf1, sizeof(buf1), buf1 + sizeof(buf1) },
|
||||
{ buf2, sizeof(buf2), buf2 + sizeof(buf2) - 3 },
|
||||
{ buf3, sizeof(buf3), buf3 + sizeof(buf3) - 3 },
|
||||
{ buf4, sizeof(buf4), buf4 + sizeof(buf4) - 2 },
|
||||
};
|
||||
|
||||
// the first test case should return true, all others false
|
||||
int expected_ret_val = TRUE;
|
||||
for (i = 0; i < FLUID_N_ELEMENTS(buf); i++)
|
||||
{
|
||||
SET_BUF2(buf[i].start, buf[i].size);
|
||||
TEST_ASSERT(load_func(sf, buf[i].size) == expected_ret_val);
|
||||
expected_ret_val = FALSE;
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 0));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
TEST_ASSERT(gen->id == GEN_KEYRANGE);
|
||||
TEST_ASSERT(gen->amount.range.lo == 60);
|
||||
TEST_ASSERT(gen->amount.range.hi == 127);
|
||||
|
||||
// delete this generator
|
||||
FLUID_FREE(gen);
|
||||
zone1->gen->data = NULL;
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 1));
|
||||
TEST_ASSERT(gen != NULL);
|
||||
if (load_func == &load_igen)
|
||||
{
|
||||
TEST_ASSERT(gen->id == GEN_SAMPLEID);
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST_ASSERT(gen->id == GEN_INSTRUMENT);
|
||||
}
|
||||
TEST_ASSERT(gen->amount.uword == 0xDDDDu);
|
||||
// delete this generator
|
||||
FLUID_FREE(gen);
|
||||
zone1->gen->data = NULL;
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 2));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 3));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
gen = fluid_list_get(fluid_list_nth(zone1->gen, 4));
|
||||
TEST_ASSERT(gen == NULL);
|
||||
|
||||
TEST_ASSERT(file_buf == buf[i].end);
|
||||
UNSET_BUF;
|
||||
|
||||
// The test cases above expect zone1 to be pre-populated with 5 generators
|
||||
delete_fluid_list(zone1->gen);
|
||||
zone1->gen = NULL;
|
||||
zone1->gen = fluid_list_prepend(zone1->gen, NULL);
|
||||
zone1->gen = fluid_list_prepend(zone1->gen, NULL);
|
||||
zone1->gen = fluid_list_prepend(zone1->gen, NULL);
|
||||
zone1->gen = fluid_list_prepend(zone1->gen, NULL);
|
||||
zone1->gen = fluid_list_prepend(zone1->gen, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// prepare a soundfont that has one preset and one instrument, with up to 2 zones
|
||||
|
||||
SFZone *zone1;
|
||||
SFData *sf = FLUID_NEW(SFData);
|
||||
SFPreset *preset = FLUID_NEW(SFPreset);
|
||||
SFInst *inst = FLUID_NEW(SFInst);
|
||||
|
||||
TEST_ASSERT(sf != NULL);
|
||||
FLUID_MEMSET(sf, 0, sizeof(*sf));
|
||||
TEST_ASSERT(preset != NULL);
|
||||
FLUID_MEMSET(preset, 0, sizeof(*preset));
|
||||
TEST_ASSERT(inst != NULL);
|
||||
FLUID_MEMSET(inst, 0, sizeof(*inst));
|
||||
|
||||
sf->fcbs = &fcb;
|
||||
sf->preset = fluid_list_append(sf->preset, preset);
|
||||
sf->inst = fluid_list_append(sf->inst, inst);
|
||||
|
||||
// Calls the given test function for 1 zone once for preset and once for inst case.
|
||||
#define TEST_CASE_1(TEST_FUNC, GEN_COUNT) \
|
||||
do \
|
||||
{ \
|
||||
zone1 = new_test_zone(&preset->zone, GEN_COUNT); \
|
||||
TEST_FUNC(&load_pgen, sf, zone1); \
|
||||
delete_zone(zone1); \
|
||||
delete_fluid_list(preset->zone); \
|
||||
preset->zone = NULL; \
|
||||
\
|
||||
zone1 = new_test_zone(&inst->zone, GEN_COUNT); \
|
||||
TEST_FUNC(&load_igen, sf, zone1); \
|
||||
delete_zone(zone1); \
|
||||
delete_fluid_list(inst->zone); \
|
||||
inst->zone = NULL; \
|
||||
} while (0)
|
||||
|
||||
TEST_CASE_1(good_test_1zone_2gen_1termgen, 2);
|
||||
TEST_CASE_1(good_test_1zone_2gen_1termgen, 3);
|
||||
|
||||
TEST_CASE_1(bad_test_too_short_gen_buffer, 2);
|
||||
|
||||
TEST_CASE_1(bad_test_duplicate_gen, 2);
|
||||
|
||||
TEST_CASE_1(bad_test_gen_wrong_order, 3);
|
||||
|
||||
TEST_CASE_1(bad_test_additional_gens_after_final_gen, 5);
|
||||
|
||||
zone1 = new_test_zone(&preset->zone, 2);
|
||||
(void)new_test_zone(&preset->zone, 5);
|
||||
bad_test_issue_808(&load_pgen, sf, zone1);
|
||||
// zone 2 was dropped
|
||||
TEST_ASSERT(preset->zone->next == NULL);
|
||||
delete_zone(zone1);
|
||||
// zone2 already deleted
|
||||
delete_fluid_list(preset->zone);
|
||||
preset->zone = NULL;
|
||||
|
||||
zone1 = new_test_zone(&inst->zone, 2);
|
||||
(void)new_test_zone(&inst->zone, 5);
|
||||
bad_test_issue_808(&load_igen, sf, zone1);
|
||||
// zone 2 was dropped
|
||||
TEST_ASSERT(inst->zone->next == NULL);
|
||||
delete_zone(zone1);
|
||||
// zone2 already deleted
|
||||
delete_fluid_list(inst->zone);
|
||||
inst->zone = NULL;
|
||||
|
||||
delete_inst(inst);
|
||||
delete_preset(preset);
|
||||
delete_fluid_list(sf->inst);
|
||||
delete_fluid_list(sf->preset);
|
||||
// we cannot call fluid_sffile_close here, because it would destroy the mutex which is not initialized
|
||||
FLUID_FREE(sf);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in a new issue