Everyone should now use the normalized versions

This commit is contained in:
Paul Fd 2020-03-26 00:25:26 +01:00 committed by Paul Ferrand
parent e7686d233e
commit cc8944e452
10 changed files with 225 additions and 213 deletions

View file

@ -55,7 +55,7 @@ namespace sfz
inline float ccSwitchedValue(const MidiState& state, const absl::optional<CCValuePair<float>>& ccSwitch, float value) noexcept inline float ccSwitchedValue(const MidiState& state, const absl::optional<CCValuePair<float>>& ccSwitch, float value) noexcept
{ {
if (ccSwitch) if (ccSwitch)
return value + ccSwitch->value * normalizeCC(state.getCCValue(ccSwitch->cc)); return value + ccSwitch->value * state.getCCValueNormalized(ccSwitch->cc);
else else
return value; return value;
} }

View file

@ -152,7 +152,7 @@ public:
T modulate(T value, const CCMap<U>& modifiers, const Range<T>& validRange, const modFunction<T, U>& lambda = addToBase<T>) const noexcept T modulate(T value, const CCMap<U>& modifiers, const Range<T>& validRange, const modFunction<T, U>& lambda = addToBase<T>) const noexcept
{ {
for (auto& mod: modifiers) { for (auto& mod: modifiers) {
lambda(value, normalizeCC(getCCValue(mod.cc)) * mod.value); lambda(value, getCCValueNormalized(mod.cc) * mod.value);
} }
return validRange.clamp(value); return validRange.clamp(value);
} }

View file

