@@ -9,6 +9,7 @@
|
||||
#include <vamp_zero/notation.hpp>
|
||||
#include <vamp_zero/page_control.hpp>
|
||||
#include <vamp_zero/performance.hpp>
|
||||
#include <vamp_zero/score.hpp>
|
||||
|
||||
|
||||
namespace {
|
||||
@@ -29,7 +30,7 @@ auto state(bool metronome = false, bool backing = false) -> vamp_zero::app_state
|
||||
auto audio = vamp_zero::parse_audio_assets(read("manifest.audio"));
|
||||
BOOST_REQUIRE(audio);
|
||||
catalog->audio_assets = *audio;
|
||||
catalog->parts.push_back({.id = "score", .title = "Fixture", .part = "Vocal", .total_pages = 2, .song_id = "fixture"});
|
||||
catalog->parts.push_back({.id = "score", .title = "Fixture", .part = "Vocal", .total_pages = 2, .song_id = "fixture", .playback_pages = 3});
|
||||
catalog->groups.push_back({.title = "Fixture", .parts = {0}});
|
||||
auto result = vamp_zero::app_state{.catalog = catalog, .mode = vamp_zero::app_mode::PERFORMANCE_SCORE};
|
||||
result.selected_song_index = 1;
|
||||
@@ -139,6 +140,94 @@ BOOST_AUTO_TEST_CASE(stale_performance_updates_do_not_navigate_or_restart) {
|
||||
BOOST_CHECK(control.snapshot().mode == vamp_zero::app_mode::PERFORMANCE_PART_MENU);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(playback_advances_one_system_and_highlights_each_measure) {
|
||||
auto document = score();
|
||||
BOOST_TEST(document.pages.size() == 2U);
|
||||
BOOST_TEST(document.playback_pages.size() == 3U);
|
||||
for (auto bpm : {60U, 90U, 120U}) {
|
||||
auto count_in = vamp_zero::frame_at({4, 1}, bpm);
|
||||
BOOST_CHECK(!vamp_zero::performance_at(document, count_in - 1, bpm).measure);
|
||||
for (std::size_t m = 0; m < document.measure_count; ++m) {
|
||||
auto frame = count_in + vamp_zero::frame_at(document.measure_boundaries[m], bpm);
|
||||
auto now = vamp_zero::performance_at(document, frame, bpm);
|
||||
BOOST_REQUIRE(now.measure);
|
||||
BOOST_TEST(*now.measure == m + 1);
|
||||
BOOST_TEST(now.page == std::min(m, std::size_t{2}));
|
||||
if (m) {
|
||||
BOOST_TEST(*vamp_zero::performance_at(document, frame - 1, bpm).measure == m);
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_TEST(document.playback_pages.back().systems.size() == 1U);
|
||||
auto app = state(true);
|
||||
auto control = vamp_zero::control_state{{}, app};
|
||||
control.update_performance(1, 2, "Sustain", app.catalog, 3);
|
||||
auto revision = control.snapshot().input_revision;
|
||||
control.update_performance(1, 2, "Sustain", app.catalog, 4);
|
||||
BOOST_TEST(*control.snapshot().active_measure == 4U);
|
||||
BOOST_TEST(control.snapshot().input_revision == revision + 1);
|
||||
auto remote = vamp_zero::remote_display_text(control.snapshot());
|
||||
BOOST_TEST(remote.find("page=3\npages=3") != std::string::npos);
|
||||
control.finish_playback(1, "failed", app.catalog);
|
||||
BOOST_CHECK(!control.snapshot().active_measure);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fractional_pickups_and_unequal_measures_use_exact_boundaries) {
|
||||
auto document = score();
|
||||
document.measure_boundaries = {{0, 1}, {1, 2}, {7, 2}, {41, 6}, {65, 6}, {89, 6}};
|
||||
document.playback_pages[1].start_beat = {1, 2};
|
||||
document.playback_pages[2].start_beat = {7, 2};
|
||||
document.duration = {89, 6};
|
||||
for (auto bpm : {60U, 110U, 120U}) {
|
||||
for (std::size_t i = 1; i < document.measure_count; ++i) {
|
||||
auto frame = vamp_zero::frame_at({4, 1}, bpm) + vamp_zero::frame_at(document.measure_boundaries[i], bpm);
|
||||
BOOST_TEST(*vamp_zero::performance_at(document, frame - 1, bpm).measure == i);
|
||||
BOOST_TEST(*vamp_zero::performance_at(document, frame, bpm).measure == i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(highlight_geometry_follows_letterboxed_page_and_active_view) {
|
||||
auto document = score();
|
||||
for (auto bounds : {luma::rect{0, 0, 976, 484}, luma::rect{10, 20, 488, 484}, luma::rect{10, 20, 1952, 968}}) {
|
||||
auto image = vamp_zero::page_rectangle(bounds);
|
||||
auto a = vamp_zero::measure_highlight(document.playback_pages[0], 2, image);
|
||||
auto b = vamp_zero::measure_highlight(document.playback_pages[1], 2, image);
|
||||
BOOST_REQUIRE(a);
|
||||
BOOST_REQUIRE(b);
|
||||
auto scale = image.width / 976.F;
|
||||
BOOST_TEST(b->x == image.x + 27.F * scale);
|
||||
BOOST_TEST(b->y == image.y + 67.F * scale);
|
||||
BOOST_TEST(a->y - b->y == 220.F * scale);
|
||||
BOOST_TEST(b->width == 18.F * scale);
|
||||
BOOST_CHECK(!vamp_zero::measure_highlight(document.playback_pages[0], {}, image));
|
||||
BOOST_CHECK(!vamp_zero::measure_highlight(document.playback_pages[0], 5, image));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(playback_parser_requires_complete_views_and_safe_label_geometry) {
|
||||
auto original = boost::json::parse(read("score.json"));
|
||||
for (auto fault : {"missing", "pair", "label", "bounds", "time", "path"}) {
|
||||
auto value = original;
|
||||
auto &presentation = value.at("presentation").as_object();
|
||||
auto &views = presentation.at("playback_pages").as_array();
|
||||
if (std::string_view{fault} == "missing") {
|
||||
presentation.erase("playback_pages");
|
||||
} else if (std::string_view{fault} == "pair") {
|
||||
views[1] = views[0];
|
||||
} else if (std::string_view{fault} == "label") {
|
||||
views[0].at("systems").as_array()[0].at("labels").as_array()[0].at("measure") = 99;
|
||||
} else if (std::string_view{fault} == "bounds") {
|
||||
views[0].at("systems").as_array()[0].at("labels").as_array()[0].at("bounds").as_array()[2] = 1000;
|
||||
} else if (std::string_view{fault} == "time") {
|
||||
views[1].at("start_beat").at("numerator") = 3;
|
||||
} else {
|
||||
views[1].at("path") = "../outside.png";
|
||||
}
|
||||
BOOST_CHECK_MESSAGE(!vamp_zero::parse_notation_document(boost::json::serialize(value), "score.json"), fault);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(recording_transport_cancellation_does_not_advance_clock) {
|
||||
auto prepared = vamp_zero::prepare_performance(score(), state(true), VAMP_TEST_PERFORMANCE_ASSETS_DIR, 1.F);
|
||||
BOOST_REQUIRE(prepared);
|
||||
|
||||
Reference in New Issue
Block a user