#include "catch2/catch.hpp" #include "../sources/SIMDHelpers.h" #include #include #include #include using namespace Catch::literals; constexpr int smallBufferSize { 3 }; constexpr int bigBufferSize { 4095 }; constexpr int medBufferSize { 127 }; constexpr double fillValue { 1.3 }; 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] fill() - Manual buffer") { std::vector buffer (5); std::vector expected { fillValue, fillValue, fillValue, fillValue, fillValue }; fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Small buffer") { std::vector buffer (smallBufferSize); std::vector expected (smallBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Big buffer") { std::vector buffer (bigBufferSize); std::vector expected (bigBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Small buffer -- SIMD") { std::vector buffer (smallBufferSize); std::vector expected (smallBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Big buffer -- SIMD") { std::vector buffer (bigBufferSize); std::vector expected (bigBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Small buffer -- doubles") { std::vector buffer (smallBufferSize); std::vector expected (smallBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } TEST_CASE("[Helpers] fill() - Big buffer -- doubles") { std::vector buffer (bigBufferSize); std::vector expected (bigBufferSize); std::fill(expected.begin(), expected.end(), fillValue); fill(absl::MakeSpan(buffer), fillValue); REQUIRE(buffer == expected); } 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; 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; 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; 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; 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; 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; 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); readInterleaved(input, absl::MakeSpan(leftOutputScalar), absl::MakeSpan(rightOutputScalar)); 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}; 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}; 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}; 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}; 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}; 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}; 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(), medBufferSize); writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputScalar)); writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputSIMD)); REQUIRE( outputScalar == outputSIMD ); } TEST_CASE("[Helpers] Gain, single") { std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; applyGain(fillValue, input, absl::MakeSpan(output)); REQUIRE( output == expected ); } TEST_CASE("[Helpers] Gain, single and inplace") { std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; applyGain(fillValue, buffer, absl::MakeSpan(buffer)); REQUIRE( buffer == expected ); } TEST_CASE("[Helpers] Gain, spans") { std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; applyGain(gain, input, absl::MakeSpan(output)); REQUIRE( output == expected ); } TEST_CASE("[Helpers] Gain, spans and inplace") { std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; applyGain(gain, buffer, absl::MakeSpan(buffer)); REQUIRE( buffer == expected ); } TEST_CASE("[Helpers] Gain, single (SIMD)") { std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; applyGain(fillValue, input, absl::MakeSpan(output)); REQUIRE( output == expected ); } TEST_CASE("[Helpers] Gain, single and inplace (SIMD)") { std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array expected { fillValue, fillValue, fillValue, fillValue, fillValue }; applyGain(fillValue, buffer, absl::MakeSpan(buffer)); REQUIRE( buffer == expected ); } TEST_CASE("[Helpers] Gain, spans (SIMD)") { std::array input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; applyGain(gain, input, absl::MakeSpan(output)); REQUIRE( output == expected ); } TEST_CASE("[Helpers] Gain, spans and inplace (SIMD)") { std::array buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; std::array gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; std::array expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; applyGain(gain, buffer, absl::MakeSpan(buffer)); REQUIRE( buffer == expected ); } TEST_CASE("[Helpers] SFZ looping index") { std::array jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f}; // 1.1 2.3 3.6 5.0 6.5 8.1 std::array indices; std::array leftCoeffs; std::array rightCoeffs; std::array expectedIndices { 2, 3, 4, 1, 2, 4 }; std::array expectedLeft { 0.9f, 0.7f, 0.4f, 1.0f, 0.5f, 0.9f }; std::array expectedRight { 0.1f, 0.3f, 0.6f, 0.0f, 0.5f, 0.1f }; loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6, 1); REQUIRE( indices == expectedIndices ); REQUIRE( approxEqual(leftCoeffs, expectedLeft) ); REQUIRE( approxEqual(rightCoeffs, expectedRight) ); } TEST_CASE("[Helpers] SFZ looping index (SIMD)") { std::array jumps { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f}; // 1.1 2.3 3.6 5.0 6.5 8.1 std::array indices; std::array leftCoeffs; std::array rightCoeffs; std::array expectedIndices { 2, 3, 4, 1, 2, 4 }; std::array expectedLeft { 0.9f, 0.7f, 0.4f, 1.0f, 0.5f, 0.9f }; std::array expectedRight { 0.1f, 0.3f, 0.6f, 0.0f, 0.5f, 0.1f }; loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, 6, 1); REQUIRE( indices == expectedIndices ); REQUIRE( approxEqual(leftCoeffs, expectedLeft) ); REQUIRE( approxEqual(rightCoeffs, expectedRight) ); } // TEST_CASE("[Helpers] SFZ looping index (SIMD vs Scalar)") // { // std::vector jumps(bigBufferSize); // absl::c_fill(jumps, fillValue); // std::vector indices(bigBufferSize); // std::vector leftCoeffs(bigBufferSize); // std::vector rightCoeffs(bigBufferSize); // std::vector indicesSIMD(bigBufferSize); // std::vector leftCoeffsSIMD(bigBufferSize); // std::vector rightCoeffsSIMD(bigBufferSize); // loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffs), absl::MakeSpan(rightCoeffs), absl::MakeSpan(indices), 1.0f, medBufferSize, 1); // loopingSFZIndex(jumps, absl::MakeSpan(leftCoeffsSIMD), absl::MakeSpan(rightCoeffsSIMD), absl::MakeSpan(indicesSIMD), 1.0f, medBufferSize, 1); // REQUIRE( approxEqual(indices, indicesSIMD, 1) ); // REQUIRE( approxEqual(leftCoeffs, leftCoeffsSIMD, 1e-2) ); // REQUIRE( approxEqual(rightCoeffs, rightCoeffsSIMD, 1e-2) ); // }