Merge pull request #264 from paulfd/simd-runtime
Revamp the SIMD helpers
This commit is contained in:
commit
0213a561d0
70 changed files with 2101 additions and 4137 deletions
|
|
@ -21,8 +21,6 @@ The sfizz library also uses in some subprojects:
|
|||
- [benchmark], licensed under the Apache License 2.0
|
||||
- [LV2], licensed under the ISC license
|
||||
- [JACK], licensed under the GNU Lesser General Public License v2.1
|
||||
- `neon_mathfun.h` and `sse_mathfun.h` by Julien Pommier,
|
||||
licensed under the zlib license
|
||||
|
||||
[Abseil]: https://github.com/abseil/abseil-cpp
|
||||
[atomic_queue]: https://github.com/max0x7ba/atomic_queue
|
||||
|
|
|
|||
|
|
@ -36,56 +36,64 @@ public:
|
|||
BENCHMARK_DEFINE_F(AddArray, Value_Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::add<float, false>(1.1f, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add1, false);
|
||||
sfz::add1<float>(1.1f, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(AddArray, Value_SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::add<float, true>(1.1f, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add1, true);
|
||||
sfz::add1<float>(1.1f, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(AddArray, Value_Scalar_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::add<float, false>(1.1f, absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add1, false);
|
||||
sfz::add1<float>(1.1f, absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(AddArray, Value_SIMD_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::add<float, true>(1.1f, absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add1, true);
|
||||
sfz::add1<float>(1.1f, absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(AddArray, Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::add<float, false>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add, false);
|
||||
sfz::add<float>(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(AddArray, SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::add<float, true>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add, true);
|
||||
sfz::add<float>(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(AddArray, Scalar_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::add<float, false>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add, false);
|
||||
sfz::add<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(AddArray, SIMD_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::add<float, true>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add, true);
|
||||
sfz::add<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,14 +43,16 @@ BENCHMARK_DEFINE_F(CopyArray, StdCopy)(benchmark::State& state) {
|
|||
BENCHMARK_DEFINE_F(CopyArray, Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::copy<float, false>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::copy, false);
|
||||
sfz::copy<float>(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(CopyArray, SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::copy<float, true>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::copy, true);
|
||||
sfz::copy<float>(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -64,14 +66,16 @@ BENCHMARK_DEFINE_F(CopyArray, StdCopy_Unaligned)(benchmark::State& state) {
|
|||
BENCHMARK_DEFINE_F(CopyArray, Scalar_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::copy<float, false>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::copy, false);
|
||||
sfz::copy<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(CopyArray, SIMD_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::copy<float, true>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::copy, true);
|
||||
sfz::copy<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,28 +35,32 @@ public:
|
|||
BENCHMARK_DEFINE_F(CumArray, Sum_Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::cumsum<float, false>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::cumsum, false);
|
||||
sfz::cumsum<float>(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(CumArray, Sum_SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::cumsum<float, true>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::cumsum, true);
|
||||
sfz::cumsum<float>(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(CumArray, Sum_Scalar_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::cumsum<float, false>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::cumsum, false);
|
||||
sfz::cumsum<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(CumArray, Sum_SIMD_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::cumsum<float, true>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::cumsum, true);
|
||||
sfz::cumsum<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public:
|
|||
input = std::vector<float>(state.range(0));
|
||||
output = std::vector<float>(state.range(0));
|
||||
std::generate(input.begin(), input.end(), [&]() { return dist(gen); });
|
||||
sfz::cumsum<float, false>(input, absl::MakeSpan(input));
|
||||
sfz::cumsum<float>(input, absl::MakeSpan(input));
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& /* state */) {
|
||||
|
|
@ -37,28 +37,32 @@ public:
|
|||
BENCHMARK_DEFINE_F(DiffArray, Diff_Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::diff<float, false>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::diff, false);
|
||||
sfz::diff<float>(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(DiffArray, Diff_SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::diff<float, true>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::diff, true);
|
||||
sfz::diff<float>(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(DiffArray, Diff_Scalar_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::diff<float, false>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::diff, false);
|
||||
sfz::diff<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(DiffArray, Diff_SIMD_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::diff<float, true>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::diff, true);
|
||||
sfz::diff<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,28 +46,32 @@ BENCHMARK_DEFINE_F(Divide, Straight)(benchmark::State& state) {
|
|||
BENCHMARK_DEFINE_F(Divide, Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::divide<float, false>(input, divisor, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::divide, false);
|
||||
sfz::divide<float>(input, divisor, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(Divide, SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::divide<float, true>(input, divisor, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::divide, true);
|
||||
sfz::divide<float>(input, divisor, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(Divide, Scalar_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::divide<float, false>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::divide, false);
|
||||
sfz::divide<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(Divide, SIMD_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::divide<float, true>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::divide, true);
|
||||
sfz::divide<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public:
|
|||
input = std::vector<float>(state.range(0));
|
||||
output = std::vector<float>(state.range(0));
|
||||
std::generate(input.begin(), input.end(), [&]() { return dist(gen); });
|
||||
sfz::cumsum<float, false>(input, absl::MakeSpan(input));
|
||||
sfz::cumsum<float>(input, absl::MakeSpan(input));
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& /* state */)
|
||||
|
|
|
|||
|
|
@ -1,70 +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 "Buffer.h"
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
|
||||
static void Dummy(benchmark::State& state) {
|
||||
sfz::Buffer<float> buffer (state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state) {
|
||||
auto fillValue = dist(gen);
|
||||
benchmark::DoNotOptimize(fillValue);
|
||||
}
|
||||
}
|
||||
|
||||
static void FillScalar(benchmark::State& state) {
|
||||
sfz::Buffer<float> buffer (state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state) {
|
||||
sfz::fill<float, false>(absl::MakeSpan(buffer), dist(gen));
|
||||
}
|
||||
}
|
||||
|
||||
static void FillScalar_unaligned(benchmark::State& state) {
|
||||
sfz::Buffer<float> buffer (state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state) {
|
||||
sfz::fill<float, false>(absl::MakeSpan(buffer).subspan(1), dist(gen));
|
||||
}
|
||||
}
|
||||
|
||||
static void FillSIMD(benchmark::State& state) {
|
||||
sfz::Buffer<float> buffer (state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state) {
|
||||
sfz::fill<float, true>(absl::MakeSpan(buffer), dist(gen));
|
||||
}
|
||||
}
|
||||
|
||||
static void FillSIMD_unaligned(benchmark::State& state) {
|
||||
sfz::Buffer<float> buffer (state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state) {
|
||||
sfz::fill<float, true>(absl::MakeSpan(buffer).subspan(1), dist(gen));
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
|
@ -66,14 +66,16 @@ BENCHMARK_DEFINE_F(GainSingle, Straight)(benchmark::State& state) {
|
|||
BENCHMARK_DEFINE_F(GainSingle, Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::applyGain<float, false>(gain, input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain1, false);
|
||||
sfz::applyGain1<float>(gain, input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GainSingle, SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::applyGain<float, true>(gain, input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain1, true);
|
||||
sfz::applyGain1<float>(gain, input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -88,28 +90,32 @@ BENCHMARK_DEFINE_F(GainArray, Straight)(benchmark::State& state) {
|
|||
BENCHMARK_DEFINE_F(GainArray, Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::applyGain<float, false>(gain, input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain, false);
|
||||
sfz::applyGain<float>(gain, input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GainArray, SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::applyGain<float, true>(gain, input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain, true);
|
||||
sfz::applyGain<float>(gain, input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GainArray, Scalar_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::applyGain<float, false>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain, false);
|
||||
sfz::applyGain<float>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(GainArray, SIMD_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::applyGain<float, true>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain, true);
|
||||
sfz::applyGain<float>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,74 +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 jumps
|
||||
|
||||
constexpr float maxJump { 4 };
|
||||
|
||||
class InterpolationCast : 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 };
|
||||
jumps = std::vector<int>(state.range(0));
|
||||
coeffs = std::vector<float>(state.range(0));
|
||||
floatJumps = std::vector<float>(state.range(0));
|
||||
absl::c_generate(floatJumps, [&]() { return dist(gen); });
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& /* state */) {
|
||||
|
||||
}
|
||||
|
||||
std::vector<int> jumps;
|
||||
std::vector<float> coeffs;
|
||||
std::vector<float> floatJumps;
|
||||
};
|
||||
|
||||
|
||||
BENCHMARK_DEFINE_F(InterpolationCast, Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::sfzInterpolationCast<float, false>(floatJumps, absl::MakeSpan(jumps), absl::MakeSpan(coeffs));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(InterpolationCast, SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::sfzInterpolationCast<float, true>(floatJumps, absl::MakeSpan(jumps), absl::MakeSpan(coeffs));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(InterpolationCast, Scalar_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::sfzInterpolationCast<float, false>(absl::MakeSpan(floatJumps).subspan(1), absl::MakeSpan(jumps).subspan(3), absl::MakeSpan(coeffs).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(InterpolationCast, SIMD_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::sfzInterpolationCast<float, true>(absl::MakeSpan(floatJumps).subspan(1), absl::MakeSpan(jumps).subspan(3), absl::MakeSpan(coeffs).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Register the function as a benchmark
|
||||
BENCHMARK_REGISTER_F(InterpolationCast, Scalar)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_REGISTER_F(InterpolationCast, SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_REGISTER_F(InterpolationCast, Scalar_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_REGISTER_F(InterpolationCast, SIMD_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_MAIN();
|
||||
|
|
@ -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();
|
||||
|
|
@ -45,96 +45,6 @@ BENCHMARK_DEFINE_F(MyFixture, Dummy)
|
|||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, ScalarExp)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::exp<float, false>(source, absl::MakeSpan(result));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, SIMDExp)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::exp<float, true>(source, absl::MakeSpan(result));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, ScalarExp_Unaligned)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::exp<float, false>(absl::MakeSpan(source).subspan(1), absl::MakeSpan(result).subspan(1));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, SIMDExp_Unaligned)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::exp<float, true>(absl::MakeSpan(source).subspan(1), absl::MakeSpan(result).subspan(1));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, ScalarLog)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::log<float, false>(source, absl::MakeSpan(result));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, SIMDLog)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::log<float, true>(source, absl::MakeSpan(result));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, ScalarSin)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::sin<float, false>(source, absl::MakeSpan(result));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, SIMDSin)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::sin<float, true>(source, absl::MakeSpan(result));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, ScalarCos)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::cos<float, false>(source, absl::MakeSpan(result));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, SIMDCos)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::cos<float, true>(source, absl::MakeSpan(result));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, ScalarLibmFloorLog2)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
|
|
@ -159,16 +69,6 @@ BENCHMARK_DEFINE_F(MyFixture, ScalarFastFloorLog2)
|
|||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(MyFixture, Dummy)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, ScalarExp)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, SIMDExp)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, ScalarExp_Unaligned)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, SIMDExp_Unaligned)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, ScalarLog)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, SIMDLog)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, ScalarSin)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, SIMDSin)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, ScalarCos)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, SIMDCos)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, ScalarLibmFloorLog2)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, ScalarFastFloorLog2)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ BENCHMARK_DEFINE_F(MeanArray, Scalar)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = sfz::mean<float, false>(input);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::mean, false);
|
||||
auto result = sfz::mean<float>(input);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +44,8 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = sfz::mean<float, true>(input);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::mean, true);
|
||||
auto result = sfz::mean<float>(input);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -52,7 +54,8 @@ BENCHMARK_DEFINE_F(MeanArray, Scalar_Unaligned)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = sfz::mean<float, false>(absl::MakeSpan(input).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::mean, false);
|
||||
auto result = sfz::mean<float>(absl::MakeSpan(input).subspan(1));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -61,7 +64,8 @@ BENCHMARK_DEFINE_F(MeanArray, SIMD_Unaligned)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = sfz::mean<float, true>(absl::MakeSpan(input).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::mean, true);
|
||||
auto result = sfz::mean<float>(absl::MakeSpan(input).subspan(1));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = sfz::meanSquared<float, false>(input);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::meanSquared, false);
|
||||
auto result = sfz::meanSquared<float>(input);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +44,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = sfz::meanSquared<float, true>(input);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::meanSquared, true);
|
||||
auto result = sfz::meanSquared<float>(input);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -52,7 +54,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, Scalar_Unaligned)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = sfz::meanSquared<float, false>(absl::MakeSpan(input).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::meanSquared, false);
|
||||
auto result = sfz::meanSquared<float>(absl::MakeSpan(input).subspan(1));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -61,7 +64,8 @@ BENCHMARK_DEFINE_F(MeanSquaredArray, SIMD_Unaligned)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto result = sfz::meanSquared<float, true>(absl::MakeSpan(input).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::meanSquared, true);
|
||||
auto result = sfz::meanSquared<float>(absl::MakeSpan(input).subspan(1));
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,28 +46,32 @@ BENCHMARK_DEFINE_F(MultiplyAdd, Straight)(benchmark::State& state) {
|
|||
BENCHMARK_DEFINE_F(MultiplyAdd, Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::multiplyAdd<float, false>(gain, input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd, false);
|
||||
sfz::multiplyAdd<float>(gain, input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MultiplyAdd, SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::multiplyAdd<float, true>(gain, input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd, true);
|
||||
sfz::multiplyAdd<float>(gain, input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MultiplyAdd, Scalar_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::multiplyAdd<float, false>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd, false);
|
||||
sfz::multiplyAdd<float>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MultiplyAdd, SIMD_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::multiplyAdd<float, true>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd, true);
|
||||
sfz::multiplyAdd<float>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, Scalar)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::multiplyAdd<float, false>(gain, input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd1, false);
|
||||
sfz::multiplyAdd1<float>(gain, input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +57,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, SIMD)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::multiplyAdd<float, true>(gain, input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd1, true);
|
||||
sfz::multiplyAdd1<float>(gain, input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +66,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, Scalar_Unaligned)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::multiplyAdd<float, false>(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd1, false);
|
||||
sfz::multiplyAdd1<float>(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +75,8 @@ BENCHMARK_DEFINE_F(MultiplyAddFixedGain, SIMD_Unaligned)
|
|||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::multiplyAdd<float, true>(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd1, true);
|
||||
sfz::multiplyAdd1<float>(gain, absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,83 +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 <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "Config.h"
|
||||
#include "ScopedFTZ.h"
|
||||
#include "absl/types/span.h"
|
||||
|
||||
class PanArray : 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.001f, 1.0f };
|
||||
pan = std::vector<float>(state.range(0));
|
||||
left = std::vector<float>(state.range(0));
|
||||
right = std::vector<float>(state.range(0));
|
||||
std::generate(pan.begin(), pan.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<float>(state.range(0));
|
||||
temp2 = std::vector<float>(state.range(0));
|
||||
span1 = absl::MakeSpan(temp1);
|
||||
span2 = absl::MakeSpan(temp2);
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& /* state */) {
|
||||
|
||||
}
|
||||
|
||||
std::vector<float> pan;
|
||||
std::vector<float> left;
|
||||
std::vector<float> right;
|
||||
std::vector<float> temp1;
|
||||
std::vector<float> temp2;
|
||||
absl::Span<float> span1;
|
||||
absl::Span<float> span2;
|
||||
};
|
||||
|
||||
|
||||
BENCHMARK_DEFINE_F(PanArray, Scalar)(benchmark::State& state) {
|
||||
ScopedFTZ ftz;
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::pan<float, false>(pan, absl::MakeSpan(left), absl::MakeSpan(right));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(PanArray, SIMD)(benchmark::State& state) {
|
||||
ScopedFTZ ftz;
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::pan<float, true>(pan, absl::MakeSpan(left), absl::MakeSpan(right));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(PanArray, BlockOps)(benchmark::State& state) {
|
||||
ScopedFTZ ftz;
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::fill<float>(span2, 1.0f);
|
||||
sfz::add<float>(span1, span2);
|
||||
sfz::applyGain<float>(piFour<float>(), span2);
|
||||
sfz::cos<float>(span2, span1);
|
||||
sfz::sin<float>(span2, span2);
|
||||
sfz::applyGain<float>(span1, absl::MakeSpan(left));
|
||||
sfz::applyGain<float>(span2, absl::MakeSpan(right));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(PanArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(PanArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(PanArray, BlockOps)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
|
|
@ -30,7 +30,8 @@ static void LinearScalar(benchmark::State& state) {
|
|||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::linearRamp<float, false>(absl::MakeSpan(output), 0.0f, value);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, false);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(output), 0.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +43,8 @@ static void LinearSIMD(benchmark::State& state) {
|
|||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::linearRamp<float, true>(absl::MakeSpan(output), 0.0f, value);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, true);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(output), 0.0f, value);
|
||||
}
|
||||
}
|
||||
static void LinearScalarUnaligned(benchmark::State& state) {
|
||||
|
|
@ -53,7 +55,8 @@ static void LinearScalarUnaligned(benchmark::State& state) {
|
|||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::linearRamp<float, false>(absl::MakeSpan(output).subspan(1), 0.0f, value);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, false);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(output).subspan(1), 0.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +68,8 @@ static void LinearSIMDUnaligned(benchmark::State& state) {
|
|||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::linearRamp<float, true>(absl::MakeSpan(output).subspan(1), 0.0f, value);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, true);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(output).subspan(1), 0.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +81,8 @@ static void MulScalar(benchmark::State& state) {
|
|||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::multiplicativeRamp<float, false>(absl::MakeSpan(output), 1.0f, value);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplicativeRamp, false);
|
||||
sfz::multiplicativeRamp<float>(absl::MakeSpan(output), 1.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +94,8 @@ static void MulSIMD(benchmark::State& state) {
|
|||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::multiplicativeRamp<float, true>(absl::MakeSpan(output), 1.0f, value);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplicativeRamp, true);
|
||||
sfz::multiplicativeRamp<float>(absl::MakeSpan(output), 1.0f, value);
|
||||
}
|
||||
}
|
||||
static void MulScalarUnaligned(benchmark::State& state) {
|
||||
|
|
@ -100,7 +106,8 @@ static void MulScalarUnaligned(benchmark::State& state) {
|
|||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::multiplicativeRamp<float, false>(absl::MakeSpan(output).subspan(1), 1.0f, value);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplicativeRamp, false);
|
||||
sfz::multiplicativeRamp<float>(absl::MakeSpan(output).subspan(1), 1.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,64 +119,8 @@ static void MulSIMDUnaligned(benchmark::State& state) {
|
|||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::multiplicativeRamp<float, true>(absl::MakeSpan(output).subspan(1), 1.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void LogDomainScalar(benchmark::State& state) {
|
||||
sfz::Buffer<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::linearRamp<float, false>(absl::MakeSpan(output), 1.0f, value);
|
||||
sfz::applyGain<float, false>(std::log(2.0f), absl::MakeSpan(output));
|
||||
sfz::exp<float, false>(output, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
static void LogDomainSIMD(benchmark::State& state) {
|
||||
sfz::Buffer<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::linearRamp<float, true>(absl::MakeSpan(output), 1.0f, value);
|
||||
sfz::applyGain<float, true>(std::log(2.0f), absl::MakeSpan(output));
|
||||
sfz::exp<float, true>(output, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
static void LogDomainScalarUnaligned(benchmark::State& state) {
|
||||
sfz::Buffer<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
auto outputSpan = absl::MakeSpan(output).subspan(1);
|
||||
sfz::linearRamp<float, false>(outputSpan, 1.0f, value);
|
||||
sfz::applyGain<float, false>(std::log(2.0f), outputSpan);
|
||||
sfz::exp<float, false>(outputSpan, outputSpan);
|
||||
}
|
||||
}
|
||||
|
||||
static void LogDomainSIMDUnaligned(benchmark::State& state) {
|
||||
sfz::Buffer<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
auto outputSpan = absl::MakeSpan(output).subspan(1);
|
||||
sfz::linearRamp<float, true>(outputSpan, 1.0f, value);
|
||||
sfz::applyGain<float, true>(std::log(2.0f), outputSpan);
|
||||
sfz::exp<float, true>(outputSpan, outputSpan);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplicativeRamp, true);
|
||||
sfz::multiplicativeRamp<float>(absl::MakeSpan(output).subspan(1), 1.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -183,8 +134,4 @@ 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();
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ BENCHMARK_DEFINE_F(FileFixture, JustRead)(benchmark::State& state) {
|
|||
{
|
||||
sfz::Buffer<float> buffer { numFrames * sndfile.channels() };
|
||||
sndfile.readf(buffer.data(), numFrames);
|
||||
sfz::readInterleaved<float>(buffer, output->getSpan(0), output->getSpan(1));
|
||||
sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ BENCHMARK_DEFINE_F(FileFixture, AllocInside)(benchmark::State& state) {
|
|||
{
|
||||
sfz::Buffer<float> buffer { chunkSize * sndfile.channels() };
|
||||
auto read = sndfile.readf(buffer.data(), chunkSize);
|
||||
sfz::readInterleaved<float>(
|
||||
sfz::readInterleaved(
|
||||
absl::MakeSpan(buffer).first(read),
|
||||
output->getSpan(0).subspan(framesRead),
|
||||
output->getSpan(1).subspan(framesRead)
|
||||
|
|
@ -95,7 +95,7 @@ BENCHMARK_DEFINE_F(FileFixture, AllocOutside)(benchmark::State& state) {
|
|||
while(framesRead < numFrames)
|
||||
{
|
||||
auto read = sndfile.readf(buffer.data(), chunkSize);
|
||||
sfz::readInterleaved<float>(
|
||||
sfz::readInterleaved(
|
||||
absl::MakeSpan(buffer).first(read),
|
||||
output->getSpan(0).subspan(framesRead),
|
||||
output->getSpan(1).subspan(framesRead)
|
||||
|
|
@ -124,7 +124,7 @@ BENCHMARK_DEFINE_F(FileFixture, DrWavChunked)(benchmark::State& state) {
|
|||
while(framesRead < numFrames)
|
||||
{
|
||||
auto read = drwav_read_pcm_frames_f32(&wav, chunkSize, buffer.data());
|
||||
sfz::readInterleaved<float>(
|
||||
sfz::readInterleaved(
|
||||
absl::MakeSpan(buffer).first(read),
|
||||
output->getSpan(0).subspan(framesRead),
|
||||
output->getSpan(1).subspan(framesRead)
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ BENCHMARK_DEFINE_F(FileFixture, SndFileOnce)(benchmark::State& state) {
|
|||
{
|
||||
sfz::Buffer<float> buffer { numFrames * sndfile.channels() };
|
||||
sndfile.readf(buffer.data(), numFrames);
|
||||
sfz::readInterleaved<float>(buffer, output->getSpan(0), output->getSpan(1));
|
||||
sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ BENCHMARK_DEFINE_F(FileFixture, SndFileChunked)(benchmark::State& state) {
|
|||
{
|
||||
sfz::Buffer<float> buffer { chunkSize * sndfile.channels() };
|
||||
auto read = sndfile.readf(buffer.data(), chunkSize);
|
||||
sfz::readInterleaved<float>(
|
||||
sfz::readInterleaved(
|
||||
absl::MakeSpan(buffer).first(read),
|
||||
output->getSpan(0).subspan(framesRead),
|
||||
output->getSpan(1).subspan(framesRead)
|
||||
|
|
@ -104,7 +104,7 @@ BENCHMARK_DEFINE_F(FileFixture, DrWavChunked)(benchmark::State& state) {
|
|||
while(framesRead < numFrames)
|
||||
{
|
||||
auto read = drflac_read_pcm_frames_f32(flac, chunkSize, buffer.data());
|
||||
sfz::readInterleaved<float>(
|
||||
sfz::readInterleaved(
|
||||
absl::MakeSpan(buffer).first(read),
|
||||
output->getSpan(0).subspan(framesRead),
|
||||
output->getSpan(1).subspan(framesRead)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ static void Scalar(benchmark::State& state) {
|
|||
std::iota(input.begin(), input.end(), 1.0f);
|
||||
|
||||
for (auto _ : state) {
|
||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, false);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +30,8 @@ static void SSE(benchmark::State& state) {
|
|||
std::iota(input.begin(), input.end(), 1.0f);
|
||||
|
||||
for (auto _ : state) {
|
||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, true);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +41,12 @@ static void Scalar_Unaligned(benchmark::State& state) {
|
|||
sfz::Buffer<float> outputRight (state.range(0));
|
||||
std::iota(input.begin(), input.end(), 1.0f);
|
||||
for (auto _ : state) {
|
||||
sfz::readInterleaved<float, false>(absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, false);
|
||||
sfz::readInterleaved(
|
||||
absl::MakeSpan(input).subspan(2),
|
||||
absl::MakeSpan(outputLeft),
|
||||
absl::MakeSpan(outputRight)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +56,12 @@ static void SSE_Unaligned(benchmark::State& state) {
|
|||
sfz::Buffer<float> outputRight (state.range(0));
|
||||
std::iota(input.begin(), input.end(), 1.0f);
|
||||
for (auto _ : state) {
|
||||
sfz::readInterleaved<float, true>(absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft), absl::MakeSpan(outputRight));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, true);
|
||||
sfz::readInterleaved(
|
||||
absl::MakeSpan(input).subspan(2),
|
||||
absl::MakeSpan(outputLeft),
|
||||
absl::MakeSpan(outputRight)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +71,12 @@ static void Scalar_Unaligned_2(benchmark::State& state) {
|
|||
sfz::Buffer<float> outputRight (state.range(0));
|
||||
std::iota(input.begin(), input.end(), 1.0f);
|
||||
for (auto _ : state) {
|
||||
sfz::readInterleaved<float, false>(absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft).subspan(1), absl::MakeSpan(outputRight).subspan(3));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, false);
|
||||
sfz::readInterleaved(
|
||||
absl::MakeSpan(input).subspan(2),
|
||||
absl::MakeSpan(outputLeft).subspan(1),
|
||||
absl::MakeSpan(outputRight).subspan(3)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +86,12 @@ static void SSE_Unaligned_2(benchmark::State& state) {
|
|||
sfz::Buffer<float> outputRight (state.range(0));
|
||||
std::iota(input.begin(), input.end(), 1.0f);
|
||||
for (auto _ : state) {
|
||||
sfz::readInterleaved<float, true>(absl::MakeSpan(input).subspan(2), absl::MakeSpan(outputLeft).subspan(1), absl::MakeSpan(outputRight).subspan(3));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, true);
|
||||
sfz::readInterleaved(
|
||||
absl::MakeSpan(input).subspan(2),
|
||||
absl::MakeSpan(outputLeft).subspan(1),
|
||||
absl::MakeSpan(outputRight).subspan(3)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR2X_scalar)(benchmark::State& state)
|
|||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample2x<float, false>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
|
|
@ -242,7 +242,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR4X_scalar)(benchmark::State& state)
|
|||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample4x<float, false>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
|
|
@ -252,7 +252,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR8X_scalar)(benchmark::State& state)
|
|||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample8x<float, false>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
|
|
@ -262,7 +262,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR2X_vector)(benchmark::State& state)
|
|||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample2x<float, true>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
|
|
@ -272,7 +272,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR4X_vector)(benchmark::State& state)
|
|||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample4x<float, true>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
|
|
@ -282,7 +282,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR8X_vector)(benchmark::State& state)
|
|||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample8x<float, true>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
|
|
@ -300,7 +300,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC2x_BEST)(benchmark::State& state)
|
|||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_BEST_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -317,7 +317,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC2x_MEDIUM)(benchmark::State& state)
|
|||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_MEDIUM_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -334,7 +334,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC2x_FASTEST)(benchmark::State& state)
|
|||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_FASTEST, static_cast<int>(numChannels));
|
||||
auto outBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -352,7 +352,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC4x_BEST)(benchmark::State& state)
|
|||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_BEST_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -369,7 +369,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC4x_MEDIUM)(benchmark::State& state)
|
|||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_MEDIUM_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -386,7 +386,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC4x_FASTEST)(benchmark::State& state)
|
|||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_FASTEST, static_cast<int>(numChannels));
|
||||
auto outBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -403,7 +403,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC8x_BEST)(benchmark::State& state)
|
|||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_BEST_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -420,7 +420,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC8x_MEDIUM)(benchmark::State& state)
|
|||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_MEDIUM_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -437,7 +437,7 @@ BENCHMARK_DEFINE_F(SndFile, SRC8x_FASTEST)(benchmark::State& state)
|
|||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_FASTEST, static_cast<int>(numChannels));
|
||||
auto outBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -446,7 +446,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR8X_default)(benchmark::State& state)
|
|||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = absl::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
sfz::readInterleaved(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample8x<float>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ BENCHMARK_DEFINE_F(FileFixture, NoResampling)(benchmark::State& state) {
|
|||
{
|
||||
sfz::Buffer<float> buffer { numFrames * sndfile.channels() };
|
||||
sndfile.readf(buffer.data(), sndfile.frames());
|
||||
sfz::readInterleaved<float>(buffer, output->getSpan(0), output->getSpan(1));
|
||||
sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ BENCHMARK_DEFINE_F(FileFixture, ResampleAtOnce)(benchmark::State& state) {
|
|||
upsampler4x.set_coefs(coeffsStage4x.data());
|
||||
|
||||
sndfile.readf(buffer.data(), numFrames);
|
||||
sfz::readInterleaved<float>(buffer, output->getSpan(0), output->getSpan(1));
|
||||
sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1));
|
||||
|
||||
upsampler2x.process_block(temp.data(), output->channelReader(0), static_cast<long>(numFrames));
|
||||
upsampler4x.process_block(output->channelWriter(0), temp.data(), static_cast<long>(numFrames * 2));
|
||||
|
|
@ -171,7 +171,7 @@ BENCHMARK_DEFINE_F(FileFixture, ResampleInChunks)(benchmark::State& state) {
|
|||
thisChunkSize * sndfile.channels()
|
||||
);
|
||||
|
||||
sfz::readInterleaved<float>(bufferChunk, leftSpan, rightSpan);
|
||||
sfz::readInterleaved(bufferChunk, leftSpan, rightSpan);
|
||||
|
||||
upsampler2xLeft.process_block(chunkSpan.data(), leftSpan.data(), static_cast<long>(thisChunkSize));
|
||||
upsampler4xLeft.process_block(output->channelWriter(0) + outputFrameCounter, chunkSpan.data(), static_cast<long>(thisChunkSize * 2));
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
@ -36,28 +36,32 @@ public:
|
|||
BENCHMARK_DEFINE_F(SubArray, Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::subtract<float, false>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::subtract, false);
|
||||
sfz::subtract<float>(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SubArray, SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::subtract<float, true>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::subtract, true);
|
||||
sfz::subtract<float>(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SubArray, Scalar_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::subtract<float, false>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::subtract, false);
|
||||
sfz::subtract<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SubArray, SIMD_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::subtract<float, true>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::subtract, true);
|
||||
sfz::subtract<float>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,80 +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 <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#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<float> dist { 0.001f, 1.0f };
|
||||
width = std::vector<float>(state.range(0));
|
||||
position = std::vector<float>(state.range(0));
|
||||
left = std::vector<float>(state.range(0));
|
||||
right = std::vector<float>(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<float>(state.range(0));
|
||||
temp2 = std::vector<float>(state.range(0));
|
||||
temp3 = std::vector<float>(state.range(0));
|
||||
span1 = absl::MakeSpan(temp1);
|
||||
span2 = absl::MakeSpan(temp2);
|
||||
span3 = absl::MakeSpan(temp3);
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& /* state */) {
|
||||
|
||||
}
|
||||
|
||||
std::vector<float> width;
|
||||
std::vector<float> position;
|
||||
std::vector<float> left;
|
||||
std::vector<float> right;
|
||||
std::vector<float> temp1;
|
||||
std::vector<float> temp2;
|
||||
std::vector<float> temp3;
|
||||
absl::Span<float> span1;
|
||||
absl::Span<float> span2;
|
||||
absl::Span<float> span3;
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(WidthPosArray, Scalar)(benchmark::State& state) {
|
||||
ScopedFTZ ftz;
|
||||
const auto leftBuffer = absl::MakeSpan(left);
|
||||
const auto rightBuffer = absl::MakeSpan(right);
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::width<float, false>(width, leftBuffer, rightBuffer);
|
||||
sfz::pan<float, false>(position, leftBuffer, rightBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(WidthPosArray, SIMD)(benchmark::State& state) {
|
||||
ScopedFTZ ftz;
|
||||
const auto leftBuffer = absl::MakeSpan(left);
|
||||
const auto rightBuffer = absl::MakeSpan(right);
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::width<float, true>(width, leftBuffer, rightBuffer);
|
||||
sfz::pan<float, true>(position, leftBuffer, rightBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(WidthPosArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(WidthPosArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
|
|
@ -19,7 +19,8 @@ static void Interleaved_Write(benchmark::State& state) {
|
|||
std::iota(inputRight.begin(), inputRight.end(), 1.0f);
|
||||
|
||||
for (auto _ : state) {
|
||||
sfz::writeInterleaved<float, false>(inputLeft, inputRight, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, false);
|
||||
sfz::writeInterleaved(inputLeft, inputRight, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -30,8 +31,8 @@ static void Interleaved_Write_SSE(benchmark::State& state) {
|
|||
std::iota(inputLeft.begin(), inputLeft.end(), 1.0f);
|
||||
std::iota(inputRight.begin(), inputRight.end(), 1.0f);
|
||||
for (auto _ : state) {
|
||||
sfz::writeInterleaved<float, true>(inputLeft, inputRight, absl::MakeSpan(output));
|
||||
benchmark::DoNotOptimize(output);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, true);
|
||||
sfz::writeInterleaved(inputLeft, inputRight, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,8 +43,12 @@ static void Unaligned_Interleaved_Write(benchmark::State& state) {
|
|||
std::iota(inputLeft.begin(), inputLeft.end(), 1.0f);
|
||||
std::iota(inputRight.begin(), inputRight.end(), 1.0f);
|
||||
for (auto _ : state) {
|
||||
sfz::writeInterleaved<float, false>(absl::MakeSpan(inputLeft).subspan(1) , absl::MakeSpan(inputRight).subspan(1), absl::MakeSpan(output).subspan(2));
|
||||
benchmark::DoNotOptimize(output);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, false);
|
||||
sfz::writeInterleaved(
|
||||
absl::MakeSpan(inputLeft).subspan(1),
|
||||
absl::MakeSpan(inputRight).subspan(1),
|
||||
absl::MakeSpan(output).subspan(2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,8 +59,12 @@ static void Unaligned_Interleaved_Write_SSE(benchmark::State& state) {
|
|||
std::iota(inputLeft.begin(), inputLeft.end(), 1.0f);
|
||||
std::iota(inputRight.begin(), inputRight.end(), 1.0f);
|
||||
for (auto _ : state) {
|
||||
sfz::writeInterleaved<float, true>(absl::MakeSpan(inputLeft).subspan(1) , absl::MakeSpan(inputRight).subspan(1), absl::MakeSpan(output).subspan(2));
|
||||
benchmark::DoNotOptimize(output);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, true);
|
||||
sfz::writeInterleaved(
|
||||
absl::MakeSpan(inputLeft).subspan(1),
|
||||
absl::MakeSpan(inputRight).subspan(1),
|
||||
absl::MakeSpan(output).subspan(2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,8 +75,12 @@ static void Unaligned_Interleaved_Write_2(benchmark::State& state) {
|
|||
std::iota(inputLeft.begin(), inputLeft.end(), 1.0f);
|
||||
std::iota(inputRight.begin(), inputRight.end(), 1.0f);
|
||||
for (auto _ : state) {
|
||||
sfz::writeInterleaved<float, false>(absl::MakeSpan(inputLeft) , absl::MakeSpan(inputRight).subspan(1), absl::MakeSpan(output).subspan(2));
|
||||
benchmark::DoNotOptimize(output);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, false);
|
||||
sfz::writeInterleaved(
|
||||
absl::MakeSpan(inputLeft),
|
||||
absl::MakeSpan(inputRight).subspan(1),
|
||||
absl::MakeSpan(output).subspan(2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,8 +91,12 @@ static void Unaligned_Interleaved_Write_SSE_2(benchmark::State& state) {
|
|||
std::iota(inputLeft.begin(), inputLeft.end(), 1.0f);
|
||||
std::iota(inputRight.begin(), inputRight.end(), 1.0f);
|
||||
for (auto _ : state) {
|
||||
sfz::writeInterleaved<float, true>(absl::MakeSpan(inputLeft) , absl::MakeSpan(inputRight).subspan(1), absl::MakeSpan(output).subspan(2));
|
||||
benchmark::DoNotOptimize(output);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, true);
|
||||
sfz::writeInterleaved(
|
||||
absl::MakeSpan(inputLeft),
|
||||
absl::MakeSpan(inputRight).subspan(1),
|
||||
absl::MakeSpan(output).subspan(2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ if(SAMPLERATE_LIBRARY AND SAMPLERATE_INCLUDE_DIR)
|
|||
endif()
|
||||
|
||||
add_library(bm_simd STATIC ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_simd PRIVATE absl::span)
|
||||
target_link_libraries(bm_simd PRIVATE absl::span sfizz-cpuid)
|
||||
target_include_directories(bm_simd PRIVATE ../src/external)
|
||||
add_library(bm_ftz STATIC ../src/sfizz/ScopedFTZ.cpp)
|
||||
|
||||
|
|
@ -38,12 +38,9 @@ sfizz_add_benchmark(bm_opf_high_vs_low BM_OPF_high_vs_low.cpp)
|
|||
sfizz_add_benchmark(bm_clock BM_clock.cpp)
|
||||
sfizz_add_benchmark(bm_write BM_writeInterleaved.cpp)
|
||||
sfizz_add_benchmark(bm_read BM_readInterleaved.cpp)
|
||||
sfizz_add_benchmark(bm_fill BM_fill.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)
|
||||
|
|
@ -53,13 +50,10 @@ sfizz_add_benchmark(bm_multiplyAdd BM_multiplyAdd.cpp)
|
|||
sfizz_add_benchmark(bm_multiplyAddFixedGain BM_multiplyAddFixedGain.cpp)
|
||||
sfizz_add_benchmark(bm_subtract BM_subtract.cpp)
|
||||
sfizz_add_benchmark(bm_copy BM_copy.cpp)
|
||||
sfizz_add_benchmark(bm_pan BM_pan.cpp)
|
||||
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)
|
||||
sfizz_add_benchmark(bm_maps BM_maps.cpp)
|
||||
target_link_libraries(bm_maps PRIVATE absl::flat_hash_map)
|
||||
|
|
@ -71,7 +65,7 @@ target_link_libraries(bm_logger PRIVATE sfizz::sfizz)
|
|||
|
||||
if (TARGET sfizz-samplerate)
|
||||
sfizz_add_benchmark(bm_resample BM_resample.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_resample PRIVATE sfizz-samplerate sfizz-sndfile)
|
||||
target_link_libraries(bm_resample PRIVATE sfizz-samplerate sfizz-sndfile sfizz-cpuid)
|
||||
endif()
|
||||
|
||||
sfizz_add_benchmark(bm_envelopes BM_envelopes.cpp)
|
||||
|
|
@ -116,27 +110,21 @@ add_dependencies(sfizz_benchmarks
|
|||
bm_read
|
||||
bm_mean
|
||||
bm_meanSquared
|
||||
bm_fill
|
||||
bm_cumsum
|
||||
bm_diff
|
||||
bm_interpolationCast
|
||||
bm_mathfuns
|
||||
bm_gain
|
||||
bm_divide
|
||||
bm_looping
|
||||
bm_saturating
|
||||
bm_ramp
|
||||
bm_ADSR
|
||||
bm_add
|
||||
bm_logger
|
||||
bm_pan
|
||||
bm_subtract
|
||||
bm_multiplyAdd
|
||||
bm_readChunk
|
||||
bm_resampleChunk
|
||||
bm_envelopes
|
||||
bm_wavfile
|
||||
bm_widthPos
|
||||
bm_flacfile
|
||||
bm_filterModulation
|
||||
bm_filterStereoMono
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ macro(sfizz_add_simd_sources SOURCES_VAR PREFIX)
|
|||
# It needs a macro, otherwise the source properties cannot take effect.
|
||||
|
||||
list (APPEND ${SOURCES_VAR}
|
||||
${PREFIX}/sfizz/SIMDSSE.cpp
|
||||
${PREFIX}/sfizz/SIMDNEON.cpp
|
||||
${PREFIX}/sfizz/SIMDDummy.cpp)
|
||||
${PREFIX}/sfizz/SIMDHelpers.cpp
|
||||
${PREFIX}/sfizz/simd/HelpersSSE.cpp
|
||||
${PREFIX}/sfizz/simd/HelpersAVX.cpp)
|
||||
|
||||
# For CPU-dispatched X86 sources
|
||||
# Always build them for all X86 targets.
|
||||
|
|
@ -15,6 +15,7 @@ macro(sfizz_add_simd_sources SOURCES_VAR PREFIX)
|
|||
set_source_files_properties(
|
||||
${PREFIX}/sfizz/effects/impl/ResonantStringAVX.cpp
|
||||
${PREFIX}/sfizz/effects/impl/ResonantArrayAVX.cpp
|
||||
${PREFIX}/sfizz/simd/HelpersAVX.cpp
|
||||
PROPERTIES COMPILE_FLAGS "-mavx")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
7
dpf.mk
7
dpf.mk
|
|
@ -85,6 +85,7 @@ SFIZZ_SOURCES = \
|
|||
src/sfizz/OpcodeCleanup.cpp \
|
||||
src/sfizz/Opcode.cpp \
|
||||
src/sfizz/Oversampler.cpp \
|
||||
src/sfizz/Panning.cpp \
|
||||
src/sfizz/Parser.cpp \
|
||||
src/sfizz/parser/Parser.cpp \
|
||||
src/sfizz/parser/ParserPrivate.cpp \
|
||||
|
|
@ -95,9 +96,9 @@ SFIZZ_SOURCES = \
|
|||
src/sfizz/sfizz_wrapper.cpp \
|
||||
src/sfizz/SfzFilter.cpp \
|
||||
src/sfizz/SfzHelpers.cpp \
|
||||
src/sfizz/SIMDDummy.cpp \
|
||||
src/sfizz/SIMDNEON.cpp \
|
||||
src/sfizz/SIMDSSE.cpp \
|
||||
src/sfizz/SIMDHelpers.cpp \
|
||||
src/sfizz/simd/HelpersSSE.cpp \
|
||||
src/sfizz/simd/HelpersAVX.cpp \
|
||||
src/sfizz/Synth.cpp \
|
||||
src/sfizz/Tuning.cpp \
|
||||
src/sfizz/Voice.cpp \
|
||||
|
|
|
|||
|
|
@ -13,10 +13,13 @@ clang-tidy \
|
|||
src/sfizz/Opcode.cpp \
|
||||
src/sfizz/Oversampler.cpp \
|
||||
src/sfizz/Parser.cpp \
|
||||
src/sfizz/Panning.cpp \
|
||||
src/sfizz/sfizz.cpp \
|
||||
src/sfizz/Region.cpp \
|
||||
src/sfizz/SfzHelpers.cpp \
|
||||
src/sfizz/SIMDSSE.cpp \
|
||||
src/sfizz/SIMDHelpers.cpp \
|
||||
src/sfizz/simd/HelpersSSE.cpp \
|
||||
src/sfizz/simd/HelpersAVX.cpp \
|
||||
src/sfizz/Synth.cpp \
|
||||
src/sfizz/Voice.cpp \
|
||||
src/sfizz/effects/Eq.cpp \
|
||||
|
|
@ -28,5 +31,6 @@ clang-tidy \
|
|||
vst/SfizzVstEditor.cpp \
|
||||
vst/SfizzVstState.cpp \
|
||||
-- -Iexternal/abseil-cpp -Isrc/external -Isrc/external/pugixml/src \
|
||||
-Isrc/sfizz -Isrc -Isrc/external/spline \
|
||||
-Ivst -Ivst/external/VST_SDK/VST3_SDK -Ivst/external/VST_SDK/VST3_SDK/vstgui4 -Ivst/external/ring_buffer -DNDEBUG
|
||||
-Isrc/sfizz -Isrc -Isrc/external/spline -Isrc/external/cpuid/src \
|
||||
-Ivst -Ivst/external/VST_SDK/VST3_SDK -Ivst/external/VST_SDK/VST3_SDK/vstgui4 -Ivst/external/ring_buffer \
|
||||
-DNDEBUG -std=c++17
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ set (SFIZZ_SOURCES
|
|||
sfizz/Wavetables.cpp
|
||||
sfizz/Tuning.cpp
|
||||
sfizz/RTSemaphore.cpp
|
||||
sfizz/Panning.cpp
|
||||
sfizz/Effects.cpp
|
||||
sfizz/effects/Nothing.cpp
|
||||
sfizz/effects/Filter.cpp
|
||||
|
|
|
|||
301
src/external/mathfuns/neon_mathfun.h
vendored
301
src/external/mathfuns/neon_mathfun.h
vendored
|
|
@ -1,301 +0,0 @@
|
|||
/* NEON implementation of sin, cos, exp and log
|
||||
|
||||
Inspired by Intel Approximate Math library, and based on the
|
||||
corresponding algorithms of the cephes math library
|
||||
*/
|
||||
|
||||
/* Copyright (C) 2011 Julien Pommier
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
(this is the zlib license)
|
||||
*/
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
typedef float32x4_t v4sf; // vector of 4 float
|
||||
typedef uint32x4_t v4su; // vector of 4 uint32
|
||||
typedef int32x4_t v4si; // vector of 4 uint32
|
||||
|
||||
#define c_inv_mant_mask ~0x7f800000u
|
||||
#define c_cephes_SQRTHF 0.707106781186547524
|
||||
#define c_cephes_log_p0 7.0376836292E-2
|
||||
#define c_cephes_log_p1 - 1.1514610310E-1
|
||||
#define c_cephes_log_p2 1.1676998740E-1
|
||||
#define c_cephes_log_p3 - 1.2420140846E-1
|
||||
#define c_cephes_log_p4 + 1.4249322787E-1
|
||||
#define c_cephes_log_p5 - 1.6668057665E-1
|
||||
#define c_cephes_log_p6 + 2.0000714765E-1
|
||||
#define c_cephes_log_p7 - 2.4999993993E-1
|
||||
#define c_cephes_log_p8 + 3.3333331174E-1
|
||||
#define c_cephes_log_q1 -2.12194440e-4
|
||||
#define c_cephes_log_q2 0.693359375
|
||||
|
||||
/* natural logarithm computed for 4 simultaneous float
|
||||
return NaN for x <= 0
|
||||
*/
|
||||
v4sf log_ps(v4sf x) {
|
||||
v4sf one = vdupq_n_f32(1);
|
||||
|
||||
x = vmaxq_f32(x, vdupq_n_f32(0)); /* force flush to zero on denormal values */
|
||||
v4su invalid_mask = vcleq_f32(x, vdupq_n_f32(0));
|
||||
|
||||
v4si ux = vreinterpretq_s32_f32(x);
|
||||
|
||||
v4si emm0 = vshrq_n_s32(ux, 23);
|
||||
|
||||
/* keep only the fractional part */
|
||||
ux = vandq_s32(ux, vdupq_n_s32(c_inv_mant_mask));
|
||||
ux = vorrq_s32(ux, vreinterpretq_s32_f32(vdupq_n_f32(0.5f)));
|
||||
x = vreinterpretq_f32_s32(ux);
|
||||
|
||||
emm0 = vsubq_s32(emm0, vdupq_n_s32(0x7f));
|
||||
v4sf e = vcvtq_f32_s32(emm0);
|
||||
|
||||
e = vaddq_f32(e, one);
|
||||
|
||||
/* part2:
|
||||
if( x < SQRTHF ) {
|
||||
e -= 1;
|
||||
x = x + x - 1.0;
|
||||
} else { x = x - 1.0; }
|
||||
*/
|
||||
v4su mask = vcltq_f32(x, vdupq_n_f32(c_cephes_SQRTHF));
|
||||
v4sf tmp = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(x), mask));
|
||||
x = vsubq_f32(x, one);
|
||||
e = vsubq_f32(e, vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(one), mask)));
|
||||
x = vaddq_f32(x, tmp);
|
||||
|
||||
v4sf z = vmulq_f32(x,x);
|
||||
|
||||
v4sf y = vdupq_n_f32(c_cephes_log_p0);
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p1));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p2));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p3));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p4));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p5));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p6));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p7));
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p8));
|
||||
y = vmulq_f32(y, x);
|
||||
|
||||
y = vmulq_f32(y, z);
|
||||
|
||||
|
||||
tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q1));
|
||||
y = vaddq_f32(y, tmp);
|
||||
|
||||
|
||||
tmp = vmulq_f32(z, vdupq_n_f32(0.5f));
|
||||
y = vsubq_f32(y, tmp);
|
||||
|
||||
tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q2));
|
||||
x = vaddq_f32(x, y);
|
||||
x = vaddq_f32(x, tmp);
|
||||
x = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(x), invalid_mask)); // negative arg will be NAN
|
||||
return x;
|
||||
}
|
||||
|
||||
#define c_exp_hi 88.3762626647949f
|
||||
#define c_exp_lo -88.3762626647949f
|
||||
|
||||
#define c_cephes_LOG2EF 1.44269504088896341
|
||||
#define c_cephes_exp_C1 0.693359375
|
||||
#define c_cephes_exp_C2 -2.12194440e-4
|
||||
|
||||
#define c_cephes_exp_p0 1.9875691500E-4
|
||||
#define c_cephes_exp_p1 1.3981999507E-3
|
||||
#define c_cephes_exp_p2 8.3334519073E-3
|
||||
#define c_cephes_exp_p3 4.1665795894E-2
|
||||
#define c_cephes_exp_p4 1.6666665459E-1
|
||||
#define c_cephes_exp_p5 5.0000001201E-1
|
||||
|
||||
/* exp() computed for 4 float at once */
|
||||
v4sf exp_ps(v4sf x) {
|
||||
v4sf tmp, fx;
|
||||
|
||||
v4sf one = vdupq_n_f32(1);
|
||||
x = vminq_f32(x, vdupq_n_f32(c_exp_hi));
|
||||
x = vmaxq_f32(x, vdupq_n_f32(c_exp_lo));
|
||||
|
||||
/* express exp(x) as exp(g + n*log(2)) */
|
||||
fx = vmlaq_f32(vdupq_n_f32(0.5f), x, vdupq_n_f32(c_cephes_LOG2EF));
|
||||
|
||||
/* perform a floorf */
|
||||
tmp = vcvtq_f32_s32(vcvtq_s32_f32(fx));
|
||||
|
||||
/* if greater, substract 1 */
|
||||
v4su mask = vcgtq_f32(tmp, fx);
|
||||
mask = vandq_u32(mask, vreinterpretq_u32_f32(one));
|
||||
|
||||
|
||||
fx = vsubq_f32(tmp, vreinterpretq_f32_u32(mask));
|
||||
|
||||
tmp = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C1));
|
||||
v4sf z = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C2));
|
||||
x = vsubq_f32(x, tmp);
|
||||
x = vsubq_f32(x, z);
|
||||
|
||||
static const float cephes_exp_p[6] = { c_cephes_exp_p0, c_cephes_exp_p1, c_cephes_exp_p2, c_cephes_exp_p3, c_cephes_exp_p4, c_cephes_exp_p5 };
|
||||
v4sf y = vld1q_dup_f32(cephes_exp_p+0);
|
||||
v4sf c1 = vld1q_dup_f32(cephes_exp_p+1);
|
||||
v4sf c2 = vld1q_dup_f32(cephes_exp_p+2);
|
||||
v4sf c3 = vld1q_dup_f32(cephes_exp_p+3);
|
||||
v4sf c4 = vld1q_dup_f32(cephes_exp_p+4);
|
||||
v4sf c5 = vld1q_dup_f32(cephes_exp_p+5);
|
||||
|
||||
y = vmulq_f32(y, x);
|
||||
z = vmulq_f32(x,x);
|
||||
y = vaddq_f32(y, c1);
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, c2);
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, c3);
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, c4);
|
||||
y = vmulq_f32(y, x);
|
||||
y = vaddq_f32(y, c5);
|
||||
|
||||
y = vmulq_f32(y, z);
|
||||
y = vaddq_f32(y, x);
|
||||
y = vaddq_f32(y, one);
|
||||
|
||||
/* build 2^n */
|
||||
int32x4_t mm;
|
||||
mm = vcvtq_s32_f32(fx);
|
||||
mm = vaddq_s32(mm, vdupq_n_s32(0x7f));
|
||||
mm = vshlq_n_s32(mm, 23);
|
||||
v4sf pow2n = vreinterpretq_f32_s32(mm);
|
||||
|
||||
y = vmulq_f32(y, pow2n);
|
||||
return y;
|
||||
}
|
||||
|
||||
#define c_minus_cephes_DP1 -0.78515625
|
||||
#define c_minus_cephes_DP2 -2.4187564849853515625e-4
|
||||
#define c_minus_cephes_DP3 -3.77489497744594108e-8
|
||||
#define c_sincof_p0 -1.9515295891E-4
|
||||
#define c_sincof_p1 8.3321608736E-3
|
||||
#define c_sincof_p2 -1.6666654611E-1
|
||||
#define c_coscof_p0 2.443315711809948E-005
|
||||
#define c_coscof_p1 -1.388731625493765E-003
|
||||
#define c_coscof_p2 4.166664568298827E-002
|
||||
#define c_cephes_FOPI 1.27323954473516 // 4 / M_PI
|
||||
|
||||
/* evaluation of 4 sines & cosines at once.
|
||||
|
||||
The code is the exact rewriting of the cephes sinf function.
|
||||
Precision is excellent as long as x < 8192 (I did not bother to
|
||||
take into account the special handling they have for greater values
|
||||
-- it does not return garbage for arguments over 8192, though, but
|
||||
the extra precision is missing).
|
||||
|
||||
Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the
|
||||
surprising but correct result.
|
||||
|
||||
Note also that when you compute sin(x), cos(x) is available at
|
||||
almost no extra price so both sin_ps and cos_ps make use of
|
||||
sincos_ps..
|
||||
*/
|
||||
void sincos_ps(v4sf x, v4sf *ysin, v4sf *ycos) { // any x
|
||||
v4sf xmm1, xmm2, xmm3, y;
|
||||
|
||||
v4su emm2;
|
||||
|
||||
v4su sign_mask_sin, sign_mask_cos;
|
||||
sign_mask_sin = vcltq_f32(x, vdupq_n_f32(0));
|
||||
x = vabsq_f32(x);
|
||||
|
||||
/* scale by 4/Pi */
|
||||
y = vmulq_f32(x, vdupq_n_f32(c_cephes_FOPI));
|
||||
|
||||
/* store the integer part of y in mm0 */
|
||||
emm2 = vcvtq_u32_f32(y);
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
emm2 = vaddq_u32(emm2, vdupq_n_u32(1));
|
||||
emm2 = vandq_u32(emm2, vdupq_n_u32(~1));
|
||||
y = vcvtq_f32_u32(emm2);
|
||||
|
||||
/* get the polynom selection mask
|
||||
there is one polynom for 0 <= x <= Pi/4
|
||||
and another one for Pi/4<x<=Pi/2
|
||||
|
||||
Both branches will be computed.
|
||||
*/
|
||||
v4su poly_mask = vtstq_u32(emm2, vdupq_n_u32(2));
|
||||
|
||||
/* The magic pass: "Extended precision modular arithmetic"
|
||||
x = ((x - y * DP1) - y * DP2) - y * DP3; */
|
||||
xmm1 = vmulq_n_f32(y, c_minus_cephes_DP1);
|
||||
xmm2 = vmulq_n_f32(y, c_minus_cephes_DP2);
|
||||
xmm3 = vmulq_n_f32(y, c_minus_cephes_DP3);
|
||||
x = vaddq_f32(x, xmm1);
|
||||
x = vaddq_f32(x, xmm2);
|
||||
x = vaddq_f32(x, xmm3);
|
||||
|
||||
sign_mask_sin = veorq_u32(sign_mask_sin, vtstq_u32(emm2, vdupq_n_u32(4)));
|
||||
sign_mask_cos = vtstq_u32(vsubq_u32(emm2, vdupq_n_u32(2)), vdupq_n_u32(4));
|
||||
|
||||
/* Evaluate the first polynom (0 <= x <= Pi/4) in y1,
|
||||
and the second polynom (Pi/4 <= x <= 0) in y2 */
|
||||
v4sf z = vmulq_f32(x,x);
|
||||
v4sf y1, y2;
|
||||
|
||||
y1 = vmulq_n_f32(z, c_coscof_p0);
|
||||
y2 = vmulq_n_f32(z, c_sincof_p0);
|
||||
y1 = vaddq_f32(y1, vdupq_n_f32(c_coscof_p1));
|
||||
y2 = vaddq_f32(y2, vdupq_n_f32(c_sincof_p1));
|
||||
y1 = vmulq_f32(y1, z);
|
||||
y2 = vmulq_f32(y2, z);
|
||||
y1 = vaddq_f32(y1, vdupq_n_f32(c_coscof_p2));
|
||||
y2 = vaddq_f32(y2, vdupq_n_f32(c_sincof_p2));
|
||||
y1 = vmulq_f32(y1, z);
|
||||
y2 = vmulq_f32(y2, z);
|
||||
y1 = vmulq_f32(y1, z);
|
||||
y2 = vmulq_f32(y2, x);
|
||||
y1 = vsubq_f32(y1, vmulq_f32(z, vdupq_n_f32(0.5f)));
|
||||
y2 = vaddq_f32(y2, x);
|
||||
y1 = vaddq_f32(y1, vdupq_n_f32(1));
|
||||
|
||||
/* select the correct result from the two polynoms */
|
||||
v4sf ys = vbslq_f32(poly_mask, y1, y2);
|
||||
v4sf yc = vbslq_f32(poly_mask, y2, y1);
|
||||
*ysin = vbslq_f32(sign_mask_sin, vnegq_f32(ys), ys);
|
||||
*ycos = vbslq_f32(sign_mask_cos, yc, vnegq_f32(yc));
|
||||
}
|
||||
|
||||
v4sf sin_ps(v4sf x) {
|
||||
v4sf ysin, ycos;
|
||||
sincos_ps(x, &ysin, &ycos);
|
||||
return ysin;
|
||||
}
|
||||
|
||||
v4sf cos_ps(v4sf x) {
|
||||
v4sf ysin, ycos;
|
||||
sincos_ps(x, &ysin, &ycos);
|
||||
return ycos;
|
||||
}
|
||||
|
||||
|
||||
713
src/external/mathfuns/sse_mathfun.h
vendored
713
src/external/mathfuns/sse_mathfun.h
vendored
|
|
@ -1,713 +0,0 @@
|
|||
/* SIMD (SSE1+MMX or SSE2) implementation of sin, cos, exp and log
|
||||
|
||||
Inspired by Intel Approximate Math library, and based on the
|
||||
corresponding algorithms of the cephes math library
|
||||
|
||||
The default is to use the SSE1 version. If you define USE_SSE2 the
|
||||
the SSE2 intrinsics will be used in place of the MMX intrinsics. Do
|
||||
not expect any significant performance improvement with SSE2.
|
||||
*/
|
||||
|
||||
/* Copyright (C) 2007 Julien Pommier
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
(this is the zlib license)
|
||||
*/
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
/* yes I know, the top of this file is quite ugly */
|
||||
|
||||
#ifdef _MSC_VER /* visual c++ */
|
||||
# define ALIGN16_BEG __declspec(align(16))
|
||||
# define ALIGN16_END
|
||||
#else /* gcc or icc */
|
||||
# define ALIGN16_BEG
|
||||
# define ALIGN16_END __attribute__((aligned(16)))
|
||||
#endif
|
||||
|
||||
#define USE_SSE2
|
||||
|
||||
/* __m128 is ugly to write */
|
||||
typedef __m128 v4sf; // vector of 4 float (sse1)
|
||||
|
||||
#ifdef USE_SSE2
|
||||
# include <emmintrin.h>
|
||||
typedef __m128i v4si; // vector of 4 int (sse2)
|
||||
#else
|
||||
typedef __m64 v2si; // vector of 2 int (mmx)
|
||||
#endif
|
||||
|
||||
/* declare some SSE constants -- why can't I figure a better way to do that? */
|
||||
#define _PS_CONST(Name, Val) \
|
||||
static const ALIGN16_BEG float _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
|
||||
#define _PI32_CONST(Name, Val) \
|
||||
static const ALIGN16_BEG int _pi32_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
|
||||
#define _PS_CONST_TYPE(Name, Type, Val) \
|
||||
static const ALIGN16_BEG Type _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
|
||||
|
||||
_PS_CONST(1 , 1.0f);
|
||||
_PS_CONST(0p5, 0.5f);
|
||||
/* the smallest non denormalized float number */
|
||||
_PS_CONST_TYPE(min_norm_pos, int, 0x00800000);
|
||||
_PS_CONST_TYPE(mant_mask, int, 0x7f800000);
|
||||
_PS_CONST_TYPE(inv_mant_mask, int, ~0x7f800000);
|
||||
|
||||
_PS_CONST_TYPE(sign_mask, int, (int)0x80000000);
|
||||
_PS_CONST_TYPE(inv_sign_mask, int, ~0x80000000);
|
||||
|
||||
_PI32_CONST(1, 1);
|
||||
_PI32_CONST(inv1, ~1);
|
||||
_PI32_CONST(2, 2);
|
||||
_PI32_CONST(4, 4);
|
||||
_PI32_CONST(0x7f, 0x7f);
|
||||
|
||||
_PS_CONST(cephes_SQRTHF, 0.707106781186547524f);
|
||||
_PS_CONST(cephes_log_p0, 7.0376836292E-2f);
|
||||
_PS_CONST(cephes_log_p1, - 1.1514610310E-1f);
|
||||
_PS_CONST(cephes_log_p2, 1.1676998740E-1f);
|
||||
_PS_CONST(cephes_log_p3, - 1.2420140846E-1f);
|
||||
_PS_CONST(cephes_log_p4, + 1.4249322787E-1f);
|
||||
_PS_CONST(cephes_log_p5, - 1.6668057665E-1f);
|
||||
_PS_CONST(cephes_log_p6, + 2.0000714765E-1f);
|
||||
_PS_CONST(cephes_log_p7, - 2.4999993993E-1f);
|
||||
_PS_CONST(cephes_log_p8, + 3.3333331174E-1f);
|
||||
_PS_CONST(cephes_log_q1, -2.12194440e-4f);
|
||||
_PS_CONST(cephes_log_q2, 0.693359375f);
|
||||
|
||||
#ifndef USE_SSE2
|
||||
typedef union xmm_mm_union {
|
||||
__m128 xmm;
|
||||
__m64 mm[2];
|
||||
} xmm_mm_union;
|
||||
|
||||
#define COPY_XMM_TO_MM(xmm_, mm0_, mm1_) { \
|
||||
xmm_mm_union u; u.xmm = xmm_; \
|
||||
mm0_ = u.mm[0]; \
|
||||
mm1_ = u.mm[1]; \
|
||||
}
|
||||
|
||||
#define COPY_MM_TO_XMM(mm0_, mm1_, xmm_) { \
|
||||
xmm_mm_union u; u.mm[0]=mm0_; u.mm[1]=mm1_; xmm_ = u.xmm; \
|
||||
}
|
||||
|
||||
#endif // USE_SSE2
|
||||
|
||||
/* natural logarithm computed for 4 simultaneous float
|
||||
return NaN for x <= 0
|
||||
*/
|
||||
v4sf log_ps(v4sf x) {
|
||||
#ifdef USE_SSE2
|
||||
v4si emm0;
|
||||
#else
|
||||
v2si mm0, mm1;
|
||||
#endif
|
||||
v4sf one = *(v4sf*)_ps_1;
|
||||
|
||||
v4sf invalid_mask = _mm_cmple_ps(x, _mm_setzero_ps());
|
||||
|
||||
x = _mm_max_ps(x, *(v4sf*)_ps_min_norm_pos); /* cut off denormalized stuff */
|
||||
|
||||
#ifndef USE_SSE2
|
||||
/* part 1: x = frexpf(x, &e); */
|
||||
COPY_XMM_TO_MM(x, mm0, mm1);
|
||||
mm0 = _mm_srli_pi32(mm0, 23);
|
||||
mm1 = _mm_srli_pi32(mm1, 23);
|
||||
#else
|
||||
emm0 = _mm_srli_epi32(_mm_castps_si128(x), 23);
|
||||
#endif
|
||||
/* keep only the fractional part */
|
||||
x = _mm_and_ps(x, *(v4sf*)_ps_inv_mant_mask);
|
||||
x = _mm_or_ps(x, *(v4sf*)_ps_0p5);
|
||||
|
||||
#ifndef USE_SSE2
|
||||
/* now e=mm0:mm1 contain the really base-2 exponent */
|
||||
mm0 = _mm_sub_pi32(mm0, *(v2si*)_pi32_0x7f);
|
||||
mm1 = _mm_sub_pi32(mm1, *(v2si*)_pi32_0x7f);
|
||||
v4sf e = _mm_cvtpi32x2_ps(mm0, mm1);
|
||||
_mm_empty(); /* bye bye mmx */
|
||||
#else
|
||||
emm0 = _mm_sub_epi32(emm0, *(v4si*)_pi32_0x7f);
|
||||
v4sf e = _mm_cvtepi32_ps(emm0);
|
||||
#endif
|
||||
|
||||
e = _mm_add_ps(e, one);
|
||||
|
||||
/* part2:
|
||||
if( x < SQRTHF ) {
|
||||
e -= 1;
|
||||
x = x + x - 1.0;
|
||||
} else { x = x - 1.0; }
|
||||
*/
|
||||
v4sf mask = _mm_cmplt_ps(x, *(v4sf*)_ps_cephes_SQRTHF);
|
||||
v4sf tmp = _mm_and_ps(x, mask);
|
||||
x = _mm_sub_ps(x, one);
|
||||
e = _mm_sub_ps(e, _mm_and_ps(one, mask));
|
||||
x = _mm_add_ps(x, tmp);
|
||||
|
||||
|
||||
v4sf z = _mm_mul_ps(x,x);
|
||||
|
||||
v4sf y = *(v4sf*)_ps_cephes_log_p0;
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p1);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p2);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p3);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p4);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p5);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p6);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p7);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p8);
|
||||
y = _mm_mul_ps(y, x);
|
||||
|
||||
y = _mm_mul_ps(y, z);
|
||||
|
||||
|
||||
tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q1);
|
||||
y = _mm_add_ps(y, tmp);
|
||||
|
||||
|
||||
tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
|
||||
y = _mm_sub_ps(y, tmp);
|
||||
|
||||
tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q2);
|
||||
x = _mm_add_ps(x, y);
|
||||
x = _mm_add_ps(x, tmp);
|
||||
x = _mm_or_ps(x, invalid_mask); // negative arg will be NAN
|
||||
return x;
|
||||
}
|
||||
|
||||
_PS_CONST(exp_hi, 88.3762626647949f);
|
||||
_PS_CONST(exp_lo, -88.3762626647949f);
|
||||
|
||||
_PS_CONST(cephes_LOG2EF, 1.44269504088896341f);
|
||||
_PS_CONST(cephes_exp_C1, 0.693359375f);
|
||||
_PS_CONST(cephes_exp_C2, -2.12194440e-4f);
|
||||
|
||||
_PS_CONST(cephes_exp_p0, 1.9875691500E-4f);
|
||||
_PS_CONST(cephes_exp_p1, 1.3981999507E-3f);
|
||||
_PS_CONST(cephes_exp_p2, 8.3334519073E-3f);
|
||||
_PS_CONST(cephes_exp_p3, 4.1665795894E-2f);
|
||||
_PS_CONST(cephes_exp_p4, 1.6666665459E-1f);
|
||||
_PS_CONST(cephes_exp_p5, 5.0000001201E-1f);
|
||||
|
||||
v4sf exp_ps(v4sf x) {
|
||||
v4sf tmp = _mm_setzero_ps(), fx;
|
||||
#ifdef USE_SSE2
|
||||
v4si emm0;
|
||||
#else
|
||||
v2si mm0, mm1;
|
||||
#endif
|
||||
v4sf one = *(v4sf*)_ps_1;
|
||||
|
||||
x = _mm_min_ps(x, *(v4sf*)_ps_exp_hi);
|
||||
x = _mm_max_ps(x, *(v4sf*)_ps_exp_lo);
|
||||
|
||||
/* express exp(x) as exp(g + n*log(2)) */
|
||||
fx = _mm_mul_ps(x, *(v4sf*)_ps_cephes_LOG2EF);
|
||||
fx = _mm_add_ps(fx, *(v4sf*)_ps_0p5);
|
||||
|
||||
/* how to perform a floorf with SSE: just below */
|
||||
#ifndef USE_SSE2
|
||||
/* step 1 : cast to int */
|
||||
tmp = _mm_movehl_ps(tmp, fx);
|
||||
mm0 = _mm_cvttps_pi32(fx);
|
||||
mm1 = _mm_cvttps_pi32(tmp);
|
||||
/* step 2 : cast back to float */
|
||||
tmp = _mm_cvtpi32x2_ps(mm0, mm1);
|
||||
#else
|
||||
emm0 = _mm_cvttps_epi32(fx);
|
||||
tmp = _mm_cvtepi32_ps(emm0);
|
||||
#endif
|
||||
/* if greater, substract 1 */
|
||||
v4sf mask = _mm_cmpgt_ps(tmp, fx);
|
||||
mask = _mm_and_ps(mask, one);
|
||||
fx = _mm_sub_ps(tmp, mask);
|
||||
|
||||
tmp = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C1);
|
||||
v4sf z = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C2);
|
||||
x = _mm_sub_ps(x, tmp);
|
||||
x = _mm_sub_ps(x, z);
|
||||
|
||||
z = _mm_mul_ps(x,x);
|
||||
|
||||
v4sf y = *(v4sf*)_ps_cephes_exp_p0;
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p1);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p2);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p3);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p4);
|
||||
y = _mm_mul_ps(y, x);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p5);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, x);
|
||||
y = _mm_add_ps(y, one);
|
||||
|
||||
/* build 2^n */
|
||||
#ifndef USE_SSE2
|
||||
z = _mm_movehl_ps(z, fx);
|
||||
mm0 = _mm_cvttps_pi32(fx);
|
||||
mm1 = _mm_cvttps_pi32(z);
|
||||
mm0 = _mm_add_pi32(mm0, *(v2si*)_pi32_0x7f);
|
||||
mm1 = _mm_add_pi32(mm1, *(v2si*)_pi32_0x7f);
|
||||
mm0 = _mm_slli_pi32(mm0, 23);
|
||||
mm1 = _mm_slli_pi32(mm1, 23);
|
||||
|
||||
v4sf pow2n;
|
||||
COPY_MM_TO_XMM(mm0, mm1, pow2n);
|
||||
_mm_empty();
|
||||
#else
|
||||
emm0 = _mm_cvttps_epi32(fx);
|
||||
emm0 = _mm_add_epi32(emm0, *(v4si*)_pi32_0x7f);
|
||||
emm0 = _mm_slli_epi32(emm0, 23);
|
||||
v4sf pow2n = _mm_castsi128_ps(emm0);
|
||||
#endif
|
||||
y = _mm_mul_ps(y, pow2n);
|
||||
return y;
|
||||
}
|
||||
|
||||
_PS_CONST(minus_cephes_DP1, -0.78515625f);
|
||||
_PS_CONST(minus_cephes_DP2, -2.4187564849853515625e-4f);
|
||||
_PS_CONST(minus_cephes_DP3, -3.77489497744594108e-8f);
|
||||
_PS_CONST(sincof_p0, -1.9515295891E-4f);
|
||||
_PS_CONST(sincof_p1, 8.3321608736E-3f);
|
||||
_PS_CONST(sincof_p2, -1.6666654611E-1f);
|
||||
_PS_CONST(coscof_p0, 2.443315711809948E-005f);
|
||||
_PS_CONST(coscof_p1, -1.388731625493765E-003f);
|
||||
_PS_CONST(coscof_p2, 4.166664568298827E-002f);
|
||||
_PS_CONST(cephes_FOPI, 1.27323954473516f); // 4 / M_PI
|
||||
|
||||
|
||||
/* evaluation of 4 sines at onces, using only SSE1+MMX intrinsics so
|
||||
it runs also on old athlons XPs and the pentium III of your grand
|
||||
mother.
|
||||
|
||||
The code is the exact rewriting of the cephes sinf function.
|
||||
Precision is excellent as long as x < 8192 (I did not bother to
|
||||
take into account the special handling they have for greater values
|
||||
-- it does not return garbage for arguments over 8192, though, but
|
||||
the extra precision is missing).
|
||||
|
||||
Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the
|
||||
surprising but correct result.
|
||||
|
||||
Performance is also surprisingly good, 1.33 times faster than the
|
||||
macos vsinf SSE2 function, and 1.5 times faster than the
|
||||
__vrs4_sinf of amd's ACML (which is only available in 64 bits). Not
|
||||
too bad for an SSE1 function (with no special tuning) !
|
||||
However the latter libraries probably have a much better handling of NaN,
|
||||
Inf, denormalized and other special arguments..
|
||||
|
||||
On my core 1 duo, the execution of this function takes approximately 95 cycles.
|
||||
|
||||
From what I have observed on the experiments with Intel AMath lib, switching to an
|
||||
SSE2 version would improve the perf by only 10%.
|
||||
|
||||
Since it is based on SSE intrinsics, it has to be compiled at -O2 to
|
||||
deliver full speed.
|
||||
*/
|
||||
v4sf sin_ps(v4sf x) { // any x
|
||||
v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y;
|
||||
|
||||
#ifdef USE_SSE2
|
||||
v4si emm0, emm2;
|
||||
#else
|
||||
v2si mm0, mm1, mm2, mm3;
|
||||
#endif
|
||||
sign_bit = x;
|
||||
/* take the absolute value */
|
||||
x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask);
|
||||
/* extract the sign bit (upper one) */
|
||||
sign_bit = _mm_and_ps(sign_bit, *(v4sf*)_ps_sign_mask);
|
||||
|
||||
/* scale by 4/Pi */
|
||||
y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI);
|
||||
|
||||
#ifdef USE_SSE2
|
||||
/* store the integer part of y in mm0 */
|
||||
emm2 = _mm_cvttps_epi32(y);
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1);
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1);
|
||||
y = _mm_cvtepi32_ps(emm2);
|
||||
|
||||
/* get the swap sign flag */
|
||||
emm0 = _mm_and_si128(emm2, *(v4si*)_pi32_4);
|
||||
emm0 = _mm_slli_epi32(emm0, 29);
|
||||
/* get the polynom selection mask
|
||||
there is one polynom for 0 <= x <= Pi/4
|
||||
and another one for Pi/4<x<=Pi/2
|
||||
|
||||
Both branches will be computed.
|
||||
*/
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_2);
|
||||
emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
|
||||
|
||||
v4sf swap_sign_bit = _mm_castsi128_ps(emm0);
|
||||
v4sf poly_mask = _mm_castsi128_ps(emm2);
|
||||
sign_bit = _mm_xor_ps(sign_bit, swap_sign_bit);
|
||||
|
||||
#else
|
||||
/* store the integer part of y in mm0:mm1 */
|
||||
xmm2 = _mm_movehl_ps(xmm2, y);
|
||||
mm2 = _mm_cvttps_pi32(y);
|
||||
mm3 = _mm_cvttps_pi32(xmm2);
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
mm2 = _mm_add_pi32(mm2, *(v2si*)_pi32_1);
|
||||
mm3 = _mm_add_pi32(mm3, *(v2si*)_pi32_1);
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_inv1);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_inv1);
|
||||
y = _mm_cvtpi32x2_ps(mm2, mm3);
|
||||
/* get the swap sign flag */
|
||||
mm0 = _mm_and_si64(mm2, *(v2si*)_pi32_4);
|
||||
mm1 = _mm_and_si64(mm3, *(v2si*)_pi32_4);
|
||||
mm0 = _mm_slli_pi32(mm0, 29);
|
||||
mm1 = _mm_slli_pi32(mm1, 29);
|
||||
/* get the polynom selection mask */
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_2);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_2);
|
||||
mm2 = _mm_cmpeq_pi32(mm2, _mm_setzero_si64());
|
||||
mm3 = _mm_cmpeq_pi32(mm3, _mm_setzero_si64());
|
||||
v4sf swap_sign_bit, poly_mask;
|
||||
COPY_MM_TO_XMM(mm0, mm1, swap_sign_bit);
|
||||
COPY_MM_TO_XMM(mm2, mm3, poly_mask);
|
||||
sign_bit = _mm_xor_ps(sign_bit, swap_sign_bit);
|
||||
_mm_empty(); /* good-bye mmx */
|
||||
#endif
|
||||
|
||||
/* The magic pass: "Extended precision modular arithmetic"
|
||||
x = ((x - y * DP1) - y * DP2) - y * DP3; */
|
||||
xmm1 = *(v4sf*)_ps_minus_cephes_DP1;
|
||||
xmm2 = *(v4sf*)_ps_minus_cephes_DP2;
|
||||
xmm3 = *(v4sf*)_ps_minus_cephes_DP3;
|
||||
xmm1 = _mm_mul_ps(y, xmm1);
|
||||
xmm2 = _mm_mul_ps(y, xmm2);
|
||||
xmm3 = _mm_mul_ps(y, xmm3);
|
||||
x = _mm_add_ps(x, xmm1);
|
||||
x = _mm_add_ps(x, xmm2);
|
||||
x = _mm_add_ps(x, xmm3);
|
||||
|
||||
/* Evaluate the first polynom (0 <= x <= Pi/4) */
|
||||
y = *(v4sf*)_ps_coscof_p0;
|
||||
v4sf z = _mm_mul_ps(x,x);
|
||||
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p1);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p2);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_mul_ps(y, z);
|
||||
v4sf tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
|
||||
y = _mm_sub_ps(y, tmp);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_1);
|
||||
|
||||
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
|
||||
|
||||
v4sf y2 = *(v4sf*)_ps_sincof_p0;
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p1);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p2);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_mul_ps(y2, x);
|
||||
y2 = _mm_add_ps(y2, x);
|
||||
|
||||
/* select the correct result from the two polynoms */
|
||||
xmm3 = poly_mask;
|
||||
y2 = _mm_and_ps(xmm3, y2); //, xmm3);
|
||||
y = _mm_andnot_ps(xmm3, y);
|
||||
y = _mm_add_ps(y,y2);
|
||||
/* update the sign */
|
||||
y = _mm_xor_ps(y, sign_bit);
|
||||
return y;
|
||||
}
|
||||
|
||||
/* almost the same as sin_ps */
|
||||
v4sf cos_ps(v4sf x) { // any x
|
||||
v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, y;
|
||||
#ifdef USE_SSE2
|
||||
v4si emm0, emm2;
|
||||
#else
|
||||
v2si mm0, mm1, mm2, mm3;
|
||||
#endif
|
||||
/* take the absolute value */
|
||||
x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask);
|
||||
|
||||
/* scale by 4/Pi */
|
||||
y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI);
|
||||
|
||||
#ifdef USE_SSE2
|
||||
/* store the integer part of y in mm0 */
|
||||
emm2 = _mm_cvttps_epi32(y);
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1);
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1);
|
||||
y = _mm_cvtepi32_ps(emm2);
|
||||
|
||||
emm2 = _mm_sub_epi32(emm2, *(v4si*)_pi32_2);
|
||||
|
||||
/* get the swap sign flag */
|
||||
emm0 = _mm_andnot_si128(emm2, *(v4si*)_pi32_4);
|
||||
emm0 = _mm_slli_epi32(emm0, 29);
|
||||
/* get the polynom selection mask */
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_2);
|
||||
emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
|
||||
|
||||
v4sf sign_bit = _mm_castsi128_ps(emm0);
|
||||
v4sf poly_mask = _mm_castsi128_ps(emm2);
|
||||
#else
|
||||
/* store the integer part of y in mm0:mm1 */
|
||||
xmm2 = _mm_movehl_ps(xmm2, y);
|
||||
mm2 = _mm_cvttps_pi32(y);
|
||||
mm3 = _mm_cvttps_pi32(xmm2);
|
||||
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
mm2 = _mm_add_pi32(mm2, *(v2si*)_pi32_1);
|
||||
mm3 = _mm_add_pi32(mm3, *(v2si*)_pi32_1);
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_inv1);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_inv1);
|
||||
|
||||
y = _mm_cvtpi32x2_ps(mm2, mm3);
|
||||
|
||||
|
||||
mm2 = _mm_sub_pi32(mm2, *(v2si*)_pi32_2);
|
||||
mm3 = _mm_sub_pi32(mm3, *(v2si*)_pi32_2);
|
||||
|
||||
/* get the swap sign flag in mm0:mm1 and the
|
||||
polynom selection mask in mm2:mm3 */
|
||||
|
||||
mm0 = _mm_andnot_si64(mm2, *(v2si*)_pi32_4);
|
||||
mm1 = _mm_andnot_si64(mm3, *(v2si*)_pi32_4);
|
||||
mm0 = _mm_slli_pi32(mm0, 29);
|
||||
mm1 = _mm_slli_pi32(mm1, 29);
|
||||
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_2);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_2);
|
||||
|
||||
mm2 = _mm_cmpeq_pi32(mm2, _mm_setzero_si64());
|
||||
mm3 = _mm_cmpeq_pi32(mm3, _mm_setzero_si64());
|
||||
|
||||
v4sf sign_bit, poly_mask;
|
||||
COPY_MM_TO_XMM(mm0, mm1, sign_bit);
|
||||
COPY_MM_TO_XMM(mm2, mm3, poly_mask);
|
||||
_mm_empty(); /* good-bye mmx */
|
||||
#endif
|
||||
/* The magic pass: "Extended precision modular arithmetic"
|
||||
x = ((x - y * DP1) - y * DP2) - y * DP3; */
|
||||
xmm1 = *(v4sf*)_ps_minus_cephes_DP1;
|
||||
xmm2 = *(v4sf*)_ps_minus_cephes_DP2;
|
||||
xmm3 = *(v4sf*)_ps_minus_cephes_DP3;
|
||||
xmm1 = _mm_mul_ps(y, xmm1);
|
||||
xmm2 = _mm_mul_ps(y, xmm2);
|
||||
xmm3 = _mm_mul_ps(y, xmm3);
|
||||
x = _mm_add_ps(x, xmm1);
|
||||
x = _mm_add_ps(x, xmm2);
|
||||
x = _mm_add_ps(x, xmm3);
|
||||
|
||||
/* Evaluate the first polynom (0 <= x <= Pi/4) */
|
||||
y = *(v4sf*)_ps_coscof_p0;
|
||||
v4sf z = _mm_mul_ps(x,x);
|
||||
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p1);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p2);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_mul_ps(y, z);
|
||||
v4sf tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
|
||||
y = _mm_sub_ps(y, tmp);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_1);
|
||||
|
||||
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
|
||||
|
||||
v4sf y2 = *(v4sf*)_ps_sincof_p0;
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p1);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p2);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_mul_ps(y2, x);
|
||||
y2 = _mm_add_ps(y2, x);
|
||||
|
||||
/* select the correct result from the two polynoms */
|
||||
xmm3 = poly_mask;
|
||||
y2 = _mm_and_ps(xmm3, y2); //, xmm3);
|
||||
y = _mm_andnot_ps(xmm3, y);
|
||||
y = _mm_add_ps(y,y2);
|
||||
/* update the sign */
|
||||
y = _mm_xor_ps(y, sign_bit);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/* since sin_ps and cos_ps are almost identical, sincos_ps could replace both of them..
|
||||
it is almost as fast, and gives you a free cosine with your sine */
|
||||
void sincos_ps(v4sf x, v4sf *s, v4sf *c) {
|
||||
v4sf xmm1, xmm2, xmm3 = _mm_setzero_ps(), sign_bit_sin, y;
|
||||
#ifdef USE_SSE2
|
||||
v4si emm0, emm2, emm4;
|
||||
#else
|
||||
v2si mm0, mm1, mm2, mm3, mm4, mm5;
|
||||
#endif
|
||||
sign_bit_sin = x;
|
||||
/* take the absolute value */
|
||||
x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask);
|
||||
/* extract the sign bit (upper one) */
|
||||
sign_bit_sin = _mm_and_ps(sign_bit_sin, *(v4sf*)_ps_sign_mask);
|
||||
|
||||
/* scale by 4/Pi */
|
||||
y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI);
|
||||
|
||||
#ifdef USE_SSE2
|
||||
/* store the integer part of y in emm2 */
|
||||
emm2 = _mm_cvttps_epi32(y);
|
||||
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1);
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1);
|
||||
y = _mm_cvtepi32_ps(emm2);
|
||||
|
||||
emm4 = emm2;
|
||||
|
||||
/* get the swap sign flag for the sine */
|
||||
emm0 = _mm_and_si128(emm2, *(v4si*)_pi32_4);
|
||||
emm0 = _mm_slli_epi32(emm0, 29);
|
||||
v4sf swap_sign_bit_sin = _mm_castsi128_ps(emm0);
|
||||
|
||||
/* get the polynom selection mask for the sine*/
|
||||
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_2);
|
||||
emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
|
||||
v4sf poly_mask = _mm_castsi128_ps(emm2);
|
||||
#else
|
||||
/* store the integer part of y in mm2:mm3 */
|
||||
xmm3 = _mm_movehl_ps(xmm3, y);
|
||||
mm2 = _mm_cvttps_pi32(y);
|
||||
mm3 = _mm_cvttps_pi32(xmm3);
|
||||
|
||||
/* j=(j+1) & (~1) (see the cephes sources) */
|
||||
mm2 = _mm_add_pi32(mm2, *(v2si*)_pi32_1);
|
||||
mm3 = _mm_add_pi32(mm3, *(v2si*)_pi32_1);
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_inv1);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_inv1);
|
||||
|
||||
y = _mm_cvtpi32x2_ps(mm2, mm3);
|
||||
|
||||
mm4 = mm2;
|
||||
mm5 = mm3;
|
||||
|
||||
/* get the swap sign flag for the sine */
|
||||
mm0 = _mm_and_si64(mm2, *(v2si*)_pi32_4);
|
||||
mm1 = _mm_and_si64(mm3, *(v2si*)_pi32_4);
|
||||
mm0 = _mm_slli_pi32(mm0, 29);
|
||||
mm1 = _mm_slli_pi32(mm1, 29);
|
||||
v4sf swap_sign_bit_sin;
|
||||
COPY_MM_TO_XMM(mm0, mm1, swap_sign_bit_sin);
|
||||
|
||||
/* get the polynom selection mask for the sine */
|
||||
|
||||
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_2);
|
||||
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_2);
|
||||
mm2 = _mm_cmpeq_pi32(mm2, _mm_setzero_si64());
|
||||
mm3 = _mm_cmpeq_pi32(mm3, _mm_setzero_si64());
|
||||
v4sf poly_mask;
|
||||
COPY_MM_TO_XMM(mm2, mm3, poly_mask);
|
||||
#endif
|
||||
|
||||
/* The magic pass: "Extended precision modular arithmetic"
|
||||
x = ((x - y * DP1) - y * DP2) - y * DP3; */
|
||||
xmm1 = *(v4sf*)_ps_minus_cephes_DP1;
|
||||
xmm2 = *(v4sf*)_ps_minus_cephes_DP2;
|
||||
xmm3 = *(v4sf*)_ps_minus_cephes_DP3;
|
||||
xmm1 = _mm_mul_ps(y, xmm1);
|
||||
xmm2 = _mm_mul_ps(y, xmm2);
|
||||
xmm3 = _mm_mul_ps(y, xmm3);
|
||||
x = _mm_add_ps(x, xmm1);
|
||||
x = _mm_add_ps(x, xmm2);
|
||||
x = _mm_add_ps(x, xmm3);
|
||||
|
||||
#ifdef USE_SSE2
|
||||
emm4 = _mm_sub_epi32(emm4, *(v4si*)_pi32_2);
|
||||
emm4 = _mm_andnot_si128(emm4, *(v4si*)_pi32_4);
|
||||
emm4 = _mm_slli_epi32(emm4, 29);
|
||||
v4sf sign_bit_cos = _mm_castsi128_ps(emm4);
|
||||
#else
|
||||
/* get the sign flag for the cosine */
|
||||
mm4 = _mm_sub_pi32(mm4, *(v2si*)_pi32_2);
|
||||
mm5 = _mm_sub_pi32(mm5, *(v2si*)_pi32_2);
|
||||
mm4 = _mm_andnot_si64(mm4, *(v2si*)_pi32_4);
|
||||
mm5 = _mm_andnot_si64(mm5, *(v2si*)_pi32_4);
|
||||
mm4 = _mm_slli_pi32(mm4, 29);
|
||||
mm5 = _mm_slli_pi32(mm5, 29);
|
||||
v4sf sign_bit_cos;
|
||||
COPY_MM_TO_XMM(mm4, mm5, sign_bit_cos);
|
||||
_mm_empty(); /* good-bye mmx */
|
||||
#endif
|
||||
|
||||
sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin);
|
||||
|
||||
|
||||
/* Evaluate the first polynom (0 <= x <= Pi/4) */
|
||||
v4sf z = _mm_mul_ps(x,x);
|
||||
y = *(v4sf*)_ps_coscof_p0;
|
||||
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p1);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p2);
|
||||
y = _mm_mul_ps(y, z);
|
||||
y = _mm_mul_ps(y, z);
|
||||
v4sf tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
|
||||
y = _mm_sub_ps(y, tmp);
|
||||
y = _mm_add_ps(y, *(v4sf*)_ps_1);
|
||||
|
||||
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
|
||||
|
||||
v4sf y2 = *(v4sf*)_ps_sincof_p0;
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p1);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p2);
|
||||
y2 = _mm_mul_ps(y2, z);
|
||||
y2 = _mm_mul_ps(y2, x);
|
||||
y2 = _mm_add_ps(y2, x);
|
||||
|
||||
/* select the correct result from the two polynoms */
|
||||
xmm3 = poly_mask;
|
||||
v4sf ysin2 = _mm_and_ps(xmm3, y2);
|
||||
v4sf ysin1 = _mm_andnot_ps(xmm3, y);
|
||||
y2 = _mm_sub_ps(y2,ysin2);
|
||||
y = _mm_sub_ps(y, ysin1);
|
||||
|
||||
xmm1 = _mm_add_ps(ysin1,ysin2);
|
||||
xmm2 = _mm_add_ps(y,y2);
|
||||
|
||||
/* update the sign */
|
||||
*s = _mm_xor_ps(xmm1, sign_bit_sin);
|
||||
*c = _mm_xor_ps(xmm2, sign_bit_cos);
|
||||
}
|
||||
|
||||
|
|
@ -26,8 +26,8 @@ namespace sfz
|
|||
* @tparam MaxChannels the maximum number of channels in the buffer
|
||||
* @tparam Alignment the alignment for the buffers
|
||||
*/
|
||||
template <class Type, size_t MaxChannels = sfz::config::numChannels,
|
||||
unsigned int Alignment = SIMDConfig::defaultAlignment,
|
||||
template <class Type, size_t MaxChannels = config::numChannels,
|
||||
unsigned int Alignment = config::defaultAlignment,
|
||||
size_t PaddingLeft_ = 0, size_t PaddingRight_ = 0>
|
||||
class AudioBuffer {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ public:
|
|||
{
|
||||
static_assert(!std::is_const<Type>::value, "Can't allow mutating operations on const AudioSpans");
|
||||
for (size_t i = 0; i < numChannels; ++i)
|
||||
sfz::fill<Type>(getSpan(i), value);
|
||||
sfz::fill(getSpan(i), value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -303,7 +303,7 @@ public:
|
|||
{
|
||||
static_assert(!std::is_const<Type>::value, "Can't allow mutating operations on const AudioSpans");
|
||||
for (size_t i = 0; i < numChannels; ++i)
|
||||
sfz::applyGain<Type>(gain, getSpan(i));
|
||||
sfz::applyGain1<Type>(gain, getSpan(i));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -119,9 +119,9 @@ private:
|
|||
*
|
||||
* @tparam Type The buffer type
|
||||
* @tparam Alignment the required alignment in bytes (defaults to
|
||||
* SIMDConfig::defaultAlignment)
|
||||
* config::defaultAlignment)
|
||||
*/
|
||||
template <class Type, unsigned int Alignment = SIMDConfig::defaultAlignment>
|
||||
template <class Type, unsigned int Alignment = config::defaultAlignment>
|
||||
class Buffer {
|
||||
public:
|
||||
using value_type = typename std::remove_cv<Type>::type;
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ namespace config {
|
|||
constexpr uint16_t numCCs { 512 };
|
||||
constexpr int maxCurves { 256 };
|
||||
constexpr int chunkSize { 1024 };
|
||||
constexpr unsigned int defaultAlignment { 16 };
|
||||
constexpr int filtersInPool { maxVoices * 2 };
|
||||
constexpr int excessFileFrames { 8 };
|
||||
/**
|
||||
|
|
@ -96,29 +97,4 @@ namespace config {
|
|||
static constexpr double amplitudeSquare = 0.515;
|
||||
} // namespace config
|
||||
|
||||
// Enable or disable SIMD accelerators by default
|
||||
namespace SIMDConfig {
|
||||
constexpr unsigned int defaultAlignment { 16 };
|
||||
constexpr bool writeInterleaved { true };
|
||||
constexpr bool readInterleaved { true };
|
||||
constexpr bool fill { true };
|
||||
constexpr bool gain { false };
|
||||
constexpr bool divide { false };
|
||||
constexpr bool mathfuns { false };
|
||||
constexpr bool loopingSFZIndex { true };
|
||||
constexpr bool saturatingSFZIndex { true };
|
||||
constexpr bool linearRamp { false };
|
||||
constexpr bool multiplicativeRamp { true };
|
||||
constexpr bool add { false };
|
||||
constexpr bool subtract { false };
|
||||
constexpr bool multiplyAdd { false };
|
||||
constexpr bool copy { false };
|
||||
constexpr bool pan { false };
|
||||
constexpr bool cumsum { true };
|
||||
constexpr bool diff { false };
|
||||
constexpr bool sfzInterpolationCast { true };
|
||||
constexpr bool mean { false };
|
||||
constexpr bool meanSquared { false };
|
||||
constexpr bool upsampling { true };
|
||||
}
|
||||
} // namespace sfz
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
std::cerr << "Check failed at " << __FILE__ << ":" << __LINE__ << '\n'; \
|
||||
} while (0)
|
||||
|
||||
#define CHECK(expression) \
|
||||
#define SFIZZ_CHECK(expression) \
|
||||
do { \
|
||||
if (!(expression)) { \
|
||||
std::cerr << "Check failed: " << #expression << '\n'; \
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
#define ASSERTFALSE do {} while (0)
|
||||
#define ASSERT(expression) do {} while (0)
|
||||
#define CHECKFALSE do {} while (0)
|
||||
#define CHECK(expression) do {} while (0)
|
||||
#define SFIZZ_CHECK(expression) do {} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ void EffectBus::addToInputs(const float* const addInput[], float addGain, unsign
|
|||
|
||||
for (unsigned c = 0; c < EffectChannels; ++c) {
|
||||
absl::Span<const float> addIn { addInput[c], nframes };
|
||||
sfz::multiplyAdd(addGain, addIn, _inputs.getSpan(c).first(nframes));
|
||||
sfz::multiplyAdd1(addGain, addIn, _inputs.getSpan(c).first(nframes));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -154,8 +154,8 @@ void EffectBus::mixOutputsTo(float* const mainOutput[], float* const mixOutput[]
|
|||
|
||||
for (unsigned c = 0; c < EffectChannels; ++c) {
|
||||
auto fxOut = _outputs.getConstSpan(c).first(nframes);
|
||||
sfz::multiplyAdd(gainToMain, fxOut, absl::Span<float>(mainOutput[c], nframes));
|
||||
sfz::multiplyAdd(gainToMix, fxOut, absl::Span<float>(mixOutput[c], nframes));
|
||||
sfz::multiplyAdd1(gainToMain, fxOut, absl::Span<float>(mainOutput[c], nframes));
|
||||
sfz::multiplyAdd1(gainToMix, fxOut, absl::Span<float>(mixOutput[c], nframes));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ void readBaseFile(SndfileHandle& sndFile, sfz::FileAudioBuffer& output, uint32_t
|
|||
output.clear();
|
||||
sfz::Buffer<float> tempReadBuffer { 2 * numFrames };
|
||||
sndFile.readf(tempReadBuffer.data(), numFrames);
|
||||
sfz::readInterleaved<float>(tempReadBuffer, output.getSpan(0), output.getSpan(1));
|
||||
sfz::readInterleaved(tempReadBuffer, output.getSpan(0), output.getSpan(1));
|
||||
}
|
||||
|
||||
if (reverse) {
|
||||
|
|
@ -87,7 +87,6 @@ std::unique_ptr<sfz::FileAudioBuffer> readFromFile(SndfileHandle& sndFile, uint3
|
|||
return outputBuffer;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void streamFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor, bool reverse, sfz::FileAudioBuffer& output, std::atomic<size_t>* filledFrames = nullptr)
|
||||
{
|
||||
if (factor == sfz::Oversampling::x1) {
|
||||
|
|
@ -400,7 +399,7 @@ void sfz::FilePool::loadingThread() noexcept
|
|||
continue;
|
||||
}
|
||||
const auto frames = static_cast<uint32_t>(sndFile.frames());
|
||||
streamFromFile<float>(sndFile, frames, oversamplingFactor, promise->fileId.isReverse(), promise->fileData, &promise->availableFrames);
|
||||
streamFromFile(sndFile, frames, oversamplingFactor, promise->fileId.isReverse(), promise->fileData, &promise->availableFrames);
|
||||
promise->dataStatus = FilePromise::DataStatus::Ready;
|
||||
const auto loadDuration = std::chrono::high_resolution_clock::now() - loadStartTime;
|
||||
logger.logFileTime(waitDuration, loadDuration, frames, promise->fileId.filename());
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
#include <mutex>
|
||||
|
||||
namespace sfz {
|
||||
using FileAudioBuffer = AudioBuffer<float, 2, SIMDConfig::defaultAlignment,
|
||||
using FileAudioBuffer = AudioBuffer<float, 2, config::defaultAlignment,
|
||||
sfz::config::excessFileFrames, sfz::config::excessFileFrames>;
|
||||
using FileAudioBufferPtr = std::shared_ptr<FileAudioBuffer>;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public:
|
|||
void resize(size_t size)
|
||||
{
|
||||
buffer.resize(size);
|
||||
fill<ValueType>(absl::MakeSpan(buffer), 0.0);
|
||||
fill(absl::MakeSpan(buffer), ValueType { 0 });
|
||||
index = 0;
|
||||
validMean = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
* @brief Contains math helper functions and math constants
|
||||
*/
|
||||
#pragma once
|
||||
#include "Debug.h"
|
||||
#include "Config.h"
|
||||
#include "Macros.h"
|
||||
#include "SIMDConfig.h"
|
||||
|
|
@ -253,6 +254,20 @@ constexpr Type sqrtTwo() { return static_cast<Type>(1.41421356237309504880168872
|
|||
template <class Type>
|
||||
constexpr Type sqrtTwoInv() { return static_cast<Type>(0.707106781186547524400844362104849039284835937688474036588); };
|
||||
|
||||
/**
|
||||
* @brief lround for positive values
|
||||
* This optimizes a bit better by ignoring the negative code path
|
||||
*
|
||||
* @tparam T
|
||||
* @param value
|
||||
* @return constexpr long int
|
||||
*/
|
||||
template<class T, absl::enable_if_t<std::is_floating_point<T>::value, int> = 0 >
|
||||
constexpr long int lroundPositive(T value)
|
||||
{
|
||||
return static_cast<int>(0.5f + value); // NOLINT
|
||||
}
|
||||
|
||||
/**
|
||||
@brief A fraction which is parameterized by integer type
|
||||
*/
|
||||
|
|
@ -476,7 +491,7 @@ constexpr bool checkSpanSizes(const absl::Span<T>& span1, Others... others)
|
|||
return _checkSpanSizes(span1.size(), others...);
|
||||
}
|
||||
|
||||
#define CHECK_SPAN_SIZES(...) CHECK(checkSpanSizes(__VA_ARGS__))
|
||||
#define CHECK_SPAN_SIZES(...) SFIZZ_CHECK(checkSpanSizes(__VA_ARGS__))
|
||||
|
||||
|
||||
class ScopedRoundingMode {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ void linearEnvelope(const EventVector& events, absl::Span<float> envelope, F&& l
|
|||
lastValue = linearRamp<float>(envelope.subspan(lastDelay, length), lastValue, step);
|
||||
lastDelay += length;
|
||||
}
|
||||
fill<float>(envelope.subspan(lastDelay), lastValue);
|
||||
fill(envelope.subspan(lastDelay), lastValue);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
|
|
@ -100,7 +100,7 @@ void linearEnvelope(const EventVector& events, absl::Span<float> envelope, F&& l
|
|||
const auto length = min(events[i].delay, maxDelay) - lastDelay;
|
||||
|
||||
if (difference < step) {
|
||||
fill<float>(envelope.subspan(lastDelay, length), lastValue);
|
||||
fill(envelope.subspan(lastDelay, length), lastValue);
|
||||
lastValue = nextValue;
|
||||
lastDelay += length;
|
||||
continue;
|
||||
|
|
@ -109,12 +109,12 @@ void linearEnvelope(const EventVector& events, absl::Span<float> envelope, F&& l
|
|||
const auto numSteps = static_cast<int>(difference / step);
|
||||
const auto stepLength = static_cast<int>(length / numSteps);
|
||||
for (int i = 0; i < numSteps; ++i) {
|
||||
fill<float>(envelope.subspan(lastDelay, stepLength), lastValue);
|
||||
fill(envelope.subspan(lastDelay, stepLength), lastValue);
|
||||
lastValue += lastValue <= nextValue ? step : -step;
|
||||
lastDelay += stepLength;
|
||||
}
|
||||
}
|
||||
fill<float>(envelope.subspan(lastDelay), lastValue);
|
||||
fill(envelope.subspan(lastDelay), lastValue);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
|
|
@ -137,7 +137,7 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span<float> envelop
|
|||
lastValue = nextValue;
|
||||
lastDelay += length;
|
||||
}
|
||||
fill<float>(envelope.subspan(lastDelay), lastValue);
|
||||
fill(envelope.subspan(lastDelay), lastValue);
|
||||
}
|
||||
|
||||
template <class F, bool Round = false>
|
||||
|
|
@ -170,7 +170,7 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span<float> envelop
|
|||
const auto difference = nextValue > lastValue ? nextValue / lastValue : lastValue / nextValue;
|
||||
|
||||
if (difference < step) {
|
||||
fill<float>(envelope.subspan(lastDelay, length), lastValue);
|
||||
fill(envelope.subspan(lastDelay, length), lastValue);
|
||||
lastValue = nextValue;
|
||||
lastDelay += length;
|
||||
continue;
|
||||
|
|
@ -179,12 +179,12 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span<float> envelop
|
|||
const auto numSteps = std::round(std::log(difference) / logStep);
|
||||
const auto stepLength = static_cast<int>(length / numSteps);
|
||||
for (int i = 0; i < static_cast<int>(numSteps); ++i) {
|
||||
fill<float>(envelope.subspan(lastDelay, stepLength), lastValue);
|
||||
fill(envelope.subspan(lastDelay, stepLength), lastValue);
|
||||
lastValue = nextValue > lastValue ? lastValue * step : lastValue / step;
|
||||
lastDelay += stepLength;
|
||||
}
|
||||
}
|
||||
fill<float>(envelope.subspan(lastDelay), lastValue);
|
||||
fill(envelope.subspan(lastDelay), lastValue);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
|
|
|
|||
59
src/sfizz/Panning.cpp
Normal file
59
src/sfizz/Panning.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#include "Panning.h"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
namespace sfz
|
||||
{
|
||||
// Number of elements in the table, odd for equal volume at center
|
||||
constexpr int panSize = 4095;
|
||||
|
||||
// Table of pan values for the left channel, extra element for safety
|
||||
static const auto panData = []()
|
||||
{
|
||||
std::array<float, panSize + 1> pan;
|
||||
int i = 0;
|
||||
|
||||
for (; i < panSize; ++i)
|
||||
pan[i] = std::cos(i * (piTwo<double>() / (panSize - 1)));
|
||||
|
||||
for (; i < static_cast<int>(pan.size()); ++i)
|
||||
pan[i] = pan[panSize - 1];
|
||||
|
||||
return pan;
|
||||
}();
|
||||
|
||||
float panLookup(float pan)
|
||||
{
|
||||
// reduce range, round to nearest
|
||||
int index = lroundPositive(pan * (panSize - 1));
|
||||
return panData[index];
|
||||
}
|
||||
|
||||
void pan(const float* panEnvelope, float* leftBuffer, float* rightBuffer, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = panEnvelope + size;
|
||||
while (panEnvelope < sentinel) {
|
||||
auto p =(*panEnvelope + 1.0f) * 0.5f;
|
||||
p = clamp(p, 0.0f, 1.0f);
|
||||
*leftBuffer *= panLookup(p);
|
||||
*rightBuffer *= panLookup(1 - p);
|
||||
incrementAll(panEnvelope, leftBuffer, rightBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void width(const float* widthEnvelope, float* leftBuffer, float* rightBuffer, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = widthEnvelope + size;
|
||||
while (widthEnvelope < sentinel) {
|
||||
float w = (*widthEnvelope + 1.0f) * 0.5f;
|
||||
w = clamp(w, 0.0f, 1.0f);
|
||||
const auto coeff1 = panLookup(w);
|
||||
const auto coeff2 = panLookup(1 - w);
|
||||
const auto l = *leftBuffer;
|
||||
const auto r = *rightBuffer;
|
||||
*leftBuffer = l * coeff2 + r * coeff1;
|
||||
*rightBuffer = l * coeff1 + r * coeff2;
|
||||
incrementAll(widthEnvelope, leftBuffer, rightBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/sfizz/Panning.h
Normal file
47
src/sfizz/Panning.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
#include "absl/types/span.h"
|
||||
#include "MathHelpers.h"
|
||||
|
||||
namespace sfz
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Lookup a value from the pan table
|
||||
*
|
||||
* @param pan
|
||||
* @return float
|
||||
*/
|
||||
float panLookup(float pan);
|
||||
|
||||
/**
|
||||
* @brief Pans a mono signal left or right
|
||||
*
|
||||
* @param panEnvelope
|
||||
* @param leftBuffer
|
||||
* @param rightBuffer
|
||||
* @param size
|
||||
*/
|
||||
void pan(const float* panEnvelope, float* leftBuffer, float* rightBuffer, unsigned size) noexcept;
|
||||
inline void pan(absl::Span<const float> panEnvelope, absl::Span<float> leftBuffer, absl::Span<float> rightBuffer) noexcept
|
||||
{
|
||||
CHECK_SPAN_SIZES(panEnvelope, leftBuffer, rightBuffer);
|
||||
pan(panEnvelope.data(), leftBuffer.data(), rightBuffer.data(), minSpanSize(panEnvelope, leftBuffer, rightBuffer));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Controls the width of a stereo signal, setting it to mono when width = 0 and inverting the channels
|
||||
* when width = -1. Width = 1 has no effect.
|
||||
*
|
||||
* @param widthEnvelope
|
||||
* @param leftBuffer
|
||||
* @param rightBuffer
|
||||
* @param size
|
||||
*/
|
||||
void width(const float* widthEnvelope, float* leftBuffer, float* rightBuffer, unsigned size) noexcept;
|
||||
inline void width(absl::Span<const float> widthEnvelope, absl::Span<float> leftBuffer, absl::Span<float> rightBuffer) noexcept
|
||||
{
|
||||
CHECK_SPAN_SIZES(widthEnvelope, leftBuffer, rightBuffer);
|
||||
width(widthEnvelope.data(), leftBuffer.data(), rightBuffer.data(), minSpanSize(widthEnvelope, leftBuffer, rightBuffer));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -13,19 +13,27 @@
|
|||
|
||||
- SFIZZ_HAVE_SSE
|
||||
- SFIZZ_HAVE_SSE2
|
||||
- SFIZZ_HAVE_AVX
|
||||
- SFIZZ_HAVE_NEON
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# if defined(__SSE2__)
|
||||
# if defined(__AVX__)
|
||||
# define SFIZZ_DETECT_SSE 1
|
||||
# define SFIZZ_DETECT_SSE2 1
|
||||
# define SFIZZ_DETECT_AVX 1
|
||||
# elif defined(__SSE2__)
|
||||
# define SFIZZ_DETECT_SSE 1
|
||||
# define SFIZZ_DETECT_SSE2 1
|
||||
# define SFIZZ_DETECT_AVX 0
|
||||
# elif defined(__SSE__)
|
||||
# define SFIZZ_DETECT_SSE 1
|
||||
# define SFIZZ_DETECT_SSE2 0
|
||||
# define SFIZZ_DETECT_AVX 0
|
||||
# else
|
||||
# define SFIZZ_DETECT_SSE 0
|
||||
# define SFIZZ_DETECT_SSE2 0
|
||||
# define SFIZZ_DETECT_AVX 0
|
||||
# endif
|
||||
# if defined(__ARM_NEON__)
|
||||
# define SFIZZ_DETECT_NEON 1
|
||||
|
|
@ -33,15 +41,22 @@
|
|||
# define SFIZZ_DETECT_NEON 0
|
||||
# endif
|
||||
#elif defined(_MSC_VER)
|
||||
# if defined(_M_AMD64) || defined(_M_X64)
|
||||
# if defined(__AVX__)
|
||||
# define SFIZZ_DETECT_SSE 1
|
||||
# define SFIZZ_DETECT_SSE2 1
|
||||
# define SFIZZ_DETECT_AVX 1
|
||||
# elif defined(_M_AMD64) || defined(_M_X64)
|
||||
# define SFIZZ_DETECT_SSE 1
|
||||
# define SFIZZ_DETECT_SSE2 1
|
||||
# define SFIZZ_DETECT_AVX 0
|
||||
# elif _M_IX86_FP == 2
|
||||
# define SFIZZ_DETECT_SSE 1
|
||||
# define SFIZZ_DETECT_SSE2 1
|
||||
# define SFIZZ_DETECT_AVX 0
|
||||
# elif _M_IX86_FP == 1
|
||||
# define SFIZZ_DETECT_SSE 1
|
||||
# define SFIZZ_DETECT_SSE2 0
|
||||
# define SFIZZ_DETECT_AVX 0
|
||||
# endif
|
||||
// TODO: how to check for NEON on MSVC ARM?
|
||||
#endif
|
||||
|
|
@ -60,6 +75,13 @@
|
|||
# define SFIZZ_HAVE_SSE2 0
|
||||
# endif
|
||||
#endif
|
||||
#ifndef SFIZZ_HAVE_AVX
|
||||
# ifdef SFIZZ_DETECT_AVX
|
||||
# define SFIZZ_HAVE_AVX SFIZZ_DETECT_AVX
|
||||
# else
|
||||
# define SFIZZ_HAVE_AVX 0
|
||||
# endif
|
||||
#endif
|
||||
#ifndef SFIZZ_HAVE_NEON
|
||||
# ifdef SFIZZ_DETECT_NEON
|
||||
# define SFIZZ_HAVE_NEON SFIZZ_DETECT_NEON
|
||||
|
|
|
|||
|
|
@ -1,177 +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 "SIMDConfig.h"
|
||||
|
||||
#if !(SFIZZ_HAVE_SSE2 || SFIZZ_HAVE_NEON)
|
||||
|
||||
#include "SIMDHelpers.h"
|
||||
|
||||
template <>
|
||||
void sfz::readInterleaved<float, true>(absl::Span<const float> input, absl::Span<float> outputLeft, absl::Span<float> outputRight) noexcept
|
||||
{
|
||||
readInterleaved<float, false>(input, outputLeft, outputRight);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::writeInterleaved<float, true>(absl::Span<const float> inputLeft, absl::Span<const float> inputRight, absl::Span<float> output) noexcept
|
||||
{
|
||||
writeInterleaved<float, false>(inputLeft, inputRight, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::fill<float, true>(absl::Span<float> output, float value) noexcept
|
||||
{
|
||||
fill<float, false>(output, value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::exp<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
exp<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::log<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
log<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::sin<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
sin<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::cos<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
cos<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::applyGain<float, true>(float gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
applyGain<float, false>(gain, input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
applyGain<float, false>(gain, input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::divide<float, true>(absl::Span<const float> input, absl::Span<const float> divisor, absl::Span<float> output) noexcept
|
||||
{
|
||||
divide<float, false>(input, divisor, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::multiplyAdd<float, true>(absl::Span<const float> gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
multiplyAdd<float, false>(gain, input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::multiplyAdd<float, true>(const float gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
multiplyAdd<float, false>(gain, input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::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
|
||||
{
|
||||
return loopingSFZIndex<float, false>(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd, loopStart);
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::saturatingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeff, absl::Span<float> rightCoeff, absl::Span<int> indices, float floatIndex, float loopEnd) noexcept
|
||||
{
|
||||
return saturatingSFZIndex<float, false>(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd);
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
float sfz::linearRamp<float, true>(absl::Span<float> output, float start, float step) noexcept
|
||||
{
|
||||
return linearRamp<float, false>(output, start, step);
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::multiplicativeRamp<float, true>(absl::Span<float> output, float start, float step) noexcept
|
||||
{
|
||||
return multiplicativeRamp<float, false>(output, start, step);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::add<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
add<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::add<float, true>(float value, absl::Span<float> output) noexcept
|
||||
{
|
||||
add<float, false>(value, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::subtract<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
subtract<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::subtract<float, true>(const float value, absl::Span<float> output) noexcept
|
||||
{
|
||||
subtract<float, false>(value, output);
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
void sfz::copy<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
copy<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::pan<float, true>(absl::Span<const float> panEnvelope, absl::Span<float> leftBuffer, absl::Span<float> rightBuffer) noexcept
|
||||
{
|
||||
pan<float, false>(panEnvelope, leftBuffer, rightBuffer);
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::mean<float, true>(absl::Span<const float> vector) noexcept
|
||||
{
|
||||
return mean<float, false>(vector);
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::meanSquared<float, true>(absl::Span<const float> vector) noexcept
|
||||
{
|
||||
return meanSquared<float, false>(vector);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::cumsum<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
cumsum<float, false>(input, output);
|
||||
}
|
||||
|
||||
template<>
|
||||
void sfz::sfzInterpolationCast<float, true>(absl::Span<const float> floatJumps, absl::Span<int> jumps, absl::Span<float> coeffs) noexcept
|
||||
{
|
||||
sfzInterpolationCast<float, false>(floatJumps, jumps, coeffs);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::diff<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
diff<float, false>(input, output);
|
||||
}
|
||||
|
||||
#endif // !(SFIZZ_HAVE_SSE2 || SFIZZ_HAVE_NEON)
|
||||
304
src/sfizz/SIMDHelpers.cpp
Normal file
304
src/sfizz/SIMDHelpers.cpp
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
// 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 "SIMDConfig.h"
|
||||
#include "Debug.h"
|
||||
#include "simd/HelpersSSE.h"
|
||||
#include "simd/HelpersAVX.h"
|
||||
#include "cpuid/cpuinfo.hpp"
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
|
||||
namespace sfz {
|
||||
|
||||
template <class T>
|
||||
struct SIMDDispatch {
|
||||
constexpr SIMDDispatch() = default;
|
||||
void resetStatus();
|
||||
bool getStatus(SIMDOps op) const;
|
||||
void setStatus(SIMDOps op, bool enable);
|
||||
|
||||
decltype(&writeInterleavedScalar<T>) writeInterleaved = &writeInterleavedScalar<T>;
|
||||
decltype(&readInterleavedScalar<T>) readInterleaved = &readInterleavedScalar<T>;
|
||||
decltype(&gainScalar<T>) gain = &gainScalar<T>;
|
||||
decltype(&gain1Scalar<T>) gain1 = &gain1Scalar<T>;
|
||||
decltype(÷Scalar<T>) divide = ÷Scalar<T>;
|
||||
decltype(&multiplyAddScalar<T>) multiplyAdd = &multiplyAddScalar<T>;
|
||||
decltype(&multiplyAdd1Scalar<T>) multiplyAdd1 = &multiplyAdd1Scalar<T>;
|
||||
decltype(&linearRampScalar<T>) linearRamp = &linearRampScalar<T>;
|
||||
decltype(&multiplicativeRampScalar<T>) multiplicativeRamp = &multiplicativeRampScalar<T>;
|
||||
decltype(&addScalar<T>) add = &addScalar<T>;
|
||||
decltype(&add1Scalar<T>) add1 = &add1Scalar<T>;
|
||||
decltype(&subtractScalar<T>) subtract = &subtractScalar<T>;
|
||||
decltype(&subtract1Scalar<T>) subtract1 = &subtract1Scalar<T>;
|
||||
decltype(©Scalar<T>) copy = ©Scalar<T>;
|
||||
decltype(&cumsumScalar<T>) cumsum = &cumsumScalar<T>;
|
||||
decltype(&diffScalar<T>) diff = &diffScalar<T>;
|
||||
decltype(&meanScalar<T>) mean = &meanScalar<T>;
|
||||
decltype(&meanSquaredScalar<T>) meanSquared = &meanSquaredScalar<T>;
|
||||
|
||||
private:
|
||||
std::array<bool, static_cast<unsigned>(SIMDOps::_sentinel)> simdStatus;
|
||||
cpuid::cpuinfo info;
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
bool SIMDDispatch<float>::getStatus(SIMDOps op) const
|
||||
{
|
||||
const unsigned index = static_cast<unsigned>(op);
|
||||
ASSERT(index < simdStatus.size());
|
||||
return simdStatus[index];
|
||||
}
|
||||
|
||||
template <>
|
||||
void SIMDDispatch<float>::setStatus(SIMDOps op, bool enable)
|
||||
{
|
||||
const unsigned index = static_cast<unsigned>(op);
|
||||
ASSERT(index < simdStatus.size());
|
||||
simdStatus[index] = enable;
|
||||
|
||||
if (!enable) {
|
||||
#define SIMD_OP(opname) case SIMDOps::opname : (opname) = opname ## Scalar<float>; return;
|
||||
switch (op) {
|
||||
default: break;
|
||||
SIMD_OP(writeInterleaved)
|
||||
SIMD_OP(readInterleaved)
|
||||
SIMD_OP(gain)
|
||||
SIMD_OP(gain1)
|
||||
SIMD_OP(divide)
|
||||
SIMD_OP(linearRamp)
|
||||
SIMD_OP(multiplicativeRamp)
|
||||
SIMD_OP(add)
|
||||
SIMD_OP(add1)
|
||||
SIMD_OP(subtract)
|
||||
SIMD_OP(subtract1)
|
||||
SIMD_OP(multiplyAdd)
|
||||
SIMD_OP(multiplyAdd1)
|
||||
SIMD_OP(copy)
|
||||
SIMD_OP(cumsum)
|
||||
SIMD_OP(diff)
|
||||
SIMD_OP(mean)
|
||||
SIMD_OP(meanSquared)
|
||||
}
|
||||
#undef SIMD_OP
|
||||
}
|
||||
|
||||
#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386
|
||||
#define SIMD_OP(opname) case SIMDOps::opname : (opname) = opname ## AVX; return;
|
||||
if (info.has_avx()) {
|
||||
switch (op) {
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
#undef SIMD_OP
|
||||
|
||||
#define SIMD_OP(opname) case SIMDOps::opname : (opname) = opname ## SSE; return;
|
||||
if (info.has_sse()) {
|
||||
switch (op) {
|
||||
default: break;
|
||||
SIMD_OP(writeInterleaved)
|
||||
SIMD_OP(readInterleaved)
|
||||
SIMD_OP(gain)
|
||||
SIMD_OP(gain1)
|
||||
SIMD_OP(divide)
|
||||
SIMD_OP(linearRamp)
|
||||
SIMD_OP(multiplicativeRamp)
|
||||
SIMD_OP(add)
|
||||
SIMD_OP(add1)
|
||||
SIMD_OP(subtract)
|
||||
SIMD_OP(subtract1)
|
||||
SIMD_OP(multiplyAdd)
|
||||
SIMD_OP(multiplyAdd1)
|
||||
SIMD_OP(copy)
|
||||
SIMD_OP(cumsum)
|
||||
SIMD_OP(diff)
|
||||
SIMD_OP(mean)
|
||||
SIMD_OP(meanSquared)
|
||||
}
|
||||
}
|
||||
#undef SIMD_OP
|
||||
#endif // SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386
|
||||
|
||||
#if SFIZZ_CPU_FAMILY_AARCH64 || SFIZZ_CPU_FAMILY_ARM
|
||||
#define SIMD_OP(opname) case SIMDOps::opname : (opname) = opname ## NEON; return;
|
||||
if (info.has_neon()) {
|
||||
switch (op) {
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
#undef SIMD_OP
|
||||
#endif // SFIZZ_CPU_FAMILY_AARCH64 || SFIZZ_CPU_FAMILY_ARM
|
||||
}
|
||||
|
||||
template <>
|
||||
void SIMDDispatch<float>::resetStatus()
|
||||
{
|
||||
setStatus(SIMDOps::writeInterleaved, false);
|
||||
setStatus(SIMDOps::readInterleaved, false);
|
||||
setStatus(SIMDOps::fill, true);
|
||||
setStatus(SIMDOps::gain, true);
|
||||
setStatus(SIMDOps::gain1, true);
|
||||
setStatus(SIMDOps::divide, false);
|
||||
setStatus(SIMDOps::linearRamp, false);
|
||||
setStatus(SIMDOps::multiplicativeRamp, true);
|
||||
setStatus(SIMDOps::add, false);
|
||||
setStatus(SIMDOps::add1, false);
|
||||
setStatus(SIMDOps::subtract, false);
|
||||
setStatus(SIMDOps::subtract1, false);
|
||||
setStatus(SIMDOps::multiplyAdd, false);
|
||||
setStatus(SIMDOps::multiplyAdd1, false);
|
||||
setStatus(SIMDOps::copy, false);
|
||||
setStatus(SIMDOps::cumsum, true);
|
||||
setStatus(SIMDOps::diff, false);
|
||||
setStatus(SIMDOps::sfzInterpolationCast, true);
|
||||
setStatus(SIMDOps::mean, false);
|
||||
setStatus(SIMDOps::meanSquared, false);
|
||||
setStatus(SIMDOps::upsampling, true);
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
template<class T>
|
||||
static SIMDDispatch<T>& simdDispatch()
|
||||
{
|
||||
static SIMDDispatch<T> dispatch;
|
||||
return dispatch;
|
||||
}
|
||||
|
||||
template<>
|
||||
void resetSIMDOpStatus<float>()
|
||||
{
|
||||
simdDispatch<float>().resetStatus();
|
||||
}
|
||||
|
||||
template<>
|
||||
void setSIMDOpStatus<float>(SIMDOps op, bool status)
|
||||
{
|
||||
simdDispatch<float>().setStatus(op, status);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool getSIMDOpStatus<float>(SIMDOps op)
|
||||
{
|
||||
return simdDispatch<float>().getStatus(op);
|
||||
}
|
||||
|
||||
void initializeSIMDDispatchers()
|
||||
{
|
||||
simdDispatch<float>().resetStatus();
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept
|
||||
{
|
||||
return simdDispatch<float>().readInterleaved(input, outputLeft, outputRight, inputSize);
|
||||
}
|
||||
|
||||
void writeInterleaved(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept
|
||||
{
|
||||
return simdDispatch<float>().writeInterleaved(inputLeft, inputRight, output, outputSize);
|
||||
}
|
||||
|
||||
template <>
|
||||
void applyGain1<float>(float gain, const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().gain1(gain, input, output, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
void applyGain<float>(const float* gain, const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().gain(gain, input, output, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
void divide<float>(const float* input, const float* divisor, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().divide(input, divisor, output, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
void multiplyAdd<float>(const float* gain, const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().multiplyAdd(gain, input, output, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
void multiplyAdd1<float>(float gain, const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().multiplyAdd1(gain, input, output, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
float linearRamp<float>(float* output, float start, float step, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().linearRamp(output, start, step, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
float multiplicativeRamp<float>(float* output, float start, float step, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().multiplicativeRamp(output, start, step, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
void add<float>(const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().add(input, output, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
void add1<float>(float value, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().add1(value, output, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
void subtract<float>(const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().subtract(input, output, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
void subtract1<float>(float value, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().subtract1(value, output, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
void copy<float>(const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().copy(input, output, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
float mean<float>(const float* vector, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().mean(vector, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
float meanSquared<float>(const float* vector, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().meanSquared(vector, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
void cumsum<float>(const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().cumsum(input, output, size);
|
||||
}
|
||||
|
||||
template <>
|
||||
void diff<float>(const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
return simdDispatch<float>().diff(input, output, size);
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,241 +0,0 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "SIMDConfig.h"
|
||||
|
||||
#if SFIZZ_HAVE_NEON
|
||||
|
||||
#include "SIMDHelpers.h"
|
||||
#include <arm_neon.h>
|
||||
|
||||
using Type = float;
|
||||
constexpr uintptr_t TypeAlignment { 4 };
|
||||
constexpr uintptr_t ByteAlignment { TypeAlignment * sizeof(Type) };
|
||||
constexpr uintptr_t ByteAlignmentMask { ByteAlignment - 1 };
|
||||
|
||||
float* nextAligned(const float* ptr)
|
||||
{
|
||||
return reinterpret_cast<float*>((reinterpret_cast<uintptr_t>(ptr) + ByteAlignmentMask) & (~ByteAlignmentMask));
|
||||
}
|
||||
|
||||
float* prevAligned(const float* ptr)
|
||||
{
|
||||
return reinterpret_cast<float*>(reinterpret_cast<uintptr_t>(ptr) & (~ByteAlignmentMask));
|
||||
}
|
||||
|
||||
bool unaligned(const float* ptr)
|
||||
{
|
||||
return (reinterpret_cast<uintptr_t>(ptr) & ByteAlignmentMask) != 0;
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
bool unaligned(const float* ptr1, Args... rest)
|
||||
{
|
||||
return unaligned(ptr1) || unaligned(rest...);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::readInterleaved<float, true>(absl::Span<const float> input, absl::Span<float> outputLeft, absl::Span<float> outputRight) noexcept
|
||||
{
|
||||
// The size of the outputs is not big enough for the input...
|
||||
ASSERT(outputLeft.size() >= input.size() / 2);
|
||||
ASSERT(outputRight.size() >= input.size() / 2);
|
||||
// Input is too small
|
||||
ASSERT(input.size() > 1);
|
||||
|
||||
auto* in = input.begin();
|
||||
auto* lOut = outputLeft.begin();
|
||||
auto* rOut = outputRight.begin();
|
||||
|
||||
const auto size = std::min(input.size(), std::min(outputLeft.size() * 2, outputRight.size() * 2));
|
||||
const auto* lastAligned = prevAligned(input.begin() + size - TypeAlignment);
|
||||
|
||||
while (unaligned(in, lOut, rOut) && in < lastAligned)
|
||||
_internals::snippetRead<float>(in, lOut, rOut);
|
||||
|
||||
while (in < lastAligned) {
|
||||
auto reg = vld2q_f32(in);
|
||||
vst1q_f32(lOut, reg.val[0]);
|
||||
vst1q_f32(rOut, reg.val[1]);
|
||||
// *lOut = reg.val[0];
|
||||
// *rOut = reg.val[1];
|
||||
incrementAll<TypeAlignment>(in, in, lOut, rOut);
|
||||
}
|
||||
|
||||
while (in < input.end() - 1)
|
||||
_internals::snippetRead<float>(in, lOut, rOut);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::writeInterleaved<float, true>(absl::Span<const float> inputLeft, absl::Span<const float> inputRight, absl::Span<float> output) noexcept
|
||||
{
|
||||
writeInterleaved<float, false>(inputLeft, inputRight, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::fill<float, true>(absl::Span<float> output, float value) noexcept
|
||||
{
|
||||
fill<float, false>(output, value);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::exp<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
exp<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::log<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
log<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::sin<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
sin<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::cos<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
cos<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::applyGain<float, true>(float gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
applyGain<float, false>(gain, input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
applyGain<float, false>(gain, input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::divide<float, true>(absl::Span<const float> input, absl::Span<const float> divisor, absl::Span<float> output) noexcept
|
||||
{
|
||||
divide<float, false>(input, divisor, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::multiplyAdd<float, true>(absl::Span<const float> gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
multiplyAdd<float, false>(gain, input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::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
|
||||
{
|
||||
return loopingSFZIndex<float, false>(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd, loopStart);
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::saturatingSFZIndex<float, true>(absl::Span<const float> jumps, absl::Span<float> leftCoeff, absl::Span<float> rightCoeff, absl::Span<int> indices, float floatIndex, float loopEnd) noexcept
|
||||
{
|
||||
return saturatingSFZIndex<float, false>(jumps, leftCoeff, rightCoeff, indices, floatIndex, loopEnd);
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
float sfz::linearRamp<float, true>(absl::Span<float> output, float start, float step) noexcept
|
||||
{
|
||||
return linearRamp<float, false>(output, start, step);
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::multiplicativeRamp<float, true>(absl::Span<float> output, float start, float step) noexcept
|
||||
{
|
||||
return multiplicativeRamp<float, false>(output, start, step);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::add<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
add<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::add<float, true>(float value, absl::Span<float> output) noexcept
|
||||
{
|
||||
add<float, false>(value, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::subtract<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
subtract<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::subtract<float, true>(const float value, absl::Span<float> output) noexcept
|
||||
{
|
||||
subtract<float, false>(value, output);
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
void sfz::copy<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
copy<float, false>(input, output);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::pan<float, true>(absl::Span<const float> panEnvelope, absl::Span<float> leftBuffer, absl::Span<float> rightBuffer) noexcept
|
||||
{
|
||||
pan<float, false>(panEnvelope, leftBuffer, rightBuffer);
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::mean<float, true>(absl::Span<const float> vector) noexcept
|
||||
{
|
||||
return mean<float, false>(vector);
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::meanSquared<float, true>(absl::Span<const float> vector) noexcept
|
||||
{
|
||||
return meanSquared<float, false>(vector);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::cumsum<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
cumsum<float, false>(input, output);
|
||||
}
|
||||
|
||||
template<>
|
||||
void sfz::sfzInterpolationCast<float, true>(absl::Span<const float> floatJumps, absl::Span<int> jumps, absl::Span<float> coeffs) noexcept
|
||||
{
|
||||
sfzInterpolationCast<float, false>(floatJumps, jumps, coeffs);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::diff<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
diff<float, false>(input, output);
|
||||
}
|
||||
|
||||
#endif // SFIZZ_HAVE_NEON
|
||||
|
|
@ -1,849 +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 "SIMDConfig.h"
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
|
||||
#include "SIMDHelpers.h"
|
||||
#include <array>
|
||||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
|
||||
#include "mathfuns/sse_mathfun.h"
|
||||
|
||||
using Type = float;
|
||||
constexpr uintptr_t TypeAlignment { 4 };
|
||||
constexpr uintptr_t ByteAlignment { TypeAlignment * sizeof(Type) };
|
||||
constexpr uintptr_t ByteAlignmentMask { ByteAlignment - 1 };
|
||||
|
||||
struct AlignmentSentinels {
|
||||
float* nextAligned;
|
||||
float* lastAligned;
|
||||
};
|
||||
|
||||
float* nextAligned(const float* ptr)
|
||||
{
|
||||
return reinterpret_cast<float*>((reinterpret_cast<uintptr_t>(ptr) + ByteAlignmentMask) & (~ByteAlignmentMask));
|
||||
}
|
||||
|
||||
float* prevAligned(const float* ptr)
|
||||
{
|
||||
return reinterpret_cast<float*>(reinterpret_cast<uintptr_t>(ptr) & (~ByteAlignmentMask));
|
||||
}
|
||||
|
||||
bool unaligned(const float* ptr)
|
||||
{
|
||||
return (reinterpret_cast<uintptr_t>(ptr) & ByteAlignmentMask) != 0;
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
bool unaligned(const float* ptr1, Args... rest)
|
||||
{
|
||||
return unaligned(ptr1) || unaligned(rest...);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::readInterleaved<float, true>(absl::Span<const float> input, absl::Span<float> outputLeft, absl::Span<float> outputRight) noexcept
|
||||
{
|
||||
// The size of the outputs is not big enough for the input...
|
||||
CHECK(outputLeft.size() >= input.size() / 2);
|
||||
CHECK(outputRight.size() >= input.size() / 2);
|
||||
// Input is too small
|
||||
CHECK(input.size() > 1);
|
||||
|
||||
auto* in = input.begin();
|
||||
auto* lOut = outputLeft.begin();
|
||||
auto* rOut = outputRight.begin();
|
||||
|
||||
const auto size = std::min(input.size(), std::min(outputLeft.size() * 2, outputRight.size() * 2));
|
||||
const auto* lastAligned = prevAligned(input.begin() + size - TypeAlignment);
|
||||
|
||||
while (unaligned(in, lOut, rOut) && in < lastAligned)
|
||||
_internals::snippetRead<float>(in, lOut, rOut);
|
||||
|
||||
while (in < lastAligned) {
|
||||
auto register0 = _mm_load_ps(in);
|
||||
in += TypeAlignment;
|
||||
auto register1 = _mm_load_ps(in);
|
||||
in += TypeAlignment;
|
||||
auto register2 = register0;
|
||||
// register 2 holds the copy of register 0 that is going to get erased by the first operation
|
||||
// Remember that the bit mask reads from the end; 10 00 10 00 means
|
||||
// "take 0 from a, take 2 from a, take 0 from b, take 2 from b"
|
||||
register0 = _mm_shuffle_ps(register0, register1, 0b10001000);
|
||||
register1 = _mm_shuffle_ps(register2, register1, 0b11011101);
|
||||
_mm_store_ps(lOut, register0);
|
||||
_mm_store_ps(rOut, register1);
|
||||
lOut += TypeAlignment;
|
||||
rOut += TypeAlignment;
|
||||
}
|
||||
|
||||
while (in < input.end() - 1)
|
||||
_internals::snippetRead<float>(in, lOut, rOut);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::writeInterleaved<float, true>(absl::Span<const float> inputLeft, absl::Span<const float> inputRight, absl::Span<float> output) noexcept
|
||||
{
|
||||
// The size of the output is not big enough for the inputs...
|
||||
CHECK(inputLeft.size() <= output.size() / 2);
|
||||
CHECK(inputRight.size() <= output.size() / 2);
|
||||
|
||||
auto* lIn = inputLeft.begin();
|
||||
auto* rIn = inputRight.begin();
|
||||
auto* out = output.begin();
|
||||
|
||||
const auto size = std::min(output.size(), std::min(inputLeft.size(), inputRight.size()) * 2);
|
||||
const auto* lastAligned = prevAligned(output.begin() + size - TypeAlignment);
|
||||
|
||||
while (unaligned(out, rIn, lIn) && out < lastAligned)
|
||||
_internals::snippetWrite<float>(out, lIn, rIn);
|
||||
|
||||
while (out < lastAligned) {
|
||||
const auto lInRegister = _mm_load_ps(lIn);
|
||||
const auto rInRegister = _mm_load_ps(rIn);
|
||||
|
||||
const auto outRegister1 = _mm_unpacklo_ps(lInRegister, rInRegister);
|
||||
_mm_store_ps(out, outRegister1);
|
||||
out += TypeAlignment;
|
||||
|
||||
const auto outRegister2 = _mm_unpackhi_ps(lInRegister, rInRegister);
|
||||
_mm_store_ps(out, outRegister2);
|
||||
out += TypeAlignment;
|
||||
|
||||
lIn += TypeAlignment;
|
||||
rIn += TypeAlignment;
|
||||
}
|
||||
|
||||
while (out < output.end() - 1)
|
||||
_internals::snippetWrite<float>(out, lIn, rIn);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::fill<float, true>(absl::Span<float> output, float value) noexcept
|
||||
{
|
||||
const auto mmValue = _mm_set_ps1(value);
|
||||
auto* out = output.begin();
|
||||
const auto* lastAligned = prevAligned(output.end());
|
||||
|
||||
while (unaligned(out) && out < lastAligned)
|
||||
*out++ = value;
|
||||
|
||||
while (out < lastAligned) // we should only need to test a single channel
|
||||
{
|
||||
_mm_store_ps(out, mmValue);
|
||||
out += TypeAlignment;
|
||||
}
|
||||
|
||||
while (out < output.end())
|
||||
*out++ = value;
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::exp<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
CHECK(output.size() >= input.size());
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
auto* sentinel = in + std::min(input.size(), output.size());
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(in, out) && in < lastAligned)
|
||||
*out++ = std::exp(*in++);
|
||||
|
||||
while (in < lastAligned) {
|
||||
_mm_store_ps(out, exp_ps(_mm_load_ps(in)));
|
||||
incrementAll<TypeAlignment>(out, in);
|
||||
}
|
||||
|
||||
while (in < sentinel)
|
||||
*out++ = std::exp(*in++);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::cos<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
CHECK(output.size() >= input.size());
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
auto* sentinel = in + std::min(input.size(), output.size());
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(in, out) && in < lastAligned)
|
||||
*out++ = std::exp(*in++);
|
||||
|
||||
while (in < lastAligned) {
|
||||
_mm_store_ps(out, cos_ps(_mm_load_ps(in)));
|
||||
incrementAll<TypeAlignment>(out, in);
|
||||
}
|
||||
|
||||
while (in < sentinel)
|
||||
*out++ = std::exp(*in++);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::log<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
CHECK(output.size() >= input.size());
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
auto* sentinel = in + std::min(input.size(), output.size());
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(in, out) && in < lastAligned)
|
||||
*out++ = std::exp(*in++);
|
||||
|
||||
while (in < lastAligned) {
|
||||
_mm_store_ps(out, log_ps(_mm_load_ps(in)));
|
||||
incrementAll<TypeAlignment>(out, in);
|
||||
}
|
||||
|
||||
while (in < sentinel)
|
||||
*out++ = std::exp(*in++);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::sin<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
CHECK(output.size() >= input.size());
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
auto* sentinel = in + std::min(input.size(), output.size());
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(in, out) && in < lastAligned)
|
||||
*out++ = std::exp(*in++);
|
||||
|
||||
while (in < lastAligned) {
|
||||
_mm_store_ps(out, sin_ps(_mm_load_ps(in)));
|
||||
incrementAll<TypeAlignment>(out, in);
|
||||
}
|
||||
|
||||
while (in < sentinel)
|
||||
*out++ = std::exp(*in++);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::applyGain<float, true>(float gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
const auto size = std::min(output.size(), input.size());
|
||||
const auto* lastAligned = prevAligned(output.begin() + size);
|
||||
const auto mmGain = _mm_set_ps1(gain);
|
||||
|
||||
while (unaligned(out, in) && out < lastAligned)
|
||||
*out++ = gain * (*in++);
|
||||
|
||||
while (out < lastAligned) {
|
||||
_mm_store_ps(out, _mm_mul_ps(mmGain, _mm_load_ps(in)));
|
||||
incrementAll<TypeAlignment>(out, in);
|
||||
}
|
||||
|
||||
while (out < output.end())
|
||||
*out++ = gain * (*in++);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
auto* g = gain.begin();
|
||||
const auto size = std::min(output.size(), std::min(input.size(), gain.size()));
|
||||
const auto* lastAligned = prevAligned(output.begin() + size);
|
||||
|
||||
while (unaligned(out, in, g) && out < lastAligned)
|
||||
_internals::snippetGainSpan<float>(g, in, out);
|
||||
|
||||
while (out < lastAligned) {
|
||||
_mm_store_ps(out, _mm_mul_ps(_mm_load_ps(g), _mm_load_ps(in)));
|
||||
incrementAll<TypeAlignment>(g, in, out);
|
||||
}
|
||||
|
||||
while (out < output.end())
|
||||
_internals::snippetGainSpan<float>(g, in, out);
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
void sfz::divide<float, true>(absl::Span<const float> input, absl::Span<const float> divisor, absl::Span<float> output) noexcept
|
||||
{
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
auto* div = divisor.begin();
|
||||
const auto size = std::min(output.size(), std::min(input.size(), divisor.size()));
|
||||
const auto* lastAligned = prevAligned(output.begin() + size);
|
||||
|
||||
while (unaligned(out, in, div) && out < lastAligned)
|
||||
_internals::snippetDivSpan<float>(in, div, out);
|
||||
|
||||
while (out < lastAligned) {
|
||||
_mm_store_ps(out, _mm_div_ps(_mm_load_ps(in), _mm_load_ps(div)));
|
||||
incrementAll<TypeAlignment>(in, div, out);
|
||||
}
|
||||
|
||||
while (out < output.end())
|
||||
_internals::snippetDivSpan<float>(in, div, out);
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
void sfz::multiplyAdd<float, true>(absl::Span<const float> gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
auto* g = gain.begin();
|
||||
const auto size = std::min(output.size(), std::min(input.size(), gain.size()));
|
||||
const auto* lastAligned = prevAligned(output.begin() + size);
|
||||
|
||||
while (unaligned(out, in, g) && out < lastAligned)
|
||||
_internals::snippetMultiplyAdd<float>(g, in, out);
|
||||
|
||||
while (out < lastAligned) {
|
||||
auto mmOut = _mm_load_ps(out);
|
||||
mmOut = _mm_add_ps(_mm_mul_ps(_mm_load_ps(g), _mm_load_ps(in)), mmOut);
|
||||
_mm_store_ps(out, mmOut);
|
||||
incrementAll<TypeAlignment>(g, in, out);
|
||||
}
|
||||
|
||||
while (out < output.end())
|
||||
_internals::snippetMultiplyAdd<float>(g, in, out);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::multiplyAdd<float, true>(const float gain, absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
const auto size = std::min(output.size(), input.size());
|
||||
const auto* lastAligned = prevAligned(output.begin() + size);
|
||||
|
||||
while (unaligned(out, in) && out < lastAligned)
|
||||
_internals::snippetMultiplyAdd<float>(gain, in, out);
|
||||
|
||||
auto mmGain = _mm_set1_ps(gain);
|
||||
while (out < lastAligned) {
|
||||
auto mmOut = _mm_load_ps(out);
|
||||
mmOut = _mm_add_ps(_mm_mul_ps(mmGain, _mm_load_ps(in)), mmOut);
|
||||
_mm_store_ps(out, mmOut);
|
||||
incrementAll<TypeAlignment>(in, out);
|
||||
}
|
||||
|
||||
while (out < output.end())
|
||||
_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
|
||||
{
|
||||
auto* out = output.begin();
|
||||
const auto* lastAligned = prevAligned(output.end());
|
||||
|
||||
while (unaligned(out) && out < lastAligned)
|
||||
_internals::snippetRampLinear<float>(out, value, step);
|
||||
|
||||
auto mmValue = _mm_set1_ps(value - step);
|
||||
auto mmStep = _mm_set_ps(step + step + step + step, step + step + step, step + step, step);
|
||||
|
||||
while (out < lastAligned) {
|
||||
mmValue = _mm_add_ps(mmValue, mmStep);
|
||||
_mm_store_ps(out, mmValue);
|
||||
mmValue = _mm_shuffle_ps(mmValue, mmValue, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
out += TypeAlignment;
|
||||
}
|
||||
|
||||
value = _mm_cvtss_f32(mmValue) + step;
|
||||
|
||||
while (out < output.end())
|
||||
_internals::snippetRampLinear<float>(out, value, step);
|
||||
return value;
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::multiplicativeRamp<float, true>(absl::Span<float> output, float value, float step) noexcept
|
||||
{
|
||||
auto* out = output.begin();
|
||||
const auto* lastAligned = prevAligned(output.end());
|
||||
|
||||
while (unaligned(out) && out < lastAligned)
|
||||
_internals::snippetRampMultiplicative<float>(out, value, step);
|
||||
|
||||
auto mmValue = _mm_set1_ps(value / step);
|
||||
auto mmStep = _mm_set_ps(step * step * step * step, step * step * step, step * step, step);
|
||||
|
||||
while (out < lastAligned) {
|
||||
mmValue = _mm_mul_ps(mmValue, mmStep);
|
||||
_mm_store_ps(out, mmValue);
|
||||
mmValue = _mm_shuffle_ps(mmValue, mmValue, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
out += TypeAlignment;
|
||||
}
|
||||
|
||||
value = _mm_cvtss_f32(mmValue) * step;
|
||||
while (out < output.end())
|
||||
_internals::snippetRampMultiplicative<float>(out, value, step);
|
||||
return value;
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::add<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
CHECK(output.size() >= input.size());
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
auto* sentinel = out + min(input.size(), output.size());
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(in, out) && out < lastAligned)
|
||||
_internals::snippetAdd<float>(in, out);
|
||||
|
||||
while (out < lastAligned) {
|
||||
_mm_store_ps(out, _mm_add_ps(_mm_load_ps(in), _mm_load_ps(out)));
|
||||
incrementAll<TypeAlignment>(in, out);
|
||||
}
|
||||
|
||||
while (out < sentinel)
|
||||
_internals::snippetAdd<float>(in, out);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::add<float, true>(float value, absl::Span<float> output) noexcept
|
||||
{
|
||||
auto* out = output.begin();
|
||||
auto* sentinel = output.end();
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(out) && out < lastAligned)
|
||||
_internals::snippetAdd<float>(value, out);
|
||||
|
||||
auto mmValue = _mm_set_ps1(value);
|
||||
while (out < lastAligned) {
|
||||
_mm_store_ps(out, _mm_add_ps(mmValue, _mm_load_ps(out)));
|
||||
out += TypeAlignment;
|
||||
}
|
||||
|
||||
while (out < sentinel)
|
||||
_internals::snippetAdd<float>(value, out);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::subtract<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
CHECK(output.size() >= input.size());
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
auto* sentinel = out + min(input.size(), output.size());
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(in, out) && out < lastAligned)
|
||||
_internals::snippetSubtract<float>(in, out);
|
||||
|
||||
while (out < lastAligned) {
|
||||
_mm_store_ps(out, _mm_sub_ps(_mm_load_ps(out), _mm_load_ps(in)));
|
||||
incrementAll<TypeAlignment>(in, out);
|
||||
}
|
||||
|
||||
while (out < sentinel)
|
||||
_internals::snippetSubtract<float>(in, out);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::subtract<float, true>(const float value, absl::Span<float> output) noexcept
|
||||
{
|
||||
auto* out = output.begin();
|
||||
auto* sentinel = output.end();
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(out) && out < lastAligned)
|
||||
_internals::snippetSubtract<float>(value, out);
|
||||
|
||||
auto mmValue = _mm_set_ps1(value);
|
||||
while (out < lastAligned) {
|
||||
_mm_store_ps(out, _mm_sub_ps(_mm_load_ps(out), mmValue));
|
||||
out += TypeAlignment;
|
||||
}
|
||||
|
||||
while (out < sentinel)
|
||||
_internals::snippetSubtract<float>(value, out);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::copy<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
CHECK(output.size() >= input.size());
|
||||
auto* in = input.begin();
|
||||
auto* out = output.begin();
|
||||
auto* sentinel = out + min(input.size(), output.size());
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(in, out) && out < lastAligned)
|
||||
_internals::snippetCopy<float>(in, out);
|
||||
|
||||
while (out < lastAligned) {
|
||||
_mm_store_ps(out, _mm_load_ps(in));
|
||||
incrementAll<TypeAlignment>(in, out);
|
||||
}
|
||||
|
||||
while (out < sentinel)
|
||||
_internals::snippetCopy<float>(in, out);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::pan<float, true>(absl::Span<const float> panEnvelope, absl::Span<float> leftBuffer, absl::Span<float> rightBuffer) noexcept
|
||||
{
|
||||
CHECK(leftBuffer.size() >= panEnvelope.size());
|
||||
CHECK(rightBuffer.size() >= panEnvelope.size());
|
||||
auto* pan = panEnvelope.begin();
|
||||
auto* left = leftBuffer.begin();
|
||||
auto* right = rightBuffer.begin();
|
||||
auto* sentinel = pan + min(panEnvelope.size(), leftBuffer.size(), rightBuffer.size());
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(pan, left, right) && pan < lastAligned) {
|
||||
_internals::snippetPan(*pan, *left, *right);
|
||||
incrementAll(pan, left, right);
|
||||
}
|
||||
|
||||
const auto mmOne = _mm_set_ps1(1.0f);
|
||||
const auto mmPiFour = _mm_set_ps1(piFour<float>());
|
||||
__m128 mmCos;
|
||||
__m128 mmSin;
|
||||
while (pan < lastAligned) {
|
||||
auto mmPan = _mm_load_ps(pan);
|
||||
mmPan = _mm_add_ps(mmOne, mmPan);
|
||||
mmPan = _mm_mul_ps(mmPan, mmPiFour);
|
||||
sincos_ps(mmPan, &mmSin, &mmCos);
|
||||
auto mmLeft = _mm_mul_ps(mmCos, _mm_load_ps(left));
|
||||
auto mmRight = _mm_mul_ps(mmSin, _mm_load_ps(right));
|
||||
_mm_store_ps(left, mmLeft);
|
||||
_mm_store_ps(right, mmRight);
|
||||
incrementAll<TypeAlignment>(pan, left, right);
|
||||
}
|
||||
|
||||
while (pan < sentinel){
|
||||
_internals::snippetPan(*pan, *left, *right);
|
||||
incrementAll(pan, left, right);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::width<float, true>(absl::Span<const float> widthEnvelope, absl::Span<float> leftBuffer, absl::Span<float> rightBuffer) noexcept
|
||||
{
|
||||
CHECK(leftBuffer.size() >= widthEnvelope.size());
|
||||
CHECK(rightBuffer.size() >= widthEnvelope.size());
|
||||
auto* width = widthEnvelope.begin();
|
||||
auto* left = leftBuffer.begin();
|
||||
auto* right = rightBuffer.begin();
|
||||
auto* sentinel = width + min(widthEnvelope.size(), leftBuffer.size(), rightBuffer.size());
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(width, left, right) && width < lastAligned) {
|
||||
_internals::snippetWidth(*width, *left, *right);
|
||||
incrementAll(width, left, right);
|
||||
}
|
||||
|
||||
const auto mmPiFour = _mm_set_ps1(piFour<float>());
|
||||
__m128 mmCos;
|
||||
__m128 mmSin;
|
||||
while (width < lastAligned) {
|
||||
auto mmWidth = _mm_load_ps(width);
|
||||
mmWidth = _mm_mul_ps(mmWidth, mmPiFour);
|
||||
sincos_ps(mmWidth, &mmSin, &mmCos);
|
||||
auto mmCosPlusSine = _mm_add_ps(mmCos, mmSin);
|
||||
auto mmCosMinusSine = _mm_sub_ps(mmCos, mmSin);
|
||||
auto mmLeft = _mm_load_ps(left);
|
||||
auto mmRight = _mm_load_ps(right);
|
||||
auto mmTemp = _mm_mul_ps(mmCosMinusSine, mmRight);
|
||||
mmRight = _mm_add_ps(_mm_mul_ps(mmCosMinusSine, mmLeft), _mm_mul_ps(mmCosPlusSine, mmRight));
|
||||
mmLeft = _mm_add_ps(_mm_mul_ps(mmCosPlusSine, mmLeft), mmTemp);
|
||||
_mm_store_ps(left, mmLeft);
|
||||
_mm_store_ps(right, mmRight);
|
||||
incrementAll<TypeAlignment>(width, left, right);
|
||||
}
|
||||
|
||||
while (width < sentinel){
|
||||
_internals::snippetWidth(*width, *left, *right);
|
||||
incrementAll(width, left, right);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::mean<float, true>(absl::Span<const float> vector) noexcept
|
||||
{
|
||||
float result { 0.0 };
|
||||
if (vector.size() == 0)
|
||||
return result;
|
||||
|
||||
auto* value = vector.begin();
|
||||
auto* sentinel = vector.end();
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(value) && value < lastAligned)
|
||||
result += *value++;
|
||||
|
||||
auto mmSums = _mm_setzero_ps();
|
||||
while (value < lastAligned) {
|
||||
mmSums = _mm_add_ps(mmSums, _mm_load_ps(value));
|
||||
value += TypeAlignment;
|
||||
}
|
||||
|
||||
std::array<float, 4> sseResult;
|
||||
_mm_store_ps(sseResult.data(), mmSums);
|
||||
|
||||
for (auto sseValue : sseResult)
|
||||
result += sseValue;
|
||||
|
||||
while (value < sentinel)
|
||||
result += *value++;
|
||||
|
||||
return result / static_cast<float>(vector.size());
|
||||
}
|
||||
|
||||
template <>
|
||||
float sfz::meanSquared<float, true>(absl::Span<const float> vector) noexcept
|
||||
{
|
||||
float result { 0.0 };
|
||||
if (vector.size() == 0)
|
||||
return result;
|
||||
|
||||
auto* value = vector.begin();
|
||||
auto* sentinel = vector.end();
|
||||
const auto* lastAligned = prevAligned(sentinel);
|
||||
|
||||
while (unaligned(value) && value < lastAligned) {
|
||||
result += (*value) * (*value);
|
||||
value++;
|
||||
}
|
||||
|
||||
auto mmSums = _mm_setzero_ps();
|
||||
while (value < lastAligned) {
|
||||
const auto mmValues = _mm_load_ps(value);
|
||||
mmSums = _mm_add_ps(mmSums, _mm_mul_ps(mmValues, mmValues));
|
||||
value += TypeAlignment;
|
||||
}
|
||||
|
||||
std::array<float, 4> sseResult;
|
||||
_mm_store_ps(sseResult.data(), mmSums);
|
||||
|
||||
for (auto sseValue : sseResult)
|
||||
result += sseValue;
|
||||
|
||||
while (value < sentinel) {
|
||||
result += (*value) * (*value);
|
||||
value++;
|
||||
}
|
||||
|
||||
return result / static_cast<float>(vector.size());
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::cumsum<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
CHECK(output.size() >= input.size());
|
||||
if (input.size() == 0)
|
||||
return;
|
||||
|
||||
auto out = output.data();
|
||||
auto in = input.data();
|
||||
const auto sentinel = in + std::min(input.size(), output.size());
|
||||
const auto lastAligned = prevAligned(sentinel);
|
||||
|
||||
*out++ = *in++;
|
||||
while (unaligned(in, out) && in < lastAligned)
|
||||
_internals::snippetCumsum(in, out);
|
||||
|
||||
auto mmOutput = _mm_set_ps1(*(out - 1));
|
||||
while (in < lastAligned) {
|
||||
auto mmOffset = _mm_load_ps(in);
|
||||
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, _MM_SHUFFLE(1, 0, 0, 0)));
|
||||
mmOutput = _mm_add_ps(mmOutput, mmOffset);
|
||||
_mm_store_ps(out, mmOutput);
|
||||
mmOutput = _mm_shuffle_ps(mmOutput, mmOutput, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
incrementAll<TypeAlignment>(in, out);
|
||||
}
|
||||
|
||||
while (in < sentinel)
|
||||
_internals::snippetCumsum(in, out);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::sfzInterpolationCast<float, true>(absl::Span<const float> floatJumps, absl::Span<int> jumps, absl::Span<float> coeffs) noexcept
|
||||
{
|
||||
sfz::sfzInterpolationCast<float, false>(floatJumps, jumps, coeffs);
|
||||
// CHECK(jumps.size() >= floatJumps.size());
|
||||
// CHECK(jumps.size() == coeffs.size());
|
||||
|
||||
// auto floatJump = floatJumps.data();
|
||||
// auto jump = jumps.data();
|
||||
// auto coeff = coeffs.data();
|
||||
// const auto sentinel = floatJump + min(floatJumps.size(), jumps.size(), coeffs.size());
|
||||
// const auto lastAligned = prevAligned(sentinel);
|
||||
|
||||
// while (unaligned(floatJump, reinterpret_cast<float*>(jump), coeff) && floatJump < lastAligned)
|
||||
// _internals::snippetSFZInterpolationCast(floatJump, jump, coeff);
|
||||
|
||||
// while (floatJump < lastAligned) {
|
||||
// auto mmFloatJumps = _mm_load_ps(floatJump);
|
||||
// auto mmIndices = _mm_cvtps_epi32(_mm_sub_ps(mmFloatJumps, _mm_set_ps1(0.4999999552965164184570312f)));
|
||||
// _mm_store_si128(reinterpret_cast<__m128i*>(jump), mmIndices);
|
||||
|
||||
// auto mmCoeff = _mm_sub_ps(mmFloatJumps, _mm_cvtepi32_ps(mmIndices));
|
||||
// _mm_store_ps(coeff, mmCoeff);
|
||||
// incrementAll<TypeAlignment>(floatJump, jump, coeff);
|
||||
// }
|
||||
|
||||
// while(floatJump < sentinel)
|
||||
// _internals::snippetSFZInterpolationCast(floatJump, jump, coeff);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::diff<float, true>(absl::Span<const float> input, absl::Span<float> output) noexcept
|
||||
{
|
||||
CHECK(output.size() >= input.size());
|
||||
if (input.size() == 0)
|
||||
return;
|
||||
|
||||
auto out = output.data();
|
||||
auto in = input.data();
|
||||
const auto sentinel = in + std::min(input.size(), output.size());
|
||||
const auto lastAligned = prevAligned(sentinel);
|
||||
|
||||
*out++ = *in++;
|
||||
while (unaligned(in, out) && in < lastAligned)
|
||||
_internals::snippetDiff(in, out);
|
||||
|
||||
auto mmBase = _mm_set_ps1(*(in - 1));
|
||||
while (in < lastAligned) {
|
||||
auto mmOutput = _mm_load_ps(in);
|
||||
auto mmNextBase = _mm_shuffle_ps(mmOutput, mmOutput, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
mmOutput = _mm_sub_ps(mmOutput, mmBase);
|
||||
mmBase = mmNextBase;
|
||||
mmOutput = _mm_sub_ps(mmOutput, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOutput), 4)));
|
||||
_mm_store_ps(out, mmOutput);
|
||||
incrementAll<TypeAlignment>(in, out);
|
||||
}
|
||||
|
||||
while (in < sentinel)
|
||||
_internals::snippetDiff(in, out);
|
||||
}
|
||||
|
||||
#endif // SFIZZ_HAVE_SSE2
|
||||
|
|
@ -7,7 +7,9 @@
|
|||
#include "SfzHelpers.h"
|
||||
#include "StringViewHelpers.h"
|
||||
|
||||
absl::optional<uint8_t> sfz::readNoteValue(const absl::string_view& value)
|
||||
namespace sfz{
|
||||
|
||||
absl::optional<uint8_t> readNoteValue(const absl::string_view& value)
|
||||
{
|
||||
switch(hash(value))
|
||||
{
|
||||
|
|
@ -153,7 +155,7 @@ absl::optional<uint8_t> sfz::readNoteValue(const absl::string_view& value)
|
|||
}
|
||||
}
|
||||
|
||||
bool sfz::findHeader(absl::string_view& source, absl::string_view& header, absl::string_view& members)
|
||||
bool findHeader(absl::string_view& source, absl::string_view& header, absl::string_view& members)
|
||||
{
|
||||
auto openHeader = source.find("<");
|
||||
if (openHeader == absl::string_view::npos)
|
||||
|
|
@ -176,7 +178,7 @@ bool sfz::findHeader(absl::string_view& source, absl::string_view& header, absl:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool sfz::findOpcode(absl::string_view& source, absl::string_view& opcode, absl::string_view& value)
|
||||
bool findOpcode(absl::string_view& source, absl::string_view& opcode, absl::string_view& value)
|
||||
{
|
||||
auto opcodeEnd = source.find("=");
|
||||
if (opcodeEnd == absl::string_view::npos)
|
||||
|
|
@ -203,7 +205,7 @@ bool sfz::findOpcode(absl::string_view& source, absl::string_view& opcode, absl:
|
|||
}
|
||||
|
||||
|
||||
bool sfz::findDefine(absl::string_view line, absl::string_view& variable, absl::string_view& value)
|
||||
bool findDefine(absl::string_view line, absl::string_view& variable, absl::string_view& value)
|
||||
{
|
||||
const auto defPosition = line.find("#define");
|
||||
if (defPosition == absl::string_view::npos)
|
||||
|
|
@ -229,7 +231,7 @@ bool sfz::findDefine(absl::string_view line, absl::string_view& variable, absl::
|
|||
return true;
|
||||
}
|
||||
|
||||
bool sfz::findInclude(absl::string_view line, std::string& path)
|
||||
bool findInclude(absl::string_view line, std::string& path)
|
||||
{
|
||||
const auto defPosition = line.find("#include");
|
||||
if (defPosition == absl::string_view::npos)
|
||||
|
|
@ -246,3 +248,5 @@ bool sfz::findInclude(absl::string_view line, std::string& path)
|
|||
path = std::string(line.substr(pathStart + 1, pathEnd - pathStart - 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
sfz::Synth::Synth()
|
||||
: Synth(config::numVoices)
|
||||
{
|
||||
initializeSIMDDispatchers();
|
||||
}
|
||||
|
||||
sfz::Synth::Synth(int numVoices)
|
||||
|
|
@ -524,7 +525,7 @@ float sfz::Synth::getTuningFrequency() const
|
|||
|
||||
void sfz::Synth::loadStretchTuningByRatio(float ratio)
|
||||
{
|
||||
CHECK(ratio >= 0.0f && ratio <= 1.0f);
|
||||
SFIZZ_CHECK(ratio >= 0.0f && ratio <= 1.0f);
|
||||
ratio = clamp(ratio, 0.0f, 1.0f);
|
||||
|
||||
if (ratio > 0.0f)
|
||||
|
|
@ -747,8 +748,8 @@ void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
|
|||
|
||||
ASSERT(!hasNanInf(buffer.getConstSpan(0)));
|
||||
ASSERT(!hasNanInf(buffer.getConstSpan(1)));
|
||||
CHECK(isReasonableAudio(buffer.getConstSpan(0)));
|
||||
CHECK(isReasonableAudio(buffer.getConstSpan(1)));
|
||||
SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(0)));
|
||||
SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(1)));
|
||||
}
|
||||
|
||||
void sfz::Synth::noteOn(int delay, int noteNumber, uint8_t velocity) noexcept
|
||||
|
|
@ -1129,14 +1130,14 @@ int sfz::Synth::getSampleQuality(ProcessMode mode)
|
|||
case ProcessFreewheeling:
|
||||
return resources.synthConfig.freeWheelingSampleQuality;
|
||||
default:
|
||||
CHECK(false);
|
||||
SFIZZ_CHECK(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void sfz::Synth::setSampleQuality(ProcessMode mode, int quality)
|
||||
{
|
||||
CHECK(quality >= 1 && quality <= 10);
|
||||
SFIZZ_CHECK(quality >= 1 && quality <= 10);
|
||||
quality = clamp(quality, 1, 10);
|
||||
|
||||
switch (mode) {
|
||||
|
|
@ -1147,7 +1148,7 @@ void sfz::Synth::setSampleQuality(ProcessMode mode, int quality)
|
|||
resources.synthConfig.freeWheelingSampleQuality = quality;
|
||||
break;
|
||||
default:
|
||||
CHECK(false);
|
||||
SFIZZ_CHECK(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "ModifierHelpers.h"
|
||||
#include "MathHelpers.h"
|
||||
#include "SIMDHelpers.h"
|
||||
#include "Panning.h"
|
||||
#include "SfzHelpers.h"
|
||||
#include "Interpolators.h"
|
||||
#include "absl/algorithm/container.h"
|
||||
|
|
@ -263,8 +264,8 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
|||
#if 0
|
||||
ASSERT(!hasNanInf(buffer.getConstSpan(0)));
|
||||
ASSERT(!hasNanInf(buffer.getConstSpan(1)));
|
||||
CHECK(isReasonableAudio(buffer.getConstSpan(0)));
|
||||
CHECK(isReasonableAudio(buffer.getConstSpan(1)));
|
||||
SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(0)));
|
||||
SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(1)));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -281,7 +282,7 @@ void sfz::Voice::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
|
|||
egEnvelope.getBlock(modulationSpan);
|
||||
|
||||
// Amplitude envelope
|
||||
applyGain<float>(baseGain, modulationSpan);
|
||||
applyGain1<float>(baseGain, modulationSpan);
|
||||
for (const auto& mod : region->amplitudeCC) {
|
||||
linearModifier(resources, *tempSpan, mod, normalizePercents<float>);
|
||||
applyGain<float>(*tempSpan, modulationSpan);
|
||||
|
|
@ -304,7 +305,7 @@ void sfz::Voice::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
|
|||
}
|
||||
|
||||
// Volume envelope
|
||||
applyGain<float>(db2mag(baseVolumedB), modulationSpan);
|
||||
applyGain1<float>(db2mag(baseVolumedB), modulationSpan);
|
||||
for (const auto& mod : region->volumeCC) {
|
||||
multiplicativeModifier(resources, *tempSpan, mod, [](float x) {
|
||||
return db2mag(x);
|
||||
|
|
@ -358,12 +359,12 @@ void sfz::Voice::panStageMono(AudioSpan<float> buffer) noexcept
|
|||
copy<float>(leftBuffer, rightBuffer);
|
||||
|
||||
// Apply panning
|
||||
fill<float>(*modulationSpan, region->pan);
|
||||
fill(*modulationSpan, region->pan);
|
||||
for (const auto& mod : region->panCC) {
|
||||
linearModifier(resources, *tempSpan, mod, normalizePercents<float>);
|
||||
add<float>(*tempSpan, *modulationSpan);
|
||||
}
|
||||
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
|
||||
pan(*modulationSpan, leftBuffer, rightBuffer);
|
||||
}
|
||||
|
||||
void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
|
||||
|
|
@ -379,27 +380,27 @@ void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
|
|||
return;
|
||||
|
||||
// Apply panning
|
||||
fill<float>(*modulationSpan, region->pan);
|
||||
fill(*modulationSpan, region->pan);
|
||||
for (const auto& mod : region->panCC) {
|
||||
linearModifier(resources, *tempSpan, mod, normalizePercents<float>);
|
||||
add<float>(*tempSpan, *modulationSpan);
|
||||
}
|
||||
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
|
||||
pan(*modulationSpan, leftBuffer, rightBuffer);
|
||||
|
||||
// Apply the width/position process
|
||||
fill<float>(*modulationSpan, region->width);
|
||||
fill(*modulationSpan, region->width);
|
||||
for (const auto& mod : region->widthCC) {
|
||||
linearModifier(resources, *tempSpan, mod, normalizePercents<float>);
|
||||
add<float>(*tempSpan, *modulationSpan);
|
||||
}
|
||||
width<float>(*modulationSpan, leftBuffer, rightBuffer);
|
||||
width(*modulationSpan, leftBuffer, rightBuffer);
|
||||
|
||||
fill<float>(*modulationSpan, region->position);
|
||||
fill(*modulationSpan, region->position);
|
||||
for (const auto& mod : region->positionCC) {
|
||||
linearModifier(resources, *tempSpan, mod, normalizePercents<float>);
|
||||
add<float>(*tempSpan, *modulationSpan);
|
||||
}
|
||||
pan<float>(*modulationSpan, leftBuffer, rightBuffer);
|
||||
pan(*modulationSpan, leftBuffer, rightBuffer);
|
||||
}
|
||||
|
||||
void sfz::Voice::filterStageMono(AudioSpan<float> buffer) noexcept
|
||||
|
|
@ -457,7 +458,7 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
|||
if (!jumps || !bends || !indices || !coeffs)
|
||||
return;
|
||||
|
||||
fill<float>(*jumps, pitchRatio * speedRatio);
|
||||
fill(*jumps, pitchRatio * speedRatio);
|
||||
|
||||
const auto events = resources.midiState.getPitchEvents();
|
||||
const auto bendLambda = [this](float bend) {
|
||||
|
|
@ -479,7 +480,7 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
|||
jumps->front() += floatPositionOffset;
|
||||
cumsum<float>(*jumps, *jumps);
|
||||
sfzInterpolationCast<float>(*jumps, *indices, *coeffs);
|
||||
add<int>(sourcePosition, *indices);
|
||||
add1<int>(sourcePosition, *indices);
|
||||
|
||||
if (region->shouldLoop() && region->loopEnd(currentPromise->oversamplingFactor) <= source.getNumFrames()) {
|
||||
const auto loopEnd = static_cast<int>(region->loopEnd(currentPromise->oversamplingFactor));
|
||||
|
|
@ -487,7 +488,7 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
|||
for (auto* index = indices->begin(); index < indices->end(); ++index) {
|
||||
if (*index > loopEnd) {
|
||||
const auto remainingElements = static_cast<size_t>(std::distance(index, indices->end()));
|
||||
subtract<int>(offset, { index, remainingElements });
|
||||
subtract1<int>(offset, { index, remainingElements });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -541,8 +542,8 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
|||
#if 0
|
||||
ASSERT(!hasNanInf(buffer.getConstSpan(0)));
|
||||
ASSERT(!hasNanInf(buffer.getConstSpan(1)));
|
||||
CHECK(isReasonableAudio(buffer.getConstSpan(0)));
|
||||
CHECK(isReasonableAudio(buffer.getConstSpan(1)));
|
||||
SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(0)));
|
||||
SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(1)));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -588,7 +589,7 @@ void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
|||
return;
|
||||
|
||||
float keycenterFrequency = midiNoteFrequency(region->pitchKeycenter);
|
||||
fill<float>(*frequencies, pitchRatio * keycenterFrequency);
|
||||
fill(*frequencies, pitchRatio * keycenterFrequency);
|
||||
|
||||
const auto events = resources.midiState.getPitchEvents();
|
||||
const auto bendLambda = [this](float bend) {
|
||||
|
|
@ -623,8 +624,8 @@ void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
|||
for (unsigned i = 0, n = waveUnisonSize; i < n; ++i) {
|
||||
WavetableOscillator& osc = waveOscillators[i];
|
||||
osc.processModulated(frequencies->data(), waveDetuneRatio[i], tempSpan->data(), numFrames);
|
||||
sfz::multiplyAdd<float>(waveLeftGain[i], *tempSpan, leftSpan);
|
||||
sfz::multiplyAdd<float>(waveRightGain[i], *tempSpan, rightSpan);
|
||||
multiplyAdd1<float>(waveLeftGain[i], *tempSpan, leftSpan);
|
||||
multiplyAdd1<float>(waveRightGain[i], *tempSpan, rightSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -632,8 +633,8 @@ void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
|||
#if 0
|
||||
ASSERT(!hasNanInf(buffer.getConstSpan(0)));
|
||||
ASSERT(!hasNanInf(buffer.getConstSpan(1)));
|
||||
CHECK(isReasonableAudio(buffer.getConstSpan(0)));
|
||||
CHECK(isReasonableAudio(buffer.getConstSpan(1)));
|
||||
SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(0)));
|
||||
SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(1)));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,8 +103,8 @@ namespace fx {
|
|||
|
||||
// mix down the stereo signal to create the resonator excitation source
|
||||
absl::Span<float> resInput = _tempBuffer.getSpan(0).first(nframes);
|
||||
sfz::applyGain<float>(M_SQRT1_2, inputL, resInput);
|
||||
sfz::multiplyAdd<float>(M_SQRT1_2, inputR, resInput);
|
||||
sfz::applyGain1<float>(M_SQRT1_2, inputL, resInput);
|
||||
sfz::multiplyAdd1<float>(M_SQRT1_2, inputR, resInput);
|
||||
|
||||
// generate the strings summed into a common buffer
|
||||
absl::Span<float> resOutput = _tempBuffer.getSpan(1).first(nframes);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#include "Width.h"
|
||||
#include "Opcode.h"
|
||||
#include "SIMDHelpers.h"
|
||||
#include "Panning.h"
|
||||
#include "absl/memory/memory.h"
|
||||
|
||||
namespace sfz {
|
||||
|
|
@ -53,8 +53,8 @@ namespace fx {
|
|||
const float r = input2[i];
|
||||
|
||||
const float w = clamp((widths[i] + 100.0f) * 0.005f, 0.0f, 1.0f);
|
||||
const float coeff1 = _internals::panLookup(w);
|
||||
const float coeff2 = _internals::panLookup(1.0f - w);
|
||||
const float coeff1 = panLookup(w);
|
||||
const float coeff2 = panLookup(1.0f - w);
|
||||
|
||||
output1[i] = l * coeff2 + r * coeff1;
|
||||
output2[i] = l * coeff1 + r * coeff2;
|
||||
|
|
|
|||
34
src/sfizz/simd/Common.h
Normal file
34
src/sfizz/simd/Common.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// 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
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
constexpr uintptr_t ByteAlignmentMask(unsigned N) { return N - 1; }
|
||||
|
||||
template<unsigned N, class T>
|
||||
T* nextAligned(const T* ptr)
|
||||
{
|
||||
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(ptr) + ByteAlignmentMask(N) & (~ByteAlignmentMask(N)));
|
||||
}
|
||||
|
||||
template<unsigned N, class T>
|
||||
T* prevAligned(const T* ptr)
|
||||
{
|
||||
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(ptr) & (~ByteAlignmentMask(N)));
|
||||
}
|
||||
|
||||
template<unsigned N, class T>
|
||||
bool unaligned(const T* ptr)
|
||||
{
|
||||
return (reinterpret_cast<uintptr_t>(ptr) & ByteAlignmentMask(N) )!= 0;
|
||||
}
|
||||
|
||||
template<unsigned N, class T, class... Args>
|
||||
bool unaligned(const T* ptr1, Args... rest)
|
||||
{
|
||||
return unaligned<N>(ptr1) || unaligned<N>(rest...);
|
||||
}
|
||||
56
src/sfizz/simd/HelpersAVX.cpp
Normal file
56
src/sfizz/simd/HelpersAVX.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// 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 "HelpersAVX.h"
|
||||
#include "../SIMDConfig.h"
|
||||
#include "../MathHelpers.h"
|
||||
#include "Common.h"
|
||||
|
||||
#if SFIZZ_HAVE_AVX
|
||||
#include <immintrin.h>
|
||||
using Type = float;
|
||||
constexpr unsigned TypeAlignment = 8;
|
||||
constexpr unsigned ByteAlignment = TypeAlignment * sizeof(Type);
|
||||
#endif
|
||||
|
||||
void gain1AVX(float gain, const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_AVX
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
const auto mmGain = _mm256_set1_ps(gain);
|
||||
while (unaligned<ByteAlignment>(input, output) && output < lastAligned)
|
||||
*output++ = gain * (*input++);
|
||||
|
||||
while (output < lastAligned) {
|
||||
_mm256_store_ps(output, _mm256_mul_ps(mmGain, _mm256_load_ps(input)));
|
||||
incrementAll<TypeAlignment>(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel)
|
||||
*output++ = gain * (*input++);
|
||||
}
|
||||
|
||||
void gainAVX(const float* gain, const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_AVX
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(input, output) && output < lastAligned)
|
||||
*output++ = (*gain++) * (*input++);
|
||||
|
||||
while (output < lastAligned) {
|
||||
_mm256_store_ps(output, _mm256_mul_ps(_mm256_load_ps(gain), _mm256_load_ps(input)));
|
||||
incrementAll<TypeAlignment>(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel)
|
||||
*output++ = (*gain++) * (*input++);
|
||||
}
|
||||
10
src/sfizz/simd/HelpersAVX.h
Normal file
10
src/sfizz/simd/HelpersAVX.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// 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
|
||||
|
||||
#pragma once
|
||||
|
||||
void gain1AVX(float gain, const float* input, float* output, unsigned size) noexcept;
|
||||
void gainAVX(const float* gain, const float* input, float* output, unsigned size) noexcept;
|
||||
474
src/sfizz/simd/HelpersSSE.cpp
Normal file
474
src/sfizz/simd/HelpersSSE.cpp
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
// 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 "HelpersSSE.h"
|
||||
#include "../SIMDConfig.h"
|
||||
#include "../MathHelpers.h"
|
||||
#include "Common.h"
|
||||
#include <array>
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
#include <immintrin.h>
|
||||
using Type = float;
|
||||
constexpr unsigned TypeAlignment = 4;
|
||||
constexpr unsigned ByteAlignment = TypeAlignment * sizeof(Type);
|
||||
#endif
|
||||
|
||||
void readInterleavedSSE(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept
|
||||
{
|
||||
const auto sentinel = input + inputSize - 1;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(input + inputSize - TypeAlignment);
|
||||
while (unaligned<ByteAlignment>(input, outputLeft, outputRight) && input < lastAligned) {
|
||||
*outputLeft++ = *input++;
|
||||
*outputRight++ = *input++;
|
||||
}
|
||||
|
||||
while (input < lastAligned) {
|
||||
auto register0 = _mm_load_ps(input);
|
||||
auto register1 = _mm_load_ps(input + TypeAlignment);
|
||||
auto register2 = register0;
|
||||
// register 2 holds the copy of register 0 that is going to get erased by the first operation
|
||||
// Remember that the bit mask reads from the end; 10 00 10 00 means
|
||||
// "take 0 from a, take 2 from a, take 0 from b, take 2 from b"
|
||||
register0 = _mm_shuffle_ps(register0, register1, 0b10001000);
|
||||
register1 = _mm_shuffle_ps(register2, register1, 0b11011101);
|
||||
_mm_store_ps(outputLeft, register0);
|
||||
_mm_store_ps(outputRight, register1);
|
||||
incrementAll<TypeAlignment>(input, input, outputLeft, outputRight);
|
||||
}
|
||||
|
||||
// NEON wip
|
||||
// auto reg = vld2q_f32(in);
|
||||
// vst1q_f32(lOut, reg.val[0]);
|
||||
// vst1q_f32(rOut, reg.val[1]);
|
||||
#endif
|
||||
|
||||
while (input < sentinel) {
|
||||
*outputLeft++ = *input++;
|
||||
*outputRight++ = *input++;
|
||||
}
|
||||
}
|
||||
|
||||
void writeInterleavedSSE(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept
|
||||
{
|
||||
const auto sentinel = output + outputSize - 1;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(output + outputSize - TypeAlignment);
|
||||
while (unaligned<ByteAlignment>(output, inputRight, inputLeft) && output < lastAligned) {
|
||||
*output++ = *inputLeft++;
|
||||
*output++ = *inputRight++;
|
||||
}
|
||||
|
||||
while (output < lastAligned) {
|
||||
const auto lInRegister = _mm_load_ps(inputLeft);
|
||||
const auto rInRegister = _mm_load_ps(inputRight);
|
||||
const auto outRegister1 = _mm_unpacklo_ps(lInRegister, rInRegister);
|
||||
_mm_store_ps(output, outRegister1);
|
||||
const auto outRegister2 = _mm_unpackhi_ps(lInRegister, rInRegister);
|
||||
_mm_store_ps(output + 4, outRegister2);
|
||||
incrementAll<TypeAlignment>(output, output, inputLeft, inputRight);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel) {
|
||||
*output++ = *inputLeft++;
|
||||
*output++ = *inputRight++;
|
||||
}
|
||||
}
|
||||
|
||||
void gain1SSE(float gain, const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
const auto mmGain = _mm_set1_ps(gain);
|
||||
while (unaligned<ByteAlignment>(input, output) && output < lastAligned)
|
||||
*output++ = gain * (*input++);
|
||||
|
||||
while (output < lastAligned) {
|
||||
_mm_store_ps(output, _mm_mul_ps(mmGain, _mm_load_ps(input)));
|
||||
incrementAll<TypeAlignment>(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel)
|
||||
*output++ = gain * (*input++);
|
||||
}
|
||||
|
||||
void gainSSE(const float* gain, const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(input, output) && output < lastAligned)
|
||||
*output++ = (*gain++) * (*input++);
|
||||
|
||||
while (output < lastAligned) {
|
||||
_mm_store_ps(output, _mm_mul_ps(_mm_load_ps(gain), _mm_load_ps(input)));
|
||||
incrementAll<TypeAlignment>(gain, input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel)
|
||||
*output++ = (*gain++) * (*input++);
|
||||
}
|
||||
|
||||
void divideSSE(const float* input, const float* divisor, float* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(input, output) && output < lastAligned)
|
||||
*output++ = (*input++) / (*divisor++);
|
||||
|
||||
while (output < lastAligned) {
|
||||
_mm_store_ps(output, _mm_div_ps(_mm_load_ps(input), _mm_load_ps(divisor)));
|
||||
incrementAll<TypeAlignment>(divisor, input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel)
|
||||
*output++ = (*input++) / (*divisor++);
|
||||
}
|
||||
|
||||
void multiplyAddSSE(const float* gain, const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(input, output) && output < lastAligned)
|
||||
*output++ += (*gain++) * (*input++);
|
||||
|
||||
while (output < lastAligned) {
|
||||
auto mmOut = _mm_load_ps(output);
|
||||
mmOut = _mm_add_ps(_mm_mul_ps(_mm_load_ps(gain), _mm_load_ps(input)), mmOut);
|
||||
_mm_store_ps(output, mmOut);
|
||||
incrementAll<TypeAlignment>(gain, input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel)
|
||||
*output++ += (*gain++) * (*input++);
|
||||
}
|
||||
|
||||
void multiplyAdd1SSE(float gain, const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(input, output) && output < lastAligned)
|
||||
*output++ += gain * (*input++);
|
||||
|
||||
auto mmGain = _mm_set1_ps(gain);
|
||||
while (output < lastAligned) {
|
||||
auto mmOut = _mm_load_ps(output);
|
||||
mmOut = _mm_add_ps(_mm_mul_ps(mmGain, _mm_load_ps(input)), mmOut);
|
||||
_mm_store_ps(output, mmOut);
|
||||
incrementAll<TypeAlignment>(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel)
|
||||
*output++ += gain * (*input++);
|
||||
}
|
||||
|
||||
float linearRampSSE(float* output, float start, float step, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(output) && output < lastAligned) {
|
||||
*output++ = start;
|
||||
start += step;
|
||||
}
|
||||
|
||||
auto mmStart = _mm_set1_ps(start - step);
|
||||
auto mmStep = _mm_set_ps(step + step + step + step, step + step + step, step + step, step);
|
||||
while (output < lastAligned) {
|
||||
mmStart = _mm_add_ps(mmStart, mmStep);
|
||||
_mm_store_ps(output, mmStart);
|
||||
mmStart = _mm_shuffle_ps(mmStart, mmStart, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
incrementAll<TypeAlignment>(output);
|
||||
}
|
||||
start = _mm_cvtss_f32(mmStart) + step;
|
||||
#endif
|
||||
|
||||
while (output < sentinel) {
|
||||
*output++ = start;
|
||||
start += step;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
float multiplicativeRampSSE(float* output, float start, float step, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(output) && output < lastAligned) {
|
||||
*output++ = start;
|
||||
start *= step;
|
||||
}
|
||||
|
||||
auto mmStart = _mm_set1_ps(start / step);
|
||||
auto mmStep = _mm_set_ps(step * step * step * step, step * step * step, step * step, step);
|
||||
while (output < lastAligned) {
|
||||
mmStart = _mm_mul_ps(mmStart, mmStep);
|
||||
_mm_store_ps(output, mmStart);
|
||||
mmStart = _mm_shuffle_ps(mmStart, mmStart, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
incrementAll<TypeAlignment>(output);
|
||||
}
|
||||
start = _mm_cvtss_f32(mmStart) * step;
|
||||
#endif
|
||||
|
||||
while (output < sentinel) {
|
||||
*output++ = start;
|
||||
start *= step;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
void addSSE(const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(input, output) && output < lastAligned)
|
||||
*output++ += *input++;
|
||||
|
||||
while (output < lastAligned) {
|
||||
_mm_store_ps(output, _mm_add_ps(_mm_load_ps(output), _mm_load_ps(input)));
|
||||
incrementAll<TypeAlignment>(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel)
|
||||
*output++ += *input++;
|
||||
}
|
||||
|
||||
void add1SSE(float value, float* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(output) && output < lastAligned)
|
||||
*output++ += value;
|
||||
|
||||
const auto mmValue = _mm_set1_ps(value);
|
||||
while (output < lastAligned) {
|
||||
_mm_store_ps(output, _mm_add_ps(_mm_load_ps(output), mmValue));
|
||||
incrementAll<TypeAlignment>(output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel)
|
||||
*output++ += value;
|
||||
}
|
||||
|
||||
void subtractSSE(const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(input, output) && output < lastAligned)
|
||||
*output++ -= *input++;
|
||||
|
||||
while (output < lastAligned) {
|
||||
_mm_store_ps(output, _mm_sub_ps(_mm_load_ps(output), _mm_load_ps(input)));
|
||||
incrementAll<TypeAlignment>(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel)
|
||||
*output++ -= *input++;
|
||||
}
|
||||
|
||||
void subtract1SSE(float value, float* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(output) && output < lastAligned)
|
||||
*output++ -= value;
|
||||
|
||||
const auto mmValue = _mm_set1_ps(value);
|
||||
while (output < lastAligned) {
|
||||
_mm_store_ps(output, _mm_sub_ps(_mm_load_ps(output), mmValue));
|
||||
incrementAll<TypeAlignment>(output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel)
|
||||
*output++ -= value;
|
||||
}
|
||||
|
||||
void copySSE(const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
// The sentinel is the input here
|
||||
const auto sentinel = input + size;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(input, output) && input < lastAligned)
|
||||
*output++ = *input++;
|
||||
|
||||
while (input < lastAligned) {
|
||||
_mm_store_ps(output, _mm_load_ps(input));
|
||||
incrementAll<TypeAlignment>(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
std::copy(input, sentinel, output);
|
||||
}
|
||||
|
||||
float meanSSE(const float* vector, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = vector + size;
|
||||
|
||||
float result { 0.0f };
|
||||
if (size == 0)
|
||||
return result;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(vector) && vector < lastAligned)
|
||||
result += *vector++;
|
||||
|
||||
auto mmSums = _mm_setzero_ps();
|
||||
while (vector < lastAligned) {
|
||||
mmSums = _mm_add_ps(mmSums, _mm_load_ps(vector));
|
||||
incrementAll<TypeAlignment>(vector);
|
||||
}
|
||||
|
||||
std::array<float, 4> sseResult;
|
||||
_mm_store_ps(sseResult.data(), mmSums);
|
||||
|
||||
for (auto sseValue : sseResult)
|
||||
result += sseValue;
|
||||
#endif
|
||||
|
||||
while (vector < sentinel)
|
||||
result += *vector++;
|
||||
|
||||
return result / static_cast<float>(size);
|
||||
}
|
||||
|
||||
float meanSquaredSSE(const float* vector, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = vector + size;
|
||||
|
||||
float result { 0.0f };
|
||||
if (size == 0)
|
||||
return result;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(vector) && vector < lastAligned) {
|
||||
result += (*vector) * (*vector);
|
||||
vector++;
|
||||
}
|
||||
|
||||
auto mmSums = _mm_setzero_ps();
|
||||
while (vector < lastAligned) {
|
||||
const auto mmValues = _mm_load_ps(vector);
|
||||
mmSums = _mm_add_ps(mmSums, _mm_mul_ps(mmValues, mmValues));
|
||||
incrementAll<TypeAlignment>(vector);
|
||||
}
|
||||
|
||||
std::array<float, 4> sseResult;
|
||||
_mm_store_ps(sseResult.data(), mmSums);
|
||||
|
||||
for (auto sseValue : sseResult)
|
||||
result += sseValue;
|
||||
#endif
|
||||
|
||||
while (vector < sentinel) {
|
||||
result += (*vector) * (*vector);
|
||||
vector++;
|
||||
}
|
||||
|
||||
return result / static_cast<float>(size);
|
||||
}
|
||||
|
||||
void cumsumSSE(const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
const auto sentinel = output + size;
|
||||
*output++ = *input++;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(input, output) && output < lastAligned) {
|
||||
*output = *(output - 1) + *input;
|
||||
incrementAll(input, output);
|
||||
}
|
||||
|
||||
auto mmOutput = _mm_set_ps1(*(output - 1));
|
||||
while (output < lastAligned) {
|
||||
auto mmOffset = _mm_load_ps(input);
|
||||
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, _MM_SHUFFLE(1, 0, 0, 0)));
|
||||
mmOutput = _mm_add_ps(mmOutput, mmOffset);
|
||||
_mm_store_ps(output, mmOutput);
|
||||
mmOutput = _mm_shuffle_ps(mmOutput, mmOutput, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
incrementAll<TypeAlignment>(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel) {
|
||||
*output = *(output - 1) + *input;
|
||||
incrementAll(input, output);
|
||||
}
|
||||
}
|
||||
|
||||
void diffSSE(const float* input, float* output, unsigned size) noexcept
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
const auto sentinel = output + size;
|
||||
*output++ = *input++;
|
||||
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
const auto* lastAligned = prevAligned<ByteAlignment>(sentinel);
|
||||
while (unaligned<ByteAlignment>(input, output) && output < lastAligned) {
|
||||
*output = *input - *(input - 1);
|
||||
incrementAll(input, output);
|
||||
}
|
||||
|
||||
auto mmBase = _mm_set_ps1(*(input - 1));
|
||||
while (output < lastAligned) {
|
||||
auto mmOutput = _mm_load_ps(input);
|
||||
auto mmNextBase = _mm_shuffle_ps(mmOutput, mmOutput, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
mmOutput = _mm_sub_ps(mmOutput, mmBase);
|
||||
mmBase = mmNextBase;
|
||||
mmOutput = _mm_sub_ps(mmOutput, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(mmOutput), 4)));
|
||||
_mm_store_ps(output, mmOutput);
|
||||
incrementAll<TypeAlignment>(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (output < sentinel) {
|
||||
*output = *input - *(input - 1);
|
||||
incrementAll(input, output);
|
||||
}
|
||||
}
|
||||
27
src/sfizz/simd/HelpersSSE.h
Normal file
27
src/sfizz/simd/HelpersSSE.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// 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
|
||||
|
||||
#pragma once
|
||||
|
||||
/* These are the SSE versions of the SIMDHelpers */
|
||||
void readInterleavedSSE(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept;
|
||||
void writeInterleavedSSE(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept;
|
||||
void gainSSE(const float* gain, const float* input, float* output, unsigned size) noexcept;
|
||||
void gain1SSE(float gain, const float* input, float* output, unsigned size) noexcept;
|
||||
void divideSSE(const float* input, const float* divisor, float* output, unsigned size) noexcept;
|
||||
void multiplyAddSSE(const float* gain, const float* input, float* output, unsigned size) noexcept;
|
||||
void multiplyAdd1SSE(float gain, const float* input, float* output, unsigned size) noexcept;
|
||||
float linearRampSSE(float* output, float start, float step, unsigned size) noexcept;
|
||||
float multiplicativeRampSSE(float* output, float start, float step, unsigned size) noexcept;
|
||||
void addSSE(const float* input, float* output, unsigned size) noexcept;
|
||||
void add1SSE(float value, float* output, unsigned size) noexcept;
|
||||
void subtractSSE(const float* input, float* output, unsigned size) noexcept;
|
||||
void subtract1SSE(float value, float* output, unsigned size) noexcept;
|
||||
void copySSE(const float* input, float* output, unsigned size) noexcept;
|
||||
float meanSSE(const float* vector, unsigned size) noexcept;
|
||||
float meanSquaredSSE(const float* vector, unsigned size) noexcept;
|
||||
void cumsumSSE(const float* input, float* output, unsigned size) noexcept;
|
||||
void diffSSE(const float* input, float* output, unsigned size) noexcept;
|
||||
188
src/sfizz/simd/HelpersScalar.h
Normal file
188
src/sfizz/simd/HelpersScalar.h
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
// 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
|
||||
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
|
||||
template<class T>
|
||||
inline void readInterleavedScalar(const T* input, T* outputLeft, T* outputRight, unsigned inputSize) noexcept
|
||||
{
|
||||
const auto sentinel = input + inputSize - 1;
|
||||
while (input < sentinel) {
|
||||
*outputLeft++ = *input++;
|
||||
*outputRight++ = *input++;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void writeInterleavedScalar(const T* inputLeft, const T* inputRight, T* output, unsigned outputSize) noexcept
|
||||
{
|
||||
const auto sentinel = output + outputSize - 1;
|
||||
while (output < sentinel) {
|
||||
*output++ = *inputLeft++;
|
||||
*output++ = *inputRight++;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void gain1Scalar(T gain, const T* input, T* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
while (output < sentinel)
|
||||
*output++ = gain * (*input++);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void gainScalar(const T* gain, const T* input, T* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
while (output < sentinel)
|
||||
*output++ = (*gain++) * (*input++);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void divideScalar(const T* input, const T* divisor, T* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
while (output < sentinel)
|
||||
*output++ = (*input++) / (*divisor++);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void multiplyAddScalar(const T* gain, const T* input, T* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
while (output < sentinel)
|
||||
*output++ += (*gain++) * (*input++);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void multiplyAdd1Scalar(T gain, const T* input, T* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
while (output < sentinel)
|
||||
*output++ += gain * (*input++);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T linearRampScalar(T* output, T start, T step, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
while (output < sentinel) {
|
||||
*output++ = start;
|
||||
start += step;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T multiplicativeRampScalar(T* output, T start, T step, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
while (output < sentinel) {
|
||||
*output++ = start;
|
||||
start *= step;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void addScalar(const T* input, T* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
while (output < sentinel)
|
||||
*output++ += *input++;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void add1Scalar(T value, T* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
while (output < sentinel)
|
||||
*output++ += value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void subtractScalar(const T* input, T* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
while (output < sentinel)
|
||||
*output++ -= *input++;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void subtract1Scalar(T value, T* output, unsigned size) noexcept
|
||||
{
|
||||
const auto sentinel = output + size;
|
||||
while (output < sentinel)
|
||||
*output++ -= value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void copyScalar(const T* input, T* output, unsigned size) noexcept
|
||||
{
|
||||
std::copy(input, input + size, output);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T meanScalar(const T* vector, unsigned size) noexcept
|
||||
{
|
||||
T result{ 0.0 };
|
||||
if (size == 0)
|
||||
return result;
|
||||
|
||||
const auto sentinel = vector + size;
|
||||
while (vector < sentinel)
|
||||
result += *vector++;
|
||||
|
||||
return result / static_cast<T>(size);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T meanSquaredScalar(const T* vector, unsigned size) noexcept
|
||||
{
|
||||
T result{ 0.0 };
|
||||
if (size == 0)
|
||||
return result;
|
||||
|
||||
const auto sentinel = vector + size;
|
||||
while (vector < sentinel) {
|
||||
result += (*vector) * (*vector);
|
||||
vector++;
|
||||
}
|
||||
|
||||
return result / static_cast<T>(size);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void cumsumScalar(const T* input, T* output, unsigned size) noexcept
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
const auto sentinel = output + size;
|
||||
|
||||
*output++ = *input++;
|
||||
while (output < sentinel) {
|
||||
*output = *(output - 1) + *input;
|
||||
incrementAll(input, output);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void diffScalar(const T* input, T* output, unsigned size) noexcept
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
const auto sentinel = output + size;
|
||||
|
||||
*output++ = *input++;
|
||||
while (output < sentinel) {
|
||||
*output = *input - *(input - 1);
|
||||
incrementAll(input, output);
|
||||
}
|
||||
}
|
||||
|
|
@ -41,8 +41,8 @@ template <class Type>
|
|||
void checkBoundaries(sfz::Buffer<Type>& buffer, int expectedSize)
|
||||
{
|
||||
REQUIRE((int)buffer.size() == expectedSize);
|
||||
REQUIRE(((size_t)buffer.data() & (sfz::SIMDConfig::defaultAlignment - 1)) == 0);
|
||||
REQUIRE(((size_t)buffer.alignedEnd() & (sfz::SIMDConfig::defaultAlignment - 1)) == 0);
|
||||
REQUIRE(((size_t)buffer.data() & (sfz::config::defaultAlignment - 1)) == 0);
|
||||
REQUIRE(((size_t)buffer.alignedEnd() & (sfz::config::defaultAlignment - 1)) == 0);
|
||||
REQUIRE(std::distance(buffer.begin(), buffer.end()) == expectedSize);
|
||||
REQUIRE(std::distance(buffer.begin(), buffer.alignedEnd()) >= expectedSize);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// 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 "ui_DemoStereo.h"
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
|
|
@ -160,8 +160,8 @@ int DemoApp::processAudio(jack_nframes_t nframes, void *cbdata)
|
|||
std::fill(positionEnvelope.begin(), positionEnvelope.end(), self->fPan * 0.01f);
|
||||
|
||||
using namespace sfz;
|
||||
width<float>(widthEnvelope, leftBuffer, rightBuffer);
|
||||
pan<float>(positionEnvelope, leftBuffer, rightBuffer);
|
||||
width(widthEnvelope, leftBuffer, rightBuffer);
|
||||
pan(positionEnvelope, leftBuffer, rightBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ int main(int argc, char** argv)
|
|||
sfz::Buffer<float> buffer { numFrames * 2 };
|
||||
sfz::Buffer<float> right { numFrames };
|
||||
sndfile.readf(buffer.data(), numFrames * 2 );
|
||||
sfz::readInterleaved<float>(buffer, absl::MakeSpan(left), absl::MakeSpan(right));
|
||||
sfz::readInterleaved(buffer, absl::MakeSpan(left), absl::MakeSpan(right));
|
||||
} else if (sndfile.channels() == 1) {
|
||||
sndfile.readf(left.data(), numFrames);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ int main(int argc, char** argv)
|
|||
sfz::Buffer<float> buffer { numFrames * 2 };
|
||||
sfz::Buffer<float> right { numFrames };
|
||||
sndfile.readf(buffer.data(), numFrames * 2 );
|
||||
sfz::readInterleaved<float>(buffer, absl::MakeSpan(left), absl::MakeSpan(right));
|
||||
sfz::readInterleaved(buffer, absl::MakeSpan(left), absl::MakeSpan(right));
|
||||
} else if (sndfile.channels() == 1) {
|
||||
sndfile.readf(left.data(), numFrames);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,2 +1,10 @@
|
|||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch2/catch.hpp"
|
||||
#include "sfizz/SIMDHelpers.h"
|
||||
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int result = Catch::Session().run(argc, argv);
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
// 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 <absl/algorithm/container.h>
|
||||
#include <absl/types/span.h>
|
||||
|
|
@ -48,81 +49,14 @@ inline bool approxEqual(absl::Span<const Type> lhs, absl::Span<const Type> rhs,
|
|||
return true;
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] fill() - Manual buffer")
|
||||
{
|
||||
std::vector<float> buffer(5);
|
||||
std::vector<float> expected { fillValue, fillValue, fillValue, fillValue, fillValue };
|
||||
sfz::fill<float, false>(absl::MakeSpan(buffer), fillValue);
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] fill() - Small buffer")
|
||||
{
|
||||
std::vector<float> buffer(smallBufferSize);
|
||||
std::vector<float> expected(smallBufferSize);
|
||||
std::fill(expected.begin(), expected.end(), fillValue);
|
||||
|
||||
sfz::fill<float, false>(absl::MakeSpan(buffer), fillValue);
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] fill() - Big buffer")
|
||||
{
|
||||
std::vector<float> buffer(bigBufferSize);
|
||||
std::vector<float> expected(bigBufferSize);
|
||||
std::fill(expected.begin(), expected.end(), fillValue);
|
||||
|
||||
sfz::fill<float, false>(absl::MakeSpan(buffer), fillValue);
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] fill() - Small buffer -- SIMD")
|
||||
{
|
||||
std::vector<float> buffer(smallBufferSize);
|
||||
std::vector<float> expected(smallBufferSize);
|
||||
std::fill(expected.begin(), expected.end(), fillValue);
|
||||
|
||||
sfz::fill<float, true>(absl::MakeSpan(buffer), fillValue);
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] fill() - Big buffer -- SIMD")
|
||||
{
|
||||
std::vector<float> buffer(bigBufferSize);
|
||||
std::vector<float> expected(bigBufferSize);
|
||||
std::fill(expected.begin(), expected.end(), fillValue);
|
||||
|
||||
sfz::fill<float, true>(absl::MakeSpan(buffer), fillValue);
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] fill() - Small buffer -- doubles")
|
||||
{
|
||||
std::vector<double> buffer(smallBufferSize);
|
||||
std::vector<double> expected(smallBufferSize);
|
||||
std::fill(expected.begin(), expected.end(), fillValue);
|
||||
|
||||
sfz::fill<double, false>(absl::MakeSpan(buffer), fillValue);
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] fill() - Big buffer -- doubles")
|
||||
{
|
||||
std::vector<double> buffer(bigBufferSize);
|
||||
std::vector<double> expected(bigBufferSize);
|
||||
std::fill(expected.begin(), expected.end(), fillValue);
|
||||
|
||||
sfz::fill<double, false>(absl::MakeSpan(buffer), fillValue);
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Interleaved read")
|
||||
{
|
||||
std::array<float, 16> 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<float, 16> 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<float, 8> leftOutput;
|
||||
std::array<float, 8> rightOutput;
|
||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, false);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 16> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -139,7 +73,8 @@ TEST_CASE("[Helpers] Interleaved read unaligned end")
|
|||
std::array<float, 20> 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<float, 10> leftOutput;
|
||||
std::array<float, 10> rightOutput;
|
||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, false);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 20> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -156,7 +91,8 @@ TEST_CASE("[Helpers] Small interleaved read unaligned end")
|
|||
std::array<float, 6> expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f };
|
||||
std::array<float, 3> leftOutput;
|
||||
std::array<float, 3> rightOutput;
|
||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, false);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 6> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -173,7 +109,8 @@ TEST_CASE("[Helpers] Interleaved read -- SIMD")
|
|||
std::array<float, 16> 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<float, 8> leftOutput;
|
||||
std::array<float, 8> rightOutput;
|
||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, true);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 16> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -190,7 +127,8 @@ TEST_CASE("[Helpers] Interleaved read unaligned end -- SIMD")
|
|||
std::array<float, 20> 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<float, 10> leftOutput;
|
||||
std::array<float, 10> rightOutput;
|
||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, true);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 20> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -207,7 +145,8 @@ TEST_CASE("[Helpers] Small interleaved read unaligned end -- SIMD")
|
|||
std::array<float, 6> expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f };
|
||||
std::array<float, 3> leftOutput;
|
||||
std::array<float, 3> rightOutput;
|
||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, true);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 6> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -226,8 +165,10 @@ TEST_CASE("[Helpers] Interleaved read SIMD vs Scalar")
|
|||
std::array<float, medBufferSize> leftOutputSIMD;
|
||||
std::array<float, medBufferSize> rightOutputSIMD;
|
||||
std::iota(input.begin(), input.end(), 0.0f);
|
||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutputScalar), absl::MakeSpan(rightOutputScalar));
|
||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutputSIMD), absl::MakeSpan(rightOutputSIMD));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, false);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutputScalar), absl::MakeSpan(rightOutputScalar));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::readInterleaved, true);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutputSIMD), absl::MakeSpan(rightOutputSIMD));
|
||||
REQUIRE(leftOutputScalar == leftOutputSIMD);
|
||||
REQUIRE(rightOutputScalar == rightOutputSIMD);
|
||||
}
|
||||
|
|
@ -247,7 +188,8 @@ TEST_CASE("[Helpers] Interleaved write")
|
|||
std::array<float, 8> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f };
|
||||
std::array<float, 16> output;
|
||||
std::array<float, 16> 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::writeInterleaved<float, false>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, false);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -257,7 +199,8 @@ TEST_CASE("[Helpers] Interleaved write unaligned end")
|
|||
std::array<float, 10> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f };
|
||||
std::array<float, 20> output;
|
||||
std::array<float, 20> 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<float, false>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, false);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +210,8 @@ TEST_CASE("[Helpers] Small interleaved write unaligned end")
|
|||
std::array<float, 3> rightInput { 10.0f, 11.0f, 12.0f };
|
||||
std::array<float, 6> output;
|
||||
std::array<float, 6> expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f };
|
||||
sfz::writeInterleaved<float, false>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, false);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -286,7 +230,8 @@ TEST_CASE("[Helpers] Interleaved write -- SIMD")
|
|||
std::array<float, 8> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f };
|
||||
std::array<float, 16> output;
|
||||
std::array<float, 16> 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::writeInterleaved<float, true>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, true);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -296,7 +241,7 @@ TEST_CASE("[Helpers] Interleaved write unaligned end -- SIMD")
|
|||
std::array<float, 10> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f };
|
||||
std::array<float, 20> output;
|
||||
std::array<float, 20> 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<float, true>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -306,7 +251,8 @@ TEST_CASE("[Helpers] Small interleaved write unaligned end -- SIMD")
|
|||
std::array<float, 3> rightInput { 10.0f, 11.0f, 12.0f };
|
||||
std::array<float, 6> output;
|
||||
std::array<float, 6> expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f };
|
||||
sfz::writeInterleaved<float, true>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, true);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -318,180 +264,107 @@ TEST_CASE("[Helpers] Interleaved write SIMD vs Scalar")
|
|||
std::array<float, medBufferSize * 2> outputSIMD;
|
||||
std::iota(leftInput.begin(), leftInput.end(), 0.0f);
|
||||
std::iota(rightInput.begin(), rightInput.end(), static_cast<float>(medBufferSize));
|
||||
sfz::writeInterleaved<float, false>(leftInput, rightInput, absl::MakeSpan(outputScalar));
|
||||
sfz::writeInterleaved<float, true>(leftInput, rightInput, absl::MakeSpan(outputSIMD));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, false);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputScalar));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::writeInterleaved, true);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputSIMD));
|
||||
REQUIRE(outputScalar == outputSIMD);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Gain, single")
|
||||
{
|
||||
std::array<float, 5> input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
std::array<float, 5> expected { fillValue, fillValue, fillValue, fillValue, fillValue };
|
||||
sfz::applyGain<float, false>(fillValue, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
std::array<float, 65> input;
|
||||
std::array<float, 65> expected;
|
||||
absl::c_fill(input, 1.0f);
|
||||
absl::c_fill(expected, fillValue);
|
||||
|
||||
SECTION("Scalar")
|
||||
{
|
||||
std::array<float, 65> output;
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain1, false);
|
||||
sfz::applyGain1<float>(fillValue, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
SECTION("SIMD")
|
||||
{
|
||||
std::array<float, 65> output;
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain1, true);
|
||||
sfz::applyGain1<float>(fillValue, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Gain, single and inplace")
|
||||
{
|
||||
std::array<float, 5> buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> expected { fillValue, fillValue, fillValue, fillValue, fillValue };
|
||||
sfz::applyGain<float, false>(fillValue, buffer, absl::MakeSpan(buffer));
|
||||
REQUIRE(buffer == expected);
|
||||
std::array<float, 65> expected;
|
||||
std::array<float, 65> buffer;
|
||||
absl::c_fill(expected, fillValue);
|
||||
SECTION("Scalar")
|
||||
{
|
||||
absl::c_fill(buffer, 1.0f);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain1, false);
|
||||
sfz::applyGain1<float>(fillValue, buffer, absl::MakeSpan(buffer));
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
SECTION("SIMD")
|
||||
{
|
||||
absl::c_fill(buffer, 1.0f);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain1, false);
|
||||
sfz::applyGain1<float>(fillValue, buffer, absl::MakeSpan(buffer));
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Gain, spans")
|
||||
{
|
||||
std::array<float, 5> input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
std::array<float, 5> expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
sfz::applyGain<float, false>(gain, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
std::array<float, 65> input;
|
||||
std::array<float, 65> gain;
|
||||
std::array<float, 65> expected;
|
||||
absl::c_fill(input, 1.0f);
|
||||
absl::c_iota(gain, 1.0f);
|
||||
absl::c_iota(expected, 1.0f);
|
||||
|
||||
SECTION("Scalar")
|
||||
{
|
||||
std::array<float, 65> output;
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain, false);
|
||||
sfz::applyGain<float>(gain, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
SECTION("SIMD")
|
||||
{
|
||||
std::array<float, 65> output;
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain, true);
|
||||
sfz::applyGain<float>(gain, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Gain, spans and inplace")
|
||||
{
|
||||
std::array<float, 5> buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
sfz::applyGain<float, false>(gain, buffer, absl::MakeSpan(buffer));
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
std::array<float, 65> buffer;
|
||||
std::array<float, 65> gain;
|
||||
std::array<float, 65> expected;
|
||||
absl::c_iota(gain, 1.0f);
|
||||
absl::c_iota(expected, 1.0f);
|
||||
|
||||
TEST_CASE("[Helpers] Gain, single (SIMD)")
|
||||
{
|
||||
std::array<float, 5> input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
std::array<float, 5> expected { fillValue, fillValue, fillValue, fillValue, fillValue };
|
||||
sfz::applyGain<float, true>(fillValue, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
SECTION("Scalar")
|
||||
{
|
||||
absl::c_fill(buffer, 1.0f);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain, false);
|
||||
sfz::applyGain<float>(gain, buffer, absl::MakeSpan(buffer));
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Gain, single and inplace (SIMD)")
|
||||
{
|
||||
std::array<float, 5> buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> expected { fillValue, fillValue, fillValue, fillValue, fillValue };
|
||||
sfz::applyGain<float, true>(fillValue, buffer, absl::MakeSpan(buffer));
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Gain, spans (SIMD)")
|
||||
{
|
||||
std::array<float, 5> input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
std::array<float, 5> expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
sfz::applyGain<float, true>(gain, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Gain, spans and inplace (SIMD)")
|
||||
{
|
||||
std::array<float, 5> buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
sfz::applyGain<float, true>(gain, buffer, absl::MakeSpan(buffer));
|
||||
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]));
|
||||
SECTION("SIMD")
|
||||
{
|
||||
absl::c_fill(buffer, 1.0f);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::gain, false);
|
||||
sfz::applyGain<float>(gain, buffer, absl::MakeSpan(buffer));
|
||||
REQUIRE(buffer == expected);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Linear Ramp")
|
||||
|
|
@ -500,7 +373,8 @@ TEST_CASE("[Helpers] Linear Ramp")
|
|||
const float v { fillValue };
|
||||
std::array<float, 6> output;
|
||||
std::array<float, 6> expected { start, start + v, start + v + v, start + v + v + v, start + v + v + v + v, start + v + v + v + v + v };
|
||||
sfz::linearRamp<float, false>(absl::MakeSpan(output), start, v);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, false);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(output), start, v);
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -510,7 +384,8 @@ TEST_CASE("[Helpers] Linear Ramp (SIMD)")
|
|||
const float v { fillValue };
|
||||
std::array<float, 6> output;
|
||||
std::array<float, 6> expected { start, start + v, start + v + v, start + v + v + v, start + v + v + v + v, start + v + v + v + v + v };
|
||||
sfz::linearRamp<float, true>(absl::MakeSpan(output), start, v);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, true);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(output), start, v);
|
||||
REQUIRE(approxEqual<float>(output, expected));
|
||||
}
|
||||
|
||||
|
|
@ -519,8 +394,10 @@ TEST_CASE("[Helpers] Linear Ramp (SIMD vs scalar)")
|
|||
const float start { 0.0f };
|
||||
std::vector<float> outputScalar(bigBufferSize);
|
||||
std::vector<float> outputSIMD(bigBufferSize);
|
||||
sfz::linearRamp<float, false>(absl::MakeSpan(outputScalar), start, fillValue);
|
||||
sfz::linearRamp<float, true>(absl::MakeSpan(outputSIMD), start, fillValue);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, false);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(outputScalar), start, fillValue);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, true);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(outputSIMD), start, fillValue);
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
|
|
@ -529,8 +406,10 @@ TEST_CASE("[Helpers] Linear Ramp unaligned (SIMD vs scalar)")
|
|||
const float start { 0.0f };
|
||||
std::vector<float> outputScalar(bigBufferSize);
|
||||
std::vector<float> outputSIMD(bigBufferSize);
|
||||
sfz::linearRamp<float, false>(absl::MakeSpan(outputScalar).subspan(1), start, fillValue);
|
||||
sfz::linearRamp<float, true>(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, false);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(outputScalar).subspan(1), start, fillValue);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, true);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue);
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
|
|
@ -540,7 +419,8 @@ TEST_CASE("[Helpers] Multiplicative Ramp")
|
|||
const float v { fillValue };
|
||||
std::array<float, 6> output;
|
||||
std::array<float, 6> expected { start, start * v, start * v * v, start * v * v * v, start * v * v * v * v, start * v * v * v * v * v };
|
||||
sfz::multiplicativeRamp<float, false>(absl::MakeSpan(output), start, v);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplicativeRamp, false);
|
||||
sfz::multiplicativeRamp<float>(absl::MakeSpan(output), start, v);
|
||||
REQUIRE(approxEqual<float>(output, expected));
|
||||
}
|
||||
|
||||
|
|
@ -550,7 +430,8 @@ TEST_CASE("[Helpers] Multiplicative Ramp (SIMD)")
|
|||
const float v { fillValue };
|
||||
std::array<float, 6> output;
|
||||
std::array<float, 6> expected { start, start * v, start * v * v, start * v * v * v, start * v * v * v * v, start * v * v * v * v * v };
|
||||
sfz::multiplicativeRamp<float, true>(absl::MakeSpan(output), start, v);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplicativeRamp, true);
|
||||
sfz::multiplicativeRamp<float>(absl::MakeSpan(output), start, v);
|
||||
REQUIRE(approxEqual<float>(output, expected));
|
||||
}
|
||||
|
||||
|
|
@ -559,8 +440,10 @@ TEST_CASE("[Helpers] Multiplicative Ramp (SIMD vs scalar)")
|
|||
const float start { 1.0f };
|
||||
std::vector<float> outputScalar(bigBufferSize);
|
||||
std::vector<float> outputSIMD(bigBufferSize);
|
||||
sfz::multiplicativeRamp<float, false>(absl::MakeSpan(outputScalar), start, fillValue);
|
||||
sfz::multiplicativeRamp<float, true>(absl::MakeSpan(outputSIMD), start, fillValue);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplicativeRamp, false);
|
||||
sfz::multiplicativeRamp<float>(absl::MakeSpan(outputScalar), start, fillValue);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplicativeRamp, true);
|
||||
sfz::multiplicativeRamp<float>(absl::MakeSpan(outputSIMD), start, fillValue);
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
|
|
@ -569,8 +452,10 @@ TEST_CASE("[Helpers] Multiplicative Ramp unaligned (SIMD vs scalar)")
|
|||
const float start { 1.0f };
|
||||
std::vector<float> outputScalar(bigBufferSize);
|
||||
std::vector<float> outputSIMD(bigBufferSize);
|
||||
sfz::multiplicativeRamp<float, false>(absl::MakeSpan(outputScalar).subspan(1), start, fillValue);
|
||||
sfz::multiplicativeRamp<float, true>(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplicativeRamp, false);
|
||||
sfz::multiplicativeRamp<float>(absl::MakeSpan(outputScalar).subspan(1), start, fillValue);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplicativeRamp, true);
|
||||
sfz::multiplicativeRamp<float>(absl::MakeSpan(outputSIMD).subspan(1), start, fillValue);
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
|
|
@ -579,7 +464,8 @@ TEST_CASE("[Helpers] Add")
|
|||
std::array<float, 5> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> expected { 2.0f, 3.0f, 4.0f, 5.0f, 6.0f };
|
||||
sfz::add<float, false>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add, false);
|
||||
sfz::add<float>(input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -588,7 +474,8 @@ TEST_CASE("[Helpers] Add (SIMD)")
|
|||
std::array<float, 5> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> expected { 2.0f, 3.0f, 4.0f, 5.0f, 6.0f };
|
||||
sfz::add<float, true>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add, true);
|
||||
sfz::add<float>(input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -601,18 +488,32 @@ TEST_CASE("[Helpers] Add (SIMD vs scalar)")
|
|||
absl::c_fill(outputScalar, 0.0f);
|
||||
absl::c_fill(outputSIMD, 0.0f);
|
||||
|
||||
sfz::add<float, false>(input, absl::MakeSpan(outputScalar));
|
||||
sfz::add<float, true>(input, absl::MakeSpan(outputSIMD));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add, false);
|
||||
sfz::add<float>(input, absl::MakeSpan(outputScalar));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::add, true);
|
||||
sfz::add<float>(input, absl::MakeSpan(outputSIMD));
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] MultiplyAdd (Scalar)")
|
||||
{
|
||||
std::array<float, 5> gain { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f };
|
||||
std::array<float, 5> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f };
|
||||
std::array<float, 5> expected { 5.0f, 4.2f, 3.6f, 3.2f, 3.0f };
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd, false);
|
||||
sfz::multiplyAdd<float>(gain, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] MultiplyAdd (SIMD)")
|
||||
{
|
||||
std::array<float, 5> gain { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f };
|
||||
std::array<float, 5> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f };
|
||||
std::array<float, 5> expected { 5.0f, 4.2f, 3.6f, 3.2f, 3.0f };
|
||||
sfz::multiplyAdd<float, true>(gain, input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd, true);
|
||||
sfz::multiplyAdd<float>(gain, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -627,18 +528,32 @@ TEST_CASE("[Helpers] MultiplyAdd (SIMD vs scalar)")
|
|||
absl::c_iota(outputScalar, 0.0f);
|
||||
absl::c_iota(outputSIMD, 0.0f);
|
||||
|
||||
sfz::multiplyAdd<float, false>(gain, input, absl::MakeSpan(outputScalar));
|
||||
sfz::multiplyAdd<float, true>(gain, input, absl::MakeSpan(outputSIMD));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd, false);
|
||||
sfz::multiplyAdd<float>(gain, input, absl::MakeSpan(outputScalar));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd, true);
|
||||
sfz::multiplyAdd<float>(gain, input, absl::MakeSpan(outputSIMD));
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] MultiplyAdd fixed gain (Scalar)")
|
||||
{
|
||||
float gain = 0.3f;
|
||||
std::array<float, 5> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f };
|
||||
std::array<float, 5> expected { 5.3f, 4.6f, 3.9f, 3.2f, 2.5f };
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd1, false);
|
||||
sfz::multiplyAdd1<float>(gain, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] MultiplyAdd fixed gain (SIMD)")
|
||||
{
|
||||
float gain = 0.3f;
|
||||
std::array<float, 5> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f };
|
||||
std::array<float, 5> expected { 5.3f, 4.6f, 3.9f, 3.2f, 2.5f };
|
||||
sfz::multiplyAdd<float, true>(gain, input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd1, true);
|
||||
sfz::multiplyAdd1<float>(gain, input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -652,8 +567,10 @@ TEST_CASE("[Helpers] MultiplyAdd fixed gain (SIMD vs scalar)")
|
|||
absl::c_iota(outputScalar, 0.0f);
|
||||
absl::c_iota(outputSIMD, 0.0f);
|
||||
|
||||
sfz::multiplyAdd<float, false>(gain, input, absl::MakeSpan(outputScalar));
|
||||
sfz::multiplyAdd<float, true>(gain, input, absl::MakeSpan(outputSIMD));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd1, false);
|
||||
sfz::multiplyAdd1<float>(gain, input, absl::MakeSpan(outputScalar));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::multiplyAdd1, true);
|
||||
sfz::multiplyAdd1<float>(gain, input, absl::MakeSpan(outputSIMD));
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
|
|
@ -662,7 +579,7 @@ TEST_CASE("[Helpers] Subtract")
|
|||
std::array<float, 5> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> expected { 0.0f, -1.0f, -2.0f, -3.0f, -4.0f };
|
||||
sfz::subtract<float, false>(input, absl::MakeSpan(output));
|
||||
sfz::subtract<float>(input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -670,7 +587,8 @@ TEST_CASE("[Helpers] Subtract 2")
|
|||
{
|
||||
std::array<float, 5> output { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f };
|
||||
sfz::subtract<float, false>(1.0f, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::subtract1, false);
|
||||
sfz::subtract1<float>(1.0f, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -680,7 +598,8 @@ TEST_CASE("[Helpers] Subtract (SIMD)")
|
|||
std::array<float, 5> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
std::array<float, 5> expected { 0.0f, -1.0f, -2.0f, -3.0f, -4.0f };
|
||||
sfz::subtract<float, true>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::subtract, true);
|
||||
sfz::subtract<float>(input, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -693,8 +612,10 @@ TEST_CASE("[Helpers] Subtract (SIMD vs scalar)")
|
|||
absl::c_fill(outputScalar, 0.0f);
|
||||
absl::c_fill(outputSIMD, 0.0f);
|
||||
|
||||
sfz::subtract<float, false>(input, absl::MakeSpan(outputScalar));
|
||||
sfz::subtract<float, true>(input, absl::MakeSpan(outputSIMD));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::subtract, false);
|
||||
sfz::subtract<float>(input, absl::MakeSpan(outputScalar));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::subtract, true);
|
||||
sfz::subtract<float>(input, absl::MakeSpan(outputSIMD));
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
|
|
@ -705,8 +626,10 @@ TEST_CASE("[Helpers] Subtract 2 (SIMD vs scalar)")
|
|||
absl::c_iota(outputScalar, 0.0f);
|
||||
absl::c_iota(outputSIMD, 0.0f);
|
||||
|
||||
sfz::subtract<float, false>(1.2f, absl::MakeSpan(outputScalar));
|
||||
sfz::subtract<float, true>(1.2f, absl::MakeSpan(outputSIMD));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::subtract1, false);
|
||||
sfz::subtract1<float>(1.2f, absl::MakeSpan(outputScalar));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::subtract1, true);
|
||||
sfz::subtract1<float>(1.2f, absl::MakeSpan(outputSIMD));
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
|
|
@ -714,7 +637,8 @@ TEST_CASE("[Helpers] copy")
|
|||
{
|
||||
std::array<float, 5> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
sfz::copy<float, false>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::copy, false);
|
||||
sfz::copy<float>(input, absl::MakeSpan(output));
|
||||
REQUIRE(output == input);
|
||||
}
|
||||
|
||||
|
|
@ -722,7 +646,8 @@ TEST_CASE("[Helpers] copy (SIMD)")
|
|||
{
|
||||
std::array<float, 5> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
|
||||
std::array<float, 5> output { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
sfz::copy<float, true>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::copy, true);
|
||||
sfz::copy<float>(input, absl::MakeSpan(output));
|
||||
REQUIRE(output == input);
|
||||
}
|
||||
|
||||
|
|
@ -735,37 +660,51 @@ TEST_CASE("[Helpers] copy (SIMD vs scalar)")
|
|||
absl::c_fill(outputScalar, 0.0f);
|
||||
absl::c_fill(outputSIMD, 0.0f);
|
||||
|
||||
sfz::add<float, false>(input, absl::MakeSpan(outputScalar));
|
||||
sfz::add<float, true>(input, absl::MakeSpan(outputSIMD));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::copy, false);
|
||||
sfz::copy<float>(input, absl::MakeSpan(outputScalar));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::copy, true);
|
||||
sfz::copy<float>(input, absl::MakeSpan(outputSIMD));
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Mean")
|
||||
{
|
||||
std::array<float, 10> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f };
|
||||
REQUIRE(sfz::mean<float, false>(input) == 5.5f);
|
||||
REQUIRE(sfz::mean<float, true>(input) == 5.5f);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::mean, false);
|
||||
REQUIRE(sfz::mean<float>(input) == 5.5f);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::mean, true);
|
||||
REQUIRE(sfz::mean<float>(input) == 5.5f);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Mean (SIMD vs scalar)")
|
||||
{
|
||||
std::vector<float> input(bigBufferSize);
|
||||
absl::c_iota(input, 0.0f);
|
||||
REQUIRE(sfz::mean<float, false>(input) == Approx(sfz::mean<float, true>(input)).margin(0.001));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::mean, false);
|
||||
auto scalarResult = sfz::mean<float>(input);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::mean, true);
|
||||
auto simdResult = sfz::mean<float>(input);
|
||||
REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) );
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Mean Squared")
|
||||
{
|
||||
std::array<float, 10> input { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f };
|
||||
REQUIRE(sfz::meanSquared<float, false>(input) == 38.5f);
|
||||
REQUIRE(sfz::meanSquared<float, true>(input) == 38.5f);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::meanSquared, false);
|
||||
REQUIRE(sfz::meanSquared<float>(input) == 38.5f);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::meanSquared, true);
|
||||
REQUIRE(sfz::meanSquared<float>(input) == 38.5f);
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Mean Squared (SIMD vs scalar)")
|
||||
{
|
||||
std::vector<float> input(medBufferSize);
|
||||
absl::c_iota(input, 0.0f);
|
||||
REQUIRE(sfz::meanSquared<float, false>(input) == sfz::meanSquared<float, true>(input));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::meanSquared, false);
|
||||
auto scalarResult = sfz::meanSquared<float>(input);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::meanSquared, true);
|
||||
auto simdResult = sfz::meanSquared<float>(input);
|
||||
REQUIRE( scalarResult == Approx(simdResult).margin(1e-3) );
|
||||
}
|
||||
|
||||
TEST_CASE("[Helpers] Cumulative sum")
|
||||
|
|
@ -773,7 +712,8 @@ TEST_CASE("[Helpers] Cumulative sum")
|
|||
std::array<float, 6> 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<float, 6> output;
|
||||
std::array<float, 6> expected { 1.1f, 2.3f, 3.6f, 5.0f, 6.5f, 8.1f };
|
||||
sfz::cumsum<float, false>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::cumsum, false);
|
||||
sfz::cumsum<float>(input, absl::MakeSpan(output));
|
||||
REQUIRE(approxEqual<float>(output, expected));
|
||||
}
|
||||
|
||||
|
|
@ -782,9 +722,12 @@ TEST_CASE("[Helpers] Cumulative sum (SIMD vs Scalar)")
|
|||
std::vector<float> input(bigBufferSize);
|
||||
std::vector<float> outputScalar(bigBufferSize);
|
||||
std::vector<float> outputSIMD(bigBufferSize);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, true);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(input), 0.0f, 0.1f);
|
||||
sfz::cumsum<float, false>(input, absl::MakeSpan(outputScalar));
|
||||
sfz::cumsum<float, true>(input, absl::MakeSpan(outputSIMD));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::cumsum, false);
|
||||
sfz::cumsum<float>(input, absl::MakeSpan(outputScalar));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::cumsum, true);
|
||||
sfz::cumsum<float>(input, absl::MakeSpan(outputSIMD));
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
|
|
@ -793,7 +736,8 @@ TEST_CASE("[Helpers] Diff")
|
|||
std::array<float, 6> input { 1.1f, 2.3f, 3.6f, 5.0f, 6.5f, 8.1f };
|
||||
std::array<float, 6> output;
|
||||
std::array<float, 6> expected { 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f };
|
||||
sfz::diff<float, false>(input, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::diff, false);
|
||||
sfz::diff<float>(input, absl::MakeSpan(output));
|
||||
REQUIRE(approxEqual<float>(output, expected));
|
||||
}
|
||||
|
||||
|
|
@ -802,9 +746,12 @@ TEST_CASE("[Helpers] Diff (SIMD vs Scalar)")
|
|||
std::vector<float> input(bigBufferSize);
|
||||
std::vector<float> outputScalar(bigBufferSize);
|
||||
std::vector<float> outputSIMD(bigBufferSize);
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::linearRamp, true);
|
||||
sfz::linearRamp<float>(absl::MakeSpan(input), 0.0f, 0.1f);
|
||||
sfz::diff<float, false>(input, absl::MakeSpan(outputScalar));
|
||||
sfz::diff<float, true>(input, absl::MakeSpan(outputSIMD));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::diff, false);
|
||||
sfz::diff<float>(input, absl::MakeSpan(outputScalar));
|
||||
sfz::setSIMDOpStatus<float>(sfz::SIMDOps::diff, true);
|
||||
sfz::diff<float>(input, absl::MakeSpan(outputSIMD));
|
||||
REQUIRE(approxEqual<float>(outputScalar, outputSIMD));
|
||||
}
|
||||
|
||||
|
|
@ -817,21 +764,21 @@ TEST_CASE("[Helpers] Pan Scalar")
|
|||
SECTION("Pan = 0")
|
||||
{
|
||||
std::array<float, 1> pan { 0.0f };
|
||||
sfz::pan<float, false>(pan, left, right);
|
||||
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<float, 1> pan { 1.0f };
|
||||
sfz::pan<float, false>(pan, left, right);
|
||||
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<float, 1> pan { -1.0f };
|
||||
sfz::pan<float, false>(pan, left, right);
|
||||
sfz::pan(pan, left, right);
|
||||
REQUIRE(left[0] == Approx(1.0f).margin(0.001f));
|
||||
REQUIRE(right[0] == Approx(0.0f).margin(0.001f));
|
||||
}
|
||||
|
|
@ -846,21 +793,21 @@ TEST_CASE("[Helpers] Width Scalar")
|
|||
SECTION("width = 1")
|
||||
{
|
||||
std::array<float, 1> width { 1.0f };
|
||||
sfz::width<float, false>(width, left, right);
|
||||
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<float, 1> width { 0.0f };
|
||||
sfz::width<float, false>(width, left, right);
|
||||
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<float, 1> width { -1.0f };
|
||||
sfz::width<float, false>(width, left, right);
|
||||
sfz::width(width, left, right);
|
||||
REQUIRE(left[0] == Approx(1.0f).margin(0.001f));
|
||||
REQUIRE(right[0] == Approx(1.0f).margin(0.001f));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue