Use float velocities in envelopes

This commit is contained in:
Paul Fd 2020-03-26 00:46:58 +01:00 committed by Paul Ferrand
parent de0d86fa09
commit 787fb963f3
6 changed files with 97 additions and 94 deletions

View file

@ -12,7 +12,7 @@
namespace sfz { namespace sfz {
template <class Type> template <class Type>
void ADSREnvelope<Type>::reset(const Region& region, const MidiState& state, int delay, uint8_t velocity, float sampleRate) noexcept void ADSREnvelope<Type>::reset(const Region& region, const MidiState& state, int delay, float velocity, float sampleRate) noexcept
{ {
auto secondsToSamples = [sampleRate](Type timeInSeconds) { auto secondsToSamples = [sampleRate](Type timeInSeconds) {
return static_cast<int>(timeInSeconds * sampleRate); return static_cast<int>(timeInSeconds * sampleRate);

View file

@ -29,7 +29,7 @@ public:
* @param delay * @param delay
* @param velocity * @param velocity
*/ */
void reset(const Region& region, const MidiState& state, int delay, uint8_t velocity, float sampleRate) noexcept; void reset(const Region& region, const MidiState& state, int delay, float velocity, float sampleRate) noexcept;
/** /**
* @brief Get the next value for the envelope * @brief Get the next value for the envelope
* *

View file

@ -32,9 +32,7 @@
#include "MidiState.h" #include "MidiState.h"
#include <absl/types/optional.h> #include <absl/types/optional.h>
namespace sfz {
namespace sfz
{
/** /**
* @brief A description for an SFZ envelope generator, with its envelope parameters * @brief A description for an SFZ envelope generator, with its envelope parameters
* and possible CC modulation. This is a structure to be integrated directly in a * and possible CC modulation. This is a structure to be integrated directly in a
@ -60,36 +58,35 @@ inline float ccSwitchedValue(const MidiState& state, const absl::optional<CCValu
return value; return value;
} }
struct EGDescription struct EGDescription {
{
EGDescription() = default; EGDescription() = default;
EGDescription(const EGDescription&) = default; EGDescription(const EGDescription&) = default;
EGDescription(EGDescription&&) = default; EGDescription(EGDescription&&) = default;
~EGDescription() = default; ~EGDescription() = default;
float attack { Default::attack }; float attack { Default::attack };
float decay { Default::decay }; float decay { Default::decay };
float delay { Default::delayEG }; float delay { Default::delayEG };
float hold { Default::hold }; float hold { Default::hold };
float release { Default::release }; float release { Default::release };
float start { Default::start }; float start { Default::start };
float sustain { Default::sustain }; float sustain { Default::sustain };
int depth { Default::depth }; int depth { Default::depth };
float vel2attack { Default::attack }; float vel2attack { Default::attack };
float vel2decay { Default::decay }; float vel2decay { Default::decay };
float vel2delay { Default::delayEG }; float vel2delay { Default::delayEG };
float vel2hold { Default::hold }; float vel2hold { Default::hold };
float vel2release { Default::vel2release }; float vel2release { Default::vel2release };
float vel2sustain { Default::vel2sustain }; float vel2sustain { Default::vel2sustain };
int vel2depth { Default::depth }; int vel2depth { Default::depth };
absl::optional<CCValuePair<float>> ccAttack; absl::optional<CCValuePair<float>> ccAttack;
absl::optional<CCValuePair<float>> ccDecay; absl::optional<CCValuePair<float>> ccDecay;
absl::optional<CCValuePair<float>> ccDelay; absl::optional<CCValuePair<float>> ccDelay;
absl::optional<CCValuePair<float>> ccHold; absl::optional<CCValuePair<float>> ccHold;
absl::optional<CCValuePair<float>> ccRelease; absl::optional<CCValuePair<float>> ccRelease;
absl::optional<CCValuePair<float>> ccStart; absl::optional<CCValuePair<float>> ccStart;
absl::optional<CCValuePair<float>> ccSustain; absl::optional<CCValuePair<float>> ccSustain;
/** /**
* @brief Get the attack with possibly a CC modifier and a velocity modifier * @brief Get the attack with possibly a CC modifier and a velocity modifier
@ -98,9 +95,10 @@ struct EGDescription
* @param velocity * @param velocity
* @return float * @return float
*/ */
float getAttack(const MidiState &state, uint8_t velocity) const noexcept float getAttack(const MidiState& state, float velocity) const noexcept
{ {
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccAttack, attack) + normalizeVelocity(velocity)*vel2attack); ASSERT(velocity >= 0.0f && velocity <= 1.0f);
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccAttack, attack) + velocity * vel2attack);
} }
/** /**
* @brief Get the decay with possibly a CC modifier and a velocity modifier * @brief Get the decay with possibly a CC modifier and a velocity modifier
@ -109,9 +107,10 @@ struct EGDescription
* @param velocity * @param velocity
* @return float * @return float
*/ */
float getDecay(const MidiState &state, uint8_t velocity) const noexcept float getDecay(const MidiState& state, float velocity) const noexcept
{ {
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccDecay, decay) + normalizeVelocity(velocity)*vel2decay); ASSERT(velocity >= 0.0f && velocity <= 1.0f);
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccDecay, decay) + velocity * vel2decay);
} }
/** /**
* @brief Get the delay with possibly a CC modifier and a velocity modifier * @brief Get the delay with possibly a CC modifier and a velocity modifier
@ -120,9 +119,10 @@ struct EGDescription
* @param velocity * @param velocity
* @return float * @return float
*/ */
float getDelay(const MidiState &state, uint8_t velocity) const noexcept float getDelay(const MidiState& state, float velocity) const noexcept
{ {
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccDelay, delay) + normalizeVelocity(velocity)*vel2delay); ASSERT(velocity >= 0.0f && velocity <= 1.0f);
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccDelay, delay) + velocity * vel2delay);
} }
/** /**
* @brief Get the holding duration with possibly a CC modifier and a velocity modifier * @brief Get the holding duration with possibly a CC modifier and a velocity modifier
@ -131,9 +131,10 @@ struct EGDescription
* @param velocity * @param velocity
* @return float * @return float
*/ */
float getHold(const MidiState &state, uint8_t velocity) const noexcept float getHold(const MidiState& state, float velocity) const noexcept
{ {
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccHold, hold) + normalizeVelocity(velocity)*vel2hold); ASSERT(velocity >= 0.0f && velocity <= 1.0f);
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccHold, hold) + velocity * vel2hold);
} }
/** /**
* @brief Get the release duration with possibly a CC modifier and a velocity modifier * @brief Get the release duration with possibly a CC modifier and a velocity modifier
@ -142,9 +143,10 @@ struct EGDescription
* @param velocity * @param velocity
* @return float * @return float
*/ */
float getRelease(const MidiState &state, uint8_t velocity) const noexcept float getRelease(const MidiState& state, float velocity) const noexcept
{ {
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccRelease, release) + normalizeVelocity(velocity)*vel2release); ASSERT(velocity >= 0.0f && velocity <= 1.0f);
return Default::egTimeRange.clamp(ccSwitchedValue(state, ccRelease, release) + velocity * vel2release);
} }
/** /**
* @brief Get the starting level with possibly a CC modifier and a velocity modifier * @brief Get the starting level with possibly a CC modifier and a velocity modifier
@ -153,7 +155,7 @@ struct EGDescription
* @param velocity * @param velocity
* @return float * @return float
*/ */
float getStart(const MidiState &state, uint8_t velocity) const noexcept float getStart(const MidiState& state, float velocity) const noexcept
{ {
UNUSED(velocity); UNUSED(velocity);
return Default::egPercentRange.clamp(ccSwitchedValue(state, ccStart, start)); return Default::egPercentRange.clamp(ccSwitchedValue(state, ccStart, start));
@ -165,9 +167,10 @@ struct EGDescription
* @param velocity * @param velocity
* @return float * @return float
*/ */
float getSustain(const MidiState &state, uint8_t velocity) const noexcept float getSustain(const MidiState& state, float velocity) const noexcept
{ {
return Default::egPercentRange.clamp(ccSwitchedValue(state, ccSustain, sustain) + normalizeVelocity(velocity)*vel2sustain); ASSERT(velocity >= 0.0f && velocity <= 1.0f);
return Default::egPercentRange.clamp(ccSwitchedValue(state, ccSustain, sustain) + velocity * vel2sustain);
} }
LEAK_DETECTOR(EGDescription); LEAK_DETECTOR(EGDescription);
}; };

