diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 822e9cd3..8506d90f 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -110,17 +110,21 @@ namespace Default constexpr float volume { 0.0f }; constexpr Range volumeRange { -144.0, 6.0 }; constexpr Range volumeCCRange { -144.0, 48.0 }; + constexpr Range volumeStepRange { 0, 48.0 }; constexpr float amplitude { 100.0 }; constexpr Range amplitudeRange { 0.0, 100.0 }; constexpr float pan { 0.0 }; constexpr Range panRange { -100.0, 100.0 }; constexpr Range panCCRange { -200.0, 200.0 }; + constexpr Range panStepRange { 0.0, 200.0 }; constexpr float position { 0.0 }; constexpr Range positionRange { -100.0, 100.0 }; constexpr Range positionCCRange { -200.0, 200.0 }; + constexpr Range positionStepRange { 0.0, 200.0 }; constexpr float width { 100.0 }; constexpr Range widthRange { -100.0, 100.0 }; constexpr Range widthCCRange { -200.0, 200.0 }; + constexpr Range widthStepRange { 0.0, 200.0 }; constexpr uint8_t ampKeycenter { 60 }; constexpr float ampKeytrack { 0.0 }; constexpr Range ampKeytrackRange { -96, 12 }; @@ -196,6 +200,7 @@ namespace Default constexpr int tune { 0 }; constexpr Range tuneRange { -9600, 9600 }; // ±100 in SFZv1, more in ARIA constexpr Range tuneCCRange { -9600, 9600 }; + constexpr Range tuneStepRange { 0, 9600 }; constexpr Range bendBoundRange { -9600, 9600 }; constexpr Range bendStepRange { 1, 1200 }; constexpr int bendUp { 200 }; // No range here because the bounds can be inverted diff --git a/src/sfizz/ModifierHelpers.h b/src/sfizz/ModifierHelpers.h index 4aaffa75..b46bbc61 100644 --- a/src/sfizz/ModifierHelpers.h +++ b/src/sfizz/ModifierHelpers.h @@ -189,12 +189,12 @@ void linearModifier(const sfz::Resources& resources, absl::Span span, con { const auto events = resources.midiState.getCCEvents(ccData.cc); const auto curve = resources.curves.getCurve(ccData.data.curve); - if (ccData.data.steps < 2) { + if (ccData.data.step == 0.0f) { linearEnvelope(events, span, [&ccData, &curve, &lambda](float x) { return lambda(curve.evalNormalized(x) * ccData.data.value); }); } else { - const float stepSize { ccData.data.value / (ccData.data.steps - 1) }; + const float stepSize { lambda(ccData.data.step) }; linearEnvelope(events, span, [&ccData, &curve, &lambda](float x) { return lambda(curve.evalNormalized(x) * ccData.data.value); }, stepSize); @@ -206,12 +206,12 @@ void multiplicativeModifier(const sfz::Resources& resources, absl::Span s { const auto events = resources.midiState.getCCEvents(ccData.cc); const auto curve = resources.curves.getCurve(ccData.data.curve); - if (ccData.data.steps < 2) { + if (ccData.data.step == 0.0f) { multiplicativeEnvelope(events, span, [&ccData, &curve, &lambda](float x) { return lambda(curve.evalNormalized(x) * ccData.data.value); }); } else { - const float stepSize { lambda(ccData.data.value / (ccData.data.steps - 1)) }; + const float stepSize { lambda(ccData.data.step) }; multiplicativeEnvelope(events, span, [&ccData, &curve, &lambda](float x) { return lambda(curve.evalNormalized(x) * ccData.data.value); }, stepSize); diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 066c75e3..3411e915 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -305,8 +305,8 @@ bool sfz::Region::parseOpcode(const Opcode& opcode) case hash("volume_stepcc&"): if (opcode.parameters.back() > config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::stepCCRange)) - volumeCC[opcode.parameters.back()].steps = *value; + if (auto value = readOpcode(opcode.value, Default::volumeStepRange)) + volumeCC[opcode.parameters.back()].step = *value; break; case hash("volume_smoothcc&"): if (opcode.parameters.back() > config::numCCs) @@ -335,8 +335,8 @@ bool sfz::Region::parseOpcode(const Opcode& opcode) case hash("amplitude_stepcc&"): if (opcode.parameters.back() > config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::stepCCRange)) - amplitudeCC[opcode.parameters.back()].steps = *value; + if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + amplitudeCC[opcode.parameters.back()].step = normalizePercents(*value); break; case hash("amplitude_smoothcc&"): if (opcode.parameters.back() > config::numCCs) @@ -364,8 +364,8 @@ bool sfz::Region::parseOpcode(const Opcode& opcode) case hash("pan_stepcc&"): if (opcode.parameters.back() > config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::stepCCRange)) - panCC[opcode.parameters.back()].steps = *value; + if (auto value = readOpcode(opcode.value, Default::panStepRange)) + panCC[opcode.parameters.back()].step = normalizePercents(*value); break; case hash("pan_smoothcc&"): if (opcode.parameters.back() > config::numCCs) @@ -393,8 +393,8 @@ bool sfz::Region::parseOpcode(const Opcode& opcode) case hash("position_stepcc&"): if (opcode.parameters.back() > config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::stepCCRange)) - positionCC[opcode.parameters.back()].steps = *value; + if (auto value = readOpcode(opcode.value, Default::positionStepRange)) + positionCC[opcode.parameters.back()].step = normalizePercents(*value); break; case hash("position_smoothcc&"): if (opcode.parameters.back() > config::numCCs) @@ -422,8 +422,8 @@ bool sfz::Region::parseOpcode(const Opcode& opcode) case hash("width_stepcc&"): if (opcode.parameters.back() > config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::stepCCRange)) - widthCC[opcode.parameters.back()].steps = *value; + if (auto value = readOpcode(opcode.value, Default::widthStepRange)) + widthCC[opcode.parameters.back()].step = normalizePercents(*value); break; case hash("width_smoothcc&"): if (opcode.parameters.back() > config::numCCs) @@ -827,8 +827,8 @@ bool sfz::Region::parseOpcode(const Opcode& opcode) case hash("tune_stepcc&"): if (opcode.parameters.back() > config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::stepCCRange)) - tuneCC[opcode.parameters.back()].steps = *value; + if (auto value = readOpcode(opcode.value, Default::tuneStepRange)) + tuneCC[opcode.parameters.back()].step = *value; break; case hash("pitch_smoothcc&"): // fallthrough case hash("tune_smoothcc&"): diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index de19d2ed..60979282 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -32,8 +32,8 @@ struct CCData { struct Modifier { float value { 0.0f }; + float step { 0.0f }; uint8_t curve { 0 }; - uint8_t steps { 0 }; uint8_t smooth { 0 }; static_assert(config::maxCurves - 1 <= std::numeric_limits::max(), "The curve type in the Modifier struct cannot support the required number of curves"); }; diff --git a/tests/EventEnvelopesT.cpp b/tests/EventEnvelopesT.cpp index a2dc6b30..551cc807 100644 --- a/tests/EventEnvelopesT.cpp +++ b/tests/EventEnvelopesT.cpp @@ -312,10 +312,10 @@ TEST_CASE("[linearModifiers] Compare with envelopes") ccData.data.curve = 2; ccData.data.value = 20.0f; - ccData.data.steps = 10; + ccData.data.step = 2.0f; linearEnvelope(resources.midiState.getCCEvents(20), absl::MakeSpan(envelope), [&ccData](float x) { return ccData.data.value * (1 - x); - }, ccData.data.value / (ccData.data.steps - 1)); + }, ccData.data.step); linearModifier(resources, absl::MakeSpan(output), ccData); REQUIRE(approxEqual(output, envelope)); } @@ -364,10 +364,10 @@ TEST_CASE("[multiplicativeModifiers] Compare with envelopes") ccData.data.curve = 2; ccData.data.value = 20.0f; - ccData.data.steps = 10; + ccData.data.step = 2.0f; multiplicativeEnvelope(resources.midiState.getCCEvents(20), absl::MakeSpan(envelope), [&ccData](float x) { return db2mag(ccData.data.value * (1 - x)); - }, db2mag(ccData.data.value / (ccData.data.steps - 1)) ); + }, db2mag(ccData.data.step) ); multiplicativeModifier(resources, absl::MakeSpan(output), ccData, [](float x) { return db2mag(x); }); diff --git a/tests/RegionT.cpp b/tests/RegionT.cpp index 31e58fcd..f982c424 100644 --- a/tests/RegionT.cpp +++ b/tests/RegionT.cpp @@ -484,11 +484,11 @@ TEST_CASE("[Region] Parsing opcodes") region.parseOpcode({ "pan_smoothcc14", "-2" }); REQUIRE(region.panCC[14].smooth == 0); region.parseOpcode({ "pan_stepcc120", "24" }); - REQUIRE(region.panCC[120].steps == 24); + REQUIRE(region.panCC[120].step == 0.24_a); region.parseOpcode({ "pan_stepcc120", "15482" }); - REQUIRE(region.panCC[120].steps == 127); + REQUIRE(region.panCC[120].step == 2.0_a); region.parseOpcode({ "pan_stepcc120", "-2" }); - REQUIRE(region.panCC[120].steps == 0); + REQUIRE(region.panCC[120].step == 0.0f); } SECTION("width") @@ -523,11 +523,11 @@ TEST_CASE("[Region] Parsing opcodes") region.parseOpcode({ "width_smoothcc14", "-2" }); REQUIRE(region.widthCC[14].smooth == 0); region.parseOpcode({ "width_stepcc120", "24" }); - REQUIRE(region.widthCC[120].steps == 24); + REQUIRE(region.widthCC[120].step == 0.24_a); region.parseOpcode({ "width_stepcc120", "15482" }); - REQUIRE(region.widthCC[120].steps == 127); - region.parseOpcode({ "width_stepcc120", "-2" }); - REQUIRE(region.widthCC[120].steps == 0); + REQUIRE(region.widthCC[120].step == 2.0_a); + region.parseOpcode({ "width_stepcc120", "-20" }); + REQUIRE(region.widthCC[120].step == 0.0f); } SECTION("position") @@ -562,11 +562,11 @@ TEST_CASE("[Region] Parsing opcodes") region.parseOpcode({ "position_smoothcc14", "-2" }); REQUIRE(region.positionCC[14].smooth == 0); region.parseOpcode({ "position_stepcc120", "24" }); - REQUIRE(region.positionCC[120].steps == 24); + REQUIRE(region.positionCC[120].step == 0.24_a); region.parseOpcode({ "position_stepcc120", "15482" }); - REQUIRE(region.positionCC[120].steps == 127); + REQUIRE(region.positionCC[120].step == 2.0_a); region.parseOpcode({ "position_stepcc120", "-2" }); - REQUIRE(region.positionCC[120].steps == 0); + REQUIRE(region.positionCC[120].step == 0.0f); } SECTION("amp_keycenter") @@ -1519,11 +1519,11 @@ TEST_CASE("[Region] Parsing opcodes") region.parseOpcode({ "amplitude_smoothcc14", "-2" }); REQUIRE(region.amplitudeCC[14].smooth == 0); region.parseOpcode({ "amplitude_stepcc120", "24" }); - REQUIRE(region.amplitudeCC[120].steps == 24); + REQUIRE(region.amplitudeCC[120].step == 0.24_a); region.parseOpcode({ "amplitude_stepcc120", "15482" }); - REQUIRE(region.amplitudeCC[120].steps == 127); + REQUIRE(region.amplitudeCC[120].step == 1.0_a); region.parseOpcode({ "amplitude_stepcc120", "-2" }); - REQUIRE(region.amplitudeCC[120].steps == 0); + REQUIRE(region.amplitudeCC[120].step == 0.0f); } SECTION("volume_oncc/gain_cc") @@ -1551,11 +1551,11 @@ TEST_CASE("[Region] Parsing opcodes") region.parseOpcode({ "volume_smoothcc14", "-2" }); REQUIRE(region.volumeCC[14].smooth == 0); region.parseOpcode({ "volume_stepcc120", "24" }); - REQUIRE(region.volumeCC[120].steps == 24); + REQUIRE(region.volumeCC[120].step == 24.0f); region.parseOpcode({ "volume_stepcc120", "15482" }); - REQUIRE(region.volumeCC[120].steps == 127); + REQUIRE(region.volumeCC[120].step == 48.0f); region.parseOpcode({ "volume_stepcc120", "-2" }); - REQUIRE(region.volumeCC[120].steps == 0); + REQUIRE(region.volumeCC[120].step == 0.0f); } SECTION("tune_cc/pitch_cc") @@ -1583,11 +1583,11 @@ TEST_CASE("[Region] Parsing opcodes") region.parseOpcode({ "pitch_smoothcc14", "-2" }); REQUIRE(region.tuneCC[14].smooth == 0); region.parseOpcode({ "tune_stepcc120", "24" }); - REQUIRE(region.tuneCC[120].steps == 24); + REQUIRE(region.tuneCC[120].step == 24.0f); region.parseOpcode({ "pitch_stepcc120", "15482" }); - REQUIRE(region.tuneCC[120].steps == 127); + REQUIRE(region.tuneCC[120].step == 9600.0f); region.parseOpcode({ "tune_stepcc120", "-2" }); - REQUIRE(region.tuneCC[120].steps == 0); + REQUIRE(region.tuneCC[120].step == 0.0f); } }