diff --git a/src/sfizz/ADSREnvelope.cpp b/src/sfizz/ADSREnvelope.cpp index 96333be2..21a76cf9 100644 --- a/src/sfizz/ADSREnvelope.cpp +++ b/src/sfizz/ADSREnvelope.cpp @@ -18,15 +18,14 @@ void ADSREnvelope::reset(const Region& region, const MidiState& state, int return static_cast(timeInSeconds * sampleRate); }; - const auto ccArray = state.getCCArray(); - this->delay = delay + secondsToSamples(region.amplitudeEG.getDelay(ccArray, velocity)); - this->attack = secondsToSamples(region.amplitudeEG.getAttack(ccArray, velocity)); - this->decay = secondsToSamples(region.amplitudeEG.getDecay(ccArray, velocity)); - this->release = secondsToSamples(region.amplitudeEG.getRelease(ccArray, velocity)); - this->hold = secondsToSamples(region.amplitudeEG.getHold(ccArray, velocity)); + this->delay = delay + secondsToSamples(region.amplitudeEG.getDelay(state, velocity)); + this->attack = secondsToSamples(region.amplitudeEG.getAttack(state, velocity)); + this->decay = secondsToSamples(region.amplitudeEG.getDecay(state, velocity)); + this->release = secondsToSamples(region.amplitudeEG.getRelease(state, velocity)); + this->hold = secondsToSamples(region.amplitudeEG.getHold(state, velocity)); this->peak = 1.0; - this->sustain = normalizePercents(region.amplitudeEG.getSustain(ccArray, velocity)); - this->start = this->peak * normalizePercents(region.amplitudeEG.getStart(ccArray, velocity)); + this->sustain = normalizePercents(region.amplitudeEG.getSustain(state, velocity)); + this->start = this->peak * normalizePercents(region.amplitudeEG.getStart(state, velocity)); releaseDelay = 0; shouldRelease = false; diff --git a/src/sfizz/EGDescription.h b/src/sfizz/EGDescription.h index f9c422f7..afdc99f5 100644 --- a/src/sfizz/EGDescription.h +++ b/src/sfizz/EGDescription.h @@ -29,6 +29,7 @@ #include "Macros.h" #include "LeakDetector.h" #include "SfzHelpers.h" +#include "MidiState.h" #include @@ -42,6 +43,23 @@ namespace sfz * TODO: should be updated for SFZ v2 * */ + +/** + * @brief If a cc switch exists for the value, returns the value with the CC modifier, otherwise returns the value alone. + * + * @param ccValues + * @param ccSwitch + * @param value + * @return float + */ +inline float ccSwitchedValue(const MidiState& state, const absl::optional>& ccSwitch, float value) noexcept +{ + if (ccSwitch) + return value + ccSwitch->value * normalizeCC(state.getCCValue(ccSwitch->cc)); + else + return value; +} + struct EGDescription { EGDescription() = default; @@ -76,80 +94,80 @@ struct EGDescription /** * @brief Get the attack with possibly a CC modifier and a velocity modifier * - * @param ccValues + * @param state * @param velocity * @return float */ - float getAttack(const SfzCCArray &ccValues, uint8_t velocity) const noexcept + float getAttack(const MidiState &state, uint8_t velocity) const noexcept { - return Default::egTimeRange.clamp(ccSwitchedValue(ccValues, ccAttack, attack) + normalizeVelocity(velocity)*vel2attack); + return Default::egTimeRange.clamp(ccSwitchedValue(state, ccAttack, attack) + normalizeVelocity(velocity)*vel2attack); } /** * @brief Get the decay with possibly a CC modifier and a velocity modifier * - * @param ccValues + * @param state * @param velocity * @return float */ - float getDecay(const SfzCCArray &ccValues, uint8_t velocity) const noexcept + float getDecay(const MidiState &state, uint8_t velocity) const noexcept { - return Default::egTimeRange.clamp(ccSwitchedValue(ccValues, ccDecay, decay) + normalizeVelocity(velocity)*vel2decay); + return Default::egTimeRange.clamp(ccSwitchedValue(state, ccDecay, decay) + normalizeVelocity(velocity)*vel2decay); } /** * @brief Get the delay with possibly a CC modifier and a velocity modifier * - * @param ccValues + * @param state * @param velocity * @return float */ - float getDelay(const SfzCCArray &ccValues, uint8_t velocity) const noexcept + float getDelay(const MidiState &state, uint8_t velocity) const noexcept { - return Default::egTimeRange.clamp(ccSwitchedValue(ccValues, ccDelay, delay) + normalizeVelocity(velocity)*vel2delay); + return Default::egTimeRange.clamp(ccSwitchedValue(state, ccDelay, delay) + normalizeVelocity(velocity)*vel2delay); } /** * @brief Get the holding duration with possibly a CC modifier and a velocity modifier * - * @param ccValues + * @param state * @param velocity * @return float */ - float getHold(const SfzCCArray &ccValues, uint8_t velocity) const noexcept + float getHold(const MidiState &state, uint8_t velocity) const noexcept { - return Default::egTimeRange.clamp(ccSwitchedValue(ccValues, ccHold, hold) + normalizeVelocity(velocity)*vel2hold); + return Default::egTimeRange.clamp(ccSwitchedValue(state, ccHold, hold) + normalizeVelocity(velocity)*vel2hold); } /** * @brief Get the release duration with possibly a CC modifier and a velocity modifier * - * @param ccValues + * @param state * @param velocity * @return float */ - float getRelease(const SfzCCArray &ccValues, uint8_t velocity) const noexcept + float getRelease(const MidiState &state, uint8_t velocity) const noexcept { - return Default::egTimeRange.clamp(ccSwitchedValue(ccValues, ccRelease, release) + normalizeVelocity(velocity)*vel2release); + return Default::egTimeRange.clamp(ccSwitchedValue(state, ccRelease, release) + normalizeVelocity(velocity)*vel2release); } /** * @brief Get the starting level with possibly a CC modifier and a velocity modifier * - * @param ccValues + * @param state * @param velocity * @return float */ - float getStart(const SfzCCArray &ccValues, uint8_t velocity) const noexcept + float getStart(const MidiState &state, uint8_t velocity) const noexcept { UNUSED(velocity); - return Default::egPercentRange.clamp(ccSwitchedValue(ccValues, ccStart, start)); + return Default::egPercentRange.clamp(ccSwitchedValue(state, ccStart, start)); } /** * @brief Get the sustain level with possibly a CC modifier and a velocity modifier * - * @param ccValues + * @param state * @param velocity * @return float */ - float getSustain(const SfzCCArray &ccValues, uint8_t velocity) const noexcept + float getSustain(const MidiState &state, uint8_t velocity) const noexcept { - return Default::egPercentRange.clamp(ccSwitchedValue(ccValues, ccSustain, sustain) + normalizeVelocity(velocity)*vel2sustain); + return Default::egPercentRange.clamp(ccSwitchedValue(state, ccSustain, sustain) + normalizeVelocity(velocity)*vel2sustain); } LEAK_DETECTOR(EGDescription); }; diff --git a/src/sfizz/MidiState.cpp b/src/sfizz/MidiState.cpp index 23fd7ab9..475a8352 100644 --- a/src/sfizz/MidiState.cpp +++ b/src/sfizz/MidiState.cpp @@ -14,9 +14,19 @@ sfz::MidiState::MidiState() } void sfz::MidiState::noteOnEvent(int delay, int noteNumber, uint8_t velocity) noexcept +{ + noteOnEventNormalized(delay, noteNumber, normalizeVelocity(velocity)); +} + +void sfz::MidiState::noteOffEvent(int delay, int noteNumber, uint8_t velocity) noexcept +{ + noteOffEventNormalized(delay, noteNumber, normalizeVelocity(velocity)); +} + +void sfz::MidiState::noteOnEventNormalized(int delay, int noteNumber, float velocity) noexcept { ASSERT(noteNumber >= 0 && noteNumber <= 127); - ASSERT(velocity >= 0 && velocity <= 127); + ASSERT(velocity >= 0 && velocity <= 1.0); if (noteNumber >= 0 && noteNumber < 128) { lastNoteVelocities[noteNumber] = velocity; @@ -26,10 +36,10 @@ void sfz::MidiState::noteOnEvent(int delay, int noteNumber, uint8_t velocity) no } -void sfz::MidiState::noteOffEvent(int delay, int noteNumber, uint8_t velocity) noexcept +void sfz::MidiState::noteOffEventNormalized(int delay, int noteNumber, float velocity) noexcept { ASSERT(noteNumber >= 0 && noteNumber <= 127); - ASSERT(velocity >= 0 && velocity <= 127); + ASSERT(velocity >= 0.0 && velocity <= 1.0); UNUSED(velocity); if (noteNumber >= 0 && noteNumber < 128) { if (activeNotes > 0) @@ -52,12 +62,18 @@ float sfz::MidiState::getNoteDuration(int noteNumber) const } uint8_t sfz::MidiState::getNoteVelocity(int noteNumber) const noexcept +{ + return denormalizeVelocity(getNoteVelocityNormalized(noteNumber)); +} + +float sfz::MidiState::getNoteVelocityNormalized(int noteNumber) const noexcept { ASSERT(noteNumber >= 0 && noteNumber <= 127); return lastNoteVelocities[noteNumber]; } + void sfz::MidiState::pitchBendEvent(int delay, int pitchBendValue) noexcept { ASSERT(pitchBendValue >= -8192 && pitchBendValue <= 8192); @@ -72,24 +88,28 @@ int sfz::MidiState::getPitchBend() const noexcept void sfz::MidiState::ccEvent(int delay, int ccNumber, uint8_t ccValue) noexcept { - ASSERT(ccNumber >= 0 && ccNumber < config::numCCs); - ASSERT(ccValue >= 0 && ccValue <= 127); - - cc[ccNumber] = ccValue; + ccEventNormalized(delay, ccNumber, normalizeCC(ccValue)); } uint8_t sfz::MidiState::getCCValue(int ccNumber) const noexcept +{ + return denormalizeCC(getCCValueNormalized(ccNumber)); +} + +void sfz::MidiState::ccEventNormalized(int delay, int ccNumber, float ccValue) noexcept +{ + ASSERT(ccValue >= 0.0 && ccValue <= 1.0); + + cc[ccNumber] = ccValue; +} + +float sfz::MidiState::getCCValueNormalized(int ccNumber) const noexcept { ASSERT(ccNumber >= 0 && ccNumber < config::numCCs); return cc[ccNumber]; } -const sfz::SfzCCArray& sfz::MidiState::getCCArray() const noexcept -{ - return cc; -} - void sfz::MidiState::reset(int delay) noexcept { for (auto& velocity: lastNoteVelocities) diff --git a/src/sfizz/MidiState.h b/src/sfizz/MidiState.h index badb0e17..63d9b765 100644 --- a/src/sfizz/MidiState.h +++ b/src/sfizz/MidiState.h @@ -7,7 +7,6 @@ #pragma once #include #include -#include "SfzHelpers.h" #include "CCMap.h" #include "Range.h" @@ -31,6 +30,14 @@ public: */ void noteOnEvent(int delay, int noteNumber, uint8_t velocity) noexcept; + /** + * @brief Update the state after a note on event + * + * @param noteNumber + * @param velocity + */ + void noteOnEventNormalized(int delay, int noteNumber, float velocity) noexcept; + /** * @brief Update the state after a note off event * @@ -39,6 +46,14 @@ public: */ void noteOffEvent(int delay, int noteNumber, uint8_t velocity) noexcept; + /** + * @brief Update the state after a note off event + * + * @param noteNumber + * @param velocity + */ + void noteOffEventNormalized(int delay, int noteNumber, float velocity) noexcept; + int getActiveNotes() const noexcept { return activeNotes; } /** @@ -57,6 +72,14 @@ public: */ uint8_t getNoteVelocity(int noteNumber) const noexcept; + /** + * @brief Get the note on velocity for a given note + * + * @param noteNumber + * @return float + */ + float getNoteVelocityNormalized(int noteNumber) const noexcept; + /** * @brief Register a pitch bend event * @@ -79,6 +102,14 @@ public: */ void ccEvent(int delay, int ccNumber, uint8_t ccValue) noexcept; + /** + * @brief Register a CC event + * + * @param ccNumber + * @param ccValue + */ + void ccEventNormalized(int delay, int ccNumber, float ccValue) noexcept; + /** * @brief Get the CC value for CC number * @@ -88,11 +119,12 @@ public: uint8_t getCCValue(int ccNumber) const noexcept; /** - * @brief Get the full CC status + * @brief Get the CC value for CC number * - * @return const SfzCCArray& + * @param ccNumber + * @return float */ - const SfzCCArray& getCCArray() const noexcept; + float getCCValueNormalized(int ccNumber) const noexcept; /** * @brief Reset the midi state (does not impact the last note on time) @@ -140,12 +172,12 @@ private: * depressed notes. * */ - MidiNoteArray lastNoteVelocities; + MidiNoteArray lastNoteVelocities; /** * @brief Current known values for the CCs. * */ - SfzCCArray cc; + std::array cc; /** * Pitch bend status */ diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 808f031e..13df28d2 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -1009,19 +1009,19 @@ float sfz::Region::getNoteGain(int noteNumber, uint8_t velocity) const noexcept return baseGain; } -float sfz::Region::getCrossfadeGain(const sfz::SfzCCArray& ccState) const noexcept +float sfz::Region::getCrossfadeGain() const noexcept { float gain { 1.0f }; // Crossfades due to CC states for (const auto& valuePair : crossfadeCCInRange) { - const auto ccValue = ccState[valuePair.cc]; + const auto ccValue = midiState.getCCValue(valuePair.cc); const auto crossfadeRange = valuePair.value; gain *= crossfadeIn(crossfadeRange, ccValue, crossfadeCCCurve); } for (const auto& valuePair : crossfadeCCOutRange) { - const auto ccValue = ccState[valuePair.cc]; + const auto ccValue = midiState.getCCValue(valuePair.cc); const auto crossfadeRange = valuePair.value; gain *= crossfadeOut(crossfadeRange, ccValue, crossfadeCCCurve); } diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 1fd0fa67..47a6dfe6 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -152,7 +152,7 @@ struct Region { * @param ccState * @return float */ - float getCrossfadeGain(const SfzCCArray& ccState) const noexcept; + float getCrossfadeGain() const noexcept; /** * @brief Get the base volume of the region depending on which note has been * pressed to trigger the region. diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index 173eec03..a8126858 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -18,7 +18,6 @@ namespace sfz { -using SfzCCArray = std::array; using CCNamePair = std::pair; template @@ -83,6 +82,16 @@ constexpr T denormalize7Bits(float value) return static_cast(value * 127.0f); } +constexpr uint8_t denormalizeCC(float value) +{ + return denormalize7Bits(value); +} + +constexpr uint8_t denormalizeVelocity(float value) +{ + return denormalize7Bits(value); +} + template constexpr float normalize7Bits(T value) { @@ -141,22 +150,6 @@ constexpr float normalizeBend(float bendValue) return min(max(bendValue, -8191.0f), 8191.0f) / 8191.0f; } -/** - * @brief If a cc switch exists for the value, returns the value with the CC modifier, otherwise returns the value alone. - * - * @param ccValues - * @param ccSwitch - * @param value - * @return float - */ -inline float ccSwitchedValue(const SfzCCArray& ccValues, const absl::optional>& ccSwitch, float value) noexcept -{ - if (ccSwitch) - return value + ccSwitch->value * normalizeCC(ccValues[ccSwitch->cc]); - else - return value; -} - /** * @brief Convert a note in string to its equivalent midi note number * diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index e86375f2..71a06159 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -89,7 +89,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, uint8_t value gain += normalizeCC(resources.midiState.getCCValue(region->amplitudeCC->cc)) * normalizePercents(region->amplitudeCC->value); amplitudeEnvelope.reset(Default::normalizedRange.clamp(gain)); - float crossfadeGain { region->getCrossfadeGain(resources.midiState.getCCArray()) }; + float crossfadeGain { region->getCrossfadeGain() }; crossfadeEnvelope.reset(Default::normalizedRange.clamp(crossfadeGain)); basePan = normalizePercents(region->pan); @@ -225,7 +225,7 @@ void sfz::Voice::registerCC(int delay, int ccNumber, uint8_t ccValue) noexcept } if (region->crossfadeCCInRange.contains(ccNumber) || region->crossfadeCCOutRange.contains(ccNumber)) { - const float crossfadeGain = region->getCrossfadeGain(resources.midiState.getCCArray()); + const float crossfadeGain = region->getCrossfadeGain(); crossfadeEnvelope.registerEvent(delay, Default::normalizedRange.clamp(crossfadeGain)); } } diff --git a/tests/EGDescriptionT.cpp b/tests/EGDescriptionT.cpp index 70ce49ee..4e933e75 100644 --- a/tests/EGDescriptionT.cpp +++ b/tests/EGDescriptionT.cpp @@ -12,108 +12,108 @@ using namespace Catch::literals; TEST_CASE("[EGDescription] Attack range") { sfz::EGDescription eg; - sfz::SfzCCArray ccArray { 0 }; + sfz::MidiState state; eg.attack = 1; eg.vel2attack = -1.27f; eg.ccAttack = { 63, 1.27f }; - REQUIRE( eg.getAttack(ccArray, 0) == 1.0f ); - REQUIRE( eg.getAttack(ccArray, 127) == 0.0f ); - ccArray[63] = 127; - REQUIRE( eg.getAttack(ccArray, 127) == 1.0f ); - REQUIRE( eg.getAttack(ccArray, 0) == 2.27f ); + REQUIRE( eg.getAttack(state, 0) == 1.0f ); + REQUIRE( eg.getAttack(state, 127) == 0.0f ); + state.ccEvent(0, 63, 127); + REQUIRE( eg.getAttack(state, 127) == 1.0f ); + REQUIRE( eg.getAttack(state, 0) == 2.27f ); eg.ccAttack = { 63, 127.0f }; - REQUIRE( eg.getAttack(ccArray, 0) == 100.0f ); + REQUIRE( eg.getAttack(state, 0) == 100.0f ); } TEST_CASE("[EGDescription] Delay range") { sfz::EGDescription eg; - sfz::SfzCCArray ccArray { 0 }; + sfz::MidiState state; eg.delay = 1; eg.vel2delay = -1.27f; eg.ccDelay = { 63, 1.27f }; - REQUIRE( eg.getDelay(ccArray, 0) == 1.0f ); - REQUIRE( eg.getDelay(ccArray, 127) == 0.0f ); - ccArray[63] = 127; - REQUIRE( eg.getDelay(ccArray, 127) == 1.0f ); - REQUIRE( eg.getDelay(ccArray, 0) == 2.27f ); + REQUIRE( eg.getDelay(state, 0) == 1.0f ); + REQUIRE( eg.getDelay(state, 127) == 0.0f ); + state.ccEvent(0, 63, 127); + REQUIRE( eg.getDelay(state, 127) == 1.0f ); + REQUIRE( eg.getDelay(state, 0) == 2.27f ); eg.ccDelay = { 63, 127.0f }; - REQUIRE( eg.getDelay(ccArray, 0) == 100.0f ); + REQUIRE( eg.getDelay(state, 0) == 100.0f ); } TEST_CASE("[EGDescription] Decay range") { sfz::EGDescription eg; - sfz::SfzCCArray ccArray { 0 }; + sfz::MidiState state; eg.decay = 1.0f; eg.vel2decay = -1.27f; eg.ccDecay = { 63, 1.27f }; - REQUIRE( eg.getDecay(ccArray, 0) == 1.0f ); - REQUIRE( eg.getDecay(ccArray, 127) == 0.0f ); - ccArray[63] = 127; - REQUIRE( eg.getDecay(ccArray, 127) == 1.0f ); - REQUIRE( eg.getDecay(ccArray, 0) == 2.27f ); + REQUIRE( eg.getDecay(state, 0) == 1.0f ); + REQUIRE( eg.getDecay(state, 127) == 0.0f ); + state.ccEvent(0, 63, 127); + REQUIRE( eg.getDecay(state, 127) == 1.0f ); + REQUIRE( eg.getDecay(state, 0) == 2.27f ); eg.ccDecay = { 63, 127.0f }; - REQUIRE( eg.getDecay(ccArray, 0) == 100.0f ); + REQUIRE( eg.getDecay(state, 0) == 100.0f ); } TEST_CASE("[EGDescription] Release range") { sfz::EGDescription eg; - sfz::SfzCCArray ccArray { 0 }; + sfz::MidiState state; eg.release = 1; eg.vel2release = -1.27f; eg.ccRelease = { 63, 1.27f }; - REQUIRE( eg.getRelease(ccArray, 0) == 1.0f ); - REQUIRE( eg.getRelease(ccArray, 127) == 0.0f ); - ccArray[63] = 127; - REQUIRE( eg.getRelease(ccArray, 127) == 1.0f ); - REQUIRE( eg.getRelease(ccArray, 0) == 2.27f ); + REQUIRE( eg.getRelease(state, 0) == 1.0f ); + REQUIRE( eg.getRelease(state, 127) == 0.0f ); + state.ccEvent(0, 63, 127); + REQUIRE( eg.getRelease(state, 127) == 1.0f ); + REQUIRE( eg.getRelease(state, 0) == 2.27f ); eg.ccRelease = { 63, 127.0f }; - REQUIRE( eg.getRelease(ccArray, 0) == 100.0f ); + REQUIRE( eg.getRelease(state, 0) == 100.0f ); } TEST_CASE("[EGDescription] Hold range") { sfz::EGDescription eg; - sfz::SfzCCArray ccArray { 0 }; + sfz::MidiState state; eg.hold = 1; eg.vel2hold = -1.27f; eg.ccHold = { 63, 1.27f }; - REQUIRE( eg.getHold(ccArray, 0) == 1.0f ); - REQUIRE( eg.getHold(ccArray, 127) == 0.0f ); - ccArray[63] = 127; - REQUIRE( eg.getHold(ccArray, 127) == 1.0f ); - REQUIRE( eg.getHold(ccArray, 0) == 2.27f ); + REQUIRE( eg.getHold(state, 0) == 1.0f ); + REQUIRE( eg.getHold(state, 127) == 0.0f ); + state.ccEvent(0, 63, 127); + REQUIRE( eg.getHold(state, 127) == 1.0f ); + REQUIRE( eg.getHold(state, 0) == 2.27f ); eg.ccHold = { 63, 127.0f }; - REQUIRE( eg.getHold(ccArray, 0) == 100.0f ); + REQUIRE( eg.getHold(state, 0) == 100.0f ); } TEST_CASE("[EGDescription] Sustain level") { sfz::EGDescription eg; - sfz::SfzCCArray ccArray { 0 }; + sfz::MidiState state; eg.sustain = 50; eg.vel2sustain = -100; eg.ccSustain = { 63, 100.0f }; - REQUIRE( eg.getSustain(ccArray, 0) == 50.0f ); - REQUIRE( eg.getSustain(ccArray, 127) == 0.0f ); - ccArray[63] = 127; - REQUIRE( eg.getSustain(ccArray, 127) == 50.0f ); + REQUIRE( eg.getSustain(state, 0) == 50.0f ); + REQUIRE( eg.getSustain(state, 127) == 0.0f ); + state.ccEvent(0, 63, 127); + REQUIRE( eg.getSustain(state, 127) == 50.0f ); eg.ccSustain = { 63, 200.0f }; - REQUIRE( eg.getSustain(ccArray, 0) == 100.0f ); + REQUIRE( eg.getSustain(state, 0) == 100.0f ); } TEST_CASE("[EGDescription] Start level") { sfz::EGDescription eg; - sfz::SfzCCArray ccArray { 0 }; + sfz::MidiState state; eg.start = 0; eg.ccStart = { 63, 127.0f }; - REQUIRE( eg.getStart(ccArray, 0) == 0.0f ); - REQUIRE( eg.getStart(ccArray, 127) == 0.0f ); - ccArray[63] = 127; - REQUIRE( eg.getStart(ccArray, 0) == 100.0f ); + REQUIRE( eg.getStart(state, 0) == 0.0f ); + REQUIRE( eg.getStart(state, 127) == 0.0f ); + state.ccEvent(0, 63, 127); + REQUIRE( eg.getStart(state, 0) == 100.0f ); eg.ccStart = { 63, -127.0f }; - REQUIRE( eg.getStart(ccArray, 0) == 0.0f ); + REQUIRE( eg.getStart(state, 0) == 0.0f ); } diff --git a/tests/MidiStateT.cpp b/tests/MidiStateT.cpp index d06f2215..d4be5d21 100644 --- a/tests/MidiStateT.cpp +++ b/tests/MidiStateT.cpp @@ -18,21 +18,18 @@ using namespace Catch::literals; TEST_CASE("[MidiState] Initial values") { sfz::MidiState state; - for (auto& cc: state.getCCArray()) - REQUIRE( cc == 0 ); + for (unsigned cc = 0; cc < sfz::config::numCCs; cc++) + REQUIRE( state.getCCValue(cc) == 0 ); REQUIRE( state.getPitchBend() == 0 ); } TEST_CASE("[MidiState] Set and get CCs") { sfz::MidiState state; - const auto& cc = state.getCCArray(); state.ccEvent(0, 24, 23); state.ccEvent(0, 123, 124); REQUIRE(state.getCCValue(24) == 23); - REQUIRE(cc[24] == 23); REQUIRE(state.getCCValue(123) == 124); - REQUIRE(cc[123] == 124); } TEST_CASE("[MidiState] Set and get pitch bends") @@ -68,6 +65,5 @@ TEST_CASE("[MidiState] Set and get note velocities") TEST_CASE("[MidiState] Extended CCs") { sfz::MidiState state; - REQUIRE(state.getCCArray().size() >= 142); state.ccEvent(0, 142, 64); // should not trap } diff --git a/tests/RegionValueComputationsT.cpp b/tests/RegionValueComputationsT.cpp index eae54b0b..5c1ac179 100644 --- a/tests/RegionValueComputationsT.cpp +++ b/tests/RegionValueComputationsT.cpp @@ -166,13 +166,13 @@ TEST_CASE("[Region] Crossfade in on CC") region.parseOpcode({ "xfin_locc24", "20" }); region.parseOpcode({ "xfin_hicc24", "24" }); region.parseOpcode({ "amp_veltrack", "0" }); - midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a ); - midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a ); - midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.5_a ); - midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.70711_a ); - midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.86603_a ); - midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a ); - midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a ); + midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 0.0_a ); + midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 0.0_a ); + midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.5_a ); + midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.70711_a ); + midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.86603_a ); + midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 1.0_a ); + midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 1.0_a ); } TEST_CASE("[Region] Crossfade in on CC - gain") @@ -184,13 +184,13 @@ TEST_CASE("[Region] Crossfade in on CC - gain") region.parseOpcode({ "xfin_hicc24", "24" }); region.parseOpcode({ "amp_veltrack", "0" }); region.parseOpcode({ "xf_cccurve", "gain" }); - midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a ); - midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a ); - midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.25_a ); - midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.5_a ); - midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.75_a ); - midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a ); - midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a ); + midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 0.0_a ); + midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 0.0_a ); + midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.25_a ); + midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.5_a ); + midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.75_a ); + midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 1.0_a ); + midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 1.0_a ); } TEST_CASE("[Region] Crossfade out on CC") { @@ -200,13 +200,13 @@ TEST_CASE("[Region] Crossfade out on CC") region.parseOpcode({ "xfout_locc24", "20" }); region.parseOpcode({ "xfout_hicc24", "24" }); region.parseOpcode({ "amp_veltrack", "0" }); - midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a ); - midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a ); - midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.86603_a ); - midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.70711_a ); - midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.5_a ); - midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a ); - midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a ); + midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 1.0_a ); + midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 1.0_a ); + midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.86603_a ); + midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.70711_a ); + midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.5_a ); + midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 0.0_a ); + midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 0.0_a ); } TEST_CASE("[Region] Crossfade out on CC - gain") @@ -218,13 +218,13 @@ TEST_CASE("[Region] Crossfade out on CC - gain") region.parseOpcode({ "xfout_hicc24", "24" }); region.parseOpcode({ "amp_veltrack", "0" }); region.parseOpcode({ "xf_cccurve", "gain" }); - midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a ); - midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 1.0_a ); - midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.75_a ); - midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.5_a ); - midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.25_a ); - midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a ); - midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain(midiState.getCCArray()) == 0.0_a ); + midiState.ccEvent(0, 24, 19); REQUIRE( region.getCrossfadeGain() == 1.0_a ); + midiState.ccEvent(0, 24, 20); REQUIRE( region.getCrossfadeGain() == 1.0_a ); + midiState.ccEvent(0, 24, 21); REQUIRE( region.getCrossfadeGain() == 0.75_a ); + midiState.ccEvent(0, 24, 22); REQUIRE( region.getCrossfadeGain() == 0.5_a ); + midiState.ccEvent(0, 24, 23); REQUIRE( region.getCrossfadeGain() == 0.25_a ); + midiState.ccEvent(0, 24, 24); REQUIRE( region.getCrossfadeGain() == 0.0_a ); + midiState.ccEvent(0, 24, 25); REQUIRE( region.getCrossfadeGain() == 0.0_a ); } TEST_CASE("[Region] Velocity bug for extreme values - veltrack at 0")