diff --git a/src/sfizz/Curve.h b/src/sfizz/Curve.h index ad9667a3..829a2d8b 100644 --- a/src/sfizz/Curve.h +++ b/src/sfizz/Curve.h @@ -45,7 +45,7 @@ public: */ float evalNormalized(float value) const { - return evalCC7(denormalize7Bits(value)); + return evalCC7(value * 127.0f); } /** diff --git a/src/sfizz/ModifierHelpers.h b/src/sfizz/ModifierHelpers.h index 5dd3fd78..02502fcc 100644 --- a/src/sfizz/ModifierHelpers.h +++ b/src/sfizz/ModifierHelpers.h @@ -214,7 +214,7 @@ void multiplicativeModifier(const sfz::Resources& resources, absl::Span s }); } else { // FIXME: not sure about this step size for multiplicative envelopes - const float stepSize { ccData.data.value / ccData.data.steps }; + const float stepSize { lambda(ccData.data.value / ccData.data.steps) }; multiplicativeEnvelope(events, span, [&ccData, &curve, &lambda](float x) { return lambda(curve.evalNormalized(x) * ccData.data.value); }, stepSize); @@ -225,10 +225,4 @@ inline void linearModifier(const sfz::Resources& resources, absl::Span sp { linearModifier(resources, span, ccData, [](float x) { return x; }); } - -inline void multiplicativeModifier(const sfz::Resources& resources, absl::Span span, const sfz::CCData& ccData) -{ - multiplicativeModifier(resources, span, ccData, [](float x) { return x; }); -} - } diff --git a/tests/CurveT.cpp b/tests/CurveT.cpp index 1aa9e161..4c3c9f9d 100644 --- a/tests/CurveT.cpp +++ b/tests/CurveT.cpp @@ -33,7 +33,7 @@ TEST_CASE("[Curve] Bipolar -1 to 1") REQUIRE( curve.evalCC7(85) == Approx(0.3386).margin(1e-3) ); REQUIRE( curve.evalNormalized(0.0f) == -1.0f ); REQUIRE( curve.evalNormalized(1.0f) == 1.0f ); - REQUIRE( curve.evalNormalized(0.3f) == Approx(-0.402).margin(1e-3) ); + REQUIRE( curve.evalNormalized(0.3f) == Approx(-0.4).margin(1e-3) ); } TEST_CASE("[Curve] Bipolar 1 to 0") @@ -59,7 +59,7 @@ TEST_CASE("[Curve] Bipolar 1 to -1") REQUIRE( curve.evalCC7(85) == Approx(-0.3386).margin(1e-3) ); REQUIRE( curve.evalNormalized(0.0f) == 1.0f ); REQUIRE( curve.evalNormalized(1.0f) == -1.0f ); - REQUIRE( curve.evalNormalized(0.3f) == Approx(0.402).margin(1e-3) ); + REQUIRE( curve.evalNormalized(0.3f) == Approx(0.4).margin(1e-3) ); } TEST_CASE("[Curve] x**2") @@ -220,7 +220,7 @@ TEST_CASE("[Curve] Default CurveSet") REQUIRE( curveSet.getCurve(1).evalNormalized(0.0f) == -1.0f ); REQUIRE( curveSet.getCurve(1).evalNormalized(1.0f) == 1.0f ); - REQUIRE( curveSet.getCurve(1).evalNormalized(0.3f) == Approx(-0.402).margin(1e-3) ); + REQUIRE( curveSet.getCurve(1).evalNormalized(0.3f) == Approx(-0.4).margin(1e-3) ); REQUIRE( curveSet.getCurve(2).evalNormalized(0.0f) == 1.0f ); REQUIRE( curveSet.getCurve(2).evalNormalized(1.0f) == 0.0f ); @@ -228,7 +228,7 @@ TEST_CASE("[Curve] Default CurveSet") REQUIRE( curveSet.getCurve(3).evalNormalized(0.0f) == 1.0f ); REQUIRE( curveSet.getCurve(3).evalNormalized(1.0f) == -1.0f ); - REQUIRE( curveSet.getCurve(3).evalNormalized(0.3f) == Approx(0.402).margin(1e-3) ); + REQUIRE( curveSet.getCurve(3).evalNormalized(0.3f) == Approx(0.4).margin(1e-3) ); REQUIRE( curveSet.getCurve(4).evalNormalized(0.0f) == 0.0f ); REQUIRE( curveSet.getCurve(4).evalNormalized(1.0f) == 1.0f ); diff --git a/tests/EventEnvelopesT.cpp b/tests/EventEnvelopesT.cpp index 10954504..71df4a79 100644 --- a/tests/EventEnvelopesT.cpp +++ b/tests/EventEnvelopesT.cpp @@ -273,3 +273,104 @@ TEST_CASE("[MultiplicativeEnvelope] Get quantized with unclean events") multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier, 2.0f); REQUIRE(output == expected); } + +TEST_CASE("[linearModifiers] Compare with envelopes") +{ + sfz::Resources resources; + resources.curves = sfz::CurveSet::createPredefined(); + + sfz::CCData ccData; + ccData.cc = 20; + ccData.data.value = 100.0f; + + resources.midiState.ccEvent(5, 20, 0.1); + resources.midiState.ccEvent(10, 20, 0.2); + + std::array output; + std::array envelope; + + linearEnvelope(resources.midiState.getCCEvents(20), absl::MakeSpan(envelope), [&ccData](float x) { + return ccData.data.value * x; + }); + linearModifier(resources, absl::MakeSpan(output), ccData); + REQUIRE(approxEqual(output, envelope)); + + ccData.data.curve = 1; + linearEnvelope(resources.midiState.getCCEvents(20), absl::MakeSpan(envelope), [&ccData](float x) { + return ccData.data.value * (2 * x - 1); + }); + linearModifier(resources, absl::MakeSpan(output), ccData); + REQUIRE(approxEqual(output, envelope)); + + ccData.data.curve = 3; + ccData.data.value = 10.0f; + linearEnvelope(resources.midiState.getCCEvents(20), absl::MakeSpan(envelope), [&ccData](float x) { + return ccData.data.value * (1 - 2 * x); + }); + linearModifier(resources, absl::MakeSpan(output), ccData); + REQUIRE(approxEqual(output, envelope)); + + ccData.data.curve = 2; + ccData.data.value = 20.0f; + ccData.data.steps = 10; + linearEnvelope(resources.midiState.getCCEvents(20), absl::MakeSpan(envelope), [&ccData](float x) { + return ccData.data.value * (1 - x); + }, ccData.data.value / ccData.data.steps); + linearModifier(resources, absl::MakeSpan(output), ccData); + REQUIRE(approxEqual(output, envelope)); +} + +TEST_CASE("[multiplicativeModifiers] Compare with envelopes") +{ + sfz::Resources resources; + resources.curves = sfz::CurveSet::createPredefined(); + + sfz::CCData ccData; + ccData.cc = 20; + ccData.data.value = 100.0f; + + resources.midiState.ccEvent(5, 20, 0.1); + resources.midiState.ccEvent(10, 20, 0.2); + + std::array output; + std::array envelope; + + multiplicativeEnvelope(resources.midiState.getCCEvents(20), absl::MakeSpan(envelope), [&ccData](float x) { + return db2mag(ccData.data.value * x); + }); + multiplicativeModifier(resources, absl::MakeSpan(output), ccData, [](float x) { + return db2mag(x); + }); + REQUIRE(approxEqual(output, envelope)); + + ccData.data.curve = 1; + multiplicativeEnvelope(resources.midiState.getCCEvents(20), absl::MakeSpan(envelope), [&ccData](float x) { + return db2mag(ccData.data.value * (2 * x - 1)); + }); + multiplicativeModifier(resources, absl::MakeSpan(output), ccData, [](float x) { + return db2mag(x); + }); + REQUIRE(approxEqual(output, envelope)); + + ccData.data.curve = 3; + ccData.data.value = 10.0f; + multiplicativeEnvelope(resources.midiState.getCCEvents(20), absl::MakeSpan(envelope), [&ccData](float x) { + return db2mag(ccData.data.value * (1 - 2 * x)); + }); + multiplicativeModifier(resources, absl::MakeSpan(output), ccData, [](float x) { + return db2mag(x); + }); + REQUIRE(approxEqual(output, envelope)); + + ccData.data.curve = 2; + ccData.data.value = 20.0f; + ccData.data.steps = 10; + 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) ); + multiplicativeModifier(resources, absl::MakeSpan(output), ccData, [](float x) { + return db2mag(x); + }); + REQUIRE(approxEqual(output, envelope)); +} +