2020-01-25 10:04:31 +01:00
|
|
|
// SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
|
2020-01-25 13:13:07 +01:00
|
|
|
// 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
|
2019-09-06 22:16:09 +02:00
|
|
|
|
2020-01-18 17:35:27 +01:00
|
|
|
#include "sfizz/AudioBuffer.h"
|
|
|
|
|
#include "sfizz/AudioSpan.h"
|
2019-09-06 22:16:09 +02:00
|
|
|
#include "catch2/catch.hpp"
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
using namespace Catch::literals;
|
|
|
|
|
|
|
|
|
|
TEST_CASE("[AudioBuffer] Empty buffers")
|
|
|
|
|
{
|
2019-09-25 23:48:52 +02:00
|
|
|
sfz::AudioBuffer<float> floatBuffer;
|
2019-09-06 22:16:09 +02:00
|
|
|
REQUIRE(floatBuffer.empty());
|
|
|
|
|
REQUIRE(floatBuffer.getNumFrames() == 0);
|
2019-09-25 23:48:52 +02:00
|
|
|
sfz::AudioBuffer<double> doubleBuffer;
|
2019-09-06 22:16:09 +02:00
|
|
|
REQUIRE(doubleBuffer.empty());
|
|
|
|
|
REQUIRE(doubleBuffer.getNumFrames() == 0);
|
2019-09-25 23:48:52 +02:00
|
|
|
sfz::AudioBuffer<int> intBuffer;
|
2019-09-06 22:16:09 +02:00
|
|
|
REQUIRE(intBuffer.empty());
|
|
|
|
|
REQUIRE(intBuffer.getNumFrames() == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("[AudioBuffer] Non-empty")
|
|
|
|
|
{
|
2019-09-25 23:48:52 +02:00
|
|
|
sfz::AudioBuffer<float> floatBuffer(1, 10);
|
2019-09-06 22:16:09 +02:00
|
|
|
REQUIRE(!floatBuffer.empty());
|
|
|
|
|
REQUIRE(floatBuffer.getNumFrames() == 10);
|
|
|
|
|
REQUIRE(floatBuffer.getNumChannels() == 1);
|
2019-09-25 23:48:52 +02:00
|
|
|
sfz::AudioBuffer<double> doubleBuffer(2, 10);
|
2019-09-06 22:16:09 +02:00
|
|
|
REQUIRE(!doubleBuffer.empty());
|
|
|
|
|
REQUIRE(doubleBuffer.getNumFrames() == 10);
|
|
|
|
|
REQUIRE(doubleBuffer.getNumChannels() == 2);
|
2019-09-25 23:48:52 +02:00
|
|
|
sfz::AudioBuffer<int> intBuffer(1, 10);
|
2019-09-06 22:16:09 +02:00
|
|
|
REQUIRE(!intBuffer.empty());
|
|
|
|
|
REQUIRE(intBuffer.getNumFrames() == 10);
|
|
|
|
|
REQUIRE(intBuffer.getNumChannels() == 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("[AudioBuffer] Access")
|
|
|
|
|
{
|
|
|
|
|
const int size { 5 };
|
2019-09-25 23:48:52 +02:00
|
|
|
sfz::AudioBuffer<float> buffer(2, size);
|
2019-09-06 22:16:09 +02:00
|
|
|
for (size_t frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx) {
|
2020-01-05 00:19:08 +01:00
|
|
|
buffer.getSample(0, frameIdx) = static_cast<float>(buffer.getNumFrames()) + frameIdx;
|
|
|
|
|
buffer.getSample(1, frameIdx) = static_cast<float>(buffer.getNumFrames()) - frameIdx;
|
2019-09-06 22:16:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (size_t frameIdx = 0; frameIdx < buffer.getNumFrames(); ++frameIdx) {
|
2020-01-05 00:19:08 +01:00
|
|
|
REQUIRE(buffer.getSample(0, frameIdx) == static_cast<float>(buffer.getNumFrames()) + frameIdx);
|
|
|
|
|
REQUIRE(buffer(0, frameIdx) == static_cast<float>(buffer.getNumFrames()) + frameIdx);
|
|
|
|
|
REQUIRE(buffer.getSample(1, frameIdx) == static_cast<float>(buffer.getNumFrames()) - frameIdx);
|
|
|
|
|
REQUIRE(buffer(1, frameIdx) == static_cast<float>(buffer.getNumFrames()) - frameIdx);
|
2019-09-06 22:16:09 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("[AudioBuffer] Iterators")
|
|
|
|
|
{
|
|
|
|
|
const int size { 256 };
|
|
|
|
|
const float fillValue { 2.0f };
|
2019-09-25 23:48:52 +02:00
|
|
|
sfz::AudioBuffer<float> buffer(2, size);
|
2019-09-06 22:16:09 +02:00
|
|
|
std::fill(buffer.channelWriter(0), buffer.channelWriterEnd(0), fillValue);
|
|
|
|
|
std::fill(buffer.channelWriter(1), buffer.channelWriterEnd(1), fillValue);
|
|
|
|
|
|
2020-03-10 18:02:00 +01:00
|
|
|
REQUIRE(std::all_of(buffer.channelReader(0), buffer.channelReaderEnd(0), [fillValue](float value) { return value == fillValue; }));
|
|
|
|
|
REQUIRE(std::all_of(buffer.channelReader(1), buffer.channelReaderEnd(1), [fillValue](float value) { return value == fillValue; }));
|
2019-09-06 22:16:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("[AudioSpan] Constructions")
|
|
|
|
|
{
|
|
|
|
|
const int size { 256 };
|
|
|
|
|
const float fillValue { 2.0f };
|
2019-09-25 23:48:52 +02:00
|
|
|
sfz::AudioBuffer<float> buffer(2, size);
|
2019-09-06 22:16:09 +02:00
|
|
|
std::fill(buffer.channelWriter(0), buffer.channelWriterEnd(0), fillValue);
|
|
|
|
|
std::fill(buffer.channelWriter(1), buffer.channelWriterEnd(1), fillValue);
|
|
|
|
|
|
2019-09-25 23:48:52 +02:00
|
|
|
sfz::AudioSpan<float> span { buffer };
|
|
|
|
|
sfz::AudioSpan<const float> constSpan { buffer };
|
|
|
|
|
sfz::AudioSpan<float> manualSpan { { buffer.channelWriter(0), buffer.channelWriter(1) }, buffer.getNumFrames() };
|
|
|
|
|
sfz::AudioSpan<const float> manualConstSpan { { buffer.channelReader(0), buffer.channelReader(1) }, buffer.getNumFrames() };
|
|
|
|
|
sfz::AudioSpan<float> manualSpan2 { {buffer.getSpan(0), buffer.getSpan(1) } };
|
2020-01-05 00:19:08 +01:00
|
|
|
sfz::AudioSpan<const float> manualConstSpan2 { { buffer.getConstSpan(0), buffer.getConstSpan(1) } };
|
|
|
|
|
}
|
2020-06-11 03:36:49 +02:00
|
|
|
|
|
|
|
|
TEST_CASE("[AudioBuffer] Padding")
|
|
|
|
|
{
|
|
|
|
|
constexpr size_t channels = 2;
|
|
|
|
|
constexpr size_t numFrames = 7777;
|
|
|
|
|
constexpr unsigned alignment = 32;
|
|
|
|
|
constexpr size_t padLeft = 13;
|
|
|
|
|
constexpr size_t padRight = 51;
|
|
|
|
|
|
|
|
|
|
sfz::AudioBuffer<float, channels, alignment, padLeft, padRight> padded { channels, numFrames };
|
|
|
|
|
|
|
|
|
|
// ensure padding to be extended to respect alignment
|
|
|
|
|
constexpr size_t extendedPadLeft = padded.PaddingLeft;
|
|
|
|
|
REQUIRE(extendedPadLeft == 32);
|
|
|
|
|
|
|
|
|
|
// ensure access functions to return consistent addresses with offset
|
|
|
|
|
for (size_t c = 0; c < channels; ++c) {
|
|
|
|
|
REQUIRE(padded.getSpan(c).data() == &padded.getSample(c, 0));
|
|
|
|
|
REQUIRE(padded.getConstSpan(c).data() == &padded.getSample(c, 0));
|
|
|
|
|
REQUIRE(padded.getSpan(c).data() == padded.channelReader(c));
|
|
|
|
|
REQUIRE(padded.getSpan(c).data() == padded.channelWriter(c));
|
|
|
|
|
REQUIRE(padded.getSpan(c).end() == padded.channelReaderEnd(c));
|
|
|
|
|
REQUIRE(padded.getSpan(c).end() == padded.channelWriterEnd(c));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
padded.clear();
|
|
|
|
|
|
|
|
|
|
// ensure all padding areas to be accessible and zero after clearing
|
|
|
|
|
for (size_t c = 0; c < channels; ++c) {
|
|
|
|
|
absl::Span<const float> leftSpan { padded.getSpan(0).data() - extendedPadLeft, extendedPadLeft };
|
|
|
|
|
absl::Span<const float> rightSpan { padded.getSpan(0).end(), padRight };
|
|
|
|
|
REQUIRE(std::all_of(leftSpan.begin(), leftSpan.end(), [](float value) { return value == 0.0f; }));
|
|
|
|
|
REQUIRE(std::all_of(rightSpan.begin(), rightSpan.end(), [](float value) { return value == 0.0f; }));
|
|
|
|
|
}
|
|
|
|
|
}
|