@ -181,8 +181,9 @@ void sfz::Synth::handleControlOpcodes(const std::vector<Opcode>& members)
case hash("Set_cc&"): // fallthrough case hash("Set_cc&"): // fallthrough
case hash("set_cc&"): case hash("set_cc&"):
if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) { if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) {
const auto ccValue = readOpcode(member.value, Default::midi7Range).value_or(0); const auto ccValue = readOpcode(member.value, Default::midi7Range);
resources.midiState.ccEvent(0, member.parameters.back(), ccValue); if (ccValue)
resources.midiState.ccEventNormalized(0, member.parameters.back(), normalizeCC(*ccValue));
} }
break; break;
case hash("Label_cc&"): // fallthrough case hash("Label_cc&"): // fallthrough
@ -386,12 +387,12 @@ bool sfz::Synth::loadSfzFile(const fs::path& file)
// Defaults // Defaults
for (unsigned cc = 0; cc < config::numCCs; cc++) { for (unsigned cc = 0; cc < config::numCCs; cc++) {
region->registerCC(cc, resources.midiState.getCCValue(cc)); region->registerCCNormalized(cc, resources.midiState.getCCValueNormalized(cc));
} }
if (defaultSwitch) { if (defaultSwitch) {
region->registerNoteOn(*defaultSwitch, 127, 1.0); region->registerNoteOnNormalized(*defaultSwitch, 1.0f, 1.0f);
region->registerNoteOff(*defaultSwitch, 0, 1.0); region->registerNoteOffNormalized(*defaultSwitch, 0.0f, 1.0f);
} }
// Set the default frequencies on equalizers if needed // Set the default frequencies on equalizers if needed
@ -616,9 +617,9 @@ void sfz::Synth::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept
ASSERT(noteNumber < 128); ASSERT(noteNumber < 128);
ASSERT(noteNumber >= 0); ASSERT(noteNumber >= 0);
UNUSED(velocity); UNUSED(velocity);
const auto normalizedVelocity = normalizeVelocity(velocity);
ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration }; ScopedTiming logger { dispatchDuration, ScopedTiming::Operation::addToDuration };
resources.midiState.noteOffEvent(delay, noteNumber, velocity); resources.midiState.noteOffEventNormalized(delay, noteNumber, normalizedVelocity);
AtomicGuard callbackGuard { inCallback }; AtomicGuard callbackGuard { inCallback };
if (!canEnterCallback) if (!canEnterCallback)
@ -690,7 +691,7 @@ void sfz::Synth::cc(int delay, int ccNumber, uint8_t ccValue) noexcept
voice->registerCC(delay, ccNumber, normalizedCC); voice->registerCC(delay, ccNumber, normalizedCC);
for (auto& region : ccActivationLists[ccNumber]) { for (auto& region : ccActivationLists[ccNumber]) {
if (region->registerCC(ccNumber, ccValue)) { if (region->registerCCNormalized(ccNumber, normalizedCC)) {
auto voice = findFreeVoice(); auto voice = findFreeVoice();
if (voice == nullptr) if (voice == nullptr)
continue; continue;

View file

@ -6,8 +6,10 @@
#include "sfizz/EGDescription.h" #include "sfizz/EGDescription.h"
#include "sfizz/SfzHelpers.h"
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
using namespace Catch::literals; using namespace Catch::literals;
using namespace sfz::literals;
TEST_CASE("[EGDescription] Attack range") TEST_CASE("[EGDescription] Attack range")
{ {
@ -18,7 +20,7 @@ TEST_CASE("[EGDescription] Attack range")
eg.ccAttack = { 63, 1.27f }; eg.ccAttack = { 63, 1.27f };
REQUIRE( eg.getAttack(state, 0) == 1.0f ); REQUIRE( eg.getAttack(state, 0) == 1.0f );
REQUIRE( eg.getAttack(state, 127) == 0.0f ); REQUIRE( eg.getAttack(state, 127) == 0.0f );
state.ccEvent(0, 63, 127); state.ccEventNormalized(0, 63, 127_norm);
REQUIRE( eg.getAttack(state, 127) == 1.0f ); REQUIRE( eg.getAttack(state, 127) == 1.0f );
REQUIRE( eg.getAttack(state, 0) == 2.27f ); REQUIRE( eg.getAttack(state, 0) == 2.27f );
eg.ccAttack = { 63, 127.0f }; eg.ccAttack = { 63, 127.0f };
@ -34,7 +36,7 @@ TEST_CASE("[EGDescription] Delay range")
eg.ccDelay = { 63, 1.27f }; eg.ccDelay = { 63, 1.27f };
REQUIRE( eg.getDelay(state, 0) == 1.0f ); REQUIRE( eg.getDelay(state, 0) == 1.0f );
REQUIRE( eg.getDelay(state, 127) == 0.0f ); REQUIRE( eg.getDelay(state, 127) == 0.0f );
state.ccEvent(0, 63, 127); state.ccEventNormalized(0, 63, 127_norm);
REQUIRE( eg.getDelay(state, 127) == 1.0f ); REQUIRE( eg.getDelay(state, 127) == 1.0f );
REQUIRE( eg.getDelay(state, 0) == 2.27f ); REQUIRE( eg.getDelay(state, 0) == 2.27f );
eg.ccDelay = { 63, 127.0f }; eg.ccDelay = { 63, 127.0f };
@ -50,7 +52,7 @@ TEST_CASE("[EGDescription] Decay range")
eg.ccDecay = { 63, 1.27f }; eg.ccDecay = { 63, 1.27f };
REQUIRE( eg.getDecay(state, 0) == 1.0f ); REQUIRE( eg.getDecay(state, 0) == 1.0f );
REQUIRE( eg.getDecay(state, 127) == 0.0f ); REQUIRE( eg.getDecay(state, 127) == 0.0f );
state.ccEvent(0, 63, 127); state.ccEventNormalized(0, 63, 127_norm);
REQUIRE( eg.getDecay(state, 127) == 1.0f ); REQUIRE( eg.getDecay(state, 127) == 1.0f );
REQUIRE( eg.getDecay(state, 0) == 2.27f ); REQUIRE( eg.getDecay(state, 0) == 2.27f );
eg.ccDecay = { 63, 127.0f }; eg.ccDecay = { 63, 127.0f };
@ -66,7 +68,7 @@ TEST_CASE("[EGDescription] Release range")
eg.ccRelease = { 63, 1.27f }; eg.ccRelease = { 63, 1.27f };
REQUIRE( eg.getRelease(state, 0) == 1.0f ); REQUIRE( eg.getRelease(state, 0) == 1.0f );
REQUIRE( eg.getRelease(state, 127) == 0.0f ); REQUIRE( eg.getRelease(state, 127) == 0.0f );
state.ccEvent(0, 63, 127); state.ccEventNormalized(0, 63, 127_norm);
REQUIRE( eg.getRelease(state, 127) == 1.0f ); REQUIRE( eg.getRelease(state, 127) == 1.0f );
REQUIRE( eg.getRelease(state, 0) == 2.27f ); REQUIRE( eg.getRelease(state, 0) == 2.27f );
eg.ccRelease = { 63, 127.0f }; eg.ccRelease = { 63, 127.0f };
@ -82,7 +84,7 @@ TEST_CASE("[EGDescription] Hold range")
eg.ccHold = { 63, 1.27f }; eg.ccHold = { 63, 1.27f };
REQUIRE( eg.getHold(state, 0) == 1.0f ); REQUIRE( eg.getHold(state, 0) == 1.0f );
REQUIRE( eg.getHold(state, 127) == 0.0f ); REQUIRE( eg.getHold(state, 127) == 0.0f );
state.ccEvent(0, 63, 127); state.ccEventNormalized(0, 63, 127_norm);
REQUIRE( eg.getHold(state, 127) == 1.0f ); REQUIRE( eg.getHold(state, 127) == 1.0f );
REQUIRE( eg.getHold(state, 0) == 2.27f ); REQUIRE( eg.getHold(state, 0) == 2.27f );
eg.ccHold = { 63, 127.0f }; eg.ccHold = { 63, 127.0f };
@ -98,7 +100,7 @@ TEST_CASE("[EGDescription] Sustain level")
eg.ccSustain = { 63, 100.0f }; eg.ccSustain = { 63, 100.0f };
REQUIRE( eg.getSustain(state, 0) == 50.0f ); REQUIRE( eg.getSustain(state, 0) == 50.0f );
REQUIRE( eg.getSustain(state, 127) == 0.0f ); REQUIRE( eg.getSustain(state, 127) == 0.0f );
state.ccEvent(0, 63, 127); state.ccEventNormalized(0, 63, 127_norm);
REQUIRE( eg.getSustain(state, 127) == 50.0f ); REQUIRE( eg.getSustain(state, 127) == 50.0f );
eg.ccSustain = { 63, 200.0f }; eg.ccSustain = { 63, 200.0f };
REQUIRE( eg.getSustain(state, 0) == 100.0f ); REQUIRE( eg.getSustain(state, 0) == 100.0f );
@ -112,7 +114,7 @@ TEST_CASE("[EGDescription] Start level")
eg.ccStart = { 63, 127.0f }; eg.ccStart = { 63, 127.0f };
REQUIRE( eg.getStart(state, 0) == 0.0f ); REQUIRE( eg.getStart(state, 0) == 0.0f );
REQUIRE( eg.getStart(state, 127) == 0.0f ); REQUIRE( eg.getStart(state, 127) == 0.0f );
state.ccEvent(0, 63, 127); state.ccEventNormalized(0, 63, 127_norm);
REQUIRE( eg.getStart(state, 0) == 100.0f ); REQUIRE( eg.getStart(state, 0) == 100.0f );
eg.ccStart = { 63, -127.0f }; eg.ccStart = { 63, -127.0f };
REQUIRE( eg.getStart(state, 0) == 0.0f ); REQUIRE( eg.getStart(state, 0) == 0.0f );

View file

@ -355,8 +355,8 @@ TEST_CASE("[Files] Set CC applies properly")
{ {
sfz::Synth synth; sfz::Synth synth;
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_cc.sfz"); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_cc.sfz");
REQUIRE(synth.getMidiState().getCCValue(142) == 63); REQUIRE(synth.getMidiState().getCCValueNormalized(142) == 63_norm);
REQUIRE(synth.getMidiState().getCCValue(61) == 122); REQUIRE(synth.getMidiState().getCCValueNormalized(61) == 122_norm);
} }
TEST_CASE("[Files] Note and octave offsets") TEST_CASE("[Files] Note and octave offsets")

View file

@ -11,25 +11,27 @@
*/ */
#include "sfizz/MidiState.h" #include "sfizz/MidiState.h"
#include "sfizz/SfzHelpers.h"
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
using namespace Catch::literals; using namespace Catch::literals;
using namespace sfz::literals;
TEST_CASE("[MidiState] Initial values") TEST_CASE("[MidiState] Initial values")
{ {
sfz::MidiState state; sfz::MidiState state;
for (unsigned cc = 0; cc < sfz::config::numCCs; cc++) for (unsigned cc = 0; cc < sfz::config::numCCs; cc++)
REQUIRE( state.getCCValue(cc) == 0 ); REQUIRE( state.getCCValueNormalized(cc) == 0_norm );
REQUIRE( state.getPitchBend() == 0 ); REQUIRE( state.getPitchBend() == 0 );
} }
TEST_CASE("[MidiState] Set and get CCs") TEST_CASE("[MidiState] Set and get CCs")
{ {
sfz::MidiState state; sfz::MidiState state;
state.ccEvent(0, 24, 23); state.ccEventNormalized(0, 24, 23_norm);
state.ccEvent(0, 123, 124); state.ccEventNormalized(0, 123, 124_norm);
REQUIRE(state.getCCValue(24) == 23); REQUIRE(state.getCCValueNormalized(24) == 23_norm);
REQUIRE(state.getCCValue(123) == 124); REQUIRE(state.getCCValueNormalized(123) == 124_norm);
} }
TEST_CASE("[MidiState] Set and get pitch bends") TEST_CASE("[MidiState] Set and get pitch bends")
@ -45,25 +47,25 @@ TEST_CASE("[MidiState] Reset")
{ {
sfz::MidiState state; sfz::MidiState state;
state.pitchBendEvent(0, 894); state.pitchBendEvent(0, 894);
state.noteOnEvent(0, 64, 24); state.noteOnEventNormalized(0, 64, 24_norm);
state.ccEvent(0, 123, 124); state.ccEventNormalized(0, 123, 124_norm);
state.reset(0); state.reset(0);
REQUIRE(state.getPitchBend() == 0); REQUIRE(state.getPitchBend() == 0);
REQUIRE(state.getNoteVelocity(64) == 0); REQUIRE(state.getNoteVelocityNormalized(64) == 0_norm);
REQUIRE(state.getCCValue(123) == 0); REQUIRE(state.getCCValueNormalized(123) == 0_norm);
} }
TEST_CASE("[MidiState] Set and get note velocities") TEST_CASE("[MidiState] Set and get note velocities")
{ {
sfz::MidiState state; sfz::MidiState state;
state.noteOnEvent(0, 64, 24); state.noteOnEventNormalized(0, 64, 24_norm);
REQUIRE(+state.getNoteVelocity(64) == 24); REQUIRE(+state.getNoteVelocityNormalized(64) == 24_norm);
state.noteOnEvent(0, 64, 123); state.noteOnEventNormalized(0, 64, 123_norm);
REQUIRE(+state.getNoteVelocity(64) == 123); REQUIRE(+state.getNoteVelocityNormalized(64) == 123_norm);
} }
TEST_CASE("[MidiState] Extended CCs") TEST_CASE("[MidiState] Extended CCs")
{ {
sfz::MidiState state; sfz::MidiState state;
state.ccEvent(0, 142, 64); // should not trap state.ccEventNormalized(0, 142, 64_norm); // should not trap
} }

View file

@ -5,8 +5,10 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "sfizz/Region.h" #include "sfizz/Region.h"
#include "sfizz/SfzHelpers.h"
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
using namespace Catch::literals; using namespace Catch::literals;
using namespace sfz::literals;
TEST_CASE("Region activation", "Region tests") TEST_CASE("Region activation", "Region tests")
{ {
@ -16,7 +18,7 @@ TEST_CASE("Region activation", "Region tests")
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
SECTION("Basic state") SECTION("Basic state")
{ {
region.registerCC(4, 0); region.registerCCNormalized(4, 0_norm);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
} }
@ -24,19 +26,19 @@ TEST_CASE("Region activation", "Region tests")
{ {
region.parseOpcode({ "locc4", "56" }); region.parseOpcode({ "locc4", "56" });
region.parseOpcode({ "hicc4", "59" }); region.parseOpcode({ "hicc4", "59" });
region.registerCC(4, 0); region.registerCCNormalized(4, 0_norm);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerCC(4, 57); region.registerCCNormalized(4, 57_norm);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerCC(4, 56); region.registerCCNormalized(4, 56_norm);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerCC(4, 59); region.registerCCNormalized(4, 59_norm);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerCC(4, 43); region.registerCCNormalized(4, 43_norm);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerCC(4, 65); region.registerCCNormalized(4, 65_norm);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerCC(6, 57); region.registerCCNormalized(6, 57_norm);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
} }
@ -46,26 +48,26 @@ TEST_CASE("Region activation", "Region tests")
region.parseOpcode({ "hicc4", "59" }); region.parseOpcode({ "hicc4", "59" });
region.parseOpcode({ "locc54", "18" }); region.parseOpcode({ "locc54", "18" });
region.parseOpcode({ "hicc54", "27" }); region.parseOpcode({ "hicc54", "27" });
region.registerCC(4, 0); region.registerCCNormalized(4, 0_norm);
region.registerCC(54, 0); region.registerCCNormalized(54, 0_norm);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerCC(4, 57); region.registerCCNormalized(4, 57_norm);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerCC(54, 19); region.registerCCNormalized(54, 19_norm);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerCC(54, 18); region.registerCCNormalized(54, 18_norm);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerCC(54, 27); region.registerCCNormalized(54, 27_norm);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerCC(4, 56); region.registerCCNormalized(4, 56_norm);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerCC(4, 59); region.registerCCNormalized(4, 59_norm);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerCC(54, 2); region.registerCCNormalized(54, 2_norm);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerCC(54, 26); region.registerCCNormalized(54, 26_norm);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerCC(4, 65); region.registerCCNormalized(4, 65_norm);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
} }
@ -116,13 +118,13 @@ TEST_CASE("Region activation", "Region tests")
{ {
region.parseOpcode({ "sw_last", "40" }); region.parseOpcode({ "sw_last", "40" });
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOff(40, 64, 0.5f); region.registerNoteOffNormalized(40, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOn(41, 64, 0.5f); region.registerNoteOnNormalized(41, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(41, 0, 0.5f); region.registerNoteOffNormalized(41, 0_norm, 0.5f);
} }
SECTION("Keyswitches: sw_last with non-default keyswitch range") SECTION("Keyswitches: sw_last with non-default keyswitch range")
@ -131,20 +133,20 @@ TEST_CASE("Region activation", "Region tests")
region.parseOpcode({ "sw_hikey", "50" }); region.parseOpcode({ "sw_hikey", "50" });
region.parseOpcode({ "sw_last", "40" }); region.parseOpcode({ "sw_last", "40" });
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(60, 64, 0.5f); region.registerNoteOnNormalized(60, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(60, 0, 0.5f); region.registerNoteOffNormalized(60, 0_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOn(60, 64, 0.5f); region.registerNoteOnNormalized(60, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOff(60, 0, 0.5f); region.registerNoteOffNormalized(60, 0_norm, 0.5f);
region.registerNoteOn(41, 64, 0.5f); region.registerNoteOnNormalized(41, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(41, 0, 0.5f); region.registerNoteOffNormalized(41, 0_norm, 0.5f);
} }
SECTION("Keyswitches: sw_down with non-default keyswitch range") SECTION("Keyswitches: sw_down with non-default keyswitch range")
@ -153,20 +155,20 @@ TEST_CASE("Region activation", "Region tests")
region.parseOpcode({ "sw_hikey", "50" }); region.parseOpcode({ "sw_hikey", "50" });
region.parseOpcode({ "sw_down", "40" }); region.parseOpcode({ "sw_down", "40" });
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(60, 64, 0.5f); region.registerNoteOnNormalized(60, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(60, 0, 0.5f); region.registerNoteOffNormalized(60, 0_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(60, 64, 0.5f); region.registerNoteOnNormalized(60, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(60, 0, 0.5f); region.registerNoteOffNormalized(60, 0_norm, 0.5f);
region.registerNoteOn(41, 64, 0.5f); region.registerNoteOnNormalized(41, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(41, 0, 0.5f); region.registerNoteOffNormalized(41, 0_norm, 0.5f);
} }
SECTION("Keyswitches: sw_up with non-default keyswitch range") SECTION("Keyswitches: sw_up with non-default keyswitch range")
@ -175,16 +177,16 @@ TEST_CASE("Region activation", "Region tests")
region.parseOpcode({ "sw_hikey", "50" }); region.parseOpcode({ "sw_hikey", "50" });
region.parseOpcode({ "sw_up", "40" }); region.parseOpcode({ "sw_up", "40" });
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOn(41, 64, 0.5f); region.registerNoteOnNormalized(41, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
region.registerNoteOff(41, 0, 0.5f); region.registerNoteOffNormalized(41, 0_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
} }
@ -192,20 +194,20 @@ TEST_CASE("Region activation", "Region tests")
{ {
region.parseOpcode({ "sw_previous", "40" }); region.parseOpcode({ "sw_previous", "40" });
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOn(41, 64, 0.5f); region.registerNoteOnNormalized(41, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
region.registerNoteOff(41, 0, 0.5f); region.registerNoteOffNormalized(41, 0_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOn(41, 64, 0.5f); region.registerNoteOnNormalized(41, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(41, 0, 0.5f); region.registerNoteOffNormalized(41, 0_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
} }
@ -215,17 +217,17 @@ TEST_CASE("Region activation", "Region tests")
region.parseOpcode({ "seq_position", "1" }); region.parseOpcode({ "seq_position", "1" });
region.parseOpcode({ "key", "40" }); region.parseOpcode({ "key", "40" });
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
} }
SECTION("Sequences: length 2, position 2") SECTION("Sequences: length 2, position 2")
@ -234,17 +236,17 @@ TEST_CASE("Region activation", "Region tests")
region.parseOpcode({ "seq_position", "2" }); region.parseOpcode({ "seq_position", "2" });
region.parseOpcode({ "key", "40" }); region.parseOpcode({ "key", "40" });
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
} }
SECTION("Sequences: length 3, position 2") SECTION("Sequences: length 3, position 2")
@ -253,21 +255,21 @@ TEST_CASE("Region activation", "Region tests")
region.parseOpcode({ "seq_position", "2" }); region.parseOpcode({ "seq_position", "2" });
region.parseOpcode({ "key", "40" }); region.parseOpcode({ "key", "40" });
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(!region.isSwitchedOn()); REQUIRE(!region.isSwitchedOn());
region.registerNoteOn(40, 64, 0.5f); region.registerNoteOnNormalized(40, 64_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
REQUIRE(region.isSwitchedOn()); REQUIRE(region.isSwitchedOn());
} }
} }

View file

@ -5,8 +5,10 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "sfizz/Region.h" #include "sfizz/Region.h"
#include "sfizz/SfzHelpers.h"
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
using namespace Catch::literals; using namespace Catch::literals;
using namespace sfz::literals;
TEST_CASE("Basic triggers", "Region triggers") TEST_CASE("Basic triggers", "Region triggers")
{ {
@ -17,44 +19,44 @@ TEST_CASE("Basic triggers", "Region triggers")
SECTION("key") SECTION("key")
{ {
region.parseOpcode({ "key", "40" }); region.parseOpcode({ "key", "40" });
REQUIRE(region.registerNoteOn(40, 64, 0.5f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 0.5f));
REQUIRE(!region.registerNoteOff(40, 64, 0.5f)); REQUIRE(!region.registerNoteOffNormalized(40, 64_norm, 0.5f));
REQUIRE(!region.registerNoteOn(41, 64, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(41, 64_norm, 0.5f));
REQUIRE(!region.registerCC(63, 64)); REQUIRE(!region.registerCCNormalized(63, 64_norm));
} }
SECTION("lokey and hikey") SECTION("lokey and hikey")
{ {
region.parseOpcode({ "lokey", "40" }); region.parseOpcode({ "lokey", "40" });
region.parseOpcode({ "hikey", "42" }); region.parseOpcode({ "hikey", "42" });
REQUIRE(!region.registerNoteOn(39, 64, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(39, 64_norm, 0.5f));
REQUIRE(region.registerNoteOn(40, 64, 0.5f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 0.5f));
REQUIRE(!region.registerNoteOff(40, 64, 0.5f)); REQUIRE(!region.registerNoteOffNormalized(40, 64_norm, 0.5f));
REQUIRE(region.registerNoteOn(41, 64, 0.5f)); REQUIRE(region.registerNoteOnNormalized(41, 64_norm, 0.5f));
REQUIRE(region.registerNoteOn(42, 64, 0.5f)); REQUIRE(region.registerNoteOnNormalized(42, 64_norm, 0.5f));
REQUIRE(!region.registerNoteOn(43, 64, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(43, 64_norm, 0.5f));
REQUIRE(!region.registerNoteOff(42, 64, 0.5f)); REQUIRE(!region.registerNoteOffNormalized(42, 64_norm, 0.5f));
REQUIRE(!region.registerNoteOff(42, 64, 0.5f)); REQUIRE(!region.registerNoteOffNormalized(42, 64_norm, 0.5f));
REQUIRE(!region.registerCC(63, 64)); REQUIRE(!region.registerCCNormalized(63, 64_norm));
} }
SECTION("key and release trigger") SECTION("key and release trigger")
{ {
region.parseOpcode({ "key", "40" }); region.parseOpcode({ "key", "40" });
region.parseOpcode({ "trigger", "release" }); region.parseOpcode({ "trigger", "release" });
REQUIRE(!region.registerNoteOn(40, 64, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(40, 64_norm, 0.5f));
REQUIRE(region.registerNoteOff(40, 64, 0.5f)); REQUIRE(region.registerNoteOffNormalized(40, 64_norm, 0.5f));
REQUIRE(!region.registerNoteOn(41, 64, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(41, 64_norm, 0.5f));
REQUIRE(!region.registerNoteOff(41, 64, 0.5f)); REQUIRE(!region.registerNoteOffNormalized(41, 64_norm, 0.5f));
REQUIRE(!region.registerCC(63, 64)); REQUIRE(!region.registerCCNormalized(63, 64_norm));
} }
SECTION("key and release_key trigger") SECTION("key and release_key trigger")
{ {
region.parseOpcode({ "key", "40" }); region.parseOpcode({ "key", "40" });
region.parseOpcode({ "trigger", "release_key" }); region.parseOpcode({ "trigger", "release_key" });
REQUIRE(!region.registerNoteOn(40, 64, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(40, 64_norm, 0.5f));
REQUIRE(region.registerNoteOff(40, 64, 0.5f)); REQUIRE(region.registerNoteOffNormalized(40, 64_norm, 0.5f));
REQUIRE(!region.registerNoteOn(41, 64, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(41, 64_norm, 0.5f));
REQUIRE(!region.registerNoteOff(41, 64, 0.5f)); REQUIRE(!region.registerNoteOffNormalized(41, 64_norm, 0.5f));
REQUIRE(!region.registerCC(63, 64)); REQUIRE(!region.registerCCNormalized(63, 64_norm));
} }
// TODO: first and legato triggers // TODO: first and legato triggers
SECTION("lovel and hivel") SECTION("lovel and hivel")
@ -62,11 +64,11 @@ TEST_CASE("Basic triggers", "Region triggers")
region.parseOpcode({ "key", "40" }); region.parseOpcode({ "key", "40" });
region.parseOpcode({ "lovel", "60" }); region.parseOpcode({ "lovel", "60" });
region.parseOpcode({ "hivel", "70" }); region.parseOpcode({ "hivel", "70" });
REQUIRE(region.registerNoteOn(40, 64, 0.5f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 0.5f));
REQUIRE(region.registerNoteOn(40, 60, 0.5f)); REQUIRE(region.registerNoteOnNormalized(40, 60_norm, 0.5f));
REQUIRE(region.registerNoteOn(40, 70, 0.5f)); REQUIRE(region.registerNoteOnNormalized(40, 70_norm, 0.5f));
REQUIRE(!region.registerNoteOn(41, 71, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(41, 71_norm, 0.5f));
REQUIRE(!region.registerNoteOn(41, 59, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(41, 59_norm, 0.5f));
} }
SECTION("lorand and hirand") SECTION("lorand and hirand")
@ -74,54 +76,54 @@ TEST_CASE("Basic triggers", "Region triggers")
region.parseOpcode({ "key", "40" }); region.parseOpcode({ "key", "40" });
region.parseOpcode({ "lorand", "0.35" }); region.parseOpcode({ "lorand", "0.35" });
region.parseOpcode({ "hirand", "0.40" }); region.parseOpcode({ "hirand", "0.40" });
REQUIRE(!region.registerNoteOn(40, 64, 0.34f)); REQUIRE(!region.registerNoteOnNormalized(40, 64_norm, 0.34f));
REQUIRE(region.registerNoteOn(40, 64, 0.35f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 0.35f));
REQUIRE(region.registerNoteOn(40, 64, 0.36f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 0.36f));
REQUIRE(region.registerNoteOn(40, 64, 0.37f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 0.37f));
REQUIRE(region.registerNoteOn(40, 64, 0.38f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 0.38f));
REQUIRE(region.registerNoteOn(40, 64, 0.39f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 0.39f));
REQUIRE(!region.registerNoteOn(40, 64, 0.40f)); REQUIRE(!region.registerNoteOnNormalized(40, 64_norm, 0.40f));
REQUIRE(!region.registerNoteOn(40, 64, 0.41f)); REQUIRE(!region.registerNoteOnNormalized(40, 64_norm, 0.41f));
} }
SECTION("lorand and hirand on 1.0f") SECTION("lorand and hirand on 1.0f")
{ {
region.parseOpcode({ "key", "40" }); region.parseOpcode({ "key", "40" });
region.parseOpcode({ "lorand", "0.35" }); region.parseOpcode({ "lorand", "0.35" });
REQUIRE(!region.registerNoteOn(40, 64, 0.34f)); REQUIRE(!region.registerNoteOnNormalized(40, 64_norm, 0.34f));
REQUIRE(region.registerNoteOn(40, 64, 0.35f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 0.35f));
REQUIRE(region.registerNoteOn(40, 64, 1.0f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 1.0f));
} }
SECTION("Disable key trigger") SECTION("Disable key trigger")
{ {
region.parseOpcode({ "key", "40" }); region.parseOpcode({ "key", "40" });
REQUIRE(region.registerNoteOn(40, 64, 1.0f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 1.0f));
region.parseOpcode({ "hikey", "-1" }); region.parseOpcode({ "hikey", "-1" });
REQUIRE(!region.registerNoteOn(40, 64, 1.0f)); REQUIRE(!region.registerNoteOnNormalized(40, 64_norm, 1.0f));
region.parseOpcode({ "hikey", "40" }); region.parseOpcode({ "hikey", "40" });
REQUIRE(region.registerNoteOn(40, 64, 1.0f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 1.0f));
region.parseOpcode({ "key", "-1" }); region.parseOpcode({ "key", "-1" });
REQUIRE(!region.registerNoteOn(40, 64, 1.0f)); REQUIRE(!region.registerNoteOnNormalized(40, 64_norm, 1.0f));
region.parseOpcode({ "key", "40" }); region.parseOpcode({ "key", "40" });
REQUIRE(region.registerNoteOn(40, 64, 1.0f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 1.0f));
} }
SECTION("on_loccN, on_hiccN") SECTION("on_loccN, on_hiccN")
{ {
region.parseOpcode({ "on_locc47", "64" }); region.parseOpcode({ "on_locc47", "64" });
region.parseOpcode({ "on_hicc47", "68" }); region.parseOpcode({ "on_hicc47", "68" });
REQUIRE(!region.registerCC(47, 63)); REQUIRE(!region.registerCCNormalized(47, 63_norm));
REQUIRE(!region.registerCC(47, 64)); REQUIRE(!region.registerCCNormalized(47, 64_norm));
REQUIRE(!region.registerCC(47, 65)); REQUIRE(!region.registerCCNormalized(47, 65_norm));
region.parseOpcode({ "hikey", "-1" }); region.parseOpcode({ "hikey", "-1" });
REQUIRE(region.registerCC(47, 64)); REQUIRE(region.registerCCNormalized(47, 64_norm));
REQUIRE(region.registerCC(47, 65)); REQUIRE(region.registerCCNormalized(47, 65_norm));
REQUIRE(region.registerCC(47, 66)); REQUIRE(region.registerCCNormalized(47, 66_norm));
REQUIRE(region.registerCC(47, 67)); REQUIRE(region.registerCCNormalized(47, 67_norm));
REQUIRE(region.registerCC(47, 68)); REQUIRE(region.registerCCNormalized(47, 68_norm));
REQUIRE(!region.registerCC(47, 69)); REQUIRE(!region.registerCCNormalized(47, 69_norm));
REQUIRE(!region.registerCC(40, 64)); REQUIRE(!region.registerCCNormalized(40, 64_norm));
} }
} }
@ -135,16 +137,16 @@ TEST_CASE("Legato triggers", "Region triggers")
region.parseOpcode({ "lokey", "40" }); region.parseOpcode({ "lokey", "40" });
region.parseOpcode({ "hikey", "50" }); region.parseOpcode({ "hikey", "50" });
region.parseOpcode({ "trigger", "first" }); region.parseOpcode({ "trigger", "first" });
midiState.noteOnEvent(0, 40, 64); midiState.noteOnEventNormalized(0, 40, 64_norm);
REQUIRE(region.registerNoteOn(40, 64, 0.5f)); REQUIRE(region.registerNoteOnNormalized(40, 64_norm, 0.5f));
midiState.noteOnEvent(0, 41, 64); midiState.noteOnEventNormalized(0, 41, 64_norm);
REQUIRE(!region.registerNoteOn(41, 64, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(41, 64_norm, 0.5f));
midiState.noteOffEvent(0, 40, 0); midiState.noteOffEventNormalized(0, 40, 0_norm);
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
midiState.noteOffEvent(0, 41, 0); midiState.noteOffEventNormalized(0, 41, 0_norm);
region.registerNoteOff(41, 0, 0.5f); region.registerNoteOffNormalized(41, 0_norm, 0.5f);
midiState.noteOnEvent(0, 42, 64); midiState.noteOnEventNormalized(0, 42, 64_norm);
REQUIRE(region.registerNoteOn(42, 64, 0.5f)); REQUIRE(region.registerNoteOnNormalized(42, 64_norm, 0.5f));
} }
SECTION("Second note playing") SECTION("Second note playing")
@ -152,15 +154,15 @@ TEST_CASE("Legato triggers", "Region triggers")
region.parseOpcode({ "lokey", "40" }); region.parseOpcode({ "lokey", "40" });
region.parseOpcode({ "hikey", "50" }); region.parseOpcode({ "hikey", "50" });
region.parseOpcode({ "trigger", "legato" }); region.parseOpcode({ "trigger", "legato" });
midiState.noteOnEvent(0, 40, 64); midiState.noteOnEventNormalized(0, 40, 64_norm);
REQUIRE(!region.registerNoteOn(40, 64, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(40, 64_norm, 0.5f));
midiState.noteOnEvent(0, 41, 64); midiState.noteOnEventNormalized(0, 41, 64_norm);
REQUIRE(region.registerNoteOn(41, 64, 0.5f)); REQUIRE(region.registerNoteOnNormalized(41, 64_norm, 0.5f));
midiState.noteOffEvent(0, 40, 64); midiState.noteOffEventNormalized(0, 40, 64_norm);
region.registerNoteOff(40, 0, 0.5f); region.registerNoteOffNormalized(40, 0_norm, 0.5f);
midiState.noteOffEvent(0, 41, 64); midiState.noteOffEventNormalized(0, 41, 64_norm);
region.registerNoteOff(41, 0, 0.5f); region.registerNoteOffNormalized(41, 0_norm, 0.5f);
midiState.noteOnEvent(0, 42, 64); midiState.noteOnEventNormalized(0, 42, 64_norm);
REQUIRE(!region.registerNoteOn(42, 64, 0.5f)); REQUIRE(!region.registerNoteOnNormalized(42, 64_norm, 0.5f));
} }
} }

View file

@ -12,6 +12,7 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
using namespace Catch::literals; using namespace Catch::literals;
using namespace sfz::literals;
constexpr int numRandomTests { 64 }; constexpr int numRandomTests { 64 };
TEST_CASE("[Region] Crossfade in on key") TEST_CASE("[Region] Crossfade in on key")
{ {
@ -166,13 +167,13 @@ TEST_CASE("[Region] Crossfade in on CC")
region.parseOpcode({ "xfin_locc24", "20" }); region.parseOpcode({ "xfin_locc24", "20" });
region.parseOpcode({ "xfin_hicc24", "24" }); region.parseOpcode({ "xfin_hicc24", "24" });
region.parseOpcode({ "amp_veltrack", "0" }); region.parseOpcode({ "amp_veltrack", "0" });
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 0.0_a ); midiState.ccEventNormalized(0, 24, 19_norm); REQUIRE( region.getCrossfadeGain() == 0.0_a );
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 0.0_a ); midiState.ccEventNormalized(0, 24, 20_norm); REQUIRE( region.getCrossfadeGain() == 0.0_a );
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.5_a ); midiState.ccEventNormalized(0, 24, 21_norm); REQUIRE( region.getCrossfadeGain() == 0.5_a );
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.70711_a ); midiState.ccEventNormalized(0, 24, 22_norm); REQUIRE( region.getCrossfadeGain() == 0.70711_a );
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.86603_a ); midiState.ccEventNormalized(0, 24, 23_norm); REQUIRE( region.getCrossfadeGain() == 0.86603_a );
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 1.0_a ); midiState.ccEventNormalized(0, 24, 24_norm); REQUIRE( region.getCrossfadeGain() == 1.0_a );
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 1.0_a ); midiState.ccEventNormalized(0, 24, 25_norm); REQUIRE( region.getCrossfadeGain() == 1.0_a );
} }
TEST_CASE("[Region] Crossfade in on CC - gain") TEST_CASE("[Region] Crossfade in on CC - gain")
@ -184,13 +185,13 @@ TEST_CASE("[Region] Crossfade in on CC - gain")
region.parseOpcode({ "xfin_hicc24", "24" }); region.parseOpcode({ "xfin_hicc24", "24" });
region.parseOpcode({ "amp_veltrack", "0" }); region.parseOpcode({ "amp_veltrack", "0" });
region.parseOpcode({ "xf_cccurve", "gain" }); region.parseOpcode({ "xf_cccurve", "gain" });
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 0.0_a ); midiState.ccEventNormalized(0, 24, 19_norm); REQUIRE( region.getCrossfadeGain() == 0.0_a );
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 0.0_a ); midiState.ccEventNormalized(0, 24, 20_norm); REQUIRE( region.getCrossfadeGain() == 0.0_a );
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.25_a ); midiState.ccEventNormalized(0, 24, 21_norm); REQUIRE( region.getCrossfadeGain() == 0.25_a );
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.5_a ); midiState.ccEventNormalized(0, 24, 22_norm); REQUIRE( region.getCrossfadeGain() == 0.5_a );
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.75_a ); midiState.ccEventNormalized(0, 24, 23_norm); REQUIRE( region.getCrossfadeGain() == 0.75_a );
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 1.0_a ); midiState.ccEventNormalized(0, 24, 24_norm); REQUIRE( region.getCrossfadeGain() == 1.0_a );
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 1.0_a ); midiState.ccEventNormalized(0, 24, 25_norm); REQUIRE( region.getCrossfadeGain() == 1.0_a );
} }
TEST_CASE("[Region] Crossfade out on CC") TEST_CASE("[Region] Crossfade out on CC")
{ {
@ -200,13 +201,13 @@ TEST_CASE("[Region] Crossfade out on CC")
region.parseOpcode({ "xfout_locc24", "20" }); region.parseOpcode({ "xfout_locc24", "20" });
region.parseOpcode({ "xfout_hicc24", "24" }); region.parseOpcode({ "xfout_hicc24", "24" });
region.parseOpcode({ "amp_veltrack", "0" }); region.parseOpcode({ "amp_veltrack", "0" });
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 1.0_a ); midiState.ccEventNormalized(0, 24, 19_norm); REQUIRE( region.getCrossfadeGain() == 1.0_a );
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 1.0_a ); midiState.ccEventNormalized(0, 24, 20_norm); REQUIRE( region.getCrossfadeGain() == 1.0_a );
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.86603_a ); midiState.ccEventNormalized(0, 24, 21_norm); REQUIRE( region.getCrossfadeGain() == 0.86603_a );
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.70711_a ); midiState.ccEventNormalized(0, 24, 22_norm); REQUIRE( region.getCrossfadeGain() == 0.70711_a );
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.5_a ); midiState.ccEventNormalized(0, 24, 23_norm); REQUIRE( region.getCrossfadeGain() == 0.5_a );
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 0.0_a ); midiState.ccEventNormalized(0, 24, 24_norm); REQUIRE( region.getCrossfadeGain() == 0.0_a );
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 0.0_a ); midiState.ccEventNormalized(0, 24, 25_norm); REQUIRE( region.getCrossfadeGain() == 0.0_a );
} }
TEST_CASE("[Region] Crossfade out on CC - gain") TEST_CASE("[Region] Crossfade out on CC - gain")
@ -218,13 +219,13 @@ TEST_CASE("[Region] Crossfade out on CC - gain")
region.parseOpcode({ "xfout_hicc24", "24" }); region.parseOpcode({ "xfout_hicc24", "24" });
region.parseOpcode({ "amp_veltrack", "0" }); region.parseOpcode({ "amp_veltrack", "0" });
region.parseOpcode({ "xf_cccurve", "gain" }); region.parseOpcode({ "xf_cccurve", "gain" });
midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 1.0_a ); midiState.ccEventNormalized(0, 24, 19_norm); REQUIRE( region.getCrossfadeGain() == 1.0_a );
midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 1.0_a ); midiState.ccEventNormalized(0, 24, 20_norm); REQUIRE( region.getCrossfadeGain() == 1.0_a );
midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.75_a ); midiState.ccEventNormalized(0, 24, 21_norm); REQUIRE( region.getCrossfadeGain() == 0.75_a );
midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.5_a ); midiState.ccEventNormalized(0, 24, 22_norm); REQUIRE( region.getCrossfadeGain() == 0.5_a );
midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.25_a ); midiState.ccEventNormalized(0, 24, 23_norm); REQUIRE( region.getCrossfadeGain() == 0.25_a );
midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 0.0_a ); midiState.ccEventNormalized(0, 24, 24_norm); REQUIRE( region.getCrossfadeGain() == 0.0_a );
midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 0.0_a ); midiState.ccEventNormalized(0, 24, 25_norm); REQUIRE( region.getCrossfadeGain() == 0.0_a );
} }
TEST_CASE("[Region] Velocity bug for extreme values - veltrack at 0") TEST_CASE("[Region] Velocity bug for extreme values - veltrack at 0")
@ -265,15 +266,15 @@ TEST_CASE("[Region] rt_decay")
region.parseOpcode({ "sample", "*sine" }); region.parseOpcode({ "sample", "*sine" });
region.parseOpcode({ "trigger", "release" }); region.parseOpcode({ "trigger", "release" });
region.parseOpcode({ "rt_decay", "10" }); region.parseOpcode({ "rt_decay", "10" });
midiState.noteOnEvent(0, 64, 64); midiState.noteOnEventNormalized(0, 64, 64_norm);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume - 1.0f).margin(0.1) ); REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume - 1.0f).margin(0.1) );
region.parseOpcode({ "rt_decay", "20" }); region.parseOpcode({ "rt_decay", "20" });
midiState.noteOnEvent(0, 64, 64); midiState.noteOnEventNormalized(0, 64, 64_norm);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume - 2.0f).margin(0.1) ); REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume - 2.0f).margin(0.1) );
region.parseOpcode({ "trigger", "attack" }); region.parseOpcode({ "trigger", "attack" });
midiState.noteOnEvent(0, 64, 64); midiState.noteOnEventNormalized(0, 64, 64_norm);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume).margin(0.1) ); REQUIRE( region.getBaseVolumedB(64) == Approx(sfz::Default::volume).margin(0.1) );
} }

View file

@ -5,8 +5,10 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "sfizz/Synth.h" #include "sfizz/Synth.h"
#include "sfizz/SfzHelpers.h"
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
using namespace Catch::literals; using namespace Catch::literals;
using namespace sfz::literals;
constexpr int blockSize { 256 }; constexpr int blockSize { 256 };
@ -139,9 +141,9 @@ TEST_CASE("[Synth] Reset all controllers")
{ {
sfz::Synth synth; sfz::Synth synth;
synth.cc(0, 12, 64); synth.cc(0, 12, 64);
REQUIRE( synth.getMidiState().getCCValue(12) == 64 ); REQUIRE( synth.getMidiState().getCCValueNormalized(12) == 64_norm );
synth.cc(0, 121, 64); synth.cc(0, 121, 64);
REQUIRE( synth.getMidiState().getCCValue(12) == 0 ); REQUIRE( synth.getMidiState().getCCValueNormalized(12) == 0_norm );
} }
TEST_CASE("[Synth] Releasing before the EG started smoothing (initial delay) kills the voice") TEST_CASE("[Synth] Releasing before the EG started smoothing (initial delay) kills the voice")