- Add some expected behavior tests- Correct the evalNormalized in curves- Remove the no-lambda multiplicative modifiers... it's a trap that makes you create nans and infs
This commit is contained in:
parent
5e6584a51a
commit
e975877569
4 changed files with 107 additions and 12 deletions
|
|
@ -45,7 +45,7 @@ public:
|
||||||
*/
|
*/
|
||||||
float evalNormalized(float value) const
|
float evalNormalized(float value) const
|
||||||
{
|
{
|
||||||
return evalCC7(denormalize7Bits<int>(value));
|
return evalCC7(value * 127.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ void multiplicativeModifier(const sfz::Resources& resources, absl::Span<float> s
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// FIXME: not sure about this step size for multiplicative envelopes
|
// 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) {
|
multiplicativeEnvelope(events, span, [&ccData, &curve, &lambda](float x) {
|
||||||
return lambda(curve.evalNormalized(x) * ccData.data.value);
|
return lambda(curve.evalNormalized(x) * ccData.data.value);
|
||||||
}, stepSize);
|
}, stepSize);
|
||||||
|
|
@ -225,10 +225,4 @@ inline void linearModifier(const sfz::Resources& resources, absl::Span<float> sp
|
||||||
{
|
{
|
||||||
linearModifier(resources, span, ccData, [](float x) { return x; });
|
linearModifier(resources, span, ccData, [](float x) { return x; });
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void multiplicativeModifier(const sfz::Resources& resources, absl::Span<float> span, const sfz::CCData<sfz::Modifier>& ccData)
|
|
||||||
{
|
|
||||||
multiplicativeModifier(resources, span, ccData, [](float x) { return x; });
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ TEST_CASE("[Curve] Bipolar -1 to 1")
|
||||||
REQUIRE( curve.evalCC7(85) == Approx(0.3386).margin(1e-3) );
|
REQUIRE( curve.evalCC7(85) == Approx(0.3386).margin(1e-3) );
|
||||||
REQUIRE( curve.evalNormalized(0.0f) == -1.0f );
|
REQUIRE( curve.evalNormalized(0.0f) == -1.0f );
|
||||||
REQUIRE( curve.evalNormalized(1.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")
|
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.evalCC7(85) == Approx(-0.3386).margin(1e-3) );
|
||||||
REQUIRE( curve.evalNormalized(0.0f) == 1.0f );
|
REQUIRE( curve.evalNormalized(0.0f) == 1.0f );
|
||||||
REQUIRE( curve.evalNormalized(1.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")
|
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(0.0f) == -1.0f );
|
||||||
REQUIRE( curveSet.getCurve(1).evalNormalized(1.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(0.0f) == 1.0f );
|
||||||
REQUIRE( curveSet.getCurve(2).evalNormalized(1.0f) == 0.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(0.0f) == 1.0f );
|
||||||
REQUIRE( curveSet.getCurve(3).evalNormalized(1.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(0.0f) == 0.0f );
|
||||||
REQUIRE( curveSet.getCurve(4).evalNormalized(1.0f) == 1.0f );
|
REQUIRE( curveSet.getCurve(4).evalNormalized(1.0f) == 1.0f );
|
||||||
|
|
|
||||||
|
|
@ -273,3 +273,104 @@ TEST_CASE("[MultiplicativeEnvelope] Get quantized with unclean events")
|
||||||
multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier, 2.0f);
|
multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier, 2.0f);
|
||||||
REQUIRE(output == expected);
|
REQUIRE(output == expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[linearModifiers] Compare with envelopes")
|
||||||
|
{
|
||||||
|
sfz::Resources resources;
|
||||||
|
resources.curves = sfz::CurveSet::createPredefined();
|
||||||
|
|
||||||
|
sfz::CCData<sfz::Modifier> 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<float, 16> output;
|
||||||
|
std::array<float, 16> 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<float>(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<float>(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<float>(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<float>(output, envelope));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[multiplicativeModifiers] Compare with envelopes")
|
||||||
|
{
|
||||||
|
sfz::Resources resources;
|
||||||
|
resources.curves = sfz::CurveSet::createPredefined();
|
||||||
|
|
||||||
|
sfz::CCData<sfz::Modifier> 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<float, 16> output;
|
||||||
|
std::array<float, 16> 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<float>(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<float>(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<float>(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<float>(output, envelope));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue