From 0e2ebe6d467ed6951c3721b4177c5edf9962a8b0 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 1 Jul 2020 17:37:44 +0200 Subject: [PATCH] ampeg_XX_oncc can now contain multiple modifiers --- src/sfizz/EGDescription.h | 56 +++++++++++++----- src/sfizz/Region.cpp | 49 +++++++++++++--- tests/EGDescriptionT.cpp | 79 ++++++++++++++++++++----- tests/RegionT.cpp | 120 +++++++++++++++++++++++++------------- 4 files changed, 227 insertions(+), 77 deletions(-) diff --git a/src/sfizz/EGDescription.h b/src/sfizz/EGDescription.h index e64fa642..683b4d51 100644 --- a/src/sfizz/EGDescription.h +++ b/src/sfizz/EGDescription.h @@ -80,13 +80,13 @@ struct EGDescription { float vel2sustain { Default::vel2sustain }; int vel2depth { Default::depth }; - absl::optional> ccAttack; - absl::optional> ccDecay; - absl::optional> ccDelay; - absl::optional> ccHold; - absl::optional> ccRelease; - absl::optional> ccStart; - absl::optional> ccSustain; + CCMap ccAttack; + CCMap ccDecay; + CCMap ccDelay; + CCMap ccHold; + CCMap ccRelease; + CCMap ccStart; + CCMap ccSustain; /** * @brief Get the attack with possibly a CC modifier and a velocity modifier @@ -98,7 +98,11 @@ struct EGDescription { float getAttack(const MidiState& state, float velocity) const noexcept { ASSERT(velocity >= 0.0f && velocity <= 1.0f); - return Default::egTimeRange.clamp(ccSwitchedValue(state, ccAttack, attack) + velocity * vel2attack); + float returnedValue { attack + velocity * vel2attack }; + for (auto& mod: ccAttack) { + returnedValue += state.getCCValue(mod.cc) * mod.data; + } + return Default::egTimeRange.clamp(returnedValue); } /** * @brief Get the decay with possibly a CC modifier and a velocity modifier @@ -110,7 +114,11 @@ struct EGDescription { float getDecay(const MidiState& state, float velocity) const noexcept { ASSERT(velocity >= 0.0f && velocity <= 1.0f); - return Default::egTimeRange.clamp(ccSwitchedValue(state, ccDecay, decay) + velocity * vel2decay); + float returnedValue { decay + velocity * vel2decay }; + for (auto& mod: ccDecay) { + returnedValue += state.getCCValue(mod.cc) * mod.data; + } + return Default::egTimeRange.clamp(returnedValue); } /** * @brief Get the delay with possibly a CC modifier and a velocity modifier @@ -122,7 +130,11 @@ struct EGDescription { float getDelay(const MidiState& state, float velocity) const noexcept { ASSERT(velocity >= 0.0f && velocity <= 1.0f); - return Default::egTimeRange.clamp(ccSwitchedValue(state, ccDelay, delay) + velocity * vel2delay); + float returnedValue { delay + velocity * vel2delay }; + for (auto& mod: ccDelay) { + returnedValue += state.getCCValue(mod.cc) * mod.data; + } + return Default::egTimeRange.clamp(returnedValue); } /** * @brief Get the holding duration with possibly a CC modifier and a velocity modifier @@ -134,7 +146,11 @@ struct EGDescription { float getHold(const MidiState& state, float velocity) const noexcept { ASSERT(velocity >= 0.0f && velocity <= 1.0f); - return Default::egTimeRange.clamp(ccSwitchedValue(state, ccHold, hold) + velocity * vel2hold); + float returnedValue { hold + velocity * vel2hold }; + for (auto& mod: ccHold) { + returnedValue += state.getCCValue(mod.cc) * mod.data; + } + return Default::egTimeRange.clamp(returnedValue); } /** * @brief Get the release duration with possibly a CC modifier and a velocity modifier @@ -146,7 +162,11 @@ struct EGDescription { float getRelease(const MidiState& state, float velocity) const noexcept { ASSERT(velocity >= 0.0f && velocity <= 1.0f); - return Default::egTimeRange.clamp(ccSwitchedValue(state, ccRelease, release) + velocity * vel2release); + float returnedValue { release + velocity * vel2release }; + for (auto& mod: ccRelease) { + returnedValue += state.getCCValue(mod.cc) * mod.data; + } + return Default::egTimeRange.clamp(returnedValue); } /** * @brief Get the starting level with possibly a CC modifier and a velocity modifier @@ -158,7 +178,11 @@ struct EGDescription { float getStart(const MidiState& state, float velocity) const noexcept { UNUSED(velocity); - return Default::egPercentRange.clamp(ccSwitchedValue(state, ccStart, start)); + float returnedValue { start }; + for (auto& mod: ccStart) { + returnedValue += state.getCCValue(mod.cc) * mod.data; + } + return Default::egPercentRange.clamp(returnedValue); } /** * @brief Get the sustain level with possibly a CC modifier and a velocity modifier @@ -170,7 +194,11 @@ struct EGDescription { float getSustain(const MidiState& state, float velocity) const noexcept { ASSERT(velocity >= 0.0f && velocity <= 1.0f); - return Default::egPercentRange.clamp(ccSwitchedValue(state, ccSustain, sustain) + velocity * vel2sustain); + float returnedValue { sustain + velocity * vel2sustain }; + for (auto& mod: ccSustain) { + returnedValue += state.getCCValue(mod.cc) * mod.data; + } + return Default::egPercentRange.clamp(returnedValue); } LEAK_DETECTOR(EGDescription); }; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 287fc7ad..5d6bbe55 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -816,25 +816,60 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) setValueFromOpcode(opcode, amplitudeEG.vel2sustain, Default::egOnCCPercentRange); break; case hash("ampeg_attack_oncc&"): // also ampeg_attackcc& - setCCPairFromOpcode(opcode, amplitudeEG.ccAttack, Default::egOnCCTimeRange); + if (opcode.parameters.back() >= config::numCCs) + return false; + + if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + amplitudeEG.ccAttack[opcode.parameters.back()] = *value; + break; case hash("ampeg_decay_oncc&"): // also ampeg_decaycc& - setCCPairFromOpcode(opcode, amplitudeEG.ccDecay, Default::egOnCCTimeRange); + if (opcode.parameters.back() >= config::numCCs) + return false; + + if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + amplitudeEG.ccDecay[opcode.parameters.back()] = *value; + break; case hash("ampeg_delay_oncc&"): // also ampeg_delaycc& - setCCPairFromOpcode(opcode, amplitudeEG.ccDelay, Default::egOnCCTimeRange); + if (opcode.parameters.back() >= config::numCCs) + return false; + + if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + amplitudeEG.ccDelay[opcode.parameters.back()] = *value; + break; case hash("ampeg_hold_oncc&"): // also ampeg_holdcc& - setCCPairFromOpcode(opcode, amplitudeEG.ccHold, Default::egOnCCTimeRange); + if (opcode.parameters.back() >= config::numCCs) + return false; + + if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + amplitudeEG.ccHold[opcode.parameters.back()] = *value; + break; case hash("ampeg_release_oncc&"): // also ampeg_releasecc& - setCCPairFromOpcode(opcode, amplitudeEG.ccRelease, Default::egOnCCTimeRange); + if (opcode.parameters.back() >= config::numCCs) + return false; + + if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + amplitudeEG.ccRelease[opcode.parameters.back()] = *value; + break; case hash("ampeg_start_oncc&"): // also ampeg_startcc& - setCCPairFromOpcode(opcode, amplitudeEG.ccStart, Default::egOnCCPercentRange); + if (opcode.parameters.back() >= config::numCCs) + return false; + + if (auto value = readOpcode(opcode.value, Default::egOnCCPercentRange)) + amplitudeEG.ccStart[opcode.parameters.back()] = *value; + break; case hash("ampeg_sustain_oncc&"): // also ampeg_sustaincc& - setCCPairFromOpcode(opcode, amplitudeEG.ccSustain, Default::egOnCCPercentRange); + if (opcode.parameters.back() >= config::numCCs) + return false; + + if (auto value = readOpcode(opcode.value, Default::egOnCCPercentRange)) + amplitudeEG.ccSustain[opcode.parameters.back()] = *value; + break; case hash("effect&"): diff --git a/tests/EGDescriptionT.cpp b/tests/EGDescriptionT.cpp index 25730dc9..950e7d3b 100644 --- a/tests/EGDescriptionT.cpp +++ b/tests/EGDescriptionT.cpp @@ -17,14 +17,21 @@ TEST_CASE("[EGDescription] Attack range") sfz::MidiState state; eg.attack = 1; eg.vel2attack = -1.27f; - eg.ccAttack = { 63, 1.27f }; + eg.ccAttack[63] = 1.27f; REQUIRE(eg.getAttack(state, 0_norm) == 1.0f); REQUIRE(eg.getAttack(state, 127_norm) == 0.0f); state.ccEvent(0, 63, 127_norm); REQUIRE(eg.getAttack(state, 127_norm) == 1.0f); REQUIRE(eg.getAttack(state, 0_norm) == 2.27f); - eg.ccAttack = { 63, 127.0f }; + eg.ccAttack[63] = 127.0f; REQUIRE(eg.getAttack(state, 0_norm) == 100.0f); + eg.ccAttack[63] = 1.27f; + eg.ccAttack[65] = 1.0f; + REQUIRE(eg.getAttack(state, 0_norm) == 2.27f); + REQUIRE(eg.getAttack(state, 127_norm) == 1.0f); + state.ccEvent(0, 65, 127_norm); + REQUIRE(eg.getAttack(state, 0_norm) == 3.27f); + REQUIRE(eg.getAttack(state, 127_norm) == 2.0f); } TEST_CASE("[EGDescription] Delay range") @@ -33,14 +40,21 @@ TEST_CASE("[EGDescription] Delay range") sfz::MidiState state; eg.delay = 1; eg.vel2delay = -1.27f; - eg.ccDelay = { 63, 1.27f }; + eg.ccDelay[63] = 1.27f; REQUIRE(eg.getDelay(state, 0_norm) == 1.0f); REQUIRE(eg.getDelay(state, 127_norm) == 0.0f); state.ccEvent(0, 63, 127_norm); REQUIRE(eg.getDelay(state, 127_norm) == 1.0f); REQUIRE(eg.getDelay(state, 0_norm) == 2.27f); - eg.ccDelay = { 63, 127.0f }; + eg.ccDelay[63] = 127.0f; REQUIRE(eg.getDelay(state, 0_norm) == 100.0f); + eg.ccDelay[63] = 1.27f; + eg.ccDelay[65] = 1.0f; + REQUIRE(eg.getDelay(state, 0_norm) == 2.27f); + REQUIRE(eg.getDelay(state, 127_norm) == 1.0f); + state.ccEvent(0, 65, 127_norm); + REQUIRE(eg.getDelay(state, 0_norm) == 3.27f); + REQUIRE(eg.getDelay(state, 127_norm) == 2.0f); } TEST_CASE("[EGDescription] Decay range") @@ -49,14 +63,21 @@ TEST_CASE("[EGDescription] Decay range") sfz::MidiState state; eg.decay = 1.0f; eg.vel2decay = -1.27f; - eg.ccDecay = { 63, 1.27f }; + eg.ccDecay[63] = 1.27f; REQUIRE(eg.getDecay(state, 0_norm) == 1.0f); REQUIRE(eg.getDecay(state, 127_norm) == 0.0f); state.ccEvent(0, 63, 127_norm); REQUIRE(eg.getDecay(state, 127_norm) == 1.0f); REQUIRE(eg.getDecay(state, 0_norm) == 2.27f); - eg.ccDecay = { 63, 127.0f }; + eg.ccDecay[63] = 127.0f; REQUIRE(eg.getDecay(state, 0_norm) == 100.0f); + eg.ccDecay[63] = 1.27f; + eg.ccDecay[65] = 1.0f; + REQUIRE(eg.getDecay(state, 0_norm) == 2.27f); + REQUIRE(eg.getDecay(state, 127_norm) == 1.0f); + state.ccEvent(0, 65, 127_norm); + REQUIRE(eg.getDecay(state, 0_norm) == 3.27f); + REQUIRE(eg.getDecay(state, 127_norm) == 2.0f); } TEST_CASE("[EGDescription] Release range") @@ -65,14 +86,21 @@ TEST_CASE("[EGDescription] Release range") sfz::MidiState state; eg.release = 1; eg.vel2release = -1.27f; - eg.ccRelease = { 63, 1.27f }; + eg.ccRelease[63] = 1.27f; REQUIRE(eg.getRelease(state, 0_norm) == 1.0f); REQUIRE(eg.getRelease(state, 127_norm) == 0.0f); state.ccEvent(0, 63, 127_norm); REQUIRE(eg.getRelease(state, 127_norm) == 1.0f); REQUIRE(eg.getRelease(state, 0_norm) == 2.27f); - eg.ccRelease = { 63, 127.0f }; + eg.ccRelease[63] = 127.0f; REQUIRE(eg.getRelease(state, 0_norm) == 100.0f); + eg.ccRelease[63] = 1.27f; + eg.ccRelease[65] = 1.0f; + REQUIRE(eg.getRelease(state, 0_norm) == 2.27f); + REQUIRE(eg.getRelease(state, 127_norm) == 1.0f); + state.ccEvent(0, 65, 127_norm); + REQUIRE(eg.getRelease(state, 0_norm) == 3.27f); + REQUIRE(eg.getRelease(state, 127_norm) == 2.0f); } TEST_CASE("[EGDescription] Hold range") @@ -81,14 +109,21 @@ TEST_CASE("[EGDescription] Hold range") sfz::MidiState state; eg.hold = 1; eg.vel2hold = -1.27f; - eg.ccHold = { 63, 1.27f }; + eg.ccHold[63] = 1.27f; REQUIRE(eg.getHold(state, 0_norm) == 1.0f); REQUIRE(eg.getHold(state, 127_norm) == 0.0f); state.ccEvent(0, 63, 127_norm); REQUIRE(eg.getHold(state, 127_norm) == 1.0f); REQUIRE(eg.getHold(state, 0_norm) == 2.27f); - eg.ccHold = { 63, 127.0f }; + eg.ccHold[63] = 127.0f; REQUIRE(eg.getHold(state, 0_norm) == 100.0f); + eg.ccHold[63] = 1.27f; + eg.ccHold[65] = 1.0f; + REQUIRE(eg.getHold(state, 0_norm) == 2.27f); + REQUIRE(eg.getHold(state, 127_norm) == 1.0f); + state.ccEvent(0, 65, 127_norm); + REQUIRE(eg.getHold(state, 0_norm) == 3.27f); + REQUIRE(eg.getHold(state, 127_norm) == 2.0f); } TEST_CASE("[EGDescription] Sustain level") @@ -97,13 +132,21 @@ TEST_CASE("[EGDescription] Sustain level") sfz::MidiState state; eg.sustain = 50; eg.vel2sustain = -100; - eg.ccSustain = { 63, 100.0f }; + eg.ccSustain[63] = 100.0f; REQUIRE(eg.getSustain(state, 0_norm) == 50.0f); REQUIRE(eg.getSustain(state, 127_norm) == 0.0f); state.ccEvent(0, 63, 127_norm); REQUIRE(eg.getSustain(state, 127_norm) == 50.0f); - eg.ccSustain = { 63, 200.0f }; + eg.ccSustain[63] = 200.0f; REQUIRE(eg.getSustain(state, 0_norm) == 100.0f); + eg.sustain = 0; + eg.ccSustain[63] = 50.0f; + eg.ccSustain[65] = 50.0f; + REQUIRE(eg.getSustain(state, 0_norm) == 50.0f); + REQUIRE(eg.getSustain(state, 127_norm) == 0.0f); + state.ccEvent(0, 65, 127_norm); + REQUIRE(eg.getSustain(state, 0_norm) == 100.0f); + REQUIRE(eg.getSustain(state, 127_norm) == 0.0f); } TEST_CASE("[EGDescription] Start level") @@ -111,11 +154,19 @@ TEST_CASE("[EGDescription] Start level") sfz::EGDescription eg; sfz::MidiState state; eg.start = 0; - eg.ccStart = { 63, 127.0f }; + eg.ccStart[63] = 127.0f; REQUIRE(eg.getStart(state, 0_norm) == 0.0f); REQUIRE(eg.getStart(state, 127_norm) == 0.0f); state.ccEvent(0, 63, 127_norm); REQUIRE(eg.getStart(state, 0_norm) == 100.0f); - eg.ccStart = { 63, -127.0f }; + eg.ccStart[63] = -127.0f; REQUIRE(eg.getStart(state, 0_norm) == 0.0f); + eg.start = 0; + eg.ccStart[63] = 50.0f; + eg.ccStart[65] = 50.0f; + REQUIRE(eg.getStart(state, 0_norm) == 50.0f); + REQUIRE(eg.getStart(state, 127_norm) == 50.0f); + state.ccEvent(0, 65, 127_norm); + REQUIRE(eg.getStart(state, 0_norm) == 100.0f); + REQUIRE(eg.getStart(state, 127_norm) == 100.0f); } diff --git a/tests/RegionT.cpp b/tests/RegionT.cpp index e4a9c09d..eba8df05 100644 --- a/tests/RegionT.cpp +++ b/tests/RegionT.cpp @@ -1083,13 +1083,13 @@ TEST_CASE("[Region] Parsing opcodes") SECTION("ampeg_XX_onccNN") { // Defaults - REQUIRE(!region.amplitudeEG.ccAttack); - REQUIRE(!region.amplitudeEG.ccDecay); - REQUIRE(!region.amplitudeEG.ccDelay); - REQUIRE(!region.amplitudeEG.ccHold); - REQUIRE(!region.amplitudeEG.ccRelease); - REQUIRE(!region.amplitudeEG.ccStart); - REQUIRE(!region.amplitudeEG.ccSustain); + REQUIRE(region.amplitudeEG.ccAttack.empty()); + REQUIRE(region.amplitudeEG.ccDecay.empty()); + REQUIRE(region.amplitudeEG.ccDelay.empty()); + REQUIRE(region.amplitudeEG.ccHold.empty()); + REQUIRE(region.amplitudeEG.ccRelease.empty()); + REQUIRE(region.amplitudeEG.ccStart.empty()); + REQUIRE(region.amplitudeEG.ccSustain.empty()); // region.parseOpcode({ "ampeg_attack_oncc1", "1" }); region.parseOpcode({ "ampeg_decay_oncc2", "2" }); @@ -1098,27 +1098,20 @@ TEST_CASE("[Region] Parsing opcodes") region.parseOpcode({ "ampeg_release_oncc5", "5" }); region.parseOpcode({ "ampeg_start_oncc6", "6" }); region.parseOpcode({ "ampeg_sustain_oncc7", "7" }); - REQUIRE(region.amplitudeEG.ccAttack); - REQUIRE(region.amplitudeEG.ccDecay); - REQUIRE(region.amplitudeEG.ccDelay); - REQUIRE(region.amplitudeEG.ccHold); - REQUIRE(region.amplitudeEG.ccRelease); - REQUIRE(region.amplitudeEG.ccStart); - REQUIRE(region.amplitudeEG.ccSustain); - REQUIRE(region.amplitudeEG.ccAttack->cc == 1); - REQUIRE(region.amplitudeEG.ccDecay->cc == 2); - REQUIRE(region.amplitudeEG.ccDelay->cc == 3); - REQUIRE(region.amplitudeEG.ccHold->cc == 4); - REQUIRE(region.amplitudeEG.ccRelease->cc == 5); - REQUIRE(region.amplitudeEG.ccStart->cc == 6); - REQUIRE(region.amplitudeEG.ccSustain->cc == 7); - REQUIRE(region.amplitudeEG.ccAttack->data == 1.0f); - REQUIRE(region.amplitudeEG.ccDecay->data == 2.0f); - REQUIRE(region.amplitudeEG.ccDelay->data == 3.0f); - REQUIRE(region.amplitudeEG.ccHold->data == 4.0f); - REQUIRE(region.amplitudeEG.ccRelease->data == 5.0f); - REQUIRE(region.amplitudeEG.ccStart->data == 6.0f); - REQUIRE(region.amplitudeEG.ccSustain->data == 7.0f); + REQUIRE(region.amplitudeEG.ccAttack.contains(1)); + REQUIRE(region.amplitudeEG.ccDecay.contains(2)); + REQUIRE(region.amplitudeEG.ccDelay.contains(3)); + REQUIRE(region.amplitudeEG.ccHold.contains(4)); + REQUIRE(region.amplitudeEG.ccRelease.contains(5)); + REQUIRE(region.amplitudeEG.ccStart.contains(6)); + REQUIRE(region.amplitudeEG.ccSustain.contains(7)); + REQUIRE(region.amplitudeEG.ccAttack[1] == 1.0f); + REQUIRE(region.amplitudeEG.ccDecay[2] == 2.0f); + REQUIRE(region.amplitudeEG.ccDelay[3] == 3.0f); + REQUIRE(region.amplitudeEG.ccHold[4] == 4.0f); + REQUIRE(region.amplitudeEG.ccRelease[5] == 5.0f); + REQUIRE(region.amplitudeEG.ccStart[6] == 6.0f); + REQUIRE(region.amplitudeEG.ccSustain[7] == 7.0f); // region.parseOpcode({ "ampeg_attack_oncc1", "101" }); region.parseOpcode({ "ampeg_decay_oncc2", "101" }); @@ -1127,13 +1120,13 @@ TEST_CASE("[Region] Parsing opcodes") region.parseOpcode({ "ampeg_release_oncc5", "101" }); region.parseOpcode({ "ampeg_start_oncc6", "101" }); region.parseOpcode({ "ampeg_sustain_oncc7", "101" }); - REQUIRE(region.amplitudeEG.ccAttack->data == 100.0f); - REQUIRE(region.amplitudeEG.ccDecay->data == 100.0f); - REQUIRE(region.amplitudeEG.ccDelay->data == 100.0f); - REQUIRE(region.amplitudeEG.ccHold->data == 100.0f); - REQUIRE(region.amplitudeEG.ccRelease->data == 100.0f); - REQUIRE(region.amplitudeEG.ccStart->data == 100.0f); - REQUIRE(region.amplitudeEG.ccSustain->data == 100.0f); + REQUIRE(region.amplitudeEG.ccAttack[1] == 100.0f); + REQUIRE(region.amplitudeEG.ccDecay[2] == 100.0f); + REQUIRE(region.amplitudeEG.ccDelay[3] == 100.0f); + REQUIRE(region.amplitudeEG.ccHold[4] == 100.0f); + REQUIRE(region.amplitudeEG.ccRelease[5] == 100.0f); + REQUIRE(region.amplitudeEG.ccStart[6] == 100.0f); + REQUIRE(region.amplitudeEG.ccSustain[7] == 100.0f); // region.parseOpcode({ "ampeg_attack_oncc1", "-101" }); region.parseOpcode({ "ampeg_decay_oncc2", "-101" }); @@ -1142,13 +1135,56 @@ TEST_CASE("[Region] Parsing opcodes") region.parseOpcode({ "ampeg_release_oncc5", "-101" }); region.parseOpcode({ "ampeg_start_oncc6", "-101" }); region.parseOpcode({ "ampeg_sustain_oncc7", "-101" }); - REQUIRE(region.amplitudeEG.ccAttack->data == -100.0f); - REQUIRE(region.amplitudeEG.ccDecay->data == -100.0f); - REQUIRE(region.amplitudeEG.ccDelay->data == -100.0f); - REQUIRE(region.amplitudeEG.ccHold->data == -100.0f); - REQUIRE(region.amplitudeEG.ccRelease->data == -100.0f); - REQUIRE(region.amplitudeEG.ccStart->data == -100.0f); - REQUIRE(region.amplitudeEG.ccSustain->data == -100.0f); + REQUIRE(region.amplitudeEG.ccAttack[1] == -100.0f); + REQUIRE(region.amplitudeEG.ccDecay[2] == -100.0f); + REQUIRE(region.amplitudeEG.ccDelay[3] == -100.0f); + REQUIRE(region.amplitudeEG.ccHold[4] == -100.0f); + REQUIRE(region.amplitudeEG.ccRelease[5] == -100.0f); + REQUIRE(region.amplitudeEG.ccStart[6] == -100.0f); + REQUIRE(region.amplitudeEG.ccSustain[7] == -100.0f); + // + region.parseOpcode({ "ampeg_attack_oncc1", "1" }); + region.parseOpcode({ "ampeg_decay_oncc2", "2" }); + region.parseOpcode({ "ampeg_delay_oncc3", "3" }); + region.parseOpcode({ "ampeg_hold_oncc4", "4" }); + region.parseOpcode({ "ampeg_release_oncc5", "5" }); + region.parseOpcode({ "ampeg_start_oncc6", "6" }); + region.parseOpcode({ "ampeg_sustain_oncc7", "7" }); + region.parseOpcode({ "ampeg_attack_oncc2", "2" }); + region.parseOpcode({ "ampeg_decay_oncc3", "3" }); + region.parseOpcode({ "ampeg_delay_oncc4", "4" }); + region.parseOpcode({ "ampeg_hold_oncc5", "5" }); + region.parseOpcode({ "ampeg_release_oncc6", "6" }); + region.parseOpcode({ "ampeg_start_oncc7", "7" }); + region.parseOpcode({ "ampeg_sustain_oncc8", "8" }); + REQUIRE(region.amplitudeEG.ccAttack.contains(1)); + REQUIRE(region.amplitudeEG.ccDecay.contains(2)); + REQUIRE(region.amplitudeEG.ccDelay.contains(3)); + REQUIRE(region.amplitudeEG.ccHold.contains(4)); + REQUIRE(region.amplitudeEG.ccRelease.contains(5)); + REQUIRE(region.amplitudeEG.ccStart.contains(6)); + REQUIRE(region.amplitudeEG.ccSustain.contains(7)); + REQUIRE(region.amplitudeEG.ccAttack.contains(2)); + REQUIRE(region.amplitudeEG.ccDecay.contains(3)); + REQUIRE(region.amplitudeEG.ccDelay.contains(4)); + REQUIRE(region.amplitudeEG.ccHold.contains(5)); + REQUIRE(region.amplitudeEG.ccRelease.contains(6)); + REQUIRE(region.amplitudeEG.ccStart.contains(7)); + REQUIRE(region.amplitudeEG.ccSustain.contains(8)); + REQUIRE(region.amplitudeEG.ccAttack[1] == 1.0f); + REQUIRE(region.amplitudeEG.ccDecay[2] == 2.0f); + REQUIRE(region.amplitudeEG.ccDelay[3] == 3.0f); + REQUIRE(region.amplitudeEG.ccHold[4] == 4.0f); + REQUIRE(region.amplitudeEG.ccRelease[5] == 5.0f); + REQUIRE(region.amplitudeEG.ccStart[6] == 6.0f); + REQUIRE(region.amplitudeEG.ccSustain[7] == 7.0f); + REQUIRE(region.amplitudeEG.ccAttack[2] == 2.0f); + REQUIRE(region.amplitudeEG.ccDecay[3] == 3.0f); + REQUIRE(region.amplitudeEG.ccDelay[4] == 4.0f); + REQUIRE(region.amplitudeEG.ccHold[5] == 5.0f); + REQUIRE(region.amplitudeEG.ccRelease[6] == 6.0f); + REQUIRE(region.amplitudeEG.ccStart[7] == 7.0f); + REQUIRE(region.amplitudeEG.ccSustain[8] == 8.0f); } SECTION("sustain_sw and sostenuto_sw")