Tab Generation
ci / checks (push) Successful in 1h19m14s

This commit is contained in:
khodowany
2026-09-20 16:20:43 -05:00
parent 68ded4d8c8
commit cf7c0c010c
423 changed files with 1422 additions and 1332 deletions
+47 -76
View File
@@ -78,15 +78,15 @@ auto clamp_state(vamp_zero::app_state state) -> vamp_zero::app_state {
state.selected_part_index = 0U;
}
state.selected_practice_exercise_index = std::min(state.selected_practice_exercise_index, state.catalog->practice.exercises.size());
state.selected_practice_key_index = std::min(state.selected_practice_key_index, practice_key_row_count(state) - 1U);
state.selected_practice_part_index = std::min(state.selected_practice_part_index, practice_part_row_count(state) - 1U);
if (state.mode == vamp_zero::app_mode::PERFORMANCE_PART_MENU && selected_group(state) == nullptr) {
state.mode = vamp_zero::app_mode::PERFORMANCE_SONG_MENU;
}
if (state.mode == vamp_zero::app_mode::PRACTICE_KEY_MENU) {
if (state.mode == vamp_zero::app_mode::PRACTICE_PART_MENU) {
auto const *exercise = selected_practice_exercise(state);
if (exercise == nullptr || exercise->variants.empty()) {
if (exercise == nullptr || exercise->parts.empty()) {
state.mode = vamp_zero::app_mode::PRACTICE_EXERCISE_MENU;
state.selected_practice_key_index = 0U;
state.selected_practice_part_index = 0U;
}
}
if (state.mode == vamp_zero::app_mode::PERFORMANCE_SCORE && active_part(state) == nullptr) {
@@ -100,8 +100,8 @@ auto clamp_state(vamp_zero::app_state state) -> vamp_zero::app_state {
state.mode = vamp_zero::app_mode::PRACTICE_EXERCISE_MENU;
state.active_practice_id.clear();
state.page_index = 0;
} else if (selected_practice_variant(state, *exercise) == nullptr) {
state.mode = vamp_zero::app_mode::PRACTICE_KEY_MENU;
} else if (selected_practice_part(state, *exercise) == nullptr) {
state.mode = vamp_zero::app_mode::PRACTICE_PART_MENU;
state.active_practice_id.clear();
state.page_index = 0;
}
@@ -155,30 +155,16 @@ auto part_json(vamp_zero::library_part const &part) -> boost::json::object {
}
auto exercise_json(vamp_zero::practice_exercise const &exercise) -> boost::json::object {
auto variants = boost::json::array{};
for (auto const &variant : exercise.variants) {
auto item = boost::json::object{};
item["id"] = variant.id;
item["key_signature"] = variant.key_signature;
item["source_path"] = variant.source_path;
item["measures"] = static_cast<std::uint64_t>(variant.measure_count);
item["pages"] = static_cast<std::uint64_t>(variant.total_pages);
variants.push_back(std::move(item));
auto parts = boost::json::array{};
for (auto const &part : exercise.parts) {
parts.push_back(part_json(part));
}
auto result = boost::json::object{};
result["id"] = exercise.id;
result["title"] = exercise.title;
result["composer"] = exercise.composer;
result["authored_key_signature"] = exercise.authored_key_signature;
if (!exercise.variants.empty()) {
auto const &primary = exercise.variants.front();
result["key_signature"] = primary.key_signature;
result["source_path"] = primary.source_path;
result["measures"] = static_cast<std::uint64_t>(primary.measure_count);
result["pages"] = static_cast<std::uint64_t>(primary.total_pages);
}
result["variant_count"] = static_cast<std::uint64_t>(exercise.variants.size());
result["variants"] = std::move(variants);
result["part_count"] = static_cast<std::uint64_t>(exercise.parts.size());
result["parts"] = std::move(parts);
return result;
}
@@ -207,36 +193,19 @@ auto practice_json(vamp_zero::app_state const &state) -> boost::json::object {
for (auto const &exercise : state.catalog->practice.exercises) {
exercises.push_back(exercise_json(exercise));
}
auto keys = boost::json::array{};
for (auto key : vamp_zero::practice_key_names()) {
keys.push_back(boost::json::value{std::string{key}});
}
auto selection = boost::json::object{};
selection["exercise_row_index"] = static_cast<std::uint64_t>(state.selected_practice_exercise_index);
selection["key_row_index"] = static_cast<std::uint64_t>(state.selected_practice_key_index);
selection["part_row_index"] = static_cast<std::uint64_t>(state.selected_practice_part_index);
if (auto const *exercise = selected_practice_exercise(state); exercise != nullptr) {
selection["exercise"] = exercise_json(*exercise);
auto variant = selected_practice_variant(state, *exercise);
if (variant != nullptr) {
auto item = boost::json::object{};
item["id"] = variant->id;
item["key_signature"] = variant->key_signature;
item["source_path"] = variant->source_path;
item["measures"] = static_cast<std::uint64_t>(variant->measure_count);
item["pages"] = static_cast<std::uint64_t>(variant->total_pages);
selection["variant"] = std::move(item);
}
}
if (auto const *exercise = selected_practice_exercise(state); exercise != nullptr) {
if (auto key = selected_practice_key(state, *exercise)) {
selection["key"] = std::string{*key};
auto practice_part = selected_practice_part(state, *exercise);
if (practice_part != nullptr) {
selection["part"] = part_json(*practice_part);
}
}
auto practice = boost::json::object{};
practice["exercise_count"] = static_cast<std::uint64_t>(state.catalog->practice.exercises.size());
practice["exercises"] = std::move(exercises);
practice["key_count"] = static_cast<std::uint64_t>(vamp_zero::practice_key_names().size());
practice["keys"] = std::move(keys);
practice["selection"] = std::move(selection);
return practice;
}
@@ -285,7 +254,7 @@ auto vamp_zero::apply_app_command(vamp_zero::app_state state, vamp_protocol::pag
} else if (state.selected_main_menu_index == main_menu_practice) {
state.mode = vamp_zero::app_mode::PRACTICE_EXERCISE_MENU;
state.selected_practice_exercise_index = 0;
state.selected_practice_key_index = 0;
state.selected_practice_part_index = 0;
state.active_practice_id.clear();
state.page_index = 0;
} else if (state.selected_main_menu_index == main_menu_playback) {
@@ -347,10 +316,10 @@ auto vamp_zero::apply_app_command(vamp_zero::app_state state, vamp_protocol::pag
case vamp_zero::app_mode::PRACTICE_EXERCISE_MENU:
if (command == vamp_protocol::page_command::NEXT) {
state.selected_practice_exercise_index = wrap_next(state.selected_practice_exercise_index, menu_row_count(state.catalog->practice.exercises.size()));
state.selected_practice_key_index = 0;
state.selected_practice_part_index = 0;
} else if (command == vamp_protocol::page_command::PREVIOUS) {
state.selected_practice_exercise_index = wrap_previous(state.selected_practice_exercise_index, menu_row_count(state.catalog->practice.exercises.size()));
state.selected_practice_key_index = 0;
state.selected_practice_part_index = 0;
} else if (state.selected_practice_exercise_index == 0U) {
state.mode = vamp_zero::app_mode::MAIN_MENU;
state.active_practice_id.clear();
@@ -359,24 +328,24 @@ auto vamp_zero::apply_app_command(vamp_zero::app_state state, vamp_protocol::pag
state.active_part_id.clear();
state.active_practice_id.clear();
state.page_index = 0;
state.mode = vamp_zero::app_mode::PRACTICE_KEY_MENU;
state.selected_practice_key_index = 0;
state.mode = vamp_zero::app_mode::PRACTICE_PART_MENU;
state.selected_practice_part_index = 0;
}
return clamp_state(std::move(state));
case vamp_zero::app_mode::PRACTICE_KEY_MENU:
case vamp_zero::app_mode::PRACTICE_PART_MENU:
if (auto const *exercise = selected_practice_exercise(state);
exercise != nullptr) {
if (command == vamp_protocol::page_command::NEXT) {
state.selected_practice_key_index =
wrap_next(state.selected_practice_key_index, menu_row_count(exercise->variants.size()));
state.selected_practice_part_index =
wrap_next(state.selected_practice_part_index, menu_row_count(exercise->parts.size()));
} else if (command == vamp_protocol::page_command::PREVIOUS) {
state.selected_practice_key_index =
wrap_previous(state.selected_practice_key_index, menu_row_count(exercise->variants.size()));
} else if (state.selected_practice_key_index == 0U) {
state.selected_practice_part_index =
wrap_previous(state.selected_practice_part_index, menu_row_count(exercise->parts.size()));
} else if (state.selected_practice_part_index == 0U) {
state.mode = vamp_zero::app_mode::PRACTICE_EXERCISE_MENU;
state.active_practice_id.clear();
state.page_index = 0;
} else if (selected_practice_variant(state, *exercise) != nullptr) {
} else if (selected_practice_part(state, *exercise) != nullptr) {
state.active_practice_id = exercise->id;
state.active_part_id.clear();
state.page_index = 0;
@@ -388,14 +357,14 @@ auto vamp_zero::apply_app_command(vamp_zero::app_state state, vamp_protocol::pag
return clamp_state(std::move(state));
case vamp_zero::app_mode::PRACTICE_SCORE:
if (auto const *exercise = active_practice(state); exercise != nullptr) {
auto const *variant = selected_practice_variant(state, *exercise);
auto const *practice_part = selected_practice_part(state, *exercise);
if (command == vamp_protocol::page_command::NEXT) {
auto pages = variant == nullptr ? 0U : variant->total_pages;
auto pages = practice_part == nullptr ? 0U : practice_part->total_pages;
state.page_index = std::min(state.page_index + 1U, pages == 0U ? 0U : pages - 1U);
} else if (command == vamp_protocol::page_command::PREVIOUS) {
state.page_index = state.page_index == 0U ? 0U : state.page_index - 1U;
} else {
state.mode = vamp_zero::app_mode::PRACTICE_KEY_MENU;
state.mode = vamp_zero::app_mode::PRACTICE_PART_MENU;
state.active_practice_id.clear();
state.page_index = 0;
}
@@ -429,14 +398,16 @@ auto vamp_zero::app_status_json(vamp_zero::app_state const &state) -> boost::jso
}
} else if (state.mode == vamp_zero::app_mode::PRACTICE_SCORE) {
if (auto const *exercise = active_practice(state); exercise != nullptr) {
auto const *variant = selected_practice_variant(state, *exercise);
auto const *practice_part = selected_practice_part(state, *exercise);
active["selected"] = true;
active["kind"] = "practice";
active["exercise"] = exercise_json(*exercise);
active["key"] = effective_practice_key(state, *exercise);
if (practice_part != nullptr) {
active["part"] = part_json(*practice_part);
}
active["page_index"] = static_cast<std::uint64_t>(state.page_index);
active["page_number"] = static_cast<std::uint64_t>(state.page_index + 1U);
active["page_total"] = static_cast<std::uint64_t>(variant == nullptr ? 0U : variant->total_pages);
active["page_total"] = static_cast<std::uint64_t>(practice_part == nullptr ? 0U : practice_part->total_pages);
}
}
if (active.empty()) {
@@ -478,12 +449,12 @@ auto vamp_zero::remote_display_text(vamp_zero::app_state const &state) -> std::s
}
} else if (state.mode == vamp_zero::app_mode::PRACTICE_SCORE) {
if (auto const *selected = active_practice(state); selected != nullptr) {
auto const *variant = selected_practice_variant(state, *selected);
auto const *practice_part = selected_practice_part(state, *selected);
active = true;
title = selected->title;
part = "Key: " + effective_practice_key(state, *selected);
part = practice_part == nullptr ? std::string{} : practice_part->part;
page = state.page_index + 1U;
pages = variant == nullptr ? 0U : variant->total_pages;
pages = practice_part == nullptr ? 0U : practice_part->total_pages;
}
}
auto output = std::ostringstream{};
@@ -529,13 +500,13 @@ auto vamp_zero::validate_app_state(vamp_zero::app_state const &state) -> std::ex
if (state.selected_practice_exercise_index >= menu_row_count(state.catalog->practice.exercises.size())) {
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "selected practice exercise row is out of range"));
}
if (state.selected_practice_key_index >= practice_key_row_count(state)) {
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "selected practice key row is out of range"));
if (state.selected_practice_part_index >= practice_part_row_count(state)) {
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "selected practice part row is out of range"));
}
if (state.mode == vamp_zero::app_mode::PRACTICE_KEY_MENU) {
if (state.mode == vamp_zero::app_mode::PRACTICE_PART_MENU) {
auto const *exercise = selected_practice_exercise(state);
if (exercise == nullptr || exercise->variants.empty()) {
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "practice key mode requires an exercise with key variants"));
if (exercise == nullptr || exercise->parts.empty()) {
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "practice part mode requires an exercise with parts"));
}
}
if (state.mode == vamp_zero::app_mode::PERFORMANCE_SCORE) {
@@ -552,11 +523,11 @@ auto vamp_zero::validate_app_state(vamp_zero::app_state const &state) -> std::ex
if (exercise == nullptr) {
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "practice score mode requires an active exercise"));
}
auto const *variant = selected_practice_variant(state, *exercise);
if (variant == nullptr) {
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "practice score mode requires a selected generated variant"));
auto const *practice_part = selected_practice_part(state, *exercise);
if (practice_part == nullptr) {
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "practice score mode requires a selected generated part"));
}
if (variant->total_pages == 0U || state.page_index >= variant->total_pages) {
if (practice_part->total_pages == 0U || state.page_index >= practice_part->total_pages) {
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "practice score page index is out of range"));
}
}