From 055f233d88f6fbde2a13eea3b473ac0eaa06bd5f Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Thu, 12 Dec 2019 18:27:18 +0100 Subject: [PATCH] Added a new quantized envelope --- benchmarks/BM_fill.cpp | 10 +++--- benchmarks/BM_ramp.cpp | 61 ++++++++++++++++++++++++++++++++++++ src/sfizz/LinearEnvelope.cpp | 11 ++++--- tests/LinearEnvelopeT.cpp | 48 ++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 9 deletions(-) diff --git a/benchmarks/BM_fill.cpp b/benchmarks/BM_fill.cpp index 056a3dc1..2bb5ef0e 100644 --- a/benchmarks/BM_fill.cpp +++ b/benchmarks/BM_fill.cpp @@ -79,9 +79,9 @@ static void FillSIMD_unaligned(benchmark::State& state) { } } -BENCHMARK(Dummy)->Range((2<<6), (2<<16)); -BENCHMARK(FillScalar)->Range((2<<6), (2<<16)); -BENCHMARK(FillSIMD)->Range((2<<6), (2<<16)); -BENCHMARK(FillScalar_unaligned)->Range((2<<6), (2<<16)); -BENCHMARK(FillSIMD_unaligned)->Range((2<<6), (2<<16)); +BENCHMARK(Dummy)->RangeMultiplier(4)->Range((1<<2), (1<<12)); +BENCHMARK(FillScalar)->RangeMultiplier(4)->Range((1<<2), (1<<12)); +BENCHMARK(FillSIMD)->RangeMultiplier(4)->Range((1<<2), (1<<12)); +BENCHMARK(FillScalar_unaligned)->RangeMultiplier(4)->Range((1<<2), (1<<12)); +BENCHMARK(FillSIMD_unaligned)->RangeMultiplier(4)->Range((1<<2), (1<<12)); BENCHMARK_MAIN(); \ No newline at end of file diff --git a/benchmarks/BM_ramp.cpp b/benchmarks/BM_ramp.cpp index 313372ad..e59615b1 100644 --- a/benchmarks/BM_ramp.cpp +++ b/benchmarks/BM_ramp.cpp @@ -133,6 +133,63 @@ static void MulSIMDUnaligned(benchmark::State& state) { } } +static void LogDomainScalar(benchmark::State& state) { + sfz::Buffer output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + std::uniform_real_distribution dist { 1, 2 }; + for (auto _ : state) + { + auto value = dist(gen); + sfz::linearRamp(absl::MakeSpan(output), 1.0f, value); + sfz::applyGain(std::log(2.0f), absl::MakeSpan(output)); + sfz::exp(output, absl::MakeSpan(output)); + } +} + +static void LogDomainSIMD(benchmark::State& state) { + sfz::Buffer output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + std::uniform_real_distribution dist { 1, 2 }; + for (auto _ : state) + { + auto value = dist(gen); + sfz::linearRamp(absl::MakeSpan(output), 1.0f, value); + sfz::applyGain(std::log(2.0f), absl::MakeSpan(output)); + sfz::exp(output, absl::MakeSpan(output)); + } +} +static void LogDomainScalarUnaligned(benchmark::State& state) { + sfz::Buffer output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + std::uniform_real_distribution dist { 1, 2 }; + for (auto _ : state) + { + auto value = dist(gen); + auto outputSpan = absl::MakeSpan(output).subspan(1); + sfz::linearRamp(outputSpan, 1.0f, value); + sfz::applyGain(std::log(2.0f), outputSpan); + sfz::exp(outputSpan, outputSpan); + } +} + +static void LogDomainSIMDUnaligned(benchmark::State& state) { + sfz::Buffer output(state.range(0)); + std::random_device rd { }; + std::mt19937 gen { rd() }; + std::uniform_real_distribution dist { 1, 2 }; + for (auto _ : state) + { + auto value = dist(gen); + auto outputSpan = absl::MakeSpan(output).subspan(1); + sfz::linearRamp(outputSpan, 1.0f, value); + sfz::applyGain(std::log(2.0f), outputSpan); + sfz::exp(outputSpan, outputSpan); + } +} + // Register the function as a benchmark BENCHMARK(Dummy)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); BENCHMARK(LinearScalar)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); @@ -143,4 +200,8 @@ BENCHMARK(MulScalar)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); BENCHMARK(MulSIMD)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); BENCHMARK(MulScalarUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); BENCHMARK(MulSIMDUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); +BENCHMARK(LogDomainScalar)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); +BENCHMARK(LogDomainSIMD)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); +BENCHMARK(LogDomainScalarUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); +BENCHMARK(LogDomainSIMDUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12)); BENCHMARK_MAIN(); \ No newline at end of file diff --git a/src/sfizz/LinearEnvelope.cpp b/src/sfizz/LinearEnvelope.cpp index 7b6d03af..e110e3aa 100644 --- a/src/sfizz/LinearEnvelope.cpp +++ b/src/sfizz/LinearEnvelope.cpp @@ -103,13 +103,16 @@ void LinearEnvelope::getBlock(absl::Span output) template void LinearEnvelope::getQuantizedBlock(absl::Span output, Type quantizationStep) { + ASSERT(quantizationStep != 0.0); + absl::c_sort(events, [](const auto& lhs, const auto& rhs) { return lhs.first < rhs.first; }); int index { 0 }; - auto quantize = [quantizationStep](Type value) -> Type { - return static_cast(value / quantizationStep) * quantizationStep; + const auto halfStep = quantizationStep / 2; + auto quantize = [quantizationStep, halfStep](Type value) -> Type { + return static_cast((value + halfStep) / quantizationStep) * quantizationStep; }; currentValue = quantize(currentValue); @@ -125,9 +128,9 @@ void LinearEnvelope::getQuantizedBlock(absl::Span output, Type quant const int numSteps = abs(newValue - currentValue) / quantizationStep; const auto stepLength = static_cast(length / numSteps); - while (outputSize - index > stepLength) { - currentValue += currentValue <= newValue ? quantizationStep : -quantizationStep; + for (int i = 0; i < numSteps; ++i) { fill(output.subspan(index, stepLength), currentValue); + currentValue += currentValue <= newValue ? quantizationStep : -quantizationStep; index += stepLength; } } diff --git a/tests/LinearEnvelopeT.cpp b/tests/LinearEnvelopeT.cpp index d7cf4903..d876c8db 100644 --- a/tests/LinearEnvelopeT.cpp +++ b/tests/LinearEnvelopeT.cpp @@ -156,4 +156,52 @@ TEST_CASE("[LinearEnvelope] 2 events, function") std::array expected { 1, 2, 2.5, 3, 3.5, 4.0, 4.0, 4.0 }; envelope.getBlock(absl::MakeSpan(output)); REQUIRE(output == expected); +} + +TEST_CASE("[LinearEnvelope] Get quantized") +{ + sfz::LinearEnvelope envelope; + envelope.registerEvent(2, 1.0); + envelope.registerEvent(6, 2.0); + std::array output; + std::array expected { 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0 }; + envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); + REQUIRE(output == expected); +} + +TEST_CASE("[LinearEnvelope] Get quantized with 2 steps") +{ + sfz::LinearEnvelope envelope; + envelope.registerEvent(2, 1.0); + envelope.registerEvent(6, 3.0); + std::array output; + std::array expected { 0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0, 3.0 }; + 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.2); + envelope.registerEvent(6, 2.5); + std::array output; + std::array expected { 0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 3.0, 3.0 }; + 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.0); + envelope.registerEvent(6, 2.0); + envelope.registerEvent(10, 3.0); + std::array output; + std::array expected { 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0 }; + std::array expected2 { 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0 }; + envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); + REQUIRE(output == expected); + envelope.getQuantizedBlock(absl::MakeSpan(output), 1.0f); + REQUIRE(output == expected2); } \ No newline at end of file