Ported the old envelope tests to the new free functions

This commit is contained in:
Paul Ferrand 2020-03-31 00:18:24 +02:00
parent 5412593da9
commit bc60b19c4b
2 changed files with 168 additions and 264 deletions

View file

@ -348,11 +348,15 @@ void linearEnvelope(const EventVector& events, absl::Span<float> envelope, F&& l
{ {
ASSERT(events.size() > 0); ASSERT(events.size() > 0);
ASSERT(events[0].delay == 0); ASSERT(events[0].delay == 0);
if (envelope.size() == 0)
return;
const auto maxDelay = static_cast<int>(envelope.size() - 1);
auto lastValue = lambda(events[0].value); auto lastValue = lambda(events[0].value);
auto lastDelay = events[0].delay; 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 length = events[i].delay - lastDelay; const auto length = min(events[i].delay, maxDelay) - lastDelay;
const auto step = (lambda(events[i].value) - lastValue)/ length; const auto step = (lambda(events[i].value) - lastValue)/ length;
lastValue = linearRamp<float>(envelope.subspan(lastDelay, length), lastValue, step); lastValue = linearRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
lastDelay += length; lastDelay += length;
@ -366,16 +370,21 @@ void linearEnvelope(const EventVector& events, absl::Span<float> envelope, F&& l
ASSERT(events.size() > 0); ASSERT(events.size() > 0);
ASSERT(events[0].delay == 0); ASSERT(events[0].delay == 0);
ASSERT(step != 0.0); ASSERT(step != 0.0);
if (envelope.size() == 0)
return;
auto quantize = [step](float value) -> float { auto quantize = [step](float value) -> float {
return std::round(value / step) * step; return std::round(value / step) * step;
}; };
const auto maxDelay = static_cast<int>(envelope.size() - 1);
auto lastValue = quantize(lambda(events[0].value)); auto lastValue = quantize(lambda(events[0].value));
auto lastDelay = events[0].delay; 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 nextValue = quantize(lambda(events[i].value));
const auto difference = std::abs(nextValue - lastValue); 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) { if (difference < step) {
fill<float>(envelope.subspan(lastDelay, length), lastValue); fill<float>(envelope.subspan(lastDelay, length), lastValue);
@ -401,10 +410,14 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span<float> envelop
ASSERT(events.size() > 0); ASSERT(events.size() > 0);
ASSERT(events[0].delay == 0); ASSERT(events[0].delay == 0);
if (envelope.size() == 0)
return;
const auto maxDelay = static_cast<int>(envelope.size() - 1);
auto lastValue = lambda(events[0].value); auto lastValue = lambda(events[0].value);
auto lastDelay = events[0].delay; 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 length = events[i].delay - lastDelay; const auto length = min(events[i].delay, maxDelay) - lastDelay;
const auto nextValue = lambda(events[i].value); const auto nextValue = lambda(events[i].value);
const auto step = std::exp((std::log(nextValue) - std::log(lastValue)) / length); const auto step = std::exp((std::log(nextValue) - std::log(lastValue)) / length);
multiplicativeRamp<float>(envelope.subspan(lastDelay, length), lastValue, step); multiplicativeRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
@ -420,7 +433,10 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span<float> envelop
ASSERT(events.size() > 0); ASSERT(events.size() > 0);
ASSERT(events[0].delay == 0); ASSERT(events[0].delay == 0);
ASSERT(step != 0.0f); ASSERT(step != 0.0f);
DBG("Called the quantized version with step " << step);
if (envelope.size() == 0)
return;
const auto maxDelay = static_cast<int>(envelope.size() - 1);
const auto logStep = std::log(step); const auto logStep = std::log(step);
// If we assume that a = b.q^r for b in (1, q) then // 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<float> envelop
auto lastValue = quantize(lambda(events[0].value)); auto lastValue = quantize(lambda(events[0].value));
auto lastDelay = events[0].delay; 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 length = events[i].delay - lastDelay; const auto length = min(events[i].delay, maxDelay) - lastDelay;
const auto nextValue = quantize(lambda(events[i].value)); const auto nextValue = quantize(lambda(events[i].value));
const auto difference = nextValue > lastValue ? nextValue / lastValue : lastValue / nextValue; const auto difference = nextValue > lastValue ? nextValue / lastValue : lastValue / nextValue;

View file

@ -30,360 +30,248 @@ inline bool approxEqual(absl::Span<const Type> lhs, absl::Span<const Type> rhs,
return true; 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<float> envelope; sfz::EventVector events {
{0, 0.0f}
};
std::array<float, 5> output; std::array<float, 5> output;
std::array<float, 5> expected { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; std::array<float, 5> expected { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
envelope.getBlock(absl::MakeSpan(output)); std::array<float, 5> expectedMul { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
linearEnvelope(events, absl::MakeSpan(output), idModifier);
REQUIRE(output == expected); 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<float> envelope; sfz::EventVector events {
envelope.registerEvent(4, 1.0f); {0, 0.0f},
std::array<float, 8> output; {4, 1.0f}
std::array<float, 8> expected { 0.25f, 0.5f, 0.75f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; };
envelope.getBlock(absl::MakeSpan(output)); std::array<float, 9> output;
std::array<float, 9> 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); REQUIRE(output == expected);
} }
TEST_CASE("[LinearEnvelope] 2 events, close") TEST_CASE("[LinearEnvelope] 2 events, close")
{ {
sfz::LinearEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(4, 1.0f); {0, 0.0f},
envelope.registerEvent(5, 2.0f); {4, 1.0f},
std::array<float, 8> output; {5, 2.0f}
std::array<float, 8> expected { 0.25f, 0.5f, 0.75f, 1.0f, 2.0f, 2.0f, 2.0f, 2.0f }; };
envelope.getBlock(absl::MakeSpan(output)); std::array<float, 9> output;
std::array<float, 9> 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); REQUIRE(output == expected);
} }
TEST_CASE("[LinearEnvelope] 2 events, far") TEST_CASE("[LinearEnvelope] 2 events, far")
{ {
sfz::LinearEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(2, 1.0f); {0, 0.0f},
envelope.registerEvent(6, 2.0f); {2, 1.0f},
std::array<float, 8> output; {6, 2.0f}
std::array<float, 8> expected { 0.5f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f, 2.0f, 2.0f }; };
envelope.getBlock(absl::MakeSpan(output)); std::array<float, 9> output;
REQUIRE(output == expected); std::array<float, 9> 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);
TEST_CASE("[LinearEnvelope] 2 events, reversed")
{
sfz::LinearEnvelope<float> envelope;
envelope.registerEvent(6, 2.0f);
envelope.registerEvent(2, 1.0f);
std::array<float, 8> output;
std::array<float, 8> 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<float> envelope;
envelope.registerEvent(2, 1.0f);
envelope.registerEvent(6, 2.0f);
envelope.registerEvent(6, 3.0f);
std::array<float, 8> output;
std::array<float, 8> expected { 0.5f, 1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 3.0f, 3.0f };
envelope.getBlock(absl::MakeSpan(output));
REQUIRE(output == expected); REQUIRE(output == expected);
} }
TEST_CASE("[LinearEnvelope] 3 events, out of block") TEST_CASE("[LinearEnvelope] 3 events, out of block")
{ {
// sfz::LinearEnvelope<float> envelope; sfz::EventVector events {
// envelope.registerEvent(2, 1.0f); {0, 0.0f},
// envelope.registerEvent(6, 2.0f); {2, 1.0f},
// envelope.registerEvent(10, 3.0f); {6, 2.0f},
// std::array<float, 8> output; {10, 3.0f}
// std::array<float, 8> 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)); std::array<float, 9> output;
// REQUIRE(output == expected); std::array<float, 9> 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);
TEST_CASE("[LinearEnvelope] 3 events, out of block, with another block call")
{
sfz::LinearEnvelope<float> envelope;
envelope.registerEvent(2, 1.0f);
envelope.registerEvent(6, 2.0f);
envelope.registerEvent(10, 3.0f);
std::array<float, 8> output;
std::array<float, 8> 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<float> envelope;
envelope.registerEvent(2, 1.0f);
envelope.registerEvent(6, 2.0f);
std::array<float, 8> output;
std::array<float, 8> 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));
REQUIRE(output == expected); REQUIRE(output == expected);
} }
TEST_CASE("[LinearEnvelope] 2 events, function") TEST_CASE("[LinearEnvelope] 2 events, function")
{ {
sfz::LinearEnvelope<float> envelope; sfz::EventVector events {
envelope.setFunction([](float x) { return 2 * x; }); {0, 0.0f},
envelope.registerEvent(2, 1.0f); {2, 1.0f},
envelope.registerEvent(6, 2.0f); {6, 2.0f}
std::array<float, 8> output; };
std::array<float, 8> expected { 1.0f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.0f, 4.0f }; std::array<float, 9> output;
envelope.getBlock(absl::MakeSpan(output)); std::array<float, 9> 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); REQUIRE(output == expected);
} }
TEST_CASE("[LinearEnvelope] Get quantized") TEST_CASE("[LinearEnvelope] Get quantized")
{ {
sfz::LinearEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(2, 1.0f); {0, 0.0f},
envelope.registerEvent(6, 2.0f); {2, 1.0f},
{6, 2.0f}
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f }; std::array<float, 8> expected { 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f };
envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); linearEnvelope(events, absl::MakeSpan(output), idModifier, 1.0f);
REQUIRE(output == expected); REQUIRE(output == expected);
} }
TEST_CASE("[LinearEnvelope] Get quantized with unquantized targets") TEST_CASE("[LinearEnvelope] Get quantized with unquantized targets")
{ {
sfz::LinearEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(2, 1.1f); {0, 0.0f},
envelope.registerEvent(6, 1.9f); {2, 1.1f},
{6, 1.9f}
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f }; std::array<float, 8> expected { 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f };
envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); linearEnvelope(events, absl::MakeSpan(output), idModifier, 1.0f);
REQUIRE(output == expected); REQUIRE(output == expected);
} }
TEST_CASE("[LinearEnvelope] Get quantized with 2 steps") TEST_CASE("[LinearEnvelope] Get quantized with 2 steps")
{ {
sfz::LinearEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(2, 1.0f); {0, 0.0f},
envelope.registerEvent(6, 3.0f); {2, 1.0f},
{6, 3.0f}
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 3.0f }; std::array<float, 8> expected { 0.0f, 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f };
envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); linearEnvelope(events, absl::MakeSpan(output), idModifier, 1.0f);
REQUIRE(output == expected); REQUIRE(output == expected);
} }
TEST_CASE("[LinearEnvelope] Get quantized with 2 steps and an unquantized out of block step") TEST_CASE("[LinearEnvelope] Get quantized with 2 steps and an unquantized out of block step")
{ {
sfz::LinearEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(2, 1.0f); {0, 0.0f},
envelope.registerEvent(6, 3.0f); {2, 1.0f},
envelope.registerEvent(10, 4.2f); {6, 3.0f},
{10, 4.2f},
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 4.0f, 4.0f }; std::array<float, 8> expected { 0.0f, 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 4.0f };
std::array<float, 8> expected2 { 4.0f, 4.0f, 4.0f,4.0f, 4.0f, 4.0f, 4.0f, 4.0f }; linearEnvelope(events, absl::MakeSpan(output), idModifier, 1.0f);
envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f);
REQUIRE(output == expected); REQUIRE(output == expected);
envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f);
REQUIRE(output == expected2);
} }
TEST_CASE("[LinearEnvelope] Going down quantized with 2 steps") TEST_CASE("[LinearEnvelope] Going down quantized with 2 steps")
{ {
sfz::LinearEnvelope<float> envelope; sfz::EventVector events {
envelope.reset(3.0f); {0, 3.0f},
envelope.registerEvent(2, 2.0f); {2, 2.0f},
envelope.registerEvent(6, 0.0f); {6, 0.0f}
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 3.0f, 2.0f, 2.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f }; std::array<float, 8> expected { 3.0f, 3.0f, 2.0f, 2.0f, 1.0f, 1.0f, 0.0f, 0.0f };
envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); linearEnvelope(events, absl::MakeSpan(output), idModifier, 1.0f);
REQUIRE(output == expected);
}
TEST_CASE("[LinearEnvelope] Get quantized with 2 steps and starting unquantized")
{
sfz::LinearEnvelope<float> envelope;
envelope.reset(0.1f);
envelope.registerEvent(3, 1.0f);
envelope.registerEvent(7, 3.0f);
std::array<float, 8> output;
std::array<float, 8> 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<float> envelope;
envelope.reset(3.6f);
envelope.registerEvent(4, 1.0f);
envelope.registerEvent(7, 0.0);
std::array<float, 8> output;
std::array<float, 8> 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<float> envelope;
envelope.registerEvent(2, 1.2f);
envelope.registerEvent(6, 2.5f);
std::array<float, 8> output;
std::array<float, 8> 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<float> envelope;
envelope.registerEvent(2, 1.0f);
envelope.registerEvent(6, 2.0f);
envelope.registerEvent(10, 3.0f);
std::array<float, 8> output;
std::array<float, 8> expected { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 3.0f, 3.0f };
std::array<float, 8> 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<float> envelope;
std::array<float, 5> output;
std::array<float, 5> expected { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
envelope.getBlock(absl::MakeSpan(output));
REQUIRE(output == expected); REQUIRE(output == expected);
} }
TEST_CASE("[MultiplicativeEnvelope] Basic event") TEST_CASE("[MultiplicativeEnvelope] Basic event")
{ {
sfz::MultiplicativeEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(4, 2.0f); {0, 1.0f},
{4, 2.0f}
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 1.1892f, 1.4142f, 1.68176f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f }; std::array<float, 8> expected { 1.0f, 1.1892f, 1.4142f, 1.68176f, 2.0f, 2.0f, 2.0f, 2.0f };
envelope.getBlock(absl::MakeSpan(output)); multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier);
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
} }
TEST_CASE("[MultiplicativeEnvelope] 2 events") TEST_CASE("[MultiplicativeEnvelope] 2 events")
{ {
sfz::MultiplicativeEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(4, 2.0f); {0, 1.0f},
envelope.registerEvent(5, 4.0f); {4, 2.0f},
{5, 4.0f}
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 1.1892f, 1.4142f, 1.68176f, 2.0f, 4.0f, 4.0f, 4.0f, 4.0f }; std::array<float, 8> expected { 1.0f, 1.1892f, 1.4142f, 1.68176f, 2.0f, 4.0f, 4.0f, 4.0f};
envelope.getBlock(absl::MakeSpan(output)); multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier);
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
} }
TEST_CASE("[MultiplicativeEnvelope] 2 events, far") TEST_CASE("[MultiplicativeEnvelope] 2 events, far")
{ {
sfz::MultiplicativeEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(2, 2.0f); {0, 1.0f},
envelope.registerEvent(6, 4.0f); {2, 2.0f},
{6, 4.0f}
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 1.4142f, 2.0f, 2.37841f, 2.82843f, 3.36358f, 4.0f, 4.0f, 4.0f }; std::array<float, 8> expected { 1.0f, 1.4142f, 2.0f, 2.37841f, 2.82843f, 3.36358f, 4.0f, 4.0f};
envelope.getBlock(absl::MakeSpan(output)); multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier);
REQUIRE(approxEqual<float>(output, expected)); REQUIRE(approxEqual<float>(output, expected));
} }
TEST_CASE("[MultiplicativeEnvelope] Get quantized with 2 steps") TEST_CASE("[MultiplicativeEnvelope] Get quantized with 2 steps")
{ {
sfz::MultiplicativeEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(2, 2.0f); {0, 1.0f},
envelope.registerEvent(6, 4.0f); {2, 2.0f},
{6, 4.0f}
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 1.0f, 2.0f, 2.0f, 2.0f, 2.0f, 4.0f, 4.0f, 4.0f }; std::array<float, 8> expected { 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 2.0f, 4.0f, 4.0f};
envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f); multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier, 2.0f);
REQUIRE(output == expected); REQUIRE(output == expected);
} }
TEST_CASE("[MultiplicativeEnvelope] Get quantized with an unquantized out of range step") TEST_CASE("[MultiplicativeEnvelope] Get quantized with an unquantized out of range step")
{ {
sfz::MultiplicativeEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(2, 2.0f); {0, 1.0f},
envelope.registerEvent(6, 4.0f); {2, 2.0f},
envelope.registerEvent(10, 8.2f); {6, 4.0f},
{10, 8.2f}
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 1.0f, 2.0f, 2.0f, 2.0f, 2.0f, 4.0f, 8.0f, 8.0f }; std::array<float, 8> expected { 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 2.0f, 4.0f, 8.0f };
std::array<float, 8> expected2 { 8.0f, 8.0f, 8.0f, 8.0f, 8.0f, 8.0f, 8.0f, 8.0f }; multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier, 2.0f);
envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f);
REQUIRE(output == expected); REQUIRE(output == expected);
envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f);
REQUIRE(output == expected2);
} }
TEST_CASE("[MultiplicativeEnvelope] Going down quantized with 2 steps") TEST_CASE("[MultiplicativeEnvelope] Going down quantized with 2 steps")
{ {
sfz::MultiplicativeEnvelope<float> envelope; sfz::EventVector events {
envelope.reset(4.0f); {0, 4.0f},
envelope.registerEvent(2, 2.0f); {2, 2.0f},
envelope.registerEvent(6, 0.5f); {6, 0.5f}
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 4.0f, 2.0f, 2.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f }; std::array<float, 8> expected { 4.0f, 4.0f, 2.0f, 2.0f, 1.0f, 1.0f, 0.5f, 0.5f };
envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f); multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier, 2.0f);
REQUIRE(output == expected); REQUIRE(output == expected);
} }
TEST_CASE("[MultiplicativeEnvelope] Get quantized with unclean events") TEST_CASE("[MultiplicativeEnvelope] Get quantized with unclean events")
{ {
sfz::MultiplicativeEnvelope<float> envelope; sfz::EventVector events {
envelope.registerEvent(2, 1.2f); {0, 1.0f},
envelope.registerEvent(6, 2.5f); {2, 1.2f},
{6, 2.5f}
};
std::array<float, 8> output; std::array<float, 8> output;
std::array<float, 8> expected { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f }; std::array<float, 8> expected { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 2.0f };
envelope.getQuantizedBlock(absl::MakeSpan(output), 2.0f); multiplicativeEnvelope(events, absl::MakeSpan(output), idModifier, 2.0f);
REQUIRE(output == expected); REQUIRE(output == expected);
} }
TEST_CASE("[MultiplicativeEnvelope] Get quantized with 2 steps and starting unquantized")
{
sfz::MultiplicativeEnvelope<float> envelope;
envelope.reset(0.9f);
envelope.registerEvent(3, 1.0f);
envelope.registerEvent(7, 4.0f);
std::array<float, 8> output;
std::array<float, 8> 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<float> envelope;
envelope.reset(4.6f);
envelope.registerEvent(4, 1.0f);
envelope.registerEvent(7, 0.25f);
std::array<float, 8> output;
std::array<float, 8> 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<float> output { 256 };
sfz::MultiplicativeEnvelope<float> 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));
}