WIP on vector operations
This commit is contained in:
parent
bb95d8ed86
commit
c014a34385
5 changed files with 460 additions and 21 deletions
|
|
@ -1,9 +1,10 @@
|
||||||
#include <benchmark/benchmark.h>
|
#include <benchmark/benchmark.h>
|
||||||
#include "../sources/AudioBuffer.h"
|
#include "../sources/AudioBuffer.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
static void AB_Joint_Fill_float(benchmark::State& state) {
|
static void Joint_Fill_float(benchmark::State& state) {
|
||||||
AudioBuffer<float> buffer (65535);
|
AudioBuffer<float> buffer (100001);
|
||||||
float fillValue = 0.0f;
|
float fillValue = 0.0f;
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
buffer.fill(fillValue);
|
buffer.fill(fillValue);
|
||||||
|
|
@ -11,20 +12,43 @@ static void AB_Joint_Fill_float(benchmark::State& state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Register the function as a benchmark
|
// Register the function as a benchmark
|
||||||
BENCHMARK(AB_Joint_Fill_float);
|
BENCHMARK(Joint_Fill_float);
|
||||||
|
|
||||||
static void AB_Split_Fill_float(benchmark::State& state) {
|
static void Split_Fill_float(benchmark::State& state) {
|
||||||
SplitAudioBuffer<float> buffer (65535);
|
SplitAudioBuffer<float> buffer (100001);
|
||||||
float fillValue = 0.0f;
|
float fillValue = 0.0f;
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
buffer.fill(fillValue);
|
buffer.fill(fillValue);
|
||||||
fillValue += 1.0f;
|
fillValue += 1.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BENCHMARK(AB_Split_Fill_float);
|
BENCHMARK(Split_Fill_float);
|
||||||
|
|
||||||
static void AB_Joint_Fill_double(benchmark::State& state) {
|
static void Joint_Fill_float_SSE(benchmark::State& state) {
|
||||||
AudioBuffer<double> buffer (65535);
|
AudioBuffer<float> buffer (100001);
|
||||||
|
float fillValue = 0.0f;
|
||||||
|
for (auto _ : state) {
|
||||||
|
buffer.fill<VectorOperations::sse>(fillValue);
|
||||||
|
fillValue += 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Register the function as a benchmark
|
||||||
|
BENCHMARK(Joint_Fill_float_SSE);
|
||||||
|
|
||||||
|
|
||||||
|
static void Split_Fill_float_SSE(benchmark::State& state) {
|
||||||
|
SplitAudioBuffer<float> buffer (100001);
|
||||||
|
float fillValue = 0.0f;
|
||||||
|
for (auto _ : state) {
|
||||||
|
buffer.fill<VectorOperations::sse>(fillValue);
|
||||||
|
fillValue += 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK(Split_Fill_float_SSE);
|
||||||
|
|
||||||
|
static void Joint_Fill_double(benchmark::State& state) {
|
||||||
|
AudioBuffer<double> buffer (100001);
|
||||||
double fillValue = 0.0;
|
double fillValue = 0.0;
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
buffer.fill(fillValue);
|
buffer.fill(fillValue);
|
||||||
|
|
@ -32,15 +56,37 @@ static void AB_Joint_Fill_double(benchmark::State& state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Register the function as a benchmark
|
// Register the function as a benchmark
|
||||||
BENCHMARK(AB_Joint_Fill_double);
|
BENCHMARK(Joint_Fill_double);
|
||||||
|
|
||||||
static void AB_Split_Fill_double(benchmark::State& state) {
|
static void Split_Fill_double(benchmark::State& state) {
|
||||||
SplitAudioBuffer<double> buffer (65535);
|
SplitAudioBuffer<double> buffer (100001);
|
||||||
double fillValue = 0.0;
|
double fillValue = 0.0;
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
buffer.fill(fillValue);
|
buffer.fill(fillValue);
|
||||||
fillValue += 1.0;
|
fillValue += 1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BENCHMARK(AB_Split_Fill_double);
|
|
||||||
|
BENCHMARK(Split_Fill_double);
|
||||||
|
|
||||||
|
constexpr int size { 1039247 };
|
||||||
|
static void Interleaved_Read(benchmark::State& state) {
|
||||||
|
AudioBuffer<float> buffer (size);
|
||||||
|
std::array<float, 2*size> input;
|
||||||
|
std::iota(input.begin(), input.end(), 1.0f);
|
||||||
|
for (auto _ : state) {
|
||||||
|
buffer.readInterleaved(input.data(), size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BENCHMARK(Interleaved_Read);
|
||||||
|
|
||||||
|
static void Interleaved_Read_SSE(benchmark::State& state) {
|
||||||
|
AudioBuffer<float> buffer (size);
|
||||||
|
std::array<float, 2*size> input;
|
||||||
|
std::iota(input.begin(), input.end(), 1.0f);
|
||||||
|
for (auto _ : state) {
|
||||||
|
buffer.readInterleaved<VectorOperations::sse>(input.data(), size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BENCHMARK(Interleaved_Read_SSE);
|
||||||
BENCHMARK_MAIN();
|
BENCHMARK_MAIN();
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "Helpers.h"
|
#include "Helpers.h"
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
|
#include <array>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
template<class Type, unsigned int NumChannels = sfz::config::numChannels, unsigned int Alignment = config::defaultAlignment>
|
template<class Type, unsigned int NumChannels = sfz::config::numChannels, unsigned int Alignment = config::defaultAlignment>
|
||||||
|
|
||||||
|
|
@ -35,14 +37,19 @@ public:
|
||||||
{
|
{
|
||||||
ASSERT(channelIndex >= 0);
|
ASSERT(channelIndex >= 0);
|
||||||
ASSERT(sampleIndex >= 0);
|
ASSERT(sampleIndex >= 0);
|
||||||
return *(buffer.data() + numFrames * channelIndex + sampleIndex);
|
return *(channels[channelIndex] + sampleIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<VectorOperations op = VectorOperations::standard>
|
||||||
void fill(Type value) noexcept
|
void fill(Type value) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (config::vectorOperation == config::VectorOperations::sse)
|
if constexpr (op == VectorOperations::sse && std::is_same<Type, float>::value)
|
||||||
{
|
{
|
||||||
|
static_assert(Alignment == 16, "Wrong alignment");
|
||||||
|
const __m128 mmValue = _mm_set_ps1(value);
|
||||||
|
for(auto i = 0; i < NumChannels; ++i)
|
||||||
|
for (auto mm = (__m128*)alignedBegin(i); mm < (__m128*)alignedEnd(i); mm++)
|
||||||
|
_mm_store_ps((float*)mm, mmValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -51,6 +58,65 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<VectorOperations op = VectorOperations::standard>
|
||||||
|
void readInterleaved(float* input, int numFrames) noexcept
|
||||||
|
{
|
||||||
|
ASSERT(this->numFrames >= numFrames);
|
||||||
|
if constexpr (op == VectorOperations::sse && std::is_same<Type, float>::value && NumChannels == 2)
|
||||||
|
{
|
||||||
|
static_assert(Alignment == 16, "Wrong alignment");
|
||||||
|
const int residualFrames = numFrames & (2 * TypeAlignment - 1);
|
||||||
|
const int lastAligned = numFrames - residualFrames;
|
||||||
|
float* in = input;
|
||||||
|
float* out0 = getChannel(0);
|
||||||
|
float* out1 = getChannel(1);
|
||||||
|
const float* end = input + 2 * lastAligned;
|
||||||
|
while (in < end)
|
||||||
|
{
|
||||||
|
auto input0 = _mm_load_ps(in);
|
||||||
|
in += 4;
|
||||||
|
auto input1 = _mm_load_ps(in);
|
||||||
|
in += 4;
|
||||||
|
auto intermediate0 = _mm_unpacklo_ps(input0, input1);
|
||||||
|
auto intermediate1 = _mm_unpackhi_ps(input0, input1);
|
||||||
|
auto output0 = _mm_unpacklo_ps(intermediate0, intermediate1);
|
||||||
|
auto output1 = _mm_unpackhi_ps(intermediate0, intermediate1);
|
||||||
|
_mm_store_ps(out0, output0);
|
||||||
|
_mm_store_ps(out1, output1);
|
||||||
|
out0 += 4;
|
||||||
|
out1 += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto chanIdx = 0; chanIdx < NumChannels; chanIdx++)
|
||||||
|
{
|
||||||
|
auto* _in = input + 2 * lastAligned + chanIdx;
|
||||||
|
auto* _end = input + numFrames * NumChannels;
|
||||||
|
auto* _out = getChannel(chanIdx) + lastAligned;
|
||||||
|
while (_in < _end)
|
||||||
|
{
|
||||||
|
*_out = *_in;
|
||||||
|
_in += 2;
|
||||||
|
_out += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto chanIdx = 0; chanIdx < NumChannels; chanIdx++)
|
||||||
|
{
|
||||||
|
auto* _in = input + chanIdx;
|
||||||
|
auto* _end = input + numFrames * NumChannels;
|
||||||
|
auto* _out = getChannel(chanIdx);
|
||||||
|
while (_in < _end)
|
||||||
|
{
|
||||||
|
*_out = *_in;
|
||||||
|
_in += NumChannels;
|
||||||
|
_out += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Type* getChannel(int channelIndex) noexcept
|
Type* getChannel(int channelIndex) noexcept
|
||||||
{
|
{
|
||||||
return channels[channelIndex];
|
return channels[channelIndex];
|
||||||
|
|
@ -58,12 +124,22 @@ public:
|
||||||
|
|
||||||
Type* begin(int channelIndex) noexcept
|
Type* begin(int channelIndex) noexcept
|
||||||
{
|
{
|
||||||
return buffer.data() + numFrames * channelIndex;
|
return channels[channelIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
Type* end(int channelIndex) noexcept
|
Type* end(int channelIndex) noexcept
|
||||||
{
|
{
|
||||||
return buffer.data() + numFrames * (channelIndex + 1);
|
return buffer.data() + numFrames * (channelIndex + 1) + padding * channelIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type* alignedBegin(int channelIndex) noexcept
|
||||||
|
{
|
||||||
|
return begin(channelIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type* alignedEnd(int channelIndex) noexcept
|
||||||
|
{
|
||||||
|
return buffer.data() + (channelIndex + 1) * (numFrames + padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type& operator()(int channelIndex, int sampleIndex) noexcept
|
Type& operator()(int channelIndex, int sampleIndex) noexcept
|
||||||
|
|
@ -84,6 +160,7 @@ private:
|
||||||
int padding { 0 };
|
int padding { 0 };
|
||||||
std::array<Type*, NumChannels> channels;
|
std::array<Type*, NumChannels> channels;
|
||||||
Buffer<Type, Alignment> buffer {};
|
Buffer<Type, Alignment> buffer {};
|
||||||
|
Buffer<Type, Alignment> tempBuffer {2 * Alignment};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Type, unsigned int NumChannels = sfz::config::numChannels, unsigned int Alignment = config::defaultAlignment>
|
template<class Type, unsigned int NumChannels = sfz::config::numChannels, unsigned int Alignment = config::defaultAlignment>
|
||||||
|
|
@ -113,11 +190,16 @@ public:
|
||||||
return resizedOK;
|
return resizedOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<VectorOperations op = VectorOperations::standard>
|
||||||
void fill(Type value) noexcept
|
void fill(Type value) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (config::vectorOperation == config::VectorOperations::sse)
|
if constexpr (op == VectorOperations::sse)
|
||||||
{
|
{
|
||||||
|
static_assert(Alignment == 16, "Wrong alignment");
|
||||||
|
const __m128 mmValue = _mm_set_ps1(value);
|
||||||
|
for(auto i = 0; i < NumChannels; ++i)
|
||||||
|
for (auto mm = (__m128*)alignedBegin(i); mm < (__m128*)alignedEnd(i); mm++)
|
||||||
|
_mm_store_ps((float*)mm, mmValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -153,6 +235,16 @@ public:
|
||||||
return buffers[channelIndex].end();
|
return buffers[channelIndex].end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type* alignedBegin(int channelIndex) noexcept
|
||||||
|
{
|
||||||
|
return begin(channelIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type* alignedEnd(int channelIndex) noexcept
|
||||||
|
{
|
||||||
|
return buffers[channelIndex].alignedEnd();
|
||||||
|
}
|
||||||
|
|
||||||
int getNumFrames() const noexcept { return numFrames; }
|
int getNumFrames() const noexcept { return numFrames; }
|
||||||
int getNumChannels() const noexcept { return NumChannels; }
|
int getNumChannels() const noexcept { return NumChannels; }
|
||||||
bool empty() const noexcept { return numFrames == 0; }
|
bool empty() const noexcept { return numFrames == 0; }
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ class Buffer
|
||||||
{
|
{
|
||||||
static_assert(std::is_arithmetic<Type>::value, "Type should be arithmetic");
|
static_assert(std::is_arithmetic<Type>::value, "Type should be arithmetic");
|
||||||
static_assert(Alignment == 0 || Alignment == 4 || Alignment == 8 || Alignment == 16, "Bad alignment value");
|
static_assert(Alignment == 0 || Alignment == 4 || Alignment == 8 || Alignment == 16, "Bad alignment value");
|
||||||
|
static constexpr auto AlignmentMask { Alignment - 1 };
|
||||||
public:
|
public:
|
||||||
Buffer() { }
|
Buffer() { }
|
||||||
Buffer(size_t size)
|
Buffer(size_t size)
|
||||||
|
|
@ -23,7 +24,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tempSize = newSize + Alignment;
|
auto tempSize = newSize + 2 * AlignmentMask; // To ensure that we have leeway at the beginning and at the end
|
||||||
auto* newData = largerData != nullptr ? std::realloc(largerData, tempSize * sizeof(Type)) : std::malloc(tempSize * sizeof(Type));
|
auto* newData = largerData != nullptr ? std::realloc(largerData, tempSize * sizeof(Type)) : std::malloc(tempSize * sizeof(Type));
|
||||||
if (newData == nullptr)
|
if (newData == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -54,6 +55,7 @@ public:
|
||||||
|
|
||||||
Type* begin() noexcept { return data(); }
|
Type* begin() noexcept { return data(); }
|
||||||
Type* end() noexcept { return data() + alignedSize; }
|
Type* end() noexcept { return data() + alignedSize; }
|
||||||
|
Type* alignedEnd() noexcept { return data() + alignedSize; }
|
||||||
// const Type* cbegin() const noexcept { return data(); }
|
// const Type* cbegin() const noexcept { return data(); }
|
||||||
// const Type* cend() const noexcept { return data() + alignedSize; }
|
// const Type* cend() const noexcept { return data() + alignedSize; }
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -26,4 +26,6 @@ namespace config
|
||||||
inline constexpr unsigned int defaultAlignment { 16 };
|
inline constexpr unsigned int defaultAlignment { 16 };
|
||||||
|
|
||||||
inline constexpr VectorOperations vectorOperation { VectorOperations::standard };
|
inline constexpr VectorOperations vectorOperation { VectorOperations::standard };
|
||||||
} // namespace config
|
} // namespace config
|
||||||
|
|
||||||
|
#include <x86intrin.h>
|
||||||
|
|
@ -215,4 +215,301 @@ TEST_CASE("[AudioBuffer/SplitBuffer] Channel alignments (floats)")
|
||||||
channelAlignmentTest<float, 2, 8>(65537);
|
channelAlignmentTest<float, 2, 8>(65537);
|
||||||
channelAlignmentTest<float, 2, 8>(65536);
|
channelAlignmentTest<float, 2, 8>(65536);
|
||||||
channelAlignmentTest<float, 2, 8>(65535);
|
channelAlignmentTest<float, 2, 8>(65535);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[AudioBuffer/SplitBuffer] Channel alignments (doubles)")
|
||||||
|
{
|
||||||
|
channelAlignmentTest<double, 1>(4);
|
||||||
|
channelAlignmentTest<double, 1>(5);
|
||||||
|
channelAlignmentTest<double, 1>(8);
|
||||||
|
channelAlignmentTest<double, 1>(256);
|
||||||
|
channelAlignmentTest<double, 1>(257);
|
||||||
|
channelAlignmentTest<double, 1>(1023);
|
||||||
|
channelAlignmentTest<double, 1>(1024);
|
||||||
|
channelAlignmentTest<double, 1>(65537);
|
||||||
|
channelAlignmentTest<double, 1>(65536);
|
||||||
|
channelAlignmentTest<double, 1>(65535);
|
||||||
|
|
||||||
|
channelAlignmentTest<double, 2>(4);
|
||||||
|
channelAlignmentTest<double, 2>(5);
|
||||||
|
channelAlignmentTest<double, 2>(8);
|
||||||
|
channelAlignmentTest<double, 2>(256);
|
||||||
|
channelAlignmentTest<double, 2>(257);
|
||||||
|
channelAlignmentTest<double, 2>(1023);
|
||||||
|
channelAlignmentTest<double, 2>(1024);
|
||||||
|
channelAlignmentTest<double, 2>(65537);
|
||||||
|
channelAlignmentTest<double, 2>(65536);
|
||||||
|
channelAlignmentTest<double, 2>(65535);
|
||||||
|
|
||||||
|
channelAlignmentTest<double, 3>(4);
|
||||||
|
channelAlignmentTest<double, 3>(5);
|
||||||
|
channelAlignmentTest<double, 3>(8);
|
||||||
|
channelAlignmentTest<double, 3>(256);
|
||||||
|
channelAlignmentTest<double, 3>(257);
|
||||||
|
channelAlignmentTest<double, 3>(1023);
|
||||||
|
channelAlignmentTest<double, 3>(1024);
|
||||||
|
channelAlignmentTest<double, 3>(65537);
|
||||||
|
channelAlignmentTest<double, 3>(65536);
|
||||||
|
channelAlignmentTest<double, 3>(65535);
|
||||||
|
|
||||||
|
channelAlignmentTest<double, 4>(4);
|
||||||
|
channelAlignmentTest<double, 4>(5);
|
||||||
|
channelAlignmentTest<double, 4>(8);
|
||||||
|
channelAlignmentTest<double, 4>(256);
|
||||||
|
channelAlignmentTest<double, 4>(257);
|
||||||
|
channelAlignmentTest<double, 4>(1023);
|
||||||
|
channelAlignmentTest<double, 4>(1024);
|
||||||
|
channelAlignmentTest<double, 4>(65537);
|
||||||
|
channelAlignmentTest<double, 4>(65536);
|
||||||
|
channelAlignmentTest<double, 4>(65535);
|
||||||
|
|
||||||
|
channelAlignmentTest<double, 1, 8>(4);
|
||||||
|
channelAlignmentTest<double, 1, 8>(5);
|
||||||
|
channelAlignmentTest<double, 1, 8>(8);
|
||||||
|
channelAlignmentTest<double, 1, 8>(256);
|
||||||
|
channelAlignmentTest<double, 1, 8>(257);
|
||||||
|
channelAlignmentTest<double, 1, 8>(1023);
|
||||||
|
channelAlignmentTest<double, 1, 8>(1024);
|
||||||
|
channelAlignmentTest<double, 1, 8>(65537);
|
||||||
|
channelAlignmentTest<double, 1, 8>(65536);
|
||||||
|
channelAlignmentTest<double, 1, 8>(65535);
|
||||||
|
|
||||||
|
channelAlignmentTest<double, 2, 8>(4);
|
||||||
|
channelAlignmentTest<double, 2, 8>(5);
|
||||||
|
channelAlignmentTest<double, 2, 8>(8);
|
||||||
|
channelAlignmentTest<double, 2, 8>(256);
|
||||||
|
channelAlignmentTest<double, 2, 8>(257);
|
||||||
|
channelAlignmentTest<double, 2, 8>(1023);
|
||||||
|
channelAlignmentTest<double, 2, 8>(1024);
|
||||||
|
channelAlignmentTest<double, 2, 8>(65537);
|
||||||
|
channelAlignmentTest<double, 2, 8>(65536);
|
||||||
|
channelAlignmentTest<double, 2, 8>(65535);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[AudioBuffer] fills")
|
||||||
|
{
|
||||||
|
SECTION("Floats - 0.0")
|
||||||
|
{
|
||||||
|
AudioBuffer<float> buffer(10);
|
||||||
|
buffer.fill(0.0f);
|
||||||
|
std::array<float, 10> expected;
|
||||||
|
std::fill(expected.begin(), expected.end(), 0.0f);
|
||||||
|
std::array<float, 10> real { 2.0f };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Floats - 1.0")
|
||||||
|
{
|
||||||
|
AudioBuffer<float> buffer(10);
|
||||||
|
buffer.fill(1.0f);
|
||||||
|
std::array<float, 10> expected;
|
||||||
|
std::fill(expected.begin(), expected.end(), 1.0f);
|
||||||
|
std::array<float, 10> real { 2.0f };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Doubles - 0.0")
|
||||||
|
{
|
||||||
|
AudioBuffer<double> buffer(10);
|
||||||
|
buffer.fill(0.0);
|
||||||
|
std::array<double, 10> expected;
|
||||||
|
std::fill(expected.begin(), expected.end(), 0.0);
|
||||||
|
std::array<double, 10> real { 2.0 };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Doubles - 1.0")
|
||||||
|
{
|
||||||
|
AudioBuffer<double> buffer(10);
|
||||||
|
buffer.fill(1.0);
|
||||||
|
std::array<double, 10> expected;
|
||||||
|
std::fill(expected.begin(), expected.end(), 1.0);
|
||||||
|
std::array<double, 10> real { 2.0 };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Floats - 0.0 - SSE")
|
||||||
|
{
|
||||||
|
AudioBuffer<float> buffer(10);
|
||||||
|
buffer.fill<VectorOperations::sse>(0.0f);
|
||||||
|
std::array<float, 10> expected;
|
||||||
|
std::fill(expected.begin(), expected.end(), 0.0f);
|
||||||
|
std::array<float, 10> real { 2.0f };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Floats - 1.0 - SSE")
|
||||||
|
{
|
||||||
|
AudioBuffer<float> buffer(10);
|
||||||
|
buffer.fill<VectorOperations::sse>(1.0f);
|
||||||
|
std::array<float, 10> expected { 1.0f };
|
||||||
|
std::fill(expected.begin(), expected.end(), 1.0f);
|
||||||
|
std::array<float, 10> real { 2.0f };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[SplitAudioBuffer] fills")
|
||||||
|
{
|
||||||
|
SECTION("Floats - 0.0")
|
||||||
|
{
|
||||||
|
SplitAudioBuffer<float> buffer(10);
|
||||||
|
buffer.fill(0.0f);
|
||||||
|
std::array<float, 10> expected;
|
||||||
|
std::fill(expected.begin(), expected.end(), 0.0f);
|
||||||
|
std::array<float, 10> real { 2.0f };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Floats - 1.0")
|
||||||
|
{
|
||||||
|
SplitAudioBuffer<float> buffer(10);
|
||||||
|
buffer.fill(1.0f);
|
||||||
|
std::array<float, 10> expected;
|
||||||
|
std::fill(expected.begin(), expected.end(), 1.0f);
|
||||||
|
std::array<float, 10> real { 2.0f };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Doubles - 0.0")
|
||||||
|
{
|
||||||
|
SplitAudioBuffer<double> buffer(10);
|
||||||
|
buffer.fill(0.0);
|
||||||
|
std::array<double, 10> expected;
|
||||||
|
std::fill(expected.begin(), expected.end(), 0.0);
|
||||||
|
std::array<double, 10> real { 2.0 };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Doubles - 1.0")
|
||||||
|
{
|
||||||
|
SplitAudioBuffer<double> buffer(10);
|
||||||
|
buffer.fill(1.0);
|
||||||
|
std::array<double, 10> expected;
|
||||||
|
std::fill(expected.begin(), expected.end(), 1.0);
|
||||||
|
std::array<double, 10> real { 2.0 };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Floats - 0.0 - SSE")
|
||||||
|
{
|
||||||
|
SplitAudioBuffer<float> buffer(10);
|
||||||
|
buffer.fill<VectorOperations::sse>(0.0f);
|
||||||
|
std::array<float, 10> expected;
|
||||||
|
std::fill(expected.begin(), expected.end(), 0.0f);
|
||||||
|
std::array<float, 10> real { 2.0f };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Floats - 1.0 - SSE")
|
||||||
|
{
|
||||||
|
SplitAudioBuffer<float> buffer(10);
|
||||||
|
buffer.fill<VectorOperations::sse>(1.0f);
|
||||||
|
std::array<float, 10> expected { 1.0f };
|
||||||
|
std::fill(expected.begin(), expected.end(), 1.0f);
|
||||||
|
std::array<float, 10> real { 2.0f };
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
{
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[frameIdx] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[AudioBuffer] Interleave read")
|
||||||
|
{
|
||||||
|
AudioBuffer<float> buffer(8);
|
||||||
|
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 };
|
||||||
|
buffer.readInterleaved(input.data(), 8);
|
||||||
|
std::array<float, 16> real { 0.0f };
|
||||||
|
auto realIdx = 0;
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[realIdx++] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[AudioBuffer] Interleave read -- SSE")
|
||||||
|
{
|
||||||
|
AudioBuffer<float> buffer(8);
|
||||||
|
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 };
|
||||||
|
buffer.readInterleaved<VectorOperations::sse>(input.data(), 8);
|
||||||
|
std::array<float, 16> real { 0.0f };
|
||||||
|
auto realIdx = 0;
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[realIdx++] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[AudioBuffer] Interleave read unaligned end -- SSE")
|
||||||
|
{
|
||||||
|
AudioBuffer<float> buffer(10);
|
||||||
|
std::array<float, 20> input = { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f};
|
||||||
|
std::array<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};
|
||||||
|
buffer.readInterleaved<VectorOperations::sse>(input.data(), 10);
|
||||||
|
std::array<float, 20> real { 0.0f };
|
||||||
|
auto realIdx = 0;
|
||||||
|
for (auto chanIdx = 0; chanIdx < buffer.getNumChannels(); ++chanIdx)
|
||||||
|
for (auto frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx)
|
||||||
|
real[realIdx++] = buffer(chanIdx, frameIdx);
|
||||||
|
REQUIRE( real == expected );
|
||||||
}
|
}
|
||||||
Loading…
Add table
Reference in a new issue