Reenable and fix tests
- Add ASAN workflows - Remove flag messages from configure; these are misleading as they exclude `COMPILE_OPTIONS` - Fix non-working tests - Fix WavPack file loading on Windows - Fix ASAN traps in LoFi code due to a SIMD `loadu` call in HIIR resamplers - Add tests for st_audiofile -
This commit is contained in:
parent
507c61d458
commit
1e771a45e7
14 changed files with 228 additions and 105 deletions
90
.github/workflows/build.yml
vendored
90
.github/workflows/build.yml
vendored
|
|
@ -20,13 +20,8 @@ env:
|
|||
# shell: pwsh on windows, bash all the rest
|
||||
# working-directory: ${{ github.workspace }}
|
||||
|
||||
# FIXME:
|
||||
# Tests disabled (again); they were working one day and broken the day after
|
||||
# without changes: ./build/tests/sfizz_tests: No such file or directory
|
||||
# It didn't work either by specifying the full path (that was OK in previous builds)
|
||||
jobs:
|
||||
clang_tidy:
|
||||
# if: ${{ false }}
|
||||
name: Clang Tidy
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
|
|
@ -39,8 +34,57 @@ jobs:
|
|||
- name: Run
|
||||
run: ./scripts/run_clang_tidy.sh
|
||||
|
||||
test_with_asan:
|
||||
name: ASAN
|
||||
runs-on: ubuntu-22.04 # abseil (libabsl) is not available in 20.04 repository
|
||||
env:
|
||||
install_name: sfizz-${{ github.ref_name }}-linux
|
||||
strategy:
|
||||
matrix:
|
||||
build_type: [Debug, RelWithDebInfo]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install \
|
||||
ninja-build \
|
||||
libjack-jackd2-dev \
|
||||
libabsl-dev \
|
||||
libabsl20210324
|
||||
- name: Configure CMake
|
||||
run: |
|
||||
options=(
|
||||
-G Ninja
|
||||
-B build
|
||||
-S .
|
||||
-D CMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
-D SFIZZ_TESTS=ON
|
||||
-D SFIZZ_USE_SYSTEM_ABSEIL=ON
|
||||
-D SFIZZ_ASAN=ON
|
||||
)
|
||||
cmake "${options[@]}"
|
||||
- name: Build tests
|
||||
run: |
|
||||
options=(
|
||||
--build build
|
||||
--config ${{ matrix.build_type }}
|
||||
--parallel 2
|
||||
--target sfizz_tests
|
||||
)
|
||||
cmake "${options[@]}"
|
||||
- name: Run tests
|
||||
run: |
|
||||
options=(
|
||||
--build-config ${{ matrix.build_type }}
|
||||
--output-on-failure
|
||||
--test-dir build
|
||||
)
|
||||
ctest "${options[@]}"
|
||||
|
||||
build_for_linux:
|
||||
# if: ${{ false }}
|
||||
name: Linux Ubuntu 22.04
|
||||
runs-on: ubuntu-22.04 # abseil (libabsl) is not available in 20.04 repository
|
||||
env:
|
||||
|
|
@ -83,7 +127,6 @@ jobs:
|
|||
echo "-- github.workspace: ${{ github.workspace }}"
|
||||
echo "-- runner.workspace: ${{ runner.workspace }}"
|
||||
- name: Build tests
|
||||
if: ${{ false }}
|
||||
run: |
|
||||
options=(
|
||||
--build build
|
||||
|
|
@ -94,15 +137,10 @@ jobs:
|
|||
)
|
||||
cmake "${options[@]}"
|
||||
- name: Run tests
|
||||
if: ${{ false }}
|
||||
run: |
|
||||
./build/tests/sfizz_tests
|
||||
options=(
|
||||
--build-config ${{ env.build_type }}
|
||||
--debug
|
||||
--extra-verbose
|
||||
--output-on-failure
|
||||
--parallel 2
|
||||
--test-dir build
|
||||
)
|
||||
ctest "${options[@]}"
|
||||
|
|
@ -129,7 +167,6 @@ jobs:
|
|||
path: "${{ github.workspace }}/${{ env.install_name }}.tar.gz"
|
||||
|
||||
build_for_macos:
|
||||
# if: ${{ false }}
|
||||
name: macOS 11
|
||||
runs-on: macos-11
|
||||
env:
|
||||
|
|
@ -161,7 +198,6 @@ jobs:
|
|||
echo "-- runner.workspace: ${{ runner.workspace }}"
|
||||
echo "-- github.workspace: ${{ github.workspace }}"
|
||||
- name: Build tests
|
||||
if: ${{ false }}
|
||||
run: |
|
||||
options=(
|
||||
--build build
|
||||
|
|
@ -172,15 +208,10 @@ jobs:
|
|||
)
|
||||
cmake "${options[@]}"
|
||||
- name: Run tests
|
||||
if: ${{ false }}
|
||||
run: |
|
||||
./build/tests/sfizz_tests
|
||||
options=(
|
||||
--build-config ${{ env.build_type }}
|
||||
--debug
|
||||
--extra-verbose
|
||||
--output-on-failure
|
||||
--parallel 2
|
||||
--test-dir build
|
||||
)
|
||||
ctest "${options[@]}"
|
||||
|
|
@ -207,7 +238,6 @@ jobs:
|
|||
path: "${{ github.workspace }}/${{ env.install_name }}.tar.gz"
|
||||
|
||||
build_for_windows:
|
||||
# if: ${{ false }}
|
||||
name: Windows 2019
|
||||
runs-on: windows-2019
|
||||
strategy:
|
||||
|
|
@ -235,12 +265,10 @@ jobs:
|
|||
-A "${{ matrix.release_arch }}" `
|
||||
-B build `
|
||||
-S . `
|
||||
-D CMAKE_BUILD_TYPE=${{ env.build_type }} `
|
||||
-D SFIZZ_TESTS=ON
|
||||
echo "-- runner.workspace: ${{ runner.workspace }}"
|
||||
echo "-- github.workspace: ${{ github.workspace }}"
|
||||
- name: Build tests
|
||||
if: ${{ false }}
|
||||
run: |
|
||||
cmake `
|
||||
--build build `
|
||||
|
|
@ -249,15 +277,10 @@ jobs:
|
|||
--target sfizz_tests `
|
||||
--verbose `
|
||||
- name: Run tests
|
||||
if: ${{ false }}
|
||||
run: |
|
||||
.\build\tests\${{ env.build_type }}\sfizz_tests.exe
|
||||
ctest `
|
||||
--build-config ${{ env.build_type }} `
|
||||
--debug `
|
||||
--extra-verbose `
|
||||
--output-on-failure `
|
||||
--parallel 2 `
|
||||
--test-dir build `
|
||||
- name: Build all
|
||||
run: |
|
||||
|
|
@ -277,7 +300,6 @@ jobs:
|
|||
path: "${{ github.workspace }}/${{ env.install_name }}.zip"
|
||||
|
||||
archive_source_code:
|
||||
# if: startsWith(github.ref, 'refs/tags/')
|
||||
if: ${{ github.ref_type == 'tag' }}
|
||||
name: Source code archive
|
||||
runs-on: ubuntu-20.04
|
||||
|
|
@ -304,7 +326,6 @@ jobs:
|
|||
path: "${{ github.workspace }}/${{ env.install_name }}.tar.gz"
|
||||
|
||||
build_with_libsndfile:
|
||||
# if: ${{ false }}
|
||||
name: Linux libsndfile
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
|
|
@ -332,7 +353,6 @@ jobs:
|
|||
)
|
||||
cmake "${options[@]}"
|
||||
- name: Build tests
|
||||
if: ${{ false }}
|
||||
run: |
|
||||
options=(
|
||||
--build build
|
||||
|
|
@ -343,11 +363,15 @@ jobs:
|
|||
)
|
||||
cmake "${options[@]}"
|
||||
- name: Run tests
|
||||
if: ${{ false }}
|
||||
run: ./build/tests/sfizz_tests
|
||||
run: |
|
||||
options=(
|
||||
--build-config ${{ env.build_type }}
|
||||
--output-on-failure
|
||||
--test-dir build
|
||||
)
|
||||
ctest "${options[@]}"
|
||||
|
||||
build_with_makefile:
|
||||
# if: ${{ false }}
|
||||
name: Linux makefile
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -26,3 +26,4 @@ clients/sfzprint
|
|||
*.code-*
|
||||
.kak.tags.namecache
|
||||
.clangd
|
||||
venv
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ option_ex(SFIZZ_USE_SYSTEM_CATCH "Use Catch libraries preinstalled on system"
|
|||
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)
|
||||
|
||||
# Continuous Controller count (0 to 511)
|
||||
set(MIDI_CC_COUNT 512 CACHE STRING "Maximum number of managed Control Change messages")
|
||||
|
|
|
|||
|
|
@ -116,6 +116,11 @@ function(sfizz_enable_fast_math NAME)
|
|||
endif()
|
||||
endfunction()
|
||||
|
||||
function(sfizz_enable_release_asserts NAME)
|
||||
target_compile_definitions("${NAME}" PUBLIC "SFIZZ_ENABLE_RELEASE_ASSERT=1")
|
||||
target_compile_definitions("${NAME}" PUBLIC "SFIZZ_ENABLE_RELEASE_DBG=1")
|
||||
endfunction()
|
||||
|
||||
# If we build with Clang, optionally use libc++. Enabled by default on Apple OS.
|
||||
cmake_dependent_option(USE_LIBCPP "Use libc++ with clang" "${APPLE}"
|
||||
"CMAKE_CXX_COMPILER_ID MATCHES Clang" OFF)
|
||||
|
|
@ -133,6 +138,13 @@ else()
|
|||
set(PROJECT_IS_MAIN FALSE)
|
||||
endif()
|
||||
|
||||
if(SFIZZ_ASAN)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-fsanitize=address>)
|
||||
add_link_options($<$<COMPILE_LANGUAGE:C,CXX>:-fsanitize=address>)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-fno-omit-frame-pointer>)
|
||||
add_link_options($<$<COMPILE_LANGUAGE:C,CXX>:-fno-omit-frame-pointer>)
|
||||
endif()
|
||||
|
||||
# Don't show build information when building a different project
|
||||
function(show_build_info_if_needed)
|
||||
if(PROJECT_IS_MAIN)
|
||||
|
|
@ -155,6 +167,7 @@ Statically link sndfile: ${SFIZZ_SNDFILE_STATIC}
|
|||
|
||||
Use clang libc++: ${USE_LIBCPP}
|
||||
Release asserts: ${SFIZZ_RELEASE_ASSERTS}
|
||||
Use ASAN: ${SFIZZ_ASAN}
|
||||
|
||||
Use system abseil-cpp: ${SFIZZ_USE_SYSTEM_ABSEIL}
|
||||
Use system catch: ${SFIZZ_USE_SYSTEM_CATCH}
|
||||
|
|
@ -182,11 +195,6 @@ VST3 destination directory: ${VST3_PLUGIN_INSTALL_DIR}")
|
|||
endif()
|
||||
message(STATUS "
|
||||
Install prefix: ${CMAKE_INSTALL_PREFIX}
|
||||
|
||||
CXX Debug flags: ${CMAKE_CXX_FLAGS_DEBUG}
|
||||
CXX Release flags: ${CMAKE_CXX_FLAGS_RELEASE}
|
||||
CXX MinSize flags: ${CMAKE_CXX_FLAGS_MINSIZEREL}
|
||||
CXX RelWithDebInfo flags: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}
|
||||
")
|
||||
endif()
|
||||
endfunction()
|
||||
|
|
|
|||
15
external/st_audiofile/src/st_audiofile.c
vendored
15
external/st_audiofile/src/st_audiofile.c
vendored
|
|
@ -9,6 +9,9 @@
|
|||
#include "st_audiofile_libs.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#define WAVPACK_MEMORY_ASSUMED_VERSION 5
|
||||
|
||||
struct st_audio_file {
|
||||
|
|
@ -179,10 +182,18 @@ static st_audio_file* st_generic_open_file(const void* filename, int widepath)
|
|||
|
||||
// Try WV
|
||||
{
|
||||
af->wv =
|
||||
#if defined(_WIN32)
|
||||
WavpackOpenFileInput((const char*)filename, NULL, OPEN_FILE_UTF8, 0);
|
||||
// WavPack expects an UTF8 input and has no widechar api, so we convert the filename back...
|
||||
unsigned wsize = wcslen(filename);
|
||||
unsigned size = WideCharToMultiByte(CP_UTF8, 0, filename, wsize, NULL, 0, NULL, NULL);
|
||||
char *buffer = (char*)malloc((size+1) * sizeof(char));
|
||||
WideCharToMultiByte(CP_UTF8, 0, filename, wsize, buffer, size, NULL, NULL);
|
||||
buffer[size] = '\0';
|
||||
af->wv =
|
||||
WavpackOpenFileInput(buffer, NULL, OPEN_FILE_UTF8, 0);
|
||||
free(buffer);
|
||||
#else
|
||||
af->wv =
|
||||
WavpackOpenFileInput((const char*)filename, NULL, 0, 0);
|
||||
#endif
|
||||
if (af->wv) {
|
||||
|
|
|
|||
8
external/st_audiofile/src/st_audiofile.hpp
vendored
8
external/st_audiofile/src/st_audiofile.hpp
vendored
|
|
@ -60,13 +60,13 @@ inline ST_AudioFile::~ST_AudioFile() noexcept
|
|||
reset();
|
||||
}
|
||||
|
||||
ST_AudioFile::ST_AudioFile(ST_AudioFile&& other) noexcept
|
||||
inline ST_AudioFile::ST_AudioFile(ST_AudioFile&& other) noexcept
|
||||
: af_(other.af_)
|
||||
{
|
||||
other.af_ = nullptr;
|
||||
}
|
||||
|
||||
ST_AudioFile& ST_AudioFile::operator=(ST_AudioFile&& other) noexcept
|
||||
inline ST_AudioFile& ST_AudioFile::operator=(ST_AudioFile&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
if (af_)
|
||||
|
|
@ -91,14 +91,14 @@ inline void ST_AudioFile::reset(st_audio_file* new_af) noexcept
|
|||
}
|
||||
}
|
||||
|
||||
bool ST_AudioFile::open_file(const char* filename)
|
||||
inline bool ST_AudioFile::open_file(const char* filename)
|
||||
{
|
||||
st_audio_file* new_af = st_open_file(filename);
|
||||
reset(new_af);
|
||||
return new_af != nullptr;
|
||||
}
|
||||
|
||||
bool ST_AudioFile::open_memory(const void* memory, size_t length)
|
||||
inline bool ST_AudioFile::open_memory(const void* memory, size_t length)
|
||||
{
|
||||
st_audio_file* new_af = st_open_memory(memory, length);
|
||||
reset(new_af);
|
||||
|
|
|
|||
|
|
@ -231,9 +231,7 @@ target_include_directories(sfizz_parser PUBLIC sfizz)
|
|||
target_link_libraries(sfizz_parser
|
||||
PUBLIC sfizz::filesystem sfizz::simde absl::strings
|
||||
PRIVATE absl::flat_hash_map)
|
||||
if(SFIZZ_RELEASE_ASSERTS)
|
||||
target_compile_definitions(sfizz_parser PUBLIC "SFIZZ_ENABLE_RELEASE_ASSERT=1")
|
||||
endif()
|
||||
sfizz_enable_release_asserts(sfizz_parser)
|
||||
|
||||
# OSC messaging library
|
||||
set(SFIZZ_MESSAGING_HEADERS
|
||||
|
|
@ -250,9 +248,8 @@ target_sources(sfizz_messaging PRIVATE
|
|||
${SFIZZ_MESSAGING_HEADERS} ${SFIZZ_MESSAGING_SOURCES})
|
||||
target_include_directories(sfizz_messaging PUBLIC ".")
|
||||
target_link_libraries(sfizz_messaging PUBLIC absl::strings)
|
||||
if(SFIZZ_RELEASE_ASSERTS)
|
||||
target_compile_definitions(sfizz_messaging PUBLIC "SFIZZ_ENABLE_RELEASE_ASSERT=1")
|
||||
endif()
|
||||
sfizz_enable_release_asserts(sfizz_messaging)
|
||||
|
||||
|
||||
# Import library
|
||||
set(SFIZZ_IMPORT_HEADERS
|
||||
|
|
@ -303,9 +300,8 @@ if(SFIZZ_USE_SNDFILE)
|
|||
target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_USE_SNDFILE=1")
|
||||
target_link_libraries(sfizz_internal PUBLIC st_audiofile)
|
||||
endif()
|
||||
if(SFIZZ_RELEASE_ASSERTS)
|
||||
target_compile_definitions(sfizz_internal PUBLIC "SFIZZ_ENABLE_RELEASE_ASSERT=1")
|
||||
endif()
|
||||
sfizz_enable_release_asserts(sfizz_internal)
|
||||
|
||||
if(SFIZZ_IMPLEMENT_CXX17_ALIGNED_NEW_SUPPORT)
|
||||
target_compile_definitions(sfizz_internal PRIVATE "SFIZZ_IMPLEMENT_CXX17_ALIGNED_NEW_SUPPORT=1")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -477,7 +477,7 @@ void sfz::FilePool::loadingJob(const QueuedFileData& data) noexcept
|
|||
AudioReaderPtr reader = createAudioReader(file, id->isReverse(), &readError);
|
||||
|
||||
if (readError) {
|
||||
DBG("[sfizz] libsndfile errored for " << *id << " with message " << readError.message());
|
||||
DBG("[sfizz] reading the file errored for " << *id << " with code " << readError << ": " << readError.message());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1069,6 +1069,10 @@ void Voice::Impl::fillWithData(AudioSpan<float> buffer) noexcept
|
|||
}
|
||||
|
||||
auto source = currentPromise_->getData();
|
||||
if (source.getNumFrames() == 0) {
|
||||
DBG("[Voice] Empty source in promise");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferPool& bufferPool = resources_.getBufferPool();
|
||||
const CurveSet& curves = resources_.getCurves();
|
||||
|
|
|
|||
|
|
@ -128,13 +128,13 @@ namespace fx {
|
|||
|
||||
const float steps = (1.0f + (100.0f - fDepth)) * 0.75f;
|
||||
const float invSteps = 1.0f / steps;
|
||||
float y2x[4] { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
||||
for (uint32_t i = 0; i < nframes; ++i) {
|
||||
float x = in[i];
|
||||
|
||||
float y = std::copysign((int)(0.5f + std::fabs(x * steps)), x) * invSteps; // NOLINT
|
||||
|
||||
float y2x[2];
|
||||
y2x[0] = (y != lastValue) ? (0.5f * (y + lastValue)) : y;
|
||||
y2x[1] = y;
|
||||
|
||||
|
|
@ -185,6 +185,7 @@ namespace fx {
|
|||
|
||||
float phase = fPhase;
|
||||
float lastValue = fLastValue;
|
||||
float y2x[4] { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
||||
for (uint32_t i = 0; i < nframes; ++i) {
|
||||
float x = in[i];
|
||||
|
|
@ -193,7 +194,6 @@ namespace fx {
|
|||
float y = (phase > 1.0f) ? x : lastValue;
|
||||
phase -= static_cast<float>(static_cast<int>(phase));
|
||||
|
||||
float y2x[2];
|
||||
y2x[0] = (y != lastValue) ? (0.5f * (y + lastValue)) : y;
|
||||
y2x[1] = y;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,63 +9,137 @@
|
|||
#include "sfizz/Synth.h"
|
||||
#include "TestHelpers.h"
|
||||
#include "catch2/catch.hpp"
|
||||
#include "st_audiofile.hpp"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
using namespace Catch::literals;
|
||||
|
||||
TEST_CASE("[AudioFiles] No leakage on right")
|
||||
void compareFiles(const fs::path& lFile, const fs::path& rFile)
|
||||
{
|
||||
sfz::Synth synth;
|
||||
sfz::AudioBuffer<float> buffer { 2, static_cast<unsigned>(synth.getSamplesPerBlock()) };
|
||||
std::vector<float> zeros(synth.getSamplesPerBlock(), 0);
|
||||
sfz::AudioSpan<float> span { buffer };
|
||||
synth.loadSfzString(fs::current_path() / "tests/TestFiles/wavpack.sfz", R"(
|
||||
<region> sample=kick.wav key=60 pan=-100
|
||||
)");
|
||||
synth.noteOn(0, 60, 127);
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( numPlayingVoices(synth) == 1 );
|
||||
REQUIRE( approxEqual(span.getConstSpan(1), absl::MakeConstSpan(zeros), 1e-2f) );
|
||||
while (numPlayingVoices(synth) > 0) {
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( approxEqual(span.getConstSpan(1), absl::MakeConstSpan(zeros), 1e-2f) );
|
||||
auto l_file = ST_AudioFile();
|
||||
auto r_file = ST_AudioFile();
|
||||
#if defined(_WIN32)
|
||||
l_file.open_file_w(lFile.wstring().c_str());
|
||||
r_file.open_file_w(rFile.wstring().c_str());
|
||||
#else
|
||||
l_file.open_file(lFile.string().c_str());
|
||||
r_file.open_file(rFile.string().c_str());
|
||||
#endif
|
||||
CHECK(l_file.get_channels() == 1);
|
||||
CHECK(r_file.get_channels() == 1);
|
||||
std::vector<float> wav (l_file.get_frame_count());
|
||||
std::vector<float> flac (r_file.get_frame_count());
|
||||
l_file.read_f32(wav.data(), l_file.get_frame_count());
|
||||
r_file.read_f32(flac.data(), r_file.get_frame_count());
|
||||
REQUIRE( approxEqual<float>(wav, flac) );
|
||||
}
|
||||
|
||||
TEST_CASE("[AudioFiles] Compare Flac and WAV")
|
||||
{
|
||||
compareFiles(fs::current_path() / "tests/TestFiles/kick.wav",
|
||||
fs::current_path() / "tests/TestFiles/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");
|
||||
}
|
||||
#endif
|
||||
|
||||
struct CompareOutputOpts
|
||||
{
|
||||
int note { 60 };
|
||||
int delay { 0 };
|
||||
int velocity { 127 };
|
||||
float sampleRate { 48000.0f };
|
||||
int samplesPerBlock { 1024 };
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compare the outputs of 2 sfz files with a given set of options, for a single note pressed.
|
||||
*
|
||||
* @param lFile
|
||||
* @param rFile
|
||||
* @param opts
|
||||
*/
|
||||
void compareOutputs(const std::string& lFile, const std::string& rFile, CompareOutputOpts opts)
|
||||
{
|
||||
sfz::Synth lSynth;
|
||||
sfz::Synth rSynth;
|
||||
lSynth.enableFreeWheeling();
|
||||
rSynth.enableFreeWheeling();
|
||||
lSynth.setSampleRate(opts.sampleRate);
|
||||
rSynth.setSampleRate(opts.sampleRate);
|
||||
lSynth.setSamplesPerBlock(opts.samplesPerBlock);
|
||||
rSynth.setSamplesPerBlock(opts.samplesPerBlock);
|
||||
sfz::AudioBuffer<float> lBuffer { 2, static_cast<unsigned>(lSynth.getSamplesPerBlock()) };
|
||||
sfz::AudioBuffer<float> rBuffer { 2, static_cast<unsigned>(rSynth.getSamplesPerBlock()) };
|
||||
sfz::AudioSpan<float> lSpan { lBuffer };
|
||||
sfz::AudioSpan<float> rSpan { rBuffer };
|
||||
lSynth.loadSfzString(fs::current_path() / "tests/TestFiles/l.sfz", lFile);
|
||||
rSynth.loadSfzString(fs::current_path() / "tests/TestFiles/r.sfz", rFile);
|
||||
lSynth.noteOn(opts.delay, opts.note, opts.velocity);
|
||||
rSynth.noteOn(opts.delay, opts.note, opts.velocity);
|
||||
lSynth.renderBlock(lSpan);
|
||||
rSynth.renderBlock(rSpan);
|
||||
REQUIRE( numPlayingVoices(lSynth) == 1 );
|
||||
REQUIRE( numPlayingVoices(rSynth) == 1 );
|
||||
REQUIRE( approxEqual(lSpan.getConstSpan(0), rSpan.getConstSpan(0)) );
|
||||
REQUIRE( approxEqual(lSpan.getConstSpan(1), rSpan.getConstSpan(1)) );
|
||||
while (numPlayingVoices(lSynth) == 1) {
|
||||
REQUIRE( numPlayingVoices(rSynth) == 1 );
|
||||
lSynth.renderBlock(lSpan);
|
||||
rSynth.renderBlock(rSpan);
|
||||
REQUIRE( approxEqual(lSpan.getConstSpan(0), rSpan.getConstSpan(0)) );
|
||||
REQUIRE( approxEqual(lSpan.getConstSpan(1), rSpan.getConstSpan(1)) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[AudioFiles] WavPack file")
|
||||
TEST_CASE("[AudioFiles] Sanity check (native sample rate)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
sfz::AudioBuffer<float> buffer { 2, static_cast<unsigned>(synth.getSamplesPerBlock()) };
|
||||
sfz::AudioSpan<float> span { buffer };
|
||||
synth.loadSfzString(fs::current_path() / "tests/TestFiles/wavpack.sfz", R"(
|
||||
<region> sample=kick.wav key=60 pan=-100
|
||||
<region> sample=kick.wv key=60 pan=100
|
||||
)");
|
||||
synth.noteOn(0, 60, 127);
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( numPlayingVoices(synth) == 2 );
|
||||
REQUIRE( approxEqual(span.getConstSpan(0), span.getConstSpan(1)) );
|
||||
while (numPlayingVoices(synth) > 0) {
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( approxEqual(span.getConstSpan(0), span.getConstSpan(1)) );
|
||||
}
|
||||
std::string lFile = "<region> sample=kick.wav key=60";
|
||||
std::string rFile = "<region> sample=kick.wav key=60";
|
||||
CompareOutputOpts opts;
|
||||
opts.sampleRate = 44100.0f;
|
||||
compareOutputs(lFile, rFile, opts);
|
||||
}
|
||||
|
||||
TEST_CASE("[AudioFiles] Flac file")
|
||||
#if !defined(SFIZZ_USE_SNDFILE)
|
||||
TEST_CASE("[AudioFiles] Wavpack file (native sample rate)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
sfz::AudioBuffer<float> buffer { 2, static_cast<unsigned>(synth.getSamplesPerBlock()) };
|
||||
sfz::AudioSpan<float> span { buffer };
|
||||
synth.loadSfzString(fs::current_path() / "tests/TestFiles/wavpack.sfz", R"(
|
||||
<region> sample=kick.wav key=60 pan=-100
|
||||
<region> sample=kick.flac key=60 pan=100
|
||||
)");
|
||||
synth.noteOn(0, 60, 127);
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( numPlayingVoices(synth) == 2 );
|
||||
REQUIRE( approxEqual(span.getConstSpan(0), span.getConstSpan(1)) );
|
||||
while (numPlayingVoices(synth) > 0) {
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( approxEqual(span.getConstSpan(0), span.getConstSpan(1)) );
|
||||
std::string lFile = "<region> sample=kick.wav key=60";
|
||||
std::string rFile = "<region> sample=kick.wv key=60";
|
||||
CompareOutputOpts opts;
|
||||
opts.sampleRate = 44100.0f;
|
||||
compareOutputs(lFile, rFile, opts);
|
||||
}
|
||||
|
||||
TEST_CASE("[AudioFiles] Wavpack file (resampled)")
|
||||
{
|
||||
std::string lFile = "<region> sample=kick.wav key=60";
|
||||
std::string rFile = "<region> sample=kick.wv key=60";
|
||||
CompareOutputOpts opts;
|
||||
opts.sampleRate = 48000.0f;
|
||||
compareOutputs(lFile, rFile, opts);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("[AudioFiles] Flac file (native sample rate)")
|
||||
{
|
||||
std::string lFile = "<region> sample=kick.wav key=60";
|
||||
std::string rFile = "<region> sample=kick.flac key=60";
|
||||
CompareOutputOpts opts;
|
||||
opts.sampleRate = 44100.0f;
|
||||
compareOutputs(lFile, rFile, opts);
|
||||
}
|
||||
|
||||
TEST_CASE("[AudioFiles] Flac file (resampled)")
|
||||
{
|
||||
std::string lFile = "<region> sample=kick.wav key=60";
|
||||
std::string rFile = "<region> sample=kick.flac key=60";
|
||||
CompareOutputOpts opts;
|
||||
opts.sampleRate = 48000.0f;
|
||||
compareOutputs(lFile, rFile, opts);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ set(SFIZZ_TEST_SOURCES
|
|||
)
|
||||
|
||||
add_executable(sfizz_tests ${SFIZZ_TEST_SOURCES})
|
||||
target_link_libraries(sfizz_tests PRIVATE sfizz::internal sfizz::static sfizz::spin_mutex sfizz::jsl sfizz::filesystem)
|
||||
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
|
||||
target_compile_definitions(sfizz_tests PRIVATE "CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS")
|
||||
|
|
|
|||
|
|
@ -116,8 +116,10 @@ TEST_CASE("[Messaging] Type-safe client API")
|
|||
REQUIRE(args[index++].f == f);
|
||||
REQUIRE(args[index++].d == d);
|
||||
REQUIRE(!strcmp(args[index++].s, s));
|
||||
#if !defined(__SANITIZE_ADDRESS__)
|
||||
REQUIRE(args[index ].b->data == b.data);
|
||||
REQUIRE(args[index++].b->size == b.size);
|
||||
#endif
|
||||
});
|
||||
|
||||
client.receive<'i', 'm', 'h', 'f', 'd', 's', 'b', 'T', 'F', 'N', 'I'>(
|
||||
|
|
|
|||
|
|
@ -152,8 +152,10 @@ std::string createModulationDotGraph(std::vector<std::string> lines);
|
|||
template <class Type>
|
||||
bool approxEqual(absl::Span<const Type> lhs, absl::Span<const Type> rhs, Type eps = 1e-3)
|
||||
{
|
||||
if (lhs.size() != rhs.size())
|
||||
if (lhs.size() != rhs.size()) {
|
||||
std::cerr << "Span size are different: "<< lhs.size() << " != " << rhs.size() << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
bool different = false;
|
||||
for (size_t i = 0; i < rhs.size(); ++i)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue