134 lines
5.8 KiB
C++
134 lines
5.8 KiB
C++
#include <boost/test/unit_test.hpp>
|
|
#include <boost/json.hpp>
|
|
|
|
#include <array>
|
|
#include <fstream>
|
|
#include <iterator>
|
|
#include <thread>
|
|
|
|
#include <vamp_zero/audio.hpp>
|
|
#include <vamp_zero/config.hpp>
|
|
#include <vamp_zero/playback.hpp>
|
|
#include <vamp_zero/portal.hpp>
|
|
|
|
|
|
namespace {
|
|
|
|
auto playback_score() -> vamp_zero::score_document {
|
|
auto input = std::ifstream{std::string{VAMP_TEST_PLAYBACK_ASSETS_DIR} + "/score.json"};
|
|
auto score = vamp_zero::score_document{};
|
|
score.source_json = std::string{std::istreambuf_iterator<std::char_t>{input}, std::istreambuf_iterator<std::char_t>{}};
|
|
return score;
|
|
}
|
|
|
|
auto performance_state() -> vamp_zero::app_state {
|
|
auto catalog = std::make_shared<vamp_zero::catalog>();
|
|
catalog->performance.parts.push_back({.id = "part", .title = "Song", .part = "Vocal", .total_pages = 2U});
|
|
catalog->performance.groups.push_back({.title = "Song", .parts = {0U}});
|
|
auto state = vamp_zero::app_state{};
|
|
state.catalog = std::move(catalog);
|
|
state.mode = vamp_zero::app_mode::PERFORMANCE_SCORE;
|
|
state.selected_song_index = 1U;
|
|
state.selected_part_index = 1U;
|
|
state.active_part_id = "part";
|
|
state.score_session = 42U;
|
|
state.audio.playback_enabled = true;
|
|
return state;
|
|
}
|
|
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(generated_audio_plays_at_menu_bpm) {
|
|
auto score = playback_score();
|
|
auto normal = vamp_zero::prepare_playback(score, VAMP_TEST_PLAYBACK_ASSETS_DIR, 120U);
|
|
auto slow = vamp_zero::prepare_playback(score, VAMP_TEST_PLAYBACK_ASSETS_DIR, 60U);
|
|
BOOST_REQUIRE_MESSAGE(normal, (normal ? "" : normal.error().describe()));
|
|
BOOST_REQUIRE(slow);
|
|
BOOST_TEST(normal->duration_frames == 96000U);
|
|
BOOST_TEST(slow->duration_frames == normal->duration_frames * 2U);
|
|
BOOST_TEST(normal->samples[0].frames == slow->samples[0].frames, boost::test_tools::per_element());
|
|
auto engine = sonus::engine::create({.sample_rate = 48000U, .channels = 1U, .no_device = true});
|
|
BOOST_REQUIRE(engine);
|
|
auto session = engine->play_sequence(std::move(*normal));
|
|
BOOST_REQUIRE(session);
|
|
auto output = std::array<std::float32_t, 480>{};
|
|
auto energy = std::float32_t{};
|
|
for (auto block = std::uint32_t{}; block < 200U; ++block) {
|
|
BOOST_REQUIRE(engine->render(output.data(), output.size()));
|
|
for (auto value : output) {
|
|
energy += value * value;
|
|
}
|
|
if (block == 150U) {
|
|
BOOST_CHECK(session->status() == sonus::playback_status::PLAYING);
|
|
}
|
|
}
|
|
BOOST_TEST(energy > 0.1F);
|
|
BOOST_CHECK(session->status() == sonus::playback_status::COMPLETED);
|
|
BOOST_REQUIRE(vamp_zero::validate_playback_assets(score, VAMP_TEST_PLAYBACK_ASSETS_DIR));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(playback_completion_is_session_guarded) {
|
|
auto state = vamp_zero::control_state{{}, performance_state()};
|
|
state.finish_playback(41U);
|
|
BOOST_CHECK(state.snapshot().mode == vamp_zero::app_mode::PERFORMANCE_SCORE);
|
|
state.finish_playback(42U, {}, std::make_shared<vamp_zero::catalog const>());
|
|
BOOST_CHECK(state.snapshot().mode == vamp_zero::app_mode::PERFORMANCE_SCORE);
|
|
state.finish_playback(42U, "sample missing");
|
|
BOOST_CHECK(state.snapshot().mode == vamp_zero::app_mode::PERFORMANCE_SCORE);
|
|
BOOST_TEST(state.snapshot().audio.playback_error == "sample missing");
|
|
state.finish_playback(42U);
|
|
BOOST_CHECK(state.snapshot().mode == vamp_zero::app_mode::PERFORMANCE_PART_MENU);
|
|
BOOST_TEST(state.snapshot().selected_part_index == 1U);
|
|
BOOST_TEST(state.snapshot().select_count == 0U);
|
|
state.apply(vamp_protocol::page_command::SELECT);
|
|
BOOST_TEST(state.snapshot().score_session == 43U);
|
|
state.finish_playback(42U);
|
|
BOOST_CHECK(state.snapshot().mode == vamp_zero::app_mode::PERFORMANCE_SCORE);
|
|
auto disabled = performance_state();
|
|
disabled.audio.playback_enabled = false;
|
|
auto quiet = vamp_zero::control_state{{}, disabled};
|
|
quiet.finish_playback(42U);
|
|
BOOST_CHECK(quiet.snapshot().mode == vamp_zero::app_mode::PERFORMANCE_SCORE);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(playback_worker_discards_canceled_preparation_and_reports_errors_once) {
|
|
auto engine = sonus::engine::create({.no_device = true});
|
|
BOOST_REQUIRE(engine);
|
|
auto audio = vamp_zero::audio_controller{{}, std::move(*engine)};
|
|
auto state = performance_state();
|
|
auto invalid = std::make_shared<vamp_zero::score_document>();
|
|
invalid->id = "part";
|
|
invalid->source_json = "{}";
|
|
auto loaded = vamp_zero::score_load_state{.document = invalid};
|
|
BOOST_CHECK(!audio.tick(state, loaded, VAMP_TEST_PLAYBACK_ASSETS_DIR));
|
|
state.mode = vamp_zero::app_mode::PERFORMANCE_PART_MENU;
|
|
for (auto attempt = std::uint32_t{}; attempt < 100U; ++attempt) {
|
|
BOOST_CHECK(!audio.tick(state, {}, VAMP_TEST_PLAYBACK_ASSETS_DIR));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
|
}
|
|
state.mode = vamp_zero::app_mode::PERFORMANCE_SCORE;
|
|
++state.score_session;
|
|
auto reported = std::bool_t{};
|
|
for (auto attempt = std::uint32_t{}; attempt < 1000U && !reported; ++attempt) {
|
|
if (auto result = audio.tick(state, loaded, VAMP_TEST_PLAYBACK_ASSETS_DIR)) {
|
|
BOOST_CHECK(!*result);
|
|
reported = true;
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
|
}
|
|
BOOST_TEST(reported);
|
|
BOOST_CHECK(!audio.tick(state, loaded, VAMP_TEST_PLAYBACK_ASSETS_DIR));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(playback_rejects_legacy_config_and_invalid_assets) {
|
|
auto legacy = vamp_zero::parse_config(boost::json::object{{"audio", {{"track_enabled", true}}}});
|
|
BOOST_REQUIRE(!legacy);
|
|
BOOST_TEST(std::string{legacy.error().message()}.find("use audio.playback_enabled") != std::string::npos);
|
|
BOOST_CHECK(!vamp_zero::parse_config(boost::json::object{{"audio", {{"track_enabled", true}, {"playback_enabled", false}}}}));
|
|
auto score = playback_score();
|
|
BOOST_CHECK(!vamp_zero::prepare_playback(score, "/missing-vamp-assets", 120U));
|
|
BOOST_CHECK(!vamp_zero::prepare_playback(score, VAMP_TEST_PLAYBACK_ASSETS_DIR, 0U));
|
|
score.source_json = "{}";
|
|
BOOST_CHECK(!vamp_zero::prepare_playback(score, VAMP_TEST_PLAYBACK_ASSETS_DIR, 120U));
|
|
}
|