diff --git a/benchmarks/BM_pan.cpp b/benchmarks/BM_pan.cpp index ff764cdd..b3f522e8 100644 --- a/benchmarks/BM_pan.cpp +++ b/benchmarks/BM_pan.cpp @@ -12,6 +12,7 @@ #include #include #include "Config.h" +#include "ScopedFTZ.h" #include "absl/types/span.h" class PanArray : public benchmark::Fixture { @@ -47,6 +48,7 @@ public: BENCHMARK_DEFINE_F(PanArray, Scalar)(benchmark::State& state) { + ScopedFTZ ftz; for (auto _ : state) { sfz::pan(pan, absl::MakeSpan(left), absl::MakeSpan(right)); @@ -54,6 +56,7 @@ BENCHMARK_DEFINE_F(PanArray, Scalar)(benchmark::State& state) { } BENCHMARK_DEFINE_F(PanArray, SIMD)(benchmark::State& state) { + ScopedFTZ ftz; for (auto _ : state) { sfz::pan(pan, absl::MakeSpan(left), absl::MakeSpan(right)); @@ -61,6 +64,7 @@ BENCHMARK_DEFINE_F(PanArray, SIMD)(benchmark::State& state) { } BENCHMARK_DEFINE_F(PanArray, BlockOps)(benchmark::State& state) { + ScopedFTZ ftz; for (auto _ : state) { sfz::fill(span2, 1.0f); diff --git a/benchmarks/BM_widthPos.cpp b/benchmarks/BM_widthPos.cpp new file mode 100644 index 00000000..b7f82a4d --- /dev/null +++ b/benchmarks/BM_widthPos.cpp @@ -0,0 +1,120 @@ +// 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 +#include +#include +#include +#include +#include +#include "Config.h" +#include "ScopedFTZ.h" +#include "absl/types/span.h" + +class WidthPosArray : public benchmark::Fixture { +public: + void SetUp(const ::benchmark::State& state) { + std::random_device rd { }; + std::mt19937 gen { rd() }; + std::uniform_real_distribution dist { 0.001f, 1.0f }; + width = std::vector(state.range(0)); + position = std::vector(state.range(0)); + left = std::vector(state.range(0)); + right = std::vector(state.range(0)); + std::generate(width.begin(), width.end(), [&]() { return dist(gen); }); + std::generate(position.begin(), position.end(), [&]() { return dist(gen); }); + std::generate(right.begin(), right.end(), [&]() { return dist(gen); }); + std::generate(left.begin(), left.end(), [&]() { return dist(gen); }); + temp1 = std::vector(state.range(0)); + temp2 = std::vector(state.range(0)); + temp3 = std::vector(state.range(0)); + span1 = absl::MakeSpan(temp1); + span2 = absl::MakeSpan(temp2); + span3 = absl::MakeSpan(temp3); + } + + void TearDown(const ::benchmark::State& state [[maybe_unused]]) { + + } + + std::vector width; + std::vector position; + std::vector left; + std::vector right; + std::vector temp1; + std::vector temp2; + std::vector temp3; + absl::Span span1; + absl::Span span2; + absl::Span span3; +}; + +BENCHMARK_DEFINE_F(WidthPosArray, Scalar)(benchmark::State& state) { + ScopedFTZ ftz; + for (auto _ : state) + { + auto widthPtr = width.data(); + auto posPtr = position.data(); + auto leftPtr = left.data(); + auto rightPtr = right.data(); + const auto sentinel = width.data() + width.size(); + while(widthPtr < sentinel) + { + auto mid = (*leftPtr + *rightPtr) * sqrtTwoInv; + auto side = (*leftPtr - *rightPtr) * sqrtTwoInv; + sfz::_internals::snippetWidth(*widthPtr, mid, side); + auto midRight = mid; + sfz::_internals::snippetPan(*posPtr, mid, midRight); + *leftPtr = (mid + side) * sqrtTwoInv; + *rightPtr = (midRight - side) * sqrtTwoInv; + incrementAll(leftPtr, rightPtr, widthPtr, posPtr); + } + } +} + +BENCHMARK_DEFINE_F(WidthPosArray, BlockOps)(benchmark::State& state) { + ScopedFTZ ftz; + const auto leftBuffer = absl::MakeSpan(left); + const auto rightBuffer = absl::MakeSpan(right); + for (auto _ : state) + { + const auto leftBufferCopy = span2; + sfz::copy(left, leftBufferCopy); + + const auto midBuffer = leftBuffer; + sfz::add(rightBuffer, midBuffer); + + const auto sideBuffer = rightBuffer; + sfz::applyGain(-1.0f, sideBuffer); + sfz::add(leftBufferCopy, sideBuffer); + + sfz::applyGain(sqrtTwoInv, midBuffer); + sfz::applyGain(sqrtTwoInv, sideBuffer); + + // Apply the width process + sfz::width(width, midBuffer, sideBuffer); + + // Copy the mid channel into another span + const auto midBufferCopy = span3; + sfz::copy(midBuffer, midBufferCopy); + sfz::pan(position, midBuffer, midBufferCopy); + + // Rebuild left/right + // Recall that midBuffer and leftBuffer point to the same buffer + sfz::add(sideBuffer, leftBuffer); + sfz::applyGain(sqrtTwoInv, leftBuffer); + + // Recall that sideBuffer and rightBuffer point to the same buffer + sfz::applyGain(-1.0f, sideBuffer); + sfz::add(midBufferCopy, sideBuffer); + sfz::applyGain(sqrtTwoInv, rightBuffer); + } +} + +BENCHMARK_REGISTER_F(WidthPosArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); +BENCHMARK_REGISTER_F(WidthPosArray, BlockOps)->RangeMultiplier(4)->Range(1 << 2, 1 << 12); +BENCHMARK_MAIN(); diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 7cff1d29..a73c12b5 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -51,6 +51,7 @@ sfizz_add_benchmark(bm_mean BM_mean.cpp) sfizz_add_benchmark(bm_meanSquared BM_meanSquared.cpp) sfizz_add_benchmark(bm_cumsum BM_cumsum.cpp) sfizz_add_benchmark(bm_diff BM_diff.cpp) +sfizz_add_benchmark(bm_widthPos BM_widthPos.cpp) sfizz_add_benchmark(bm_interpolationCast BM_interpolationCast.cpp) sfizz_add_benchmark(bm_pointerIterationOrOffsets BM_pointerIterationOrOffsets.cpp) @@ -106,6 +107,7 @@ add_dependencies(sfizz_benchmarks bm_resampleChunk bm_envelopes bm_wavfile + bm_widthPos bm_flacfile bm_filterModulation bm_filterStereoMono diff --git a/tests/SIMDHelpersT.cpp b/tests/SIMDHelpersT.cpp index 1fff15b5..985be6e7 100644 --- a/tests/SIMDHelpersT.cpp +++ b/tests/SIMDHelpersT.cpp @@ -756,3 +756,61 @@ TEST_CASE("[Helpers] Diff (SIMD vs Scalar)") 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 midValue { 1.0f }; + std::array sideValue { 1.0f }; + auto mid = absl::MakeSpan(midValue); + auto side = absl::MakeSpan(sideValue); + SECTION("width = 1") + { + std::array width { 1.0f }; + sfz::width(width, mid, side); + REQUIRE(mid[0] == Approx(0.70711f).margin(0.001f)); + REQUIRE(side[0] == Approx(0.70711f).margin(0.001f)); + } + SECTION("width = 0") + { + std::array width { 0.0f }; + sfz::width(width, mid, side); + REQUIRE(mid[0] == Approx(1.0f).margin(0.001f)); + REQUIRE(side[0] == Approx(0.0f).margin(0.001f)); + } + SECTION("width = -1") + { + std::array width { -1.0f }; + sfz::width(width, mid, side); + REQUIRE(mid[0] == Approx(0.70711f).margin(0.001f)); + REQUIRE(side[0] == Approx(-0.70711f).margin(0.001f)); + } +}