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/SisterVoiceRing.h"
|
||||||
#include "sfizz/SfzHelpers.h"
|
#include "sfizz/SfzHelpers.h"
|
||||||
#include "sfizz/NumericId.h"
|
#include "sfizz/NumericId.h"
|
||||||
|
#include <algorithm>
|
||||||
#include "catch2/catch.hpp"
|
#include "catch2/catch.hpp"
|
||||||
using namespace Catch::literals;
|
using namespace Catch::literals;
|
||||||
using namespace sfz::literals;
|
using namespace sfz::literals;
|
||||||
|
|
@ -626,14 +627,48 @@ TEST_CASE("[Synth] Release")
|
||||||
{
|
{
|
||||||
sfz::Synth synth;
|
sfz::Synth synth;
|
||||||
synth.loadSfzString(fs::current_path(), R"(
|
synth.loadSfzString(fs::current_path(), R"(
|
||||||
|
<region> key=62 sample=*silence
|
||||||
<region> key=62 sample=*sine trigger=release
|
<region> key=62 sample=*sine trigger=release
|
||||||
)");
|
)");
|
||||||
synth.noteOn(0, 62, 85);
|
synth.noteOn(0, 62, 85);
|
||||||
synth.cc(0, 64, 127);
|
synth.cc(0, 64, 127);
|
||||||
synth.noteOff(0, 62, 85);
|
synth.noteOff(0, 62, 85);
|
||||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
|
||||||
synth.cc(0, 64, 0);
|
|
||||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
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)")
|
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.noteOn(0, 62, 85);
|
||||||
synth.cc(0, 54, 127);
|
synth.cc(0, 54, 127);
|
||||||
synth.noteOff(0, 62, 85);
|
synth.noteOff(0, 62, 85);
|
||||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
REQUIRE( synth.getNumActiveVoices(true) == 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[Synth] Release (Different sustain CC)")
|
TEST_CASE("[Synth] Release (Different sustain CC)")
|
||||||
|
|
@ -654,14 +689,15 @@ TEST_CASE("[Synth] Release (Different sustain CC)")
|
||||||
sfz::Synth synth;
|
sfz::Synth synth;
|
||||||
synth.loadSfzString(fs::current_path(), R"(
|
synth.loadSfzString(fs::current_path(), R"(
|
||||||
<global>sustain_cc=54
|
<global>sustain_cc=54
|
||||||
|
<region> key=62 sample=*silence
|
||||||
<region> key=62 sample=*sine trigger=release
|
<region> key=62 sample=*sine trigger=release
|
||||||
)");
|
)");
|
||||||
synth.noteOn(0, 62, 85);
|
synth.noteOn(0, 62, 85);
|
||||||
synth.cc(0, 54, 127);
|
synth.cc(0, 54, 127);
|
||||||
synth.noteOff(0, 62, 85);
|
synth.noteOff(0, 62, 85);
|
||||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
|
||||||
synth.cc(0, 54, 0);
|
|
||||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||||
|
synth.cc(0, 54, 0);
|
||||||
|
REQUIRE( synth.getNumActiveVoices(true) == 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[Synth] Sustain threshold default")
|
TEST_CASE("[Synth] Sustain threshold default")
|
||||||
|
|
@ -681,37 +717,45 @@ TEST_CASE("[Synth] Sustain threshold")
|
||||||
sfz::Synth synth;
|
sfz::Synth synth;
|
||||||
synth.loadSfzString(fs::current_path(), R"(
|
synth.loadSfzString(fs::current_path(), R"(
|
||||||
<global> sustain_lo=63
|
<global> sustain_lo=63
|
||||||
|
<region> key=62 sample=*silence
|
||||||
<region> key=62 sample=*sine trigger=release
|
<region> key=62 sample=*sine trigger=release
|
||||||
)");
|
)");
|
||||||
synth.noteOn(0, 62, 85);
|
synth.noteOn(0, 62, 85);
|
||||||
synth.cc(0, 64, 1);
|
synth.cc(0, 64, 1);
|
||||||
synth.noteOff(0, 62, 85);
|
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 );
|
REQUIRE( synth.getNumActiveVoices(true) == 2 );
|
||||||
synth.noteOn(0, 62, 85);
|
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.cc(0, 64, 64);
|
||||||
synth.noteOff(0, 62, 85);
|
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;
|
std::sort(container.begin(), container.end());
|
||||||
synth.loadSfzString(fs::current_path(), R"(
|
}
|
||||||
<region> lokey=62 hikey=64 sample=*sine trigger=release
|
|
||||||
)");
|
template<class C, class... Args>
|
||||||
synth.noteOn(0, 62, 85);
|
void sortAll(C& container, Args&... others)
|
||||||
synth.noteOn(0, 63, 78);
|
{
|
||||||
synth.noteOn(0, 64, 34);
|
std::sort(container.begin(), container.end());
|
||||||
synth.cc(0, 64, 127);
|
sortAll(others...);
|
||||||
synth.noteOff(0, 64, 0);
|
}
|
||||||
synth.noteOff(0, 63, 2);
|
|
||||||
synth.noteOff(0, 62, 85);
|
const std::vector<const sfz::Voice*> getActiveVoices(const sfz::Synth& synth)
|
||||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
{
|
||||||
synth.cc(0, 64, 0);
|
std::vector<const sfz::Voice*> activeVoices;
|
||||||
REQUIRE( synth.getNumActiveVoices(true) == 3 );
|
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)")
|
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, 63, 2);
|
||||||
synth.noteOff(0, 62, 85);
|
synth.noteOff(0, 62, 85);
|
||||||
REQUIRE( synth.getNumActiveVoices(true) == 3 );
|
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;
|
sfz::Synth synth;
|
||||||
synth.loadSfzString(fs::current_path(), R"(
|
synth.loadSfzString(fs::current_path(), R"(
|
||||||
|
<region> lokey=62 hikey=64 sample=*silence
|
||||||
<region> lokey=62 hikey=64 sample=*sine trigger=release
|
<region> lokey=62 hikey=64 sample=*sine trigger=release
|
||||||
loopmode=one_shot ampeg_attack=0.02 ampeg_release=0.1
|
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, 64, 0);
|
||||||
synth.noteOff(0, 63, 2);
|
synth.noteOff(0, 63, 2);
|
||||||
synth.noteOff(0, 62, 85);
|
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 );
|
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||||
synth.cc(0, 64, 0);
|
synth.cc(0, 64, 0);
|
||||||
REQUIRE( synth.getNumActiveVoices(true) == 3 );
|
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||||
REQUIRE( synth.getRegionView(0)->delayedReleases.empty() );
|
|
||||||
|
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