// 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 "sfizz/SIMDHelpers.h" #include "sfizz/Panning.h" #include "catch2/catch.hpp" #include #include #include #include #include using namespace Catch::literals; constexpr int smallBufferSize { 3 }; constexpr int bigBufferSize { 4095 }; constexpr int medBufferSize { 127 }; constexpr float fillValue { 1.3f }; template inline bool approxEqualMargin(absl::Span lhs, absl::Span rhs, Type eps = 1e-3) { if (lhs.size() != rhs.size()) return false; for (size_t i = 0; i < rhs.size(); ++i) if (rhs[i] != Approx(lhs[i]).margin(eps)) { std::cerr << lhs[i] << " != " << rhs[i] << " at index " << i << '\n'; return false; } return true; } template inline bool approxEqual(absl::Span lhs, absl::Span rhs, Type eps = 1e-3) { if (lhs.size() != rhs.size()) return false; for (size_t i = 0; i < rhs.size(); ++i) if (rhs[i] != Approx(lhs[i]).epsilon(eps)) { std::cerr << lhs[i] << " != " << rhs[i] << " at index " << i << '\n'; return false; } return true; } TEST_CASE("[Helpers] Interleaved read") { std::array input { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; std::array expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array leftOutput; std::array rightOutput; sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Interleaved read unaligned end") { std::array input { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f }; std::array expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array leftOutput; std::array rightOutput; sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Small interleaved read unaligned end") { std::array input { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; std::array expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f }; std::array leftOutput; std::array rightOutput; sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Interleaved read -- SIMD") { std::array input = { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; std::array expected = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array leftOutput; std::array rightOutput; sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Interleaved read unaligned end -- SIMD") { std::array input = { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f }; std::array expected = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array leftOutput; std::array rightOutput; sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Small interleaved read unaligned end -- SIMD") { std::array input { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; std::array expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f }; std::array leftOutput; std::array rightOutput; sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput)); std::array real; auto realIdx = 0; for (auto value : leftOutput) real[realIdx++] = value; for (auto value : rightOutput) real[realIdx++] = value; REQUIRE(real == expected); } TEST_CASE("[Helpers] Interleaved read SIMD vs Scalar") { std::array input; std::array leftOutputScalar; std::array rightOutputScalar; std::array leftOutputSIMD; std::array rightOutputSIMD; std::iota(input.begin(), input.end(), 0.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false); sfz::readInterleaved(input, absl::MakeSpan(leftOutputScalar), absl::MakeSpan(rightOutputScalar)); sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true); sfz::readInterleaved(input, absl::MakeSpan(leftOutputSIMD), absl::MakeSpan(rightOutputSIMD)); REQUIRE(leftOutputScalar == leftOutputSIMD); REQUIRE(rightOutputScalar == rightOutputSIMD); } TEST_CASE("[Helpers] Interleaved write") { std::array leftInput { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, }; std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Interleaved write unaligned end") { std::array leftInput { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f }; std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Small interleaved write unaligned end") { std::array leftInput { 0.0f, 1.0f, 2.0f }; std::array rightInput { 10.0f, 11.0f, 12.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Interleaved write -- SIMD") { std::array leftInput { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, }; std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Interleaved write unaligned end -- SIMD") { std::array leftInput { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f }; std::array rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f }; std::array output; std::array expected = { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f }; sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Small interleaved write unaligned end -- SIMD") { std::array leftInput { 0.0f, 1.0f, 2.0f }; std::array rightInput { 10.0f, 11.0f, 12.0f }; std::array output; std::array expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Interleaved write SIMD vs Scalar") { std::array leftInput; std::array rightInput; std::array outputScalar; std::array outputSIMD; std::iota(leftInput.begin(), leftInput.end(), 0.0f); std::iota(rightInput.begin(), rightInput.end(), static_cast(medBufferSize)); sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputScalar)); sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true); sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputSIMD)); REQUIRE(outputScalar == outputSIMD); } TEST_CASE("[Helpers] Gain, single") { std::array input; std::array expected; absl::c_fill(input, 1.0f); absl::c_fill(expected, fillValue); SECTION("Scalar") { std::array output; sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(fillValue, input, absl::MakeSpan(output)); REQUIRE(output == expected); } SECTION("SIMD") { std::array output; sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); sfz::applyGain(fillValue, input, absl::MakeSpan(output)); REQUIRE(output == expected); } } TEST_CASE("[Helpers] Gain, single and inplace") { std::array expected; std::array buffer; absl::c_fill(expected, fillValue); SECTION("Scalar") { absl::c_fill(buffer, 1.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(fillValue, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } SECTION("SIMD") { absl::c_fill(buffer, 1.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(fillValue, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } } TEST_CASE("[Helpers] Gain, spans") { std::array input; std::array gain; std::array expected; absl::c_fill(input, 1.0f); absl::c_iota(gain, 1.0f); absl::c_iota(expected, 1.0f); SECTION("Scalar") { std::array output; sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } SECTION("SIMD") { std::array output; sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true); sfz::applyGain(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } } TEST_CASE("[Helpers] Gain, spans and inplace") { std::array buffer; std::array gain; std::array expected; absl::c_iota(gain, 1.0f); absl::c_iota(expected, 1.0f); SECTION("Scalar") { absl::c_fill(buffer, 1.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(gain, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } SECTION("SIMD") { absl::c_fill(buffer, 1.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false); sfz::applyGain(gain, buffer, absl::MakeSpan(buffer)); REQUIRE(buffer == expected); } } TEST_CASE("[Helpers] Linear Ramp") { const float start { 0.0f }; const float v { fillValue }; std::array output; std::array expected { start, start + v, start + v + v, start + v + v + v, start + v + v + v + v, start + v + v + v + v + v }; sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); sfz::linearRamp(absl::MakeSpan(output), start, v); REQUIRE(output == expected); } TEST_CASE("[Helpers] Linear Ramp (SIMD)") { const float start { 0.0f }; const float v { fillValue }; std::array output; std::array expected { start, start + v, start + v + v, start + v + v + v, start + v + v + v + v, start + v + v + v + v + v }; sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(output), start, v); REQUIRE(approxEqual(output, expected)); } TEST_CASE("[Helpers] Linear Ramp (SIMD vs scalar)") { const float start { 0.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); sfz::linearRamp(absl::MakeSpan(outputScalar), start, fillValue); sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(outputSIMD), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Linear Ramp unaligned (SIMD vs scalar)") { const float start { 0.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, false); sfz::linearRamp(absl::MakeSpan(outputScalar).subspan(1), start, fillValue); sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Multiplicative Ramp") { const float start { 1.0f }; const float v { fillValue }; std::array output; std::array expected { start, start * v, start * v * v, start * v * v * v, start * v * v * v * v, start * v * v * v * v * v }; sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); sfz::multiplicativeRamp(absl::MakeSpan(output), start, v); REQUIRE(approxEqual(output, expected)); } TEST_CASE("[Helpers] Multiplicative Ramp (SIMD)") { const float start { 1.0f }; const float v { fillValue }; std::array output; std::array expected { start, start * v, start * v * v, start * v * v * v, start * v * v * v * v, start * v * v * v * v * v }; sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); sfz::multiplicativeRamp(absl::MakeSpan(output), start, v); REQUIRE(approxEqual(output, expected)); } TEST_CASE("[Helpers] Multiplicative Ramp (SIMD vs scalar)") { const float start { 1.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); sfz::multiplicativeRamp(absl::MakeSpan(outputScalar), start, fillValue); sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); sfz::multiplicativeRamp(absl::MakeSpan(outputSIMD), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Multiplicative Ramp unaligned (SIMD vs scalar)") { const float start { 1.0f }; std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, false); sfz::multiplicativeRamp(absl::MakeSpan(outputScalar).subspan(1), start, fillValue); sfz::setSIMDOpStatus(sfz::SIMDOps::multiplicativeRamp, true); sfz::multiplicativeRamp(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Add") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { 2.0f, 3.0f, 4.0f, 5.0f, 6.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); sfz::add(input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Add (SIMD)") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { 2.0f, 3.0f, 4.0f, 5.0f, 6.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); sfz::add(input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Add (SIMD vs scalar)") { std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); absl::c_iota(input, 0.0f); absl::c_fill(outputScalar, 0.0f); absl::c_fill(outputSIMD, 0.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::add, false); sfz::add(input, absl::MakeSpan(outputScalar)); sfz::setSIMDOpStatus(sfz::SIMDOps::add, true); sfz::add(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] MultiplyAdd (Scalar)") { std::array gain { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f }; std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; std::array expected { 5.0f, 4.2f, 3.6f, 3.2f, 3.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] MultiplyAdd (SIMD)") { std::array gain { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f }; std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; std::array expected { 5.0f, 4.2f, 3.6f, 3.2f, 3.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] MultiplyAdd (SIMD vs scalar)") { std::vector gain(bigBufferSize); std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); absl::c_iota(gain, 0.0f); absl::c_iota(input, 0.0f); absl::c_iota(outputScalar, 0.0f); absl::c_iota(outputSIMD, 0.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); sfz::multiplyAdd(gain, input, absl::MakeSpan(outputScalar)); sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); sfz::multiplyAdd(gain, input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] MultiplyAdd fixed gain (Scalar)") { float gain = 0.3f; std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; std::array expected { 5.3f, 4.6f, 3.9f, 3.2f, 2.5f }; sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] MultiplyAdd fixed gain (SIMD)") { float gain = 0.3f; std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; std::array expected { 5.3f, 4.6f, 3.9f, 3.2f, 2.5f }; sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); sfz::multiplyAdd(gain, input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] MultiplyAdd fixed gain (SIMD vs scalar)") { float gain = 0.3f; std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); absl::c_iota(input, 0.0f); absl::c_iota(outputScalar, 0.0f); absl::c_iota(outputSIMD, 0.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, false); sfz::multiplyAdd(gain, input, absl::MakeSpan(outputScalar)); sfz::setSIMDOpStatus(sfz::SIMDOps::multiplyAdd, true); sfz::multiplyAdd(gain, input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Subtract") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { 0.0f, -1.0f, -2.0f, -3.0f, -4.0f }; sfz::subtract(input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Subtract 2") { std::array output { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); sfz::subtract(1.0f, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Subtract (SIMD)") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { 0.0f, -1.0f, -2.0f, -3.0f, -4.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); sfz::subtract(input, absl::MakeSpan(output)); REQUIRE(output == expected); } TEST_CASE("[Helpers] Subtract (SIMD vs scalar)") { std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); absl::c_iota(input, 0.0f); absl::c_fill(outputScalar, 0.0f); absl::c_fill(outputSIMD, 0.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); sfz::subtract(input, absl::MakeSpan(outputScalar)); sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); sfz::subtract(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Subtract 2 (SIMD vs scalar)") { std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); absl::c_iota(outputScalar, 0.0f); absl::c_iota(outputSIMD, 0.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, false); sfz::subtract(1.2f, absl::MakeSpan(outputScalar)); sfz::setSIMDOpStatus(sfz::SIMDOps::subtract, true); sfz::subtract(1.2f, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] copy") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); sfz::copy(input, absl::MakeSpan(output)); REQUIRE(output == input); } TEST_CASE("[Helpers] copy (SIMD)") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); sfz::copy(input, absl::MakeSpan(output)); REQUIRE(output == input); } TEST_CASE("[Helpers] copy (SIMD vs scalar)") { std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); absl::c_iota(input, 0.0f); absl::c_fill(outputScalar, 0.0f); absl::c_fill(outputSIMD, 0.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::copy, false); sfz::copy(input, absl::MakeSpan(outputScalar)); sfz::setSIMDOpStatus(sfz::SIMDOps::copy, true); sfz::copy(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Mean") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); REQUIRE(sfz::mean(input) == 5.5f); sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); REQUIRE(sfz::mean(input) == 5.5f); } TEST_CASE("[Helpers] Mean (SIMD vs scalar)") { std::vector input(bigBufferSize); absl::c_iota(input, 0.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::mean, false); auto scalarResult = sfz::mean(input); sfz::setSIMDOpStatus(sfz::SIMDOps::mean, true); auto simdResult = sfz::mean(input); REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) ); } TEST_CASE("[Helpers] Mean Squared") { std::array input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); REQUIRE(sfz::meanSquared(input) == 38.5f); sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); REQUIRE(sfz::meanSquared(input) == 38.5f); } TEST_CASE("[Helpers] Mean Squared (SIMD vs scalar)") { std::vector input(medBufferSize); absl::c_iota(input, 0.0f); sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, false); auto scalarResult = sfz::meanSquared(input); sfz::setSIMDOpStatus(sfz::SIMDOps::meanSquared, true); auto simdResult = sfz::meanSquared(input); REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) ); } TEST_CASE("[Helpers] Cumulative sum") { std::array input { 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 output; std::array expected { 1.1f, 2.3f, 3.6f, 5.0f, 6.5f, 8.1f }; sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); sfz::cumsum(input, absl::MakeSpan(output)); REQUIRE(approxEqual(output, expected)); } TEST_CASE("[Helpers] Cumulative sum (SIMD vs Scalar)") { std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(input), 0.0f, 0.1f); sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, false); sfz::cumsum(input, absl::MakeSpan(outputScalar)); sfz::setSIMDOpStatus(sfz::SIMDOps::cumsum, true); sfz::cumsum(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Diff") { std::array input { 1.1f, 2.3f, 3.6f, 5.0f, 6.5f, 8.1f }; std::array output; std::array expected { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f }; sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); sfz::diff(input, absl::MakeSpan(output)); REQUIRE(approxEqual(output, expected)); } TEST_CASE("[Helpers] Diff (SIMD vs Scalar)") { std::vector input(bigBufferSize); std::vector outputScalar(bigBufferSize); std::vector outputSIMD(bigBufferSize); sfz::setSIMDOpStatus(sfz::SIMDOps::linearRamp, true); sfz::linearRamp(absl::MakeSpan(input), 0.0f, 0.1f); sfz::setSIMDOpStatus(sfz::SIMDOps::diff, false); sfz::diff(input, absl::MakeSpan(outputScalar)); sfz::setSIMDOpStatus(sfz::SIMDOps::diff, true); sfz::diff(input, absl::MakeSpan(outputSIMD)); REQUIRE(approxEqual(outputScalar, outputSIMD)); } TEST_CASE("[Helpers] Pan Scalar") { std::array leftValue { 1.0f }; std::array rightValue { 1.0f }; auto left = absl::MakeSpan(leftValue); auto right = absl::MakeSpan(rightValue); SECTION("Pan = 0") { std::array pan { 0.0f }; sfz::pan(pan, left, right); REQUIRE(left[0] == Approx(0.70711f).margin(0.001f)); REQUIRE(right[0] == Approx(0.70711f).margin(0.001f)); } SECTION("Pan = 1") { std::array pan { 1.0f }; sfz::pan(pan, left, right); REQUIRE(left[0] == Approx(0.0f).margin(0.001f)); REQUIRE(right[0] == Approx(1.0f).margin(0.001f)); } SECTION("Pan = -1") { std::array pan { -1.0f }; sfz::pan(pan, left, right); REQUIRE(left[0] == Approx(1.0f).margin(0.001f)); REQUIRE(right[0] == Approx(0.0f).margin(0.001f)); } } TEST_CASE("[Helpers] Width Scalar") { std::array leftValue { 1.0f }; std::array rightValue { 1.0f }; auto left = absl::MakeSpan(leftValue); auto right = absl::MakeSpan(rightValue); SECTION("width = 1") { std::array width { 1.0f }; sfz::width(width, left, right); REQUIRE(left[0] == Approx(1.0f).margin(0.001f)); REQUIRE(right[0] == Approx(1.0f).margin(0.001f)); } SECTION("width = 0") { std::array width { 0.0f }; sfz::width(width, left, right); REQUIRE(left[0] == Approx(1.414f).margin(0.001f)); REQUIRE(right[0] == Approx(1.414f).margin(0.001f)); } SECTION("width = -1") { std::array width { -1.0f }; sfz::width(width, left, right); REQUIRE(left[0] == Approx(1.0f).margin(0.001f)); REQUIRE(right[0] == Approx(1.0f).margin(0.001f)); } }