Added tests
This commit is contained in:
parent
f631f7031d
commit
a3943abf79
1 changed files with 214 additions and 27 deletions
241
tests/SynthT.cpp
241
tests/SynthT.cpp
|
|
@ -8,6 +8,7 @@
|
|||
#include "sfizz/SisterVoiceRing.h"
|
||||
#include "sfizz/SfzHelpers.h"
|
||||
#include "sfizz/NumericId.h"
|
||||
#include <algorithm>
|
||||
#include "catch2/catch.hpp"
|
||||
using namespace Catch::literals;
|
||||
using namespace sfz::literals;
|
||||
|
|
@ -626,14 +627,48 @@ TEST_CASE("[Synth] Release")
|
|||
{
|
||||
sfz::Synth synth;
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<region> key=62 sample=*silence
|
||||
<region> key=62 sample=*sine trigger=release
|
||||
)");
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.cc(0, 64, 127);
|
||||
synth.noteOff(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
synth.cc(0, 64, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
synth.cc(0, 64, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE("[Synth] Release (pedal was already down)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<region> key=62 sample=*silence
|
||||
<region> key=62 sample=*sine trigger=release
|
||||
)");
|
||||
synth.cc(0, 64, 127);
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.noteOff(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
synth.cc(0, 64, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 2 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("[Synth] Release samples don't play unless there is another playing region that matches")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<region> key=62 sample=*sine trigger=release
|
||||
)");
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.noteOff(0, 62, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
synth.cc(0, 64, 127);
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.noteOff(0, 62, 0);
|
||||
synth.cc(0, 64, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
}
|
||||
|
||||
TEST_CASE("[Synth] Release key (Different sustain CC)")
|
||||
|
|
@ -646,7 +681,7 @@ TEST_CASE("[Synth] Release key (Different sustain CC)")
|
|||
synth.noteOn(0, 62, 85);
|
||||
synth.cc(0, 54, 127);
|
||||
synth.noteOff(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE("[Synth] Release (Different sustain CC)")
|
||||
|
|
@ -654,14 +689,15 @@ TEST_CASE("[Synth] Release (Different sustain CC)")
|
|||
sfz::Synth synth;
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<global>sustain_cc=54
|
||||
<region> key=62 sample=*silence
|
||||
<region> key=62 sample=*sine trigger=release
|
||||
)");
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.cc(0, 54, 127);
|
||||
synth.noteOff(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
synth.cc(0, 54, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
synth.cc(0, 54, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 2 );
|
||||
}
|
||||
|
||||
TEST_CASE("[Synth] Sustain threshold default")
|
||||
|
|
@ -681,37 +717,45 @@ TEST_CASE("[Synth] Sustain threshold")
|
|||
sfz::Synth synth;
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<global> sustain_lo=63
|
||||
<region> key=62 sample=*silence
|
||||
<region> key=62 sample=*sine trigger=release
|
||||
)");
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.cc(0, 64, 1);
|
||||
synth.noteOff(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.noteOff(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 2 );
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.noteOff(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 4 );
|
||||
synth.noteOn(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 5 );
|
||||
synth.cc(0, 64, 64);
|
||||
synth.noteOff(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 2 );
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 5 );
|
||||
}
|
||||
|
||||
TEST_CASE("[Synth] Release (Multiple notes)")
|
||||
template<class C>
|
||||
void sortAll(C& container)
|
||||
{
|
||||
sfz::Synth synth;
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<region> lokey=62 hikey=64 sample=*sine trigger=release
|
||||
)");
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.noteOn(0, 63, 78);
|
||||
synth.noteOn(0, 64, 34);
|
||||
synth.cc(0, 64, 127);
|
||||
synth.noteOff(0, 64, 0);
|
||||
synth.noteOff(0, 63, 2);
|
||||
synth.noteOff(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
synth.cc(0, 64, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 3 );
|
||||
std::sort(container.begin(), container.end());
|
||||
}
|
||||
|
||||
template<class C, class... Args>
|
||||
void sortAll(C& container, Args&... others)
|
||||
{
|
||||
std::sort(container.begin(), container.end());
|
||||
sortAll(others...);
|
||||
}
|
||||
|
||||
const std::vector<const sfz::Voice*> getActiveVoices(const sfz::Synth& synth)
|
||||
{
|
||||
std::vector<const sfz::Voice*> 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)")
|
||||
|
|
@ -728,12 +772,21 @@ TEST_CASE("[Synth] Release (Multiple notes, release_key ignores the pedal)")
|
|||
synth.noteOff(0, 63, 2);
|
||||
synth.noteOff(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 3 );
|
||||
|
||||
std::vector<float> requiredVelocities { 34_norm, 78_norm, 85_norm};
|
||||
std::vector<float> actualVelocities;
|
||||
for (auto* v: getActiveVoices(synth)) {
|
||||
actualVelocities.push_back(v->getTriggerValue());
|
||||
}
|
||||
sortAll(requiredVelocities, actualVelocities);
|
||||
REQUIRE( requiredVelocities == actualVelocities );
|
||||
}
|
||||
|
||||
TEST_CASE("[Synth] Release (Multiple notes, cleared the delayed voices after)")
|
||||
TEST_CASE("[Synth] Release (Multiple notes, release, cleared the delayed voices after)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<region> lokey=62 hikey=64 sample=*silence
|
||||
<region> lokey=62 hikey=64 sample=*sine trigger=release
|
||||
loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1
|
||||
)");
|
||||
|
|
@ -744,8 +797,142 @@ TEST_CASE("[Synth] Release (Multiple notes, cleared the delayed voices after)")
|
|||
synth.noteOff(0, 64, 0);
|
||||
synth.noteOff(0, 63, 2);
|
||||
synth.noteOff(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 3 );
|
||||
synth.cc(0, 64, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 6 );
|
||||
|
||||
std::vector<float> requiredVelocities { 34_norm, 78_norm, 85_norm, 34_norm, 78_norm, 85_norm };
|
||||
std::vector<float> actualVelocities;
|
||||
for (auto* v: getActiveVoices(synth)) {
|
||||
actualVelocities.push_back(v->getTriggerValue());
|
||||
}
|
||||
sortAll(requiredVelocities, actualVelocities);
|
||||
REQUIRE( requiredVelocities == actualVelocities );
|
||||
|
||||
REQUIRE( synth.getRegionView(1)->delayedReleases.empty() );
|
||||
}
|
||||
|
||||
TEST_CASE("[Synth] Release (Multiple notes after pedal is down, release, cleared the delayed voices after)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<region> lokey=62 hikey=64 sample=*silence
|
||||
<region> lokey=62 hikey=64 sample=*sine trigger=release
|
||||
loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1
|
||||
)");
|
||||
synth.cc(0, 64, 127);
|
||||
synth.noteOn(1, 62, 85);
|
||||
synth.noteOn(1, 63, 78);
|
||||
synth.noteOn(1, 64, 34);
|
||||
synth.noteOff(2, 64, 0);
|
||||
synth.noteOff(2, 63, 2);
|
||||
synth.noteOff(2, 62, 3);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 3 );
|
||||
synth.cc(3, 64, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 6 );
|
||||
|
||||
std::vector<float> requiredVelocities { 34_norm, 78_norm, 85_norm, 34_norm, 78_norm, 85_norm };
|
||||
std::vector<float> actualVelocities;
|
||||
for (auto* v: getActiveVoices(synth)) {
|
||||
actualVelocities.push_back(v->getTriggerValue());
|
||||
}
|
||||
sortAll(requiredVelocities, actualVelocities);
|
||||
REQUIRE( requiredVelocities == actualVelocities );
|
||||
|
||||
REQUIRE( synth.getRegionView(1)->delayedReleases.empty() );
|
||||
}
|
||||
|
||||
TEST_CASE("[Synth] Release (Multiple note ons during pedal down)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<region> lokey=62 hikey=64 sample=*silence
|
||||
<region> lokey=62 hikey=64 sample=*sine trigger=release
|
||||
loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1
|
||||
)");
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.cc(0, 64, 127);
|
||||
synth.noteOff(0, 62, 0);
|
||||
synth.noteOn(0, 62, 78);
|
||||
synth.noteOff(0, 62, 2);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 2 );
|
||||
synth.cc(0, 64, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 4 );
|
||||
|
||||
std::vector<float> requiredVelocities { 78_norm, 85_norm, 78_norm, 85_norm };
|
||||
std::vector<float> actualVelocities;
|
||||
for (auto* v: getActiveVoices(synth)) {
|
||||
actualVelocities.push_back(v->getTriggerValue());
|
||||
}
|
||||
sortAll(requiredVelocities, actualVelocities);
|
||||
REQUIRE( requiredVelocities == actualVelocities );
|
||||
REQUIRE( synth.getRegionView(1)->delayedReleases.empty() );
|
||||
}
|
||||
|
||||
TEST_CASE("[Synth] No release sample after the main sample stopped sounding by default")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
sfz::AudioBuffer<float> buffer { 2, 4096 };
|
||||
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<region> lokey=62 hikey=64 sample=TestFiles/closedhat.wav loop_mode=one_shot
|
||||
<region> lokey=62 hikey=64 sample=*sine trigger=release
|
||||
loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1
|
||||
)");
|
||||
synth.noteOn(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
for (unsigned i = 0; i < 100; ++i) {
|
||||
synth.renderBlock(buffer);
|
||||
}
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
synth.noteOff(0, 62, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.cc(0, 64, 127);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
for (unsigned i = 0; i < 100; ++i) {
|
||||
synth.renderBlock(buffer);
|
||||
}
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
synth.noteOff(0, 62, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
synth.cc(0, 64, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 3 );
|
||||
REQUIRE( synth.getRegionView(0)->delayedReleases.empty() );
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
|
||||
REQUIRE( synth.getRegionView(1)->delayedReleases.empty() );
|
||||
}
|
||||
|
||||
TEST_CASE("[Synth] If rt_dead is active the release sample can sound after the attack sample died")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
sfz::AudioBuffer<float> buffer { 2, 4096 };
|
||||
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<region> lokey=62 hikey=64 sample=TestFiles/closedhat.wav loop_mode=one_shot
|
||||
<region> lokey=62 hikey=64 sample=*sine trigger=release
|
||||
loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1
|
||||
)");
|
||||
synth.noteOn(0, 62, 85);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
for (unsigned i = 0; i < 100; ++i) {
|
||||
synth.renderBlock(buffer);
|
||||
}
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
synth.noteOff(0, 62, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
|
||||
synth.noteOn(0, 62, 85);
|
||||
synth.cc(0, 64, 127);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
for (unsigned i = 0; i < 100; ++i) {
|
||||
synth.renderBlock(buffer);
|
||||
}
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
synth.noteOff(0, 62, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
synth.cc(0, 64, 0);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
|
||||
REQUIRE( synth.getRegionView(1)->delayedReleases.empty() );
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue