diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index 6223cf0f..32d042be 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -348,11 +348,15 @@ void linearEnvelope(const EventVector& events, absl::Span envelope, F&& l { ASSERT(events.size() > 0); ASSERT(events[0].delay == 0); + if (envelope.size() == 0) + return; + + const auto maxDelay = static_cast(envelope.size() - 1); auto lastValue = lambda(events[0].value); auto lastDelay = events[0].delay; - for (unsigned i = 1; i < events.size(); ++ i) { - const auto length = events[i].delay - lastDelay; + for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++ i) { + const auto length = min(events[i].delay, maxDelay) - lastDelay; const auto step = (lambda(events[i].value) - lastValue)/ length; lastValue = linearRamp(envelope.subspan(lastDelay, length), lastValue, step); lastDelay += length; @@ -366,16 +370,21 @@ void linearEnvelope(const EventVector& events, absl::Span envelope, F&& l ASSERT(events.size() > 0); ASSERT(events[0].delay == 0); ASSERT(step != 0.0); + + if (envelope.size() == 0) + return; + auto quantize = [step](float value) -> float { return std::round(value / step) * step; }; + const auto maxDelay = static_cast(envelope.size() - 1); auto lastValue = quantize(lambda(events[0].value)); auto lastDelay = events[0].delay; - for (unsigned i = 1; i < events.size(); ++ i) { + for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++ i) { const auto nextValue = quantize(lambda(events[i].value)); const auto difference = std::abs(nextValue - lastValue); - const auto length = events[i].delay - lastDelay; + const auto length = min(events[i].delay, maxDelay) - lastDelay; if (difference < step) { fill(envelope.subspan(lastDelay, length), lastValue); @@ -401,10 +410,14 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span envelop ASSERT(events.size() > 0); ASSERT(events[0].delay == 0); + if (envelope.size() == 0) + return; + const auto maxDelay = static_cast(envelope.size() - 1); + auto lastValue = lambda(events[0].value); auto lastDelay = events[0].delay; - for (unsigned i = 1; i < events.size(); ++ i) { - const auto length = events[i].delay - lastDelay; + for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++ i) { + const auto length = min(events[i].delay, maxDelay) - lastDelay; const auto nextValue = lambda(events[i].value); const auto step = std::exp((std::log(nextValue) - std::log(lastValue)) / length); multiplicativeRamp(envelope.subspan(lastDelay, length), lastValue, step); @@ -420,7 +433,10 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span envelop ASSERT(events.size() > 0); ASSERT(events[0].delay == 0); ASSERT(step != 0.0f); - DBG("Called the quantized version with step " << step); + + if (envelope.size() == 0) + return; + const auto maxDelay = static_cast(envelope.size() - 1); const auto logStep = std::log(step); // If we assume that a = b.q^r for b in (1, q) then @@ -434,8 +450,8 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span envelop auto lastValue = quantize(lambda(events[0].value)); auto lastDelay = events[0].delay; - for (unsigned i = 1; i < events.size(); ++ i) { - const auto length = events[i].delay - lastDelay; + for (unsigned i = 1; i < events.size() && lastDelay < maxDelay; ++ i) { + const auto length = min(events[i].delay, maxDelay) - lastDelay; const auto nextValue = quantize(lambda(events[i].value)); const auto difference = nextValue > lastValue ? nextValue / lastValue : lastValue / nextValue; diff --git a/tests/EventEnvelopesT.cpp b/tests/EventEnvelopesT.cpp index 936f6dbf..a2916165 100644 --- a/tests/EventEnvelopesT.cpp +++ b/tests/EventEnvelopesT.cpp @@ -30,360 +30,248 @@ inline bool approxEqual(absl::Span lhs, absl::Span rhs, return true; } -TEST_CASE("[LinearEnvelope] Basic state") +const auto idModifier = [] (float x) { return x; }; +const auto twiceModifier = [] (float x) { return 2 * x; }; +const auto expModifier = [] (float x) { return std::exp(x); }; + +TEST_CASE("[Envelopes] Empty") { - sfz::LinearEnvelope envelope; + sfz::EventVector events { + {0, 0.0f} + }; std::array output; std::array expected { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; - envelope.getBlock(absl::MakeSpan(output)); + std::array expectedMul { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; + linearEnvelope(events, absl::MakeSpan(output), idModifier); REQUIRE(output == expected); + linearEnvelope(events, absl::MakeSpan(output), idModifier, 1.0f); + REQUIRE(output == expected); + multiplicativeEnvelope(events, absl::MakeSpan(output), expModifier); + REQUIRE(output == expectedMul); + multiplicativeEnvelope(events, absl::MakeSpan(output), expModifier, 2.0f); + REQUIRE(output == expectedMul); } -TEST_CASE("[LinearEnvelope] Basic event") +TEST_CASE("[Envelopes] Linear basic") { - sfz::LinearEnvelope envelope; - envelope.registerEvent(4, 1.0f); - std::array output; - std::array expected { 0.25f, 0.5f, 0.75f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; - envelope.getBlock(absl::MakeSpan(output)); + sfz::EventVector events { + {0, 0.0f}, + {4, 1.0f} + }; + std::array output; + std::array expected { 0.0f, 0.25f, 0.5f, 0.75f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; + linearEnvelope(events, absl::MakeSpan(output), idModifier); REQUIRE(output == expected); } TEST_CASE("[LinearEnvelope] 2 events, close") { - sfz::LinearEnvelope envelope; - envelope.registerEvent(4, 1.0f); - envelope.registerEvent(5, 2.0f); - std::array output; - std::array expected { 0.25f, 0.5f, 0.75f, 1.0f, 2.0f, 2.0f, 2.0f, 2.0f }; - envelope.getBlock(absl::MakeSpan(output)); + sfz::EventVector events { + {0, 0.0f}, + {4, 1.0f}, + {5, 2.0f} + }; + std::array output; + std::array expected { 0.0f, 0.25f, 0.5f, 0.75f, 1.0f, 2.0f, 2.0f, 2.0f, 2.0f }; + linearEnvelope(events, absl::MakeSpan(output), idModifier); REQUIRE(output == expected); } + TEST_CASE("[LinearEnvelope] 2 events, far") { - sfz::LinearEnvelope envelope; - envelope.registerEvent(2, 1.0f); - envelope.registerEvent(6, 2.0f); - std::array output; - std::array expected { 0.5f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f, 2.0f, 2.0f }; - envelope.getBlock(absl::MakeSpan(output)); - REQUIRE(output == expected); -} - -TEST_CASE("[LinearEnvelope] 2 events, reversed") -{ - sfz::LinearEnvelope envelope; - envelope.registerEvent(6, 2.0f); - envelope.registerEvent(2, 1.0f); - std::array output; - std::array expected { 0.5f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f, 2.0f, 2.0f }; - envelope.getBlock(absl::MakeSpan(output)); - REQUIRE(output == expected); -} - -TEST_CASE("[LinearEnvelope] 3 events, overlapping") -{ - sfz::LinearEnvelope envelope; - envelope.registerEvent(2, 1.0f); - envelope.registerEvent(6, 2.0f); - envelope.registerEvent(6, 3.0f); - std::array output; - std::array expected { 0.5f, 1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 3.0f, 3.0f }; - envelope.getBlock(absl::MakeSpan(output)); + sfz::EventVector events { + {0, 0.0f}, + {2, 1.0f}, + {6, 2.0f} + }; + std::array output; + std::array expected { 0.0f, 0.5f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f, 2.0f, 2.0f }; + linearEnvelope(events, absl::MakeSpan(output), idModifier); REQUIRE(output == expected); } TEST_CASE("[LinearEnvelope] 3 events, out of block") { - // sfz::LinearEnvelope envelope; - // envelope.registerEvent(2, 1.0f); - // envelope.registerEvent(6, 2.0f); - // envelope.registerEvent(10, 3.0f); - // std::array output; - // std::array expected { 0.5f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f, 3.0f, 3.0f }; // TODO: this one is a bit strange - // envelope.getBlock(absl::MakeSpan(output)); - // REQUIRE(output == expected); -} - -TEST_CASE("[LinearEnvelope] 3 events, out of block, with another block call") -{ - sfz::LinearEnvelope envelope; - envelope.registerEvent(2, 1.0f); - envelope.registerEvent(6, 2.0f); - envelope.registerEvent(10, 3.0f); - std::array output; - std::array expected { 3.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f }; - envelope.getBlock(absl::MakeSpan(output)); - envelope.getBlock(absl::MakeSpan(output)); - REQUIRE(output == expected); -} - -TEST_CASE("[LinearEnvelope] 2 events, with another block call") -{ - sfz::LinearEnvelope envelope; - envelope.registerEvent(2, 1.0f); - envelope.registerEvent(6, 2.0f); - std::array output; - std::array expected { 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f }; - envelope.getBlock(absl::MakeSpan(output)); - envelope.getBlock(absl::MakeSpan(output)); + sfz::EventVector events { + {0, 0.0f}, + {2, 1.0f}, + {6, 2.0f}, + {10, 3.0f} + }; + std::array output; + std::array expected { 0.0f, 0.5f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f, 2.5f, 3.0f }; + linearEnvelope(events, absl::MakeSpan(output), idModifier); REQUIRE(output == expected); } TEST_CASE("[LinearEnvelope] 2 events, function") { - sfz::LinearEnvelope envelope; - envelope.setFunction([](float x) { return 2 * x; }); - envelope.registerEvent(2, 1.0f); - envelope.registerEvent(6, 2.0f); - std::array output; - std::array expected { 1.0f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.0f, 4.0f }; - envelope.getBlock(absl::MakeSpan(output)); + sfz::EventVector events { + {0, 0.0f}, + {2, 1.0f}, + {6, 2.0f} + }; + std::array output; + std::array expected { 0.0f, 1.0f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.0f, 4.0f }; + linearEnvelope(events, absl::MakeSpan(output), twiceModifier); REQUIRE(output == expected); } TEST_CASE("[LinearEnvelope] Get quantized") { - sfz::LinearEnvelope envelope; - envelope.registerEvent(2, 1.0f); - envelope.registerEvent(6, 2.0f); + sfz::EventVector events { + {0, 0.0f}, + {2, 1.0f}, + {6, 2.0f} + }; std::array output; - std::array expected { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); + std::array expected { 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f }; + linearEnvelope(events, absl::MakeSpan(output), idModifier, 1.0f); REQUIRE(output == expected); } TEST_CASE("[LinearEnvelope] Get quantized with unquantized targets") { - sfz::LinearEnvelope envelope; - envelope.registerEvent(2, 1.1f); - envelope.registerEvent(6, 1.9f); + sfz::EventVector events { + {0, 0.0f}, + {2, 1.1f}, + {6, 1.9f} + }; std::array output; - std::array expected { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); + std::array expected { 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f }; + linearEnvelope(events, absl::MakeSpan(output), idModifier, 1.0f); REQUIRE(output == expected); } TEST_CASE("[LinearEnvelope] Get quantized with 2 steps") { - sfz::LinearEnvelope envelope; - envelope.registerEvent(2, 1.0f); - envelope.registerEvent(6, 3.0f); + sfz::EventVector events { + {0, 0.0f}, + {2, 1.0f}, + {6, 3.0f} + }; std::array output; - std::array expected { 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 3.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); + std::array expected { 0.0f, 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f }; + linearEnvelope(events, absl::MakeSpan(output), idModifier, 1.0f); REQUIRE(output == expected); } TEST_CASE("[LinearEnvelope] Get quantized with 2 steps and an unquantized out of block step") { - sfz::LinearEnvelope envelope; - envelope.registerEvent(2, 1.0f); - envelope.registerEvent(6, 3.0f); - envelope.registerEvent(10, 4.2f); + sfz::EventVector events { + {0, 0.0f}, + {2, 1.0f}, + {6, 3.0f}, + {10, 4.2f}, + }; std::array output; - std::array expected { 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 4.0f, 4.0f }; - std::array expected2 { 4.0f, 4.0f, 4.0f,4.0f, 4.0f, 4.0f, 4.0f, 4.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); + std::array expected { 0.0f, 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 4.0f }; + linearEnvelope(events, absl::MakeSpan(output), idModifier, 1.0f); REQUIRE(output == expected); - envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); - REQUIRE(output == expected2); } TEST_CASE("[LinearEnvelope] Going down quantized with 2 steps") { - sfz::LinearEnvelope envelope; - envelope.reset(3.0f); - envelope.registerEvent(2, 2.0f); - envelope.registerEvent(6, 0.0f); + sfz::EventVector events { + {0, 3.0f}, + {2, 2.0f}, + {6, 0.0f} + }; std::array output; - std::array expected { 3.0f, 2.0f, 2.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); - REQUIRE(output == expected); -} - -TEST_CASE("[LinearEnvelope] Get quantized with 2 steps and starting unquantized") -{ - sfz::LinearEnvelope envelope; - envelope.reset(0.1f); - envelope.registerEvent(3, 1.0f); - envelope.registerEvent(7, 3.0f); - std::array output; - std::array expected { 0.1f, 0.1f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); - REQUIRE(output == expected); -} - - -TEST_CASE("[LinearEnvelope] Going down quantized with 2 steps and starting unquantized") -{ - sfz::LinearEnvelope envelope; - envelope.reset(3.6f); - envelope.registerEvent(4, 1.0f); - envelope.registerEvent(7, 0.0); - std::array output; - std::array expected { 3.6f, 3.0f, 2.0f, 2.0f, 1.0f, 1.0f, 0.0f, 0.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); - REQUIRE(output == expected); -} - -TEST_CASE("[LinearEnvelope] Get quantized with unclean events") -{ - sfz::LinearEnvelope envelope; - envelope.registerEvent(2, 1.2f); - envelope.registerEvent(6, 2.5f); - std::array output; - std::array expected { 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 3.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); - REQUIRE(output == expected); -} - -TEST_CASE("[LinearEnvelope] Get quantized 3 events, one out of block") -{ - sfz::LinearEnvelope envelope; - envelope.registerEvent(2, 1.0f); - envelope.registerEvent(6, 2.0f); - envelope.registerEvent(10, 3.0f); - std::array output; - std::array expected { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 3.0f, 3.0f }; - std::array expected2 { 3.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); - REQUIRE(output == expected); - envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); - REQUIRE(output == expected2); -} - -// -TEST_CASE("[MultiplicativeEnvelope] Basic state") -{ - sfz::MultiplicativeEnvelope envelope; - std::array output; - std::array expected { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; - envelope.getBlock(absl::MakeSpan(output)); + std::array expected { 3.0f, 3.0f, 2.0f, 2.0f, 1.0f, 1.0f, 0.0f, 0.0f }; + linearEnvelope(events, absl::MakeSpan(output), idModifier, 1.0f); REQUIRE(output == expected); } TEST_CASE("[MultiplicativeEnvelope] Basic event") { - sfz::MultiplicativeEnvelope envelope; - envelope.registerEvent(4, 2.0f); + sfz::EventVector events { + {0, 1.0f}, + {4, 2.0f} + }; std::array output; - std::array expected { 1.1892f, 1.4142f, 1.68176f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f }; - envelope.getBlock(absl::MakeSpan(output)); + std::array expected { 1.0f, 1.1892f, 1.4142f, 1.68176f, 2.0f, 2.0f, 2.0f, 2.0f }; + multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier); REQUIRE(approxEqual(output, expected)); } TEST_CASE("[MultiplicativeEnvelope] 2 events") { - sfz::MultiplicativeEnvelope envelope; - envelope.registerEvent(4, 2.0f); - envelope.registerEvent(5, 4.0f); + sfz::EventVector events { + {0, 1.0f}, + {4, 2.0f}, + {5, 4.0f} + }; std::array output; - std::array expected { 1.1892f, 1.4142f, 1.68176f, 2.0f, 4.0f, 4.0f, 4.0f, 4.0f }; - envelope.getBlock(absl::MakeSpan(output)); + std::array expected { 1.0f, 1.1892f, 1.4142f, 1.68176f, 2.0f, 4.0f, 4.0f, 4.0f}; + multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier); REQUIRE(approxEqual(output, expected)); } TEST_CASE("[MultiplicativeEnvelope] 2 events, far") { - sfz::MultiplicativeEnvelope envelope; - envelope.registerEvent(2, 2.0f); - envelope.registerEvent(6, 4.0f); + sfz::EventVector events { + {0, 1.0f}, + {2, 2.0f}, + {6, 4.0f} + }; std::array output; - std::array expected { 1.4142f, 2.0f, 2.37841f, 2.82843f, 3.36358f, 4.0f, 4.0f, 4.0f }; - envelope.getBlock(absl::MakeSpan(output)); + std::array expected { 1.0f, 1.4142f, 2.0f, 2.37841f, 2.82843f, 3.36358f, 4.0f, 4.0f}; + multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier); REQUIRE(approxEqual(output, expected)); } TEST_CASE("[MultiplicativeEnvelope] Get quantized with 2 steps") { - sfz::MultiplicativeEnvelope envelope; - envelope.registerEvent(2, 2.0f); - envelope.registerEvent(6, 4.0f); + sfz::EventVector events { + {0, 1.0f}, + {2, 2.0f}, + {6, 4.0f} + }; std::array output; - std::array expected { 1.0f, 2.0f, 2.0f, 2.0f, 2.0f, 4.0f, 4.0f, 4.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f); + std::array expected { 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 2.0f, 4.0f, 4.0f}; + multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier, 2.0f); REQUIRE(output == expected); } TEST_CASE("[MultiplicativeEnvelope] Get quantized with an unquantized out of range step") { - sfz::MultiplicativeEnvelope envelope; - envelope.registerEvent(2, 2.0f); - envelope.registerEvent(6, 4.0f); - envelope.registerEvent(10, 8.2f); + sfz::EventVector events { + {0, 1.0f}, + {2, 2.0f}, + {6, 4.0f}, + {10, 8.2f} + }; std::array output; - std::array expected { 1.0f, 2.0f, 2.0f, 2.0f, 2.0f, 4.0f, 8.0f, 8.0f }; - std::array expected2 { 8.0f, 8.0f, 8.0f, 8.0f, 8.0f, 8.0f, 8.0f, 8.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f); + std::array expected { 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 2.0f, 4.0f, 8.0f }; + multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier, 2.0f); REQUIRE(output == expected); - envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f); - REQUIRE(output == expected2); } TEST_CASE("[MultiplicativeEnvelope] Going down quantized with 2 steps") { - sfz::MultiplicativeEnvelope envelope; - envelope.reset(4.0f); - envelope.registerEvent(2, 2.0f); - envelope.registerEvent(6, 0.5f); + sfz::EventVector events { + {0, 4.0f}, + {2, 2.0f}, + {6, 0.5f} + }; std::array output; - std::array expected { 4.0f, 2.0f, 2.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f); + std::array expected { 4.0f, 4.0f, 2.0f, 2.0f, 1.0f, 1.0f, 0.5f, 0.5f }; + multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier, 2.0f); REQUIRE(output == expected); } TEST_CASE("[MultiplicativeEnvelope] Get quantized with unclean events") { - sfz::MultiplicativeEnvelope envelope; - envelope.registerEvent(2, 1.2f); - envelope.registerEvent(6, 2.5f); + sfz::EventVector events { + {0, 1.0f}, + {2, 1.2f}, + {6, 2.5f} + }; std::array output; - std::array expected { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f); + std::array expected { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f }; + multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier, 2.0f); REQUIRE(output == expected); } - -TEST_CASE("[MultiplicativeEnvelope] Get quantized with 2 steps and starting unquantized") -{ - sfz::MultiplicativeEnvelope envelope; - envelope.reset(0.9f); - envelope.registerEvent(3, 1.0f); - envelope.registerEvent(7, 4.0f); - std::array output; - std::array expected { 0.9f, 0.9f, 1.0f, 1.0f, 2.0f, 2.0f, 4.0f, 4.0f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f); - REQUIRE(output == expected); -} - - -TEST_CASE("[MultiplicativeEnvelope] Going down quantized with 2 steps and starting unquantized") -{ - sfz::MultiplicativeEnvelope envelope; - envelope.reset(4.6f); - envelope.registerEvent(4, 1.0f); - envelope.registerEvent(7, 0.25f); - std::array output; - std::array expected { 4.6f, 2.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.25f, 0.25f }; - envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f); - REQUIRE(output == expected); -} - -TEST_CASE("[MultiplicativeEnvelope] Pitch envelope basic function") -{ - sfz::Buffer output { 256 }; - sfz::MultiplicativeEnvelope envelope; - envelope.setFunction([](float pitchValue){ - const auto normalizedBend = sfz::normalizeBend(pitchValue); - const auto bendInCents = normalizedBend * 200.0f; - return sfz::centsFactor(bendInCents); - }); - envelope.reset(0.0f); - envelope.getBlock(absl::MakeSpan(output)); - REQUIRE(output[255] == 1.0_a); - envelope.registerEvent(252, -6020.0f); - envelope.getBlock(absl::MakeSpan(output)); - REQUIRE(output[255] == Approx(0.9168).epsilon(0.01)); -}