View file

@ -140,7 +140,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
initialDelay = delay + static_cast<int>(region->getDelay() * sampleRate); initialDelay = delay + static_cast<int>(region->getDelay() * sampleRate);
baseFrequency = midiNoteFrequency(number); baseFrequency = midiNoteFrequency(number);
bendStepFactor = centsFactor(region->bendStep); bendStepFactor = centsFactor(region->bendStep);
egEnvelope.reset(*region, resources.midiState, delay, denormalize7Bits<uint8_t>(value), sampleRate); egEnvelope.reset(*region, resources.midiState, delay, value, sampleRate);
} }
bool sfz::Voice::isFree() const noexcept bool sfz::Voice::isFree() const noexcept

View file

@ -49,14 +49,14 @@ TEST_CASE("[ADSREnvelope] Attack")
sfz::Region region { state }; sfz::Region region { state };
region.amplitudeEG.attack = 0.02f; region.amplitudeEG.attack = 0.02f;
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
std::array<float, 5> output; std::array<float, 5> output;
std::array<float, 5> expected { 0.5f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array<float, 5> expected { 0.5f, 1.0f, 1.0f, 1.0f, 1.0f };
for (auto& out : output) for (auto& out : output)
out = envelope.getNextValue(); out = envelope.getNextValue();
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
absl::c_fill(output, -1.0f); absl::c_fill(output, -1.0f);
envelope.getBlock(absl::MakeSpan(output)); envelope.getBlock(absl::MakeSpan(output));
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
@ -69,14 +69,14 @@ TEST_CASE("[ADSREnvelope] Attack again")
sfz::Region region { state }; sfz::Region region { state };
region.amplitudeEG.attack = 0.03f; region.amplitudeEG.attack = 0.03f;
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
std::array<float, 5> output; std::array<float, 5> output;
std::array<float, 5> expected { 0.33333f, 0.66667f, 1.0f, 1.0f, 1.0f }; std::array<float, 5> expected { 0.33333f, 0.66667f, 1.0f, 1.0f, 1.0f };
for (auto& out : output) for (auto& out : output)
out = envelope.getNextValue(); out = envelope.getNextValue();
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
absl::c_fill(output, -1.0f); absl::c_fill(output, -1.0f);
envelope.getBlock(absl::MakeSpan(output)); envelope.getBlock(absl::MakeSpan(output));
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
@ -90,7 +90,7 @@ TEST_CASE("[ADSREnvelope] Release")
region.amplitudeEG.attack = 0.02f; region.amplitudeEG.attack = 0.02f;
region.amplitudeEG.release = 0.04f; region.amplitudeEG.release = 0.04f;
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
envelope.startRelease(2); envelope.startRelease(2);
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 0.5f, 1.0f, 0.08409f, 0.00707f, 0.000594604f, 0.00005f, 0.0f, 0.0f }; std::array<float, 8> expected { 0.5f, 1.0f, 0.08409f, 0.00707f, 0.000594604f, 0.00005f, 0.0f, 0.0f };
@ -98,7 +98,7 @@ TEST_CASE("[ADSREnvelope] Release")
out = envelope.getNextValue(); out = envelope.getNextValue();
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
envelope.startRelease(2); envelope.startRelease(2);
absl::c_fill(output, -1.0f); absl::c_fill(output, -1.0f);
envelope.getBlock(absl::MakeSpan(output)); envelope.getBlock(absl::MakeSpan(output));
@ -114,14 +114,14 @@ TEST_CASE("[ADSREnvelope] Delay")
region.amplitudeEG.release = 0.04f; region.amplitudeEG.release = 0.04f;
region.amplitudeEG.delay = 0.02f; region.amplitudeEG.delay = 0.02f;
std::array<float, 10> output; std::array<float, 10> output;
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
envelope.startRelease(4); envelope.startRelease(4);
std::array<float, 10> expected { 0.0f, 0.0f, 0.5f, 1.0f, 0.08409f, 0.00707f, 0.000594604f, 0.00005f, 0.0f, 0.0f }; std::array<float, 10> expected { 0.0f, 0.0f, 0.5f, 1.0f, 0.08409f, 0.00707f, 0.000594604f, 0.00005f, 0.0f, 0.0f };
for (auto& out : output) for (auto& out : output)
out = envelope.getNextValue(); out = envelope.getNextValue();
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
envelope.startRelease(4); envelope.startRelease(4);
absl::c_fill(output, -1.0f); absl::c_fill(output, -1.0f);
envelope.getBlock(absl::MakeSpan(output)); envelope.getBlock(absl::MakeSpan(output));
@ -138,13 +138,13 @@ TEST_CASE("[ADSREnvelope] Lower sustain")
region.amplitudeEG.delay = 0.02f; region.amplitudeEG.delay = 0.02f;
region.amplitudeEG.sustain = 50.0f; region.amplitudeEG.sustain = 50.0f;
std::array<float, 10> output; std::array<float, 10> output;
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
std::array<float, 10> expected { 0.0f, 0.0f, 0.5f, 1.0f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f }; std::array<float, 10> expected { 0.0f, 0.0f, 0.5f, 1.0f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f };
for (auto& out : output) for (auto& out : output)
out = envelope.getNextValue(); out = envelope.getNextValue();
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
absl::c_fill(output, -1.0f); absl::c_fill(output, -1.0f);
envelope.getBlock(absl::MakeSpan(output)); envelope.getBlock(absl::MakeSpan(output));
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
@ -161,13 +161,13 @@ TEST_CASE("[ADSREnvelope] Decay")
region.amplitudeEG.sustain = 50.0f; region.amplitudeEG.sustain = 50.0f;
region.amplitudeEG.decay = 0.02f; region.amplitudeEG.decay = 0.02f;
std::array<float, 10> output; std::array<float, 10> output;
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
std::array<float, 10> expected { 0.0f, 0.0f, 0.5f, 1.0f, 0.707107f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5 }; std::array<float, 10> expected { 0.0f, 0.0f, 0.5f, 1.0f, 0.707107f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5 };
for (auto& out : output) for (auto& out : output)
out = envelope.getNextValue(); out = envelope.getNextValue();
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
absl::c_fill(output, -1.0f); absl::c_fill(output, -1.0f);
envelope.getBlock(absl::MakeSpan(output)); envelope.getBlock(absl::MakeSpan(output));
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
@ -185,13 +185,13 @@ TEST_CASE("[ADSREnvelope] Hold")
region.amplitudeEG.decay = 0.02f; region.amplitudeEG.decay = 0.02f;
region.amplitudeEG.hold = 0.02f; region.amplitudeEG.hold = 0.02f;
std::array<float, 12> output; std::array<float, 12> output;
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
std::array<float, 12> expected { 0.0f, 0.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.707107f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f }; std::array<float, 12> expected { 0.0f, 0.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.707107f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f };
for (auto& out : output) for (auto& out : output)
out = envelope.getNextValue(); out = envelope.getNextValue();
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
absl::c_fill(output, -1.0f); absl::c_fill(output, -1.0f);
envelope.getBlock(absl::MakeSpan(output)); envelope.getBlock(absl::MakeSpan(output));
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
@ -208,7 +208,7 @@ TEST_CASE("[ADSREnvelope] Hold with release")
region.amplitudeEG.sustain = 50.0f; region.amplitudeEG.sustain = 50.0f;
region.amplitudeEG.decay = 0.02f; region.amplitudeEG.decay = 0.02f;
region.amplitudeEG.hold = 0.02f; region.amplitudeEG.hold = 0.02f;
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
envelope.startRelease(8); envelope.startRelease(8);
std::array<float, 14> output; std::array<float, 14> output;
std::array<float, 14> expected { 0.0f, 0.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.707107f, 0.5f, 0.05f, 0.005f, 0.0005f, 0.00005f, 0.0f, 0.0f }; std::array<float, 14> expected { 0.0f, 0.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.707107f, 0.5f, 0.05f, 0.005f, 0.0005f, 0.00005f, 0.0f, 0.0f };
@ -216,7 +216,7 @@ TEST_CASE("[ADSREnvelope] Hold with release")
out = envelope.getNextValue(); out = envelope.getNextValue();
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
envelope.startRelease(8); envelope.startRelease(8);
absl::c_fill(output, -1.0f); absl::c_fill(output, -1.0f);
envelope.getBlock(absl::MakeSpan(output)); envelope.getBlock(absl::MakeSpan(output));
@ -234,14 +234,14 @@ TEST_CASE("[ADSREnvelope] Hold with release 2")
region.amplitudeEG.sustain = 50.0f; region.amplitudeEG.sustain = 50.0f;
region.amplitudeEG.decay = 0.02f; region.amplitudeEG.decay = 0.02f;
region.amplitudeEG.hold = 0.02f; region.amplitudeEG.hold = 0.02f;
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
envelope.startRelease(4); envelope.startRelease(4);
std::array<float, 14> output; std::array<float, 14> output;
std::array<float, 14> expected { 0.0f, 0.0f, 0.5f, 1.0f, 0.08409f, 0.00707f, 0.000594604f, 0.00005f, 0.0f, 0.0f, 0.0f, 0.0 }; std::array<float, 14> expected { 0.0f, 0.0f, 0.5f, 1.0f, 0.08409f, 0.00707f, 0.000594604f, 0.00005f, 0.0f, 0.0f, 0.0f, 0.0 };
for (auto& out : output) for (auto& out : output)
out = envelope.getNextValue(); out = envelope.getNextValue();
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
envelope.reset(region, state, 0, 0, 100.0f); envelope.reset(region, state, 0, 0.0f, 100.0f);
envelope.startRelease(4); envelope.startRelease(4);
absl::c_fill(output, -1.0f); absl::c_fill(output, -1.0f);
envelope.getBlock(absl::MakeSpan(output)); envelope.getBlock(absl::MakeSpan(output));

