Removed the now unused saturating and looping helpers

This commit is contained in:
Paul Ferrand 2020-05-30 21:25:30 +02:00 committed by Jean Pierre Cimalando
parent 04af0b8d80
commit 3c551d8f34
6 changed files with 0 additions and 484 deletions

View file

@ -1,78 +0,0 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include <benchmark/benchmark.h>
#include "SIMDHelpers.h"
#include <vector>
#include <random>
#include <numeric>
#include <absl/algorithm/container.h>
// In this one we have an array of indices
constexpr int loopStart { 5 };
constexpr int loopEnd { 1076 };
constexpr float maxJump { 4 };
class LoopingFixture : public benchmark::Fixture {
public:
void SetUp(const ::benchmark::State& state) {
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 0, maxJump };
indices = std::vector<int>(state.range(0));
leftCoeffs = std::vector<float>(state.range(0));
rightCoeffs = std::vector<float>(state.range(0));
jumps = std::vector<float>(state.range(0));
absl::c_generate(jumps, [&]() { return dist(gen); });
}
void TearDown(const ::benchmark::State& /* state */) {
}
std::vector<int> indices;
std::vector<float> leftCoeffs;
std::vector<float> rightCoeffs;
std::vector<float> jumps;
};
BENCHMARK_DEFINE_F(LoopingFixture, Scalar)(benchmark::State& state) {
for (auto _ : state)
{
sfz::loopingSFZIndex<float, false>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 2.5f, loopEnd, loopStart);
}
}
BENCHMARK_DEFINE_F(LoopingFixture, SIMD)(benchmark::State& state) {
for (auto _ : state)
{
sfz::loopingSFZIndex<float, true>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 2.5f, loopEnd, loopStart);
}
}
BENCHMARK_DEFINE_F(LoopingFixture, Scalar_Unaligned)(benchmark::State& state) {
for (auto _ : state)
{
sfz::loopingSFZIndex<float, false>(absl::MakeSpan(jumps).subspan(1), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1), absl::MakeSpan(indices).subspan(3), 2.5f, loopEnd, loopStart);
}
}
BENCHMARK_DEFINE_F(LoopingFixture, SIMD_Unaligned)(benchmark::State& state) {
for (auto _ : state)
{
sfz::loopingSFZIndex<float, true>(absl::MakeSpan(jumps).subspan(1), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1), absl::MakeSpan(indices).subspan(3), 2.5f, loopEnd, loopStart);
}
}
// Register the function as a benchmark
BENCHMARK_REGISTER_F(LoopingFixture, Scalar)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_REGISTER_F(LoopingFixture, SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_REGISTER_F(LoopingFixture, Scalar_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_REGISTER_F(LoopingFixture, SIMD_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_MAIN();

View file

@ -1,77 +0,0 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "SIMDHelpers.h"
#include <benchmark/benchmark.h>
#include <vector>
#include <random>
#include <numeric>
#include <absl/algorithm/container.h>
// In this one we have an array of indices
constexpr int loopEnd { 1076 };
constexpr float maxJump { 4 };
class SaturatingFixture : public benchmark::Fixture {
public:
void SetUp(const ::benchmark::State& state) {
std::random_device rd { };
std::mt19937 gen { rd() };
std::uniform_real_distribution<float> dist { 0, maxJump };
indices = std::vector<int>(state.range(0));
leftCoeffs = std::vector<float>(state.range(0));
rightCoeffs = std::vector<float>(state.range(0));
jumps = std::vector<float>(state.range(0));
absl::c_generate(jumps, [&]() { return dist(gen); });
}
void TearDown(const ::benchmark::State& /* state */) {
}
std::vector<int> indices;
std::vector<float> leftCoeffs;
std::vector<float> rightCoeffs;
std::vector<float> jumps;
};
BENCHMARK_DEFINE_F(SaturatingFixture, Scalar)(benchmark::State& state) {
for (auto _ : state)
{
sfz::saturatingSFZIndex<float, false>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 2.5f, loopEnd);
}
}
BENCHMARK_DEFINE_F(SaturatingFixture, SIMD)(benchmark::State& state) {
for (auto _ : state)
{
sfz::saturatingSFZIndex<float, true>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 2.5f, loopEnd);
}
}
BENCHMARK_DEFINE_F(SaturatingFixture, Scalar_Unaligned)(benchmark::State& state) {
for (auto _ : state)
{
sfz::saturatingSFZIndex<float, false>(absl::MakeSpan(jumps).subspan(1), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1), absl::MakeSpan(indices).subspan(3), 2.5f, loopEnd);
}
}
BENCHMARK_DEFINE_F(SaturatingFixture, SIMD_Unaligned)(benchmark::State& state) {
for (auto _ : state)
{
sfz::saturatingSFZIndex<float, true>(absl::MakeSpan(jumps).subspan(1), absl::MakeSpan(leftCoeffs).subspan(2), absl::MakeSpan(rightCoeffs).subspan(1), absl::MakeSpan(indices).subspan(3), 2.5f, loopEnd);
}
}
// Register the function as a benchmark
BENCHMARK_REGISTER_F(SaturatingFixture, Scalar)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_REGISTER_F(SaturatingFixture, SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_REGISTER_F(SaturatingFixture, Scalar_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_REGISTER_F(SaturatingFixture, SIMD_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
BENCHMARK_MAIN();

View file

@ -41,8 +41,6 @@ sfizz_add_benchmark(bm_read BM_readInterleaved.cpp)
sfizz_add_benchmark(bm_mathfuns BM_mathfuns.cpp)
sfizz_add_benchmark(bm_gain BM_gain.cpp)
sfizz_add_benchmark(bm_divide BM_divide.cpp)
sfizz_add_benchmark(bm_looping BM_looping.cpp)
sfizz_add_benchmark(bm_saturating BM_saturating.cpp)
sfizz_add_benchmark(bm_ramp BM_ramp.cpp)
sfizz_add_benchmark(bm_ADSR BM_ADSR.cpp)
target_link_libraries(bm_ADSR PRIVATE sfizz::sfizz)

View file

@ -152,120 +152,6 @@ void fill(absl::Span<T> output, T value) noexcept
absl::c_fill(output, value);
}
namespace _internals {
template <class T>
inline void snippetSaturatingIndex(const T*& jump, T*& leftCoeff, T*& rightCoeff, int*& index, T& floatIndex, T loopEnd)
{
floatIndex += *jump;
if (floatIndex >= loopEnd) {
floatIndex = loopEnd;
*index = static_cast<int>(floatIndex) - 1;
*rightCoeff = static_cast<T>(1.0);
*leftCoeff = static_cast<T>(0.0);
} else {
*index = static_cast<int>(floatIndex);
*rightCoeff = floatIndex - *index;
*leftCoeff = static_cast<T>(1.0) - *rightCoeff;
}
incrementAll(index, leftCoeff, rightCoeff, jump);
}
}
/**
* @brief Computes an integer index and 2 float coefficients corresponding to the
* linear interpolation procedure. This version will saturate the index to the upper
* bound if the upper bound is reached.
*
* The indices are computed starting from the given floatIndex, and each increment
* is given by the elements of jumps.
* The output size will be the minimum of the inputs span and outputs span size.
*
* @tparam T the underlying type
* @tparam SIMD use the SIMD version or the scalar version
* @param jumps the floating point increments to the index
* @param leftCoeffs the linear interpolation coefficients for the left value
* @param rightCoeffs the linear interpolation coefficients for the right value
* @param indices the integer sample indices for the left values; the right values
* for interpolation at index i are (indices[i] + 1) and not indices[i+1]
* @param floatIndex the starting floating point index
* @param loopEnd the end of the "loop" which is not really a loop because it saturate.
* @return float
*/
template <class T, bool SIMD = SIMDConfig::saturatingSFZIndex>
float saturatingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, absl::Span<T> rightCoeffs, absl::Span<int> indices, T floatIndex, T loopEnd) noexcept
{
CHECK(indices.size() >= jumps.size());
CHECK(indices.size() == leftCoeffs.size());
CHECK(indices.size() == rightCoeffs.size());
auto* index = indices.begin();
auto* leftCoeff = leftCoeffs.begin();
auto* rightCoeff = rightCoeffs.begin();
auto* jump = jumps.begin();
const auto size = min(jumps.size(), indices.size(), leftCoeffs.size(), rightCoeffs.size());
auto* sentinel = jumps.begin() + size;
while (jump < sentinel)
_internals::snippetSaturatingIndex<T>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd);
return floatIndex;
}
template <>
float saturatingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeffs, absl::Span<float> rightCoeffs, absl::Span<int> indices, float floatIndex, float loopEnd) noexcept;
namespace _internals {
template <class T>
inline void snippetLoopingIndex(const T*& jump, T*& leftCoeff, T*& rightCoeff, int*& index, T& floatIndex, T loopEnd, T loopStart)
{
floatIndex += *jump;
if (floatIndex >= loopEnd)
floatIndex -= loopEnd - loopStart;
*index = static_cast<int>(floatIndex);
*rightCoeff = floatIndex - *index;
*leftCoeff = 1.0f - *rightCoeff;
incrementAll(index, leftCoeff, rightCoeff, jump);
}
}
/**
* @brief Computes an integer index and 2 float coefficients corresponding to the
* linear interpolation procedure. This version will loop the index at the upper
* bound loopend and restart it at the start of the loop.
*
* @tparam T the underlying type
* @tparam SIMD use the SIMD version or the scalar version
* @param jumps the floating point increments to the index
* @param leftCoeffs the linear interpolation coefficients for the left value
* @param rightCoeffs the linear interpolation coefficients for the right value
* @param indices the integer sample indices for the left values; the right values
* for interpolation at index i are (indices[i] + 1) and not indices[i+1]
* @param floatIndex the starting floating point index
* @param loopEnd the end index of the loop
* @param loopStart the start index of the loop
* @return float
*/
template <class T, bool SIMD = SIMDConfig::loopingSFZIndex>
float loopingSFZIndex(absl::Span<const T> jumps, absl::Span<T> leftCoeffs, absl::Span<T> rightCoeffs, absl::Span<int> indices, T floatIndex, T loopEnd, T loopStart) noexcept
{
CHECK(indices.size() >= jumps.size());
CHECK(indices.size() == leftCoeffs.size());
CHECK(indices.size() == rightCoeffs.size());
auto* index = indices.begin();
auto* leftCoeff = leftCoeffs.begin();
auto* rightCoeff = rightCoeffs.begin();
auto* jump = jumps.begin();
const auto size = min(jumps.size(), indices.size(), leftCoeffs.size(), rightCoeffs.size());
auto* sentinel = jumps.begin() + size;
while (jump < sentinel)
_internals::snippetLoopingIndex<T>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart);
return floatIndex;
}
template <>
float loopingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeff, absl::Span<float> rightCoeff, absl::Span<int> indices, float floatIndex, float loopEnd, float loopStart) noexcept;
namespace _internals {
template <class T>
inline void snippetGain(T gain, const T*& input, T*& output)

View file

@ -127,120 +127,6 @@ void sfz::multiplyAdd<float, true>(const float gain, absl::Span<const float> inp
_internals::snippetMultiplyAdd<float>(gain, in, out);
}
template <>
float sfz::loopingSFZIndex<float, true>(absl::Span<const float> jumps,
absl::Span<float> leftCoeffs,
absl::Span<float> rightCoeffs,
absl::Span<int> indices,
float floatIndex,
float loopEnd,
float loopStart) noexcept
{
CHECK(indices.size() >= jumps.size());
CHECK(indices.size() == leftCoeffs.size());
CHECK(indices.size() == rightCoeffs.size());
auto index = indices.data();
auto leftCoeff = leftCoeffs.data();
auto rightCoeff = rightCoeffs.data();
auto jump = jumps.data();
const auto size = min(jumps.size(), indices.size(), leftCoeffs.size(), rightCoeffs.size());
const auto* sentinel = jumps.begin() + size;
const auto* alignedEnd = prevAligned(sentinel);
while (unaligned(reinterpret_cast<float*>(index), leftCoeff, rightCoeff, jump) && jump < alignedEnd)
_internals::snippetLoopingIndex<float>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart);
auto mmFloatIndex = _mm_set_ps1(floatIndex);
const auto mmJumpBack = _mm_set1_ps(loopEnd - loopStart);
const auto mmLoopEnd = _mm_set1_ps(loopEnd);
while (jump < alignedEnd) {
auto mmOffset = _mm_load_ps(jump);
mmOffset = _mm_add_ps(mmOffset, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOffset), 4)));
mmOffset = _mm_add_ps(mmOffset, _mm_shuffle_ps(_mm_setzero_ps(), mmOffset, 0x40));
mmFloatIndex = _mm_add_ps(mmFloatIndex, mmOffset);
const auto mmCompared = _mm_cmpge_ps(mmFloatIndex, mmLoopEnd);
auto mmLoopBack = _mm_sub_ps(mmFloatIndex, mmJumpBack);
mmLoopBack = _mm_and_ps(mmCompared, mmLoopBack);
mmFloatIndex = _mm_andnot_ps(mmCompared, mmFloatIndex);
mmFloatIndex = _mm_add_ps(mmFloatIndex, mmLoopBack);
auto mmIndices = _mm_cvtps_epi32(_mm_sub_ps(mmFloatIndex, _mm_set_ps1(0.4999999552965164184570312f)));
_mm_store_si128(reinterpret_cast<__m128i*>(index), mmIndices);
auto mmRight = _mm_sub_ps(mmFloatIndex, _mm_cvtepi32_ps(mmIndices));
auto mmLeft = _mm_sub_ps(_mm_set_ps1(1.0f), mmRight);
_mm_store_ps(leftCoeff, mmLeft);
_mm_store_ps(rightCoeff, mmRight);
mmFloatIndex = _mm_shuffle_ps(mmFloatIndex, mmFloatIndex, _MM_SHUFFLE(3, 3, 3, 3));
// floatingIndex = _mm_cvtss_f32(_mm_shuffle_ps(mmFloatIndex, mmFloatIndex, _MM_SHUFFLE(0, 0, 0, 3)));;
// floatingIndex = *(index + 3) + *(rightCoeff + 3);
incrementAll<TypeAlignment>(index, jump, leftCoeff, rightCoeff);
}
floatIndex = _mm_cvtss_f32(mmFloatIndex);
while (jump < sentinel)
_internals::snippetLoopingIndex<float>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd, loopStart);
return floatIndex;
}
template <>
float sfz::saturatingSFZIndex<float, true>(absl::Span<const float> jumps,
absl::Span<float> leftCoeffs,
absl::Span<float> rightCoeffs,
absl::Span<int> indices,
float floatIndex,
float loopEnd) noexcept
{
CHECK(indices.size() >= jumps.size());
CHECK(indices.size() == leftCoeffs.size());
CHECK(indices.size() == rightCoeffs.size());
auto index = indices.data();
auto leftCoeff = leftCoeffs.data();
auto rightCoeff = rightCoeffs.data();
auto jump = jumps.data();
const auto size = min(jumps.size(), indices.size(), leftCoeffs.size(), rightCoeffs.size());
const auto* sentinel = jumps.begin() + size;
const auto* alignedEnd = prevAligned(sentinel);
while (unaligned(reinterpret_cast<float*>(index), leftCoeff, rightCoeff, jump) && jump < alignedEnd)
_internals::snippetSaturatingIndex<float>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd);
auto mmFloatIndex = _mm_set_ps1(floatIndex);
const auto mmLoopEnd = _mm_set1_ps(loopEnd);
const auto mmSaturated = _mm_sub_ps(mmLoopEnd, _mm_set_ps1(0.000001f));
while (jump < alignedEnd) {
auto mmOffset = _mm_load_ps(jump);
mmOffset = _mm_add_ps(mmOffset, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOffset), 4)));
mmOffset = _mm_add_ps(mmOffset, _mm_shuffle_ps(_mm_setzero_ps(), mmOffset, 0x40));
mmFloatIndex = _mm_add_ps(mmFloatIndex, mmOffset);
const auto mmCompared = _mm_cmplt_ps(mmFloatIndex, mmLoopEnd);
mmFloatIndex = _mm_add_ps(_mm_and_ps(mmCompared, mmFloatIndex), _mm_andnot_ps(mmCompared, mmSaturated));
auto mmIndices = _mm_cvtps_epi32(_mm_sub_ps(mmFloatIndex, _mm_set_ps1(0.4999999552965164184570312f)));
_mm_store_si128(reinterpret_cast<__m128i*>(index), mmIndices);
auto mmRight = _mm_sub_ps(mmFloatIndex, _mm_cvtepi32_ps(mmIndices));
auto mmLeft = _mm_sub_ps(_mm_set_ps1(1.0f), mmRight);
_mm_store_ps(leftCoeff, mmLeft);
_mm_store_ps(rightCoeff, mmRight);
mmFloatIndex = _mm_shuffle_ps(mmFloatIndex, mmFloatIndex, _MM_SHUFFLE(3, 3, 3, 3));
// floatingIndex = _mm_cvtss_f32(_mm_shuffle_ps(mmFloatIndex, mmFloatIndex, _MM_SHUFFLE(0, 0, 0, 3)));;
// floatingIndex = *(index + 3) + *(rightCoeff + 3);
incrementAll<TypeAlignment>(index, jump, leftCoeff, rightCoeff);
}
floatIndex = _mm_cvtss_f32(mmFloatIndex);
while (jump < sentinel)
_internals::snippetSaturatingIndex<float>(jump, leftCoeff, rightCoeff, index, floatIndex, loopEnd);
return floatIndex;
}
template <>
float sfz::linearRamp<float, true>(absl::Span<float> output, float value, float step) noexcept
{

View file

@ -342,105 +342,6 @@ TEST_CASE("[Helpers] Gain, spans and inplace (SIMD)")
REQUIRE(buffer == expected);
}
TEST_CASE("[Helpers] SFZ looping index")
{
std::array<float, 6> jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0f 6.5 8.1
std::array<int, 6> indices;
std::array<float, 6> leftCoeffs;
std::array<float, 6> rightCoeffs;
std::array<int, 6> expectedIndices { 2, 3, 4, 1, 2, 4 };
std::array<float, 6> expectedLeft { 0.9f, 0.7f, 0.4f, 1.0f, 0.5f, 0.9f };
std::array<float, 6> expectedRight { 0.1f, 0.3f, 0.6f, 0.0f, 0.5f, 0.1f };
sfz::loopingSFZIndex<float, false>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6, 1);
REQUIRE(indices == expectedIndices);
REQUIRE(approxEqual<float>(leftCoeffs, expectedLeft));
REQUIRE(approxEqual<float>(rightCoeffs, expectedRight));
}
TEST_CASE("[Helpers] SFZ looping index (SIMD)")
{
std::array<float, 6> jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0f 6.5 8.1
std::array<int, 6> indices;
std::array<float, 6> leftCoeffs;
std::array<float, 6> rightCoeffs;
std::array<int, 6> expectedIndices { 2, 3, 4, 1, 2, 4 };
std::array<float, 6> expectedLeft { 0.9f, 0.7f, 0.4f, 1.0f, 0.5f, 0.9f };
std::array<float, 6> expectedRight { 0.1f, 0.3f, 0.6f, 0.0f, 0.5f, 0.1f };
sfz::loopingSFZIndex<float, true>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6, 1);
REQUIRE(indices == expectedIndices);
REQUIRE(approxEqual<float>(leftCoeffs, expectedLeft));
REQUIRE(approxEqual<float>(rightCoeffs, expectedRight));
}
// TEST_CASE("[Helpers] SFZ looping index (SIMD vs Scalar)")
// {
// std::vector<float> jumps(bigBufferSize);
// absl::c_fill(jumps, fillValue);
// std::vector<int> indices(bigBufferSize);
// std::vector<float> leftCoeffs(bigBufferSize);
// std::vector<float> rightCoeffs(bigBufferSize);
// std::vector<int> indicesSIMD(bigBufferSize);
// std::vector<float> leftCoeffsSIMD(bigBufferSize);
// std::vector<float> rightCoeffsSIMD(bigBufferSize);
// sfz::loopingSFZIndex<float, false>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, medBufferSize, 1);
// sfz::loopingSFZIndex<float, true>(jumps, absl::MakeSpan(leftCoeffsSIMD), absl::MakeSpan(rightCoeffsSIMD), absl::MakeSpan(indicesSIMD), 1.0f, medBufferSize, 1);
// for (int i = 0; i < bigBufferSize; ++i)
// REQUIRE( ((static_cast<float>(indices[i]) + rightCoeffs[i] == Approx(static_cast<float>(indicesSIMD[i]) + rightCoeffsSIMD[i]).margin(1e-2))
// || (static_cast<float>(indices[i]) + rightCoeffs[i] == Approx(static_cast<float>(indicesSIMD[i]) + rightCoeffsSIMD[i] - static_cast<float>(medBufferSize)).margin(2e-2))) );
// }
TEST_CASE("[Helpers] SFZ saturating index")
{
std::array<float, 6> jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0f 6.5 8.1
std::array<int, 6> indices;
std::array<float, 6> leftCoeffs;
std::array<float, 6> rightCoeffs;
std::array<int, 6> expectedIndices { 2, 3, 4, 5, 5, 5 };
std::array<float, 6> expectedLeft { 0.9f, 0.7f, 0.4f, 0.0f, 0.0f, 0.0f };
std::array<float, 6> expectedRight { 0.1f, 0.3f, 0.6f, 1.0f, 1.0f, 1.0f };
sfz::saturatingSFZIndex<float, false>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6);
REQUIRE(indices == expectedIndices);
REQUIRE(approxEqual<float>(leftCoeffs, expectedLeft));
REQUIRE(approxEqual<float>(rightCoeffs, expectedRight));
}
TEST_CASE("[Helpers] SFZ saturating index (SIMD)")
{
std::array<float, 6> jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; // 1.1 2.3 3.6 5.0f 6.5 8.1
std::array<int, 6> indices;
std::array<float, 6> leftCoeffs;
std::array<float, 6> rightCoeffs;
std::array<int, 6> expectedIndices { 2, 3, 4, 5, 5, 5 };
std::array<float, 6> expectedLeft { 0.9f, 0.7f, 0.4f, 0.0f, 0.0f, 0.0f };
std::array<float, 6> expectedRight { 0.1f, 0.3f, 0.6f, 1.0f, 1.0f, 1.0f };
sfz::saturatingSFZIndex<float, true>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6);
REQUIRE(indices == expectedIndices);
REQUIRE(approxEqualMargin<float>(leftCoeffs, expectedLeft));
REQUIRE(approxEqualMargin<float>(rightCoeffs, expectedRight));
}
TEST_CASE("[Helpers] SFZ saturating index (SIMD vs Scalar)")
{
std::vector<float> jumps(medBufferSize);
absl::c_fill(jumps, fillValue);
std::vector<int> indices(medBufferSize);
std::vector<float> leftCoeffs(medBufferSize);
std::vector<float> rightCoeffs(medBufferSize);
std::vector<int> indicesSIMD(medBufferSize);
std::vector<float> leftCoeffsSIMD(medBufferSize);
std::vector<float> rightCoeffsSIMD(medBufferSize);
sfz::saturatingSFZIndex<float, false>(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 78);
sfz::saturatingSFZIndex<float, true>(jumps, absl::MakeSpan(leftCoeffsSIMD), absl::MakeSpan(rightCoeffsSIMD), absl::MakeSpan(indicesSIMD), 1.0f, 78);
for (int i = 0; i < medBufferSize; ++i)
REQUIRE( static_cast<float>(indices[i]) + rightCoeffs[i] == Approx(static_cast<float>(indicesSIMD[i]) + rightCoeffsSIMD[i]));
}
TEST_CASE("[Helpers] Linear Ramp")
{
const float start { 0.0f };