From 44dbbcaf54e0ad961558696462e4b3a85adb504a Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 10 Aug 2020 17:22:49 +0200 Subject: [PATCH] Updated tests --- tests/CMakeLists.txt | 4 +- tests/FilesT.cpp | 9 +- tests/PolyphonyT.cpp | 184 +++++++++++------- tests/RegionT.cpp | 2 +- tests/SynthT.cpp | 28 +-- tests/{RegionTHelpers.cpp => TestHelpers.cpp} | 20 +- tests/{RegionTHelpers.h => TestHelpers.h} | 30 +++ 7 files changed, 176 insertions(+), 101 deletions(-) rename tests/{RegionTHelpers.cpp => TestHelpers.cpp} (68%) rename tests/{RegionTHelpers.h => TestHelpers.h} (52%) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4018edee..dba296bd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,8 +5,8 @@ project(sfizz) set(SFIZZ_TEST_SOURCES RegionT.cpp - RegionTHelpers.h - RegionTHelpers.cpp + TestHelpers.h + TestHelpers.cpp ParsingT.cpp HelpersT.cpp HelpersT.cpp diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index b47181fe..98b16dce 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -4,7 +4,7 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "RegionTHelpers.h" +#include "TestHelpers.h" #include "sfizz/Synth.h" #include "sfizz/SfzHelpers.h" #include "sfizz/modulations/ModId.h" @@ -517,7 +517,8 @@ TEST_CASE("[Files] Off by with the same notes at the same time") synth.renderBlock(buffer); synth.noteOn(0, 65, 63); synth.renderBlock(buffer); - REQUIRE( synth.getNumActiveVoices(true) == 2 ); + REQUIRE( synth.getNumActiveVoices(true) == 6 ); + REQUIRE( numPlayingVoices(synth) == 2 ); } TEST_CASE("[Files] Off modes") @@ -538,8 +539,10 @@ TEST_CASE("[Files] Off modes") synth.getVoiceView(0) ; synth.noteOn(100, 63, 63); REQUIRE( synth.getNumActiveVoices(true) == 3 ); + REQUIRE( numPlayingVoices(synth) == 1 ); AudioBuffer buffer { 2, 256 }; - synth.renderBlock(buffer); + for (unsigned i = 0; i < 10; ++i) // Not enough for the "normal" voice to die + synth.renderBlock(buffer); REQUIRE( synth.getNumActiveVoices(true) == 2 ); REQUIRE( fastVoice->isFree() ); REQUIRE( !normalVoice->isFree() ); diff --git a/tests/PolyphonyT.cpp b/tests/PolyphonyT.cpp index f1e261d1..b45b2e4c 100644 --- a/tests/PolyphonyT.cpp +++ b/tests/PolyphonyT.cpp @@ -6,6 +6,8 @@ #include "sfizz/Synth.h" #include "sfizz/SfzHelpers.h" +#include "TestHelpers.h" +#include #include "catch2/catch.hpp" using namespace Catch::literals; @@ -13,7 +15,6 @@ using namespace sfz::literals; constexpr int blockSize { 256 }; - TEST_CASE("[Polyphony] Polyphony in hierarchy") { sfz::Synth synth; @@ -71,6 +72,7 @@ TEST_CASE("[Polyphony] Polyphony groups") TEST_CASE("[Polyphony] group polyphony limits") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( group=1 polyphony=2 sample=*sine key=65 @@ -78,12 +80,15 @@ TEST_CASE("[Polyphony] group polyphony limits") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); // group polyphony should block the last note + REQUIRE( synth.getNumActiveVoices(true) == 3 ); + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing } TEST_CASE("[Polyphony] Hierarchy polyphony limits") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( polyphony=2 sample=*sine key=65 @@ -91,12 +96,15 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE( synth.getNumActiveVoices(true) == 3 ); + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing } TEST_CASE("[Polyphony] Hierarchy polyphony limits (group)") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( polyphony=2 sample=*sine key=65 @@ -104,12 +112,15 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (group)") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE( synth.getNumActiveVoices(true) == 3 ); + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing } TEST_CASE("[Polyphony] Hierarchy polyphony limits (master)") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( polyphony=2 polyphony=5 @@ -118,12 +129,15 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (master)") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE( synth.getNumActiveVoices(true) == 3 ); + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing } TEST_CASE("[Polyphony] Hierarchy polyphony limits (limit in another master)") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( polyphony=2 sample=*saw key=65 @@ -137,12 +151,15 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (limit in another master)") synth.noteOn(0, 66, 64); synth.noteOn(0, 66, 64); synth.noteOn(0, 66, 64); - REQUIRE(synth.getNumActiveVoices(true) == 5); + REQUIRE( synth.getNumActiveVoices(true) == 6); + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 5); // One is releasing } TEST_CASE("[Polyphony] Hierarchy polyphony limits (global)") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( polyphony=2 polyphony=5 @@ -151,14 +168,16 @@ TEST_CASE("[Polyphony] Hierarchy polyphony limits (global)") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); + REQUIRE( synth.getNumActiveVoices(true) == 3 ); + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing } TEST_CASE("[Polyphony] Polyphony in master") { sfz::Synth synth; - synth.setSamplesPerBlock(blockSize); sfz::AudioBuffer buffer { 2, blockSize }; + synth.setSamplesPerBlock(blockSize); synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( polyphony=2 group=2 @@ -171,75 +190,90 @@ TEST_CASE("[Polyphony] Polyphony in master") synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); synth.noteOn(0, 65, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); // group polyphony should block the last note + REQUIRE( synth.getNumActiveVoices(true) == 3 ); + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing synth.allSoundOff(); synth.renderBlock(buffer); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE( synth.getNumActiveVoices(true) == 0); synth.noteOn(0, 63, 64); synth.noteOn(0, 63, 64); synth.noteOn(0, 63, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); // group polyphony should block the last note + REQUIRE( synth.getNumActiveVoices(true) == 3 ); + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 2 ); // One is releasing synth.allSoundOff(); synth.renderBlock(buffer); - REQUIRE(synth.getNumActiveVoices(true) == 0); + REQUIRE( synth.getNumActiveVoices(true) == 0); synth.noteOn(0, 61, 64); synth.noteOn(0, 61, 64); synth.noteOn(0, 61, 64); - REQUIRE(synth.getNumActiveVoices(true) == 3); + REQUIRE( synth.getNumActiveVoices(true) == 3 ); + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 3 ); } TEST_CASE("[Polyphony] Self-masking") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( sample=*sine key=64 note_polyphony=2 )"); - synth.noteOn(0, 64, 63); - synth.noteOn(0, 64, 62); + synth.noteOn(0, 64, 63 ); + synth.noteOn(0, 64, 62 ); synth.noteOn(0, 64, 64); - REQUIRE(synth.getNumActiveVoices(true) == 3); // One of these is releasing - REQUIRE(synth.getVoiceView(0)->getTriggerValue() == 63_norm); + REQUIRE( synth.getNumActiveVoices(true) == 3 ); // One of these is releasing + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 2 ); + REQUIRE( synth.getVoiceView(0)->getTriggerValue() == 63_norm); REQUIRE(!synth.getVoiceView(0)->releasedOrFree()); - REQUIRE(synth.getVoiceView(1)->getTriggerValue() == 62_norm); - REQUIRE(synth.getVoiceView(1)->releasedOrFree()); // The lowest velocity voice is the masking candidate - REQUIRE(synth.getVoiceView(2)->getTriggerValue() == 64_norm); + REQUIRE( synth.getVoiceView(1)->getTriggerValue() == 62_norm); + REQUIRE( synth.getVoiceView(1)->releasedOrFree()); // The lowest velocity voice is the masking candidate + REQUIRE( synth.getVoiceView(2)->getTriggerValue() == 64_norm); REQUIRE(!synth.getVoiceView(2)->releasedOrFree()); } TEST_CASE("[Polyphony] Not self-masking") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( sample=*sine key=66 note_polyphony=2 note_selfmask=off )"); - synth.noteOn(0, 66, 63); - synth.noteOn(0, 66, 62); + synth.noteOn(0, 66, 63 ); + synth.noteOn(0, 66, 62 ); synth.noteOn(0, 66, 64); - REQUIRE(synth.getNumActiveVoices(true) == 3); // One of these is releasing - REQUIRE(synth.getVoiceView(0)->getTriggerValue() == 63_norm); - REQUIRE(synth.getVoiceView(0)->releasedOrFree()); - REQUIRE(synth.getVoiceView(1)->getTriggerValue() == 62_norm); + REQUIRE( synth.getNumActiveVoices(true) == 3 ); // One of these is releasing + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 2 ); + REQUIRE( synth.getVoiceView(0)->getTriggerValue() == 63_norm); + REQUIRE( synth.getVoiceView(0)->releasedOrFree()); + REQUIRE( synth.getVoiceView(1)->getTriggerValue() == 62_norm); REQUIRE(!synth.getVoiceView(1)->releasedOrFree()); - REQUIRE(synth.getVoiceView(2)->getTriggerValue() == 64_norm); + REQUIRE( synth.getVoiceView(2)->getTriggerValue() == 64_norm); REQUIRE(!synth.getVoiceView(2)->releasedOrFree()); } TEST_CASE("[Polyphony] Self-masking with the exact same velocity") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path(), R"( sample=*sine key=64 note_polyphony=2 )"); synth.noteOn(0, 64, 64); - synth.noteOn(0, 64, 63); - synth.noteOn(0, 64, 63); - REQUIRE(synth.getNumActiveVoices(true) == 3); // One of these is releasing - REQUIRE(synth.getVoiceView(0)->getTriggerValue() == 64_norm); + synth.noteOn(0, 64, 63 ); + synth.noteOn(0, 64, 63 ); + REQUIRE( synth.getNumActiveVoices(true) == 3 ); // One of these is releasing + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 2 ); + REQUIRE( synth.getVoiceView(0)->getTriggerValue() == 64_norm); REQUIRE(!synth.getVoiceView(0)->releasedOrFree()); - REQUIRE(synth.getVoiceView(1)->getTriggerValue() == 63_norm); - REQUIRE(synth.getVoiceView(1)->releasedOrFree()); // The first one is the masking candidate since they have the same velocity - REQUIRE(synth.getVoiceView(2)->getTriggerValue() == 63_norm); + REQUIRE( synth.getVoiceView(1)->getTriggerValue() == 63_norm); + REQUIRE( synth.getVoiceView(1)->releasedOrFree()); // The first one is the masking candidate since they have the same velocity + REQUIRE( synth.getVoiceView(2)->getTriggerValue() == 63_norm); REQUIRE(!synth.getVoiceView(2)->releasedOrFree()); } @@ -249,53 +283,59 @@ TEST_CASE("[Polyphony] Self-masking only works from low to high") synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( sample=*sine key=64 note_polyphony=1 )"); - synth.noteOn(0, 64, 63); - synth.noteOn(0, 64, 62); - REQUIRE(synth.getNumActiveVoices(true) == 2); // Both notes are playing - REQUIRE(synth.getVoiceView(0)->getTriggerValue() == 63_norm); + synth.noteOn(0, 64, 63 ); + synth.noteOn(0, 64, 62 ); + REQUIRE( synth.getNumActiveVoices(true) == 2 ); // Both notes are playing + REQUIRE( synth.getVoiceView(0)->getTriggerValue() == 63_norm); REQUIRE(!synth.getVoiceView(0)->releasedOrFree()); - REQUIRE(synth.getVoiceView(1)->getTriggerValue() == 62_norm); + REQUIRE( synth.getVoiceView(1)->getTriggerValue() == 62_norm); REQUIRE(!synth.getVoiceView(1)->releasedOrFree()); } TEST_CASE("[Polyphony] Note polyphony checks works across regions in the same polyphony group (default)") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( sample=*saw key=64 note_polyphony=1 sample=*sine key=64 note_polyphony=1 )"); - synth.noteOn(0, 64, 62); - synth.noteOn(0, 64, 63); - REQUIRE(synth.getNumActiveVoices(true) == 4); // Both notes are playing - REQUIRE(synth.getVoiceView(0)->getTriggerValue() == 62_norm); - REQUIRE(synth.getVoiceView(0)->releasedOrFree()); // got killed - REQUIRE(synth.getVoiceView(1)->getTriggerValue() == 62_norm); - REQUIRE(synth.getVoiceView(1)->releasedOrFree()); // got killed - REQUIRE(synth.getVoiceView(2)->getTriggerValue() == 63_norm); - REQUIRE(synth.getVoiceView(2)->releasedOrFree()); // got killed - REQUIRE(synth.getVoiceView(3)->getTriggerValue() == 63_norm); + synth.noteOn(0, 64, 62 ); + synth.noteOn(0, 64, 63 ); + REQUIRE( synth.getNumActiveVoices(true) == 4); + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 1 ); + REQUIRE( synth.getVoiceView(0)->getTriggerValue() == 62_norm); + REQUIRE( synth.getVoiceView(0)->releasedOrFree()); // got killed + REQUIRE( synth.getVoiceView(1)->getTriggerValue() == 62_norm); + REQUIRE( synth.getVoiceView(1)->releasedOrFree()); // got killed + REQUIRE( synth.getVoiceView(2)->getTriggerValue() == 63_norm); + REQUIRE( synth.getVoiceView(2)->releasedOrFree()); // got killed + REQUIRE( synth.getVoiceView(3)->getTriggerValue() == 63_norm); REQUIRE(!synth.getVoiceView(3)->releasedOrFree()); } TEST_CASE("[Polyphony] Note polyphony checks works across regions in the same polyphony group (default, with keyswitches)") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( sw_lokey=36 sw_hikey=37 sw_default=36 sw_last=36 key=48 note_polyphony=1 sample=*saw sw_last=37 key=48 transpose=12 note_polyphony=1 sample=*tri )"); - synth.noteOn(0, 48, 63); - REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 48, 63 ); + REQUIRE( synth.getNumActiveVoices(true) == 1); synth.cc(0, 64, 127); synth.noteOn(0, 37, 127); synth.noteOff(0, 37, 0); synth.noteOn(0, 48, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); - REQUIRE(synth.getVoiceView(0)->getTriggerValue() == 63_norm); - REQUIRE(synth.getVoiceView(0)->releasedOrFree()); - REQUIRE(synth.getVoiceView(1)->getTriggerValue() == 64_norm); + REQUIRE( synth.getNumActiveVoices(true) == 2 ); + synth.renderBlock(buffer); + REQUIRE( numPlayingVoices(synth) == 1 ); + REQUIRE( synth.getVoiceView(0)->getTriggerValue() == 63_norm); + REQUIRE( synth.getVoiceView(0)->releasedOrFree()); + REQUIRE( synth.getVoiceView(1)->getTriggerValue() == 64_norm); REQUIRE(!synth.getVoiceView(1)->releasedOrFree()); } @@ -303,40 +343,46 @@ TEST_CASE("[Polyphony] Note polyphony checks works across regions in the same po TEST_CASE("[Polyphony] Note polyphony do not operate across polyphony groups") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( group=1 sample=*saw key=64 note_polyphony=1 group=2 sample=*sine key=64 note_polyphony=1 )"); - synth.noteOn(0, 64, 62); - synth.noteOn(0, 64, 63); - REQUIRE(synth.getNumActiveVoices(true) == 4); // Both notes are playing - REQUIRE(synth.getVoiceView(0)->getTriggerValue() == 62_norm); - REQUIRE(synth.getVoiceView(0)->releasedOrFree()); // got killed - REQUIRE(synth.getVoiceView(1)->getTriggerValue() == 62_norm); - REQUIRE(synth.getVoiceView(1)->releasedOrFree()); // got killed - REQUIRE(synth.getVoiceView(2)->getTriggerValue() == 63_norm); + synth.noteOn(0, 64, 62 ); + synth.noteOn(0, 64, 63 ); + REQUIRE( synth.getNumActiveVoices(true) == 4); // Both notes are playing + synth.renderBlock(buffer); + REQUIRE(numPlayingVoices(synth) == 2 ); + REQUIRE( synth.getVoiceView(0)->getTriggerValue() == 62_norm); + REQUIRE( synth.getVoiceView(0)->releasedOrFree()); // got killed + REQUIRE( synth.getVoiceView(1)->getTriggerValue() == 62_norm); + REQUIRE( synth.getVoiceView(1)->releasedOrFree()); // got killed + REQUIRE( synth.getVoiceView(2)->getTriggerValue() == 63_norm); REQUIRE(!synth.getVoiceView(2)->releasedOrFree()); - REQUIRE(synth.getVoiceView(3)->getTriggerValue() == 63_norm); + REQUIRE( synth.getVoiceView(3)->getTriggerValue() == 63_norm); REQUIRE(!synth.getVoiceView(3)->releasedOrFree()); } TEST_CASE("[Polyphony] Note polyphony do not operate across polyphony groups (with keyswitches)") { sfz::Synth synth; + sfz::AudioBuffer buffer { 2, blockSize }; synth.loadSfzString(fs::current_path() / "tests/TestFiles/polyphony.sfz", R"( sw_lokey=36 sw_hikey=37 sw_default=36 group=1 sw_last=36 key=48 note_polyphony=1 sample=*saw group=2 sw_last=37 key=48 transpose=12 note_polyphony=1 sample=*tri )"); - synth.noteOn(0, 48, 63); - REQUIRE(synth.getNumActiveVoices(true) == 1); + synth.noteOn(0, 48, 63 ); + REQUIRE( synth.getNumActiveVoices(true) == 1); synth.cc(0, 64, 127); synth.noteOn(0, 37, 127); synth.noteOff(0, 37, 0); synth.noteOn(0, 48, 64); - REQUIRE(synth.getNumActiveVoices(true) == 2); - REQUIRE(synth.getVoiceView(0)->getTriggerValue() == 63_norm); + REQUIRE( synth.getNumActiveVoices(true) == 2 ); + synth.renderBlock(buffer); + REQUIRE(numPlayingVoices(synth) == 2 ); + REQUIRE( synth.getVoiceView(0)->getTriggerValue() == 63_norm); REQUIRE(!synth.getVoiceView(0)->releasedOrFree()); - REQUIRE(synth.getVoiceView(1)->getTriggerValue() == 64_norm); + REQUIRE( synth.getVoiceView(1)->getTriggerValue() == 64_norm); REQUIRE(!synth.getVoiceView(1)->releasedOrFree()); } diff --git a/tests/RegionT.cpp b/tests/RegionT.cpp index c6317a0f..189fae32 100644 --- a/tests/RegionT.cpp +++ b/tests/RegionT.cpp @@ -4,7 +4,7 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "RegionTHelpers.h" +#include "TestHelpers.h" #include "sfizz/MidiState.h" #include "sfizz/Region.h" #include "sfizz/SfzHelpers.h" diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index a6ec1aa2..bd949dd3 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -8,6 +8,7 @@ #include "sfizz/SisterVoiceRing.h" #include "sfizz/SfzHelpers.h" #include "sfizz/NumericId.h" +#include "TestHelpers.h" #include #include "catch2/catch.hpp" using namespace Catch::literals; @@ -607,7 +608,8 @@ TEST_CASE("[Synth] Sisters and off-by") REQUIRE( synth.getNumActiveVoices(true) == 2 ); synth.noteOn(0, 63, 85); REQUIRE( synth.getNumActiveVoices(true) == 3 ); - synth.renderBlock(buffer); + for (unsigned i = 0; i < 100; ++i) + synth.renderBlock(buffer); REQUIRE( synth.getNumActiveVoices(true) == 2 ); REQUIRE( sfz::SisterVoiceRing::countSisterVoices(synth.getVoiceView(0)) == 1 ); } @@ -735,30 +737,6 @@ TEST_CASE("[Synth] Sustain threshold") REQUIRE( synth.getNumActiveVoices(true) == 5 ); } -template -void sortAll(C& container) -{ - std::sort(container.begin(), container.end()); -} - -template -void sortAll(C& container, Args&... others) -{ - std::sort(container.begin(), container.end()); - sortAll(others...); -} - -const std::vector getActiveVoices(const sfz::Synth& synth) -{ - std::vector activeVoices; - for (int i = 0; i < synth.getNumVoices(); ++i) { - const auto* voice = synth.getVoiceView(i); - if (!voice->isFree()) - activeVoices.push_back(voice); - } - return activeVoices; -} - TEST_CASE("[Synth] Release (Multiple notes, release_key ignores the pedal)") { sfz::Synth synth; diff --git a/tests/RegionTHelpers.cpp b/tests/TestHelpers.cpp similarity index 68% rename from tests/RegionTHelpers.cpp rename to tests/TestHelpers.cpp index a47b56ed..ca32de0b 100644 --- a/tests/RegionTHelpers.cpp +++ b/tests/TestHelpers.cpp @@ -4,7 +4,7 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -#include "RegionTHelpers.h" +#include "TestHelpers.h" #include "sfizz/modulations/ModId.h" size_t RegionCCView::size() const @@ -39,3 +39,21 @@ bool RegionCCView::match(const sfz::Region::Connection& conn) const { return conn.source.id() == sfz::ModId::Controller && conn.target == target_; } + +const std::vector getActiveVoices(const sfz::Synth& synth) +{ + std::vector activeVoices; + for (int i = 0; i < synth.getNumVoices(); ++i) { + const auto* voice = synth.getVoiceView(i); + if (!voice->isFree()) + activeVoices.push_back(voice); + } + return activeVoices; +} + +unsigned numPlayingVoices(const sfz::Synth& synth) +{ + return absl::c_count_if(getActiveVoices(synth), [](const sfz::Voice* v) { + return !v->releasedOrFree(); + }); +} diff --git a/tests/RegionTHelpers.h b/tests/TestHelpers.h similarity index 52% rename from tests/RegionTHelpers.h rename to tests/TestHelpers.h index e9fcf897..ac8be3dc 100644 --- a/tests/RegionTHelpers.h +++ b/tests/TestHelpers.h @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "sfizz/Synth.h" #include "sfizz/Region.h" #include "sfizz/modulations/ModKey.h" @@ -26,3 +27,32 @@ private: const sfz::Region& region_; sfz::ModKey target_; }; + +template +void sortAll(C& container) +{ + std::sort(container.begin(), container.end()); +} + +template +void sortAll(C& container, Args&... others) +{ + std::sort(container.begin(), container.end()); + sortAll(others...); +} + +/** + * @brief Get active voices from the synth + * + * @param synth + * @return const std::vector + */ +const std::vector getActiveVoices(const sfz::Synth& synth); + +/** + * @brief Count the number of playing (unreleased) voices from the synth + * + * @param synth + * @return unsigned + */ +unsigned numPlayingVoices(const sfz::Synth& synth);