View file

@ -18,13 +18,13 @@ TEST_CASE("[EGDescription] Attack range")
eg.attack = 1; eg.attack = 1;
eg.vel2attack = -1.27f; eg.vel2attack = -1.27f;
eg.ccAttack = { 63, 1.27f }; eg.ccAttack = { 63, 1.27f };
REQUIRE( eg.getAttack(state, 0) == 1.0f ); REQUIRE( eg.getAttack(state, 0_norm) == 1.0f );
REQUIRE( eg.getAttack(state, 127) == 0.0f ); REQUIRE( eg.getAttack(state, 127_norm) == 0.0f );
state.ccEvent(0, 63, 127_norm); state.ccEvent(0, 63, 127_norm);
REQUIRE( eg.getAttack(state, 127) == 1.0f ); REQUIRE( eg.getAttack(state, 127_norm) == 1.0f );
REQUIRE( eg.getAttack(state, 0) == 2.27f ); REQUIRE( eg.getAttack(state, 0_norm) == 2.27f );
eg.ccAttack = { 63, 127.0f }; eg.ccAttack = { 63, 127.0f };
REQUIRE( eg.getAttack(state, 0) == 100.0f ); REQUIRE( eg.getAttack(state, 0_norm) == 100.0f );
} }
TEST_CASE("[EGDescription] Delay range") TEST_CASE("[EGDescription] Delay range")
@ -34,13 +34,13 @@ TEST_CASE("[EGDescription] Delay range")
eg.delay = 1; eg.delay = 1;
eg.vel2delay = -1.27f; eg.vel2delay = -1.27f;
eg.ccDelay = { 63, 1.27f }; eg.ccDelay = { 63, 1.27f };
REQUIRE( eg.getDelay(state, 0) == 1.0f ); REQUIRE( eg.getDelay(state, 0_norm) == 1.0f );
REQUIRE( eg.getDelay(state, 127) == 0.0f ); REQUIRE( eg.getDelay(state, 127_norm) == 0.0f );
state.ccEvent(0, 63, 127_norm); state.ccEvent(0, 63, 127_norm);
REQUIRE( eg.getDelay(state, 127) == 1.0f ); REQUIRE( eg.getDelay(state, 127_norm) == 1.0f );
REQUIRE( eg.getDelay(state, 0) == 2.27f ); REQUIRE( eg.getDelay(state, 0_norm) == 2.27f );
eg.ccDelay = { 63, 127.0f }; eg.ccDelay = { 63, 127.0f };
REQUIRE( eg.getDelay(state, 0) == 100.0f ); REQUIRE( eg.getDelay(state, 0_norm) == 100.0f );
} }
TEST_CASE("[EGDescription] Decay range") TEST_CASE("[EGDescription] Decay range")
@ -50,13 +50,13 @@ TEST_CASE("[EGDescription] Decay range")
eg.decay = 1.0f; eg.decay = 1.0f;
eg.vel2decay = -1.27f; eg.vel2decay = -1.27f;
eg.ccDecay = { 63, 1.27f }; eg.ccDecay = { 63, 1.27f };
REQUIRE( eg.getDecay(state, 0) == 1.0f ); REQUIRE( eg.getDecay(state, 0_norm) == 1.0f );
REQUIRE( eg.getDecay(state, 127) == 0.0f ); REQUIRE( eg.getDecay(state, 127_norm) == 0.0f );
state.ccEvent(0, 63, 127_norm); state.ccEvent(0, 63, 127_norm);
REQUIRE( eg.getDecay(state, 127) == 1.0f ); REQUIRE( eg.getDecay(state, 127_norm) == 1.0f );
REQUIRE( eg.getDecay(state, 0) == 2.27f ); REQUIRE( eg.getDecay(state, 0_norm) == 2.27f );
eg.ccDecay = { 63, 127.0f }; eg.ccDecay = { 63, 127.0f };
REQUIRE( eg.getDecay(state, 0) == 100.0f ); REQUIRE( eg.getDecay(state, 0_norm) == 100.0f );
} }
TEST_CASE("[EGDescription] Release range") TEST_CASE("[EGDescription] Release range")
@ -66,13 +66,13 @@ TEST_CASE("[EGDescription] Release range")
eg.release = 1; eg.release = 1;
eg.vel2release = -1.27f; eg.vel2release = -1.27f;
eg.ccRelease = { 63, 1.27f }; eg.ccRelease = { 63, 1.27f };
REQUIRE( eg.getRelease(state, 0) == 1.0f ); REQUIRE( eg.getRelease(state, 0_norm) == 1.0f );
REQUIRE( eg.getRelease(state, 127) == 0.0f ); REQUIRE( eg.getRelease(state, 127_norm) == 0.0f );
state.ccEvent(0, 63, 127_norm); state.ccEvent(0, 63, 127_norm);
REQUIRE( eg.getRelease(state, 127) == 1.0f ); REQUIRE( eg.getRelease(state, 127_norm) == 1.0f );
REQUIRE( eg.getRelease(state, 0) == 2.27f ); REQUIRE( eg.getRelease(state, 0_norm) == 2.27f );
eg.ccRelease = { 63, 127.0f }; eg.ccRelease = { 63, 127.0f };
REQUIRE( eg.getRelease(state, 0) == 100.0f ); REQUIRE( eg.getRelease(state, 0_norm) == 100.0f );
} }
TEST_CASE("[EGDescription] Hold range") TEST_CASE("[EGDescription] Hold range")
@ -82,13 +82,13 @@ TEST_CASE("[EGDescription] Hold range")
eg.hold = 1; eg.hold = 1;
eg.vel2hold = -1.27f; eg.vel2hold = -1.27f;
eg.ccHold = { 63, 1.27f }; eg.ccHold = { 63, 1.27f };
REQUIRE( eg.getHold(state, 0) == 1.0f ); REQUIRE( eg.getHold(state, 0_norm) == 1.0f );
REQUIRE( eg.getHold(state, 127) == 0.0f ); REQUIRE( eg.getHold(state, 127_norm) == 0.0f );
state.ccEvent(0, 63, 127_norm); state.ccEvent(0, 63, 127_norm);
REQUIRE( eg.getHold(state, 127) == 1.0f ); REQUIRE( eg.getHold(state, 127_norm) == 1.0f );
REQUIRE( eg.getHold(state, 0) == 2.27f ); REQUIRE( eg.getHold(state, 0_norm) == 2.27f );
eg.ccHold = { 63, 127.0f }; eg.ccHold = { 63, 127.0f };
REQUIRE( eg.getHold(state, 0) == 100.0f ); REQUIRE( eg.getHold(state, 0_norm) == 100.0f );
} }
TEST_CASE("[EGDescription] Sustain level") TEST_CASE("[EGDescription] Sustain level")
@ -98,12 +98,12 @@ TEST_CASE("[EGDescription] Sustain level")
eg.sustain = 50; eg.sustain = 50;
eg.vel2sustain = -100; eg.vel2sustain = -100;
eg.ccSustain = { 63, 100.0f }; eg.ccSustain = { 63, 100.0f };
REQUIRE( eg.getSustain(state, 0) == 50.0f ); REQUIRE( eg.getSustain(state, 0_norm) == 50.0f );
REQUIRE( eg.getSustain(state, 127) == 0.0f ); REQUIRE( eg.getSustain(state, 127_norm) == 0.0f );
state.ccEvent(0, 63, 127_norm); state.ccEvent(0, 63, 127_norm);
REQUIRE( eg.getSustain(state, 127) == 50.0f ); REQUIRE( eg.getSustain(state, 127_norm) == 50.0f );
eg.ccSustain = { 63, 200.0f }; eg.ccSustain = { 63, 200.0f };
REQUIRE( eg.getSustain(state, 0) == 100.0f ); REQUIRE( eg.getSustain(state, 0_norm) == 100.0f );
} }
TEST_CASE("[EGDescription] Start level") TEST_CASE("[EGDescription] Start level")
@ -112,10 +112,10 @@ TEST_CASE("[EGDescription] Start level")
sfz::MidiState state; sfz::MidiState state;
eg.start = 0; eg.start = 0;
eg.ccStart = { 63, 127.0f }; eg.ccStart = { 63, 127.0f };
REQUIRE( eg.getStart(state, 0) == 0.0f ); REQUIRE( eg.getStart(state, 0_norm) == 0.0f );
REQUIRE( eg.getStart(state, 127) == 0.0f ); REQUIRE( eg.getStart(state, 127_norm) == 0.0f );
state.ccEvent(0, 63, 127_norm); state.ccEvent(0, 63, 127_norm);
REQUIRE( eg.getStart(state, 0) == 100.0f ); REQUIRE( eg.getStart(state, 0_norm) == 100.0f );
eg.ccStart = { 63, -127.0f }; eg.ccStart = { 63, -127.0f };
REQUIRE( eg.getStart(state, 0) == 0.0f ); REQUIRE( eg.getStart(state, 0_norm) == 0.0f );
} }