123 lines
5.1 KiB
C++
123 lines
5.1 KiB
C++
#include <boost/test/unit_test.hpp>
|
|
|
|
#include <array>
|
|
#include <thread>
|
|
|
|
#include <sonus.hpp>
|
|
|
|
|
|
namespace {
|
|
|
|
auto fixture() -> sonus::sample_sequence {
|
|
return {.samples = {{.sample_rate = 48000U, .frames = {0.1F, 0.2F, 0.3F, 0.4F}, .loop_start = 2U, .loop_end = 4U}},
|
|
.events = {{.sample = 0U, .start_frame = 2U, .duration_frames = 6U}},
|
|
.release_envelope = {1.0F, 0.5F, 0.0F},
|
|
.duration_frames = 12U,
|
|
.max_voices = 2U,
|
|
.gain = 1.0F};
|
|
}
|
|
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(sequence_sample_clock_and_completion) {
|
|
auto engine = sonus::engine::create({.sample_rate = 48000U, .channels = 1U, .master_volume = 1.0F, .no_device = true});
|
|
BOOST_REQUIRE(engine);
|
|
auto session = engine->play_sequence(fixture());
|
|
BOOST_REQUIRE(session);
|
|
auto output = std::array<std::float32_t, 12>{};
|
|
BOOST_REQUIRE(engine->render(output.data(), output.size()));
|
|
auto expected = std::array<std::float32_t, 12>{0.0F, 0.0F, 0.1F, 0.2F, 0.3F, 0.4F, 0.3F, 0.4F, 0.3F, 0.2F, 0.0F, 0.0F};
|
|
BOOST_TEST(output == expected, boost::test_tools::per_element());
|
|
BOOST_CHECK(session->status() == sonus::playback_status::COMPLETED);
|
|
engine->collect_finished();
|
|
BOOST_CHECK(session->status() == sonus::playback_status::COMPLETED);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(sequence_cancel_replace_and_independent_unisons) {
|
|
auto engine = sonus::engine::create({.channels = 1U, .master_volume = 1.0F, .no_device = true});
|
|
BOOST_REQUIRE(engine);
|
|
auto value = fixture();
|
|
value.events.push_back({.sample = 0U, .start_frame = 2U, .duration_frames = 2U});
|
|
auto first = engine->play_sequence(value);
|
|
BOOST_REQUIRE(first);
|
|
auto output = std::array<std::float32_t, 4>{};
|
|
BOOST_REQUIRE(engine->render(output.data(), output.size()));
|
|
BOOST_TEST(output[2] == 0.2F);
|
|
auto second = engine->play_sequence(value);
|
|
BOOST_REQUIRE(second);
|
|
BOOST_CHECK(first->status() == sonus::playback_status::STOPPED);
|
|
second->stop();
|
|
BOOST_REQUIRE(engine->render(output.data(), output.size()));
|
|
BOOST_TEST(output[2] == 0.0F);
|
|
BOOST_CHECK(second->status() == sonus::playback_status::STOPPED);
|
|
value.max_voices = 1U;
|
|
BOOST_CHECK(!engine->play_sequence(value));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(sequence_clips_overlapping_samples) {
|
|
auto engine = sonus::engine::create({.sample_rate = 48000U, .channels = 2U, .master_volume = 1.0F, .no_device = true});
|
|
BOOST_REQUIRE(engine);
|
|
auto value = sonus::sample_sequence{.samples = {{.sample_rate = 48000U, .frames = {1.0F, -1.0F}, .loop_start = 0U, .loop_end = 2U}},
|
|
.events = {{.sample = 0U, .duration_frames = 2U}, {.sample = 0U, .duration_frames = 2U}},
|
|
.release_envelope = {1.0F, 0.0F},
|
|
.duration_frames = 4U,
|
|
.max_voices = 2U,
|
|
.gain = 1.0F};
|
|
auto session = engine->play_sequence(std::move(value));
|
|
BOOST_REQUIRE(session);
|
|
auto output = std::array<std::float32_t, 8>{};
|
|
BOOST_REQUIRE(engine->render(output.data(), output.size() / 2U));
|
|
auto expected = std::array<std::float32_t, 8>{1.0F, 1.0F, -1.0F, -1.0F, 1.0F, 1.0F, 0.0F, 0.0F};
|
|
BOOST_TEST(output == expected, boost::test_tools::per_element());
|
|
BOOST_CHECK(session->status() == sonus::playback_status::COMPLETED);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(sequence_concurrent_control) {
|
|
auto engine = sonus::engine::create({.channels = 1U, .no_device = true});
|
|
BOOST_REQUIRE(engine);
|
|
auto render = std::thread{[&] {
|
|
auto output = std::array<std::float32_t, 128>{};
|
|
for (auto i = std::uint32_t{}; i < 1000U; ++i) {
|
|
static_cast<void>(engine->render(output.data(), output.size()));
|
|
}
|
|
}};
|
|
for (auto i = std::uint32_t{}; i < 1000U; ++i) {
|
|
auto session = engine->play_sequence(fixture());
|
|
if (session) {
|
|
session->stop();
|
|
}
|
|
engine->collect_finished();
|
|
}
|
|
render.join();
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(sequence_preparation_is_single_use_and_rate_checked) {
|
|
auto prepared = sonus::prepared_sequence::create(fixture(), 48000U);
|
|
BOOST_REQUIRE(prepared);
|
|
auto engine = sonus::engine::create({.channels = 1U, .master_volume = 1.0F, .no_device = true});
|
|
BOOST_REQUIRE(engine);
|
|
auto session = engine->play_sequence(std::move(*prepared));
|
|
BOOST_REQUIRE(session);
|
|
BOOST_CHECK(!engine->play_sequence(std::move(*prepared)));
|
|
auto output = std::array<std::float32_t, 12>{};
|
|
for (auto i = std::size_t{}; i < output.size(); ++i) {
|
|
BOOST_REQUIRE(engine->render(output.data() + i, 1U));
|
|
}
|
|
BOOST_TEST(output[8] == 0.3F);
|
|
BOOST_CHECK(session->status() == sonus::playback_status::COMPLETED);
|
|
auto invalid = fixture();
|
|
invalid.samples[0].loop_end = 0U;
|
|
BOOST_CHECK(!sonus::prepared_sequence::create(invalid, 48000U));
|
|
BOOST_CHECK(!sonus::prepared_sequence::create(fixture(), 44100U));
|
|
auto silent = fixture();
|
|
silent.samples.clear();
|
|
silent.events.clear();
|
|
auto quiet = engine->play_sequence(std::move(silent));
|
|
BOOST_REQUIRE(quiet);
|
|
BOOST_REQUIRE(engine->render(output.data(), output.size()));
|
|
BOOST_CHECK(quiet->status() == sonus::playback_status::COMPLETED);
|
|
for (auto value : output) {
|
|
BOOST_TEST(value == 0.0F);
|
|
}
|
|
}
|