Cleanup
ci / checks (push) Successful in 38m56s

This commit is contained in:
khodowany
2026-09-08 08:53:41 -05:00
parent 62abb2d3f6
commit d7919f148d
21 changed files with 1322 additions and 479 deletions
+59 -110
View File
@@ -3,11 +3,13 @@
#include <algorithm>
#include <cstdint>
#include <expected>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>
#include <boost/asio/any_io_executor.hpp>
@@ -19,8 +21,47 @@
#include <vamp_style/font.hpp>
#include <vamp_zero/color.hpp>
#include <vamp_zero/library.hpp>
#include <vamp_zero/navigation.hpp>
#include <vamp_zero/score.hpp>
struct vamp_zero::score_draw_cache {
struct entry {
std::string source_json{};
std::shared_ptr<vamp_zero::score_document const> document{};
};
auto get(std::string_view source_json, std::string source_path, std::string part_override) -> std::expected<std::shared_ptr<vamp_zero::score_document const>, modulus::error> {
auto key = source_path;
key.push_back('\n');
key += part_override;
key.push_back('\n');
key += std::to_string(source_json.size());
key.push_back('\n');
key += std::to_string(std::hash<std::string_view>{}(source_json));
auto found = entries.find(key);
if (found != entries.end() && found->second.source_json == source_json && found->second.document) {
return found->second.document;
}
auto parsed = vamp_zero::parse_score_document(source_json, source_path);
if (!parsed) {
return std::unexpected(parsed.error());
}
if (!part_override.empty()) {
parsed->part = std::move(part_override);
}
auto document = std::make_shared<vamp_zero::score_document const>(std::move(*parsed));
entries[key] = {
.source_json = std::string{source_json},
.document = document,
};
return document;
}
std::unordered_map<std::string, entry> entries{};
};
namespace {
constexpr auto touch_hold_duration = std::chrono::milliseconds{700};
@@ -41,102 +82,6 @@ auto bind_port(vamp_zero::config const& config) -> std::uint16_t {
}
}
auto active_part(vamp_zero::app_state const& state) -> vamp_zero::library_part const* {
auto found = std::find_if(state.performance.parts.begin(), state.performance.parts.end(), [&](auto const& part) {
return part.id == state.active_part_id;
});
return found == state.performance.parts.end() ? nullptr : &*found;
}
auto selected_group(vamp_zero::app_state const& state) -> vamp_zero::song_group const* {
if (state.selected_song_index == 0U || state.performance.groups.empty()) {
return nullptr;
}
auto index = state.selected_song_index - 1U;
if (index >= state.performance.groups.size()) {
return nullptr;
}
return &state.performance.groups[index];
}
auto active_practice(vamp_zero::app_state const& state) -> vamp_zero::practice_exercise const* {
auto found = std::find_if(state.practice.exercises.begin(), state.practice.exercises.end(), [&](auto const& exercise) {
return exercise.id == state.active_practice_id;
});
return found == state.practice.exercises.end() ? nullptr : &*found;
}
auto selected_practice_type(vamp_zero::app_state const& state) -> vamp_zero::practice_type_group const* {
if (state.selected_practice_type_index == 0U || state.practice.types.empty()) {
return nullptr;
}
auto index = state.selected_practice_type_index - 1U;
if (index >= state.practice.types.size()) {
return nullptr;
}
return &state.practice.types[index];
}
auto selected_practice_lesson(vamp_zero::app_state const& state) -> vamp_zero::practice_lesson_group const* {
auto const* type = selected_practice_type(state);
if (state.selected_practice_lesson_index == 0U || type == nullptr || type->lesson_groups.empty()) {
return nullptr;
}
auto index = state.selected_practice_lesson_index - 1U;
if (index >= type->lesson_groups.size()) {
return nullptr;
}
return &type->lesson_groups[index];
}
auto selected_practice_exercise(vamp_zero::app_state const& state) -> vamp_zero::practice_exercise const* {
auto const* lesson = selected_practice_lesson(state);
if (state.selected_practice_exercise_index == 0U || lesson == nullptr || lesson->exercises.empty()) {
return nullptr;
}
auto index = state.selected_practice_exercise_index - 1U;
if (index >= lesson->exercises.size()) {
return nullptr;
}
return &lesson->exercises[index];
}
auto supports_key_selection(vamp_zero::practice_exercise const& exercise) -> std::bool_t {
return vamp_zero::practice_type_supports_key_selection(exercise.practice_type_id);
}
auto selected_practice_variant(vamp_zero::app_state const& state, vamp_zero::practice_exercise const& exercise) -> vamp_zero::practice_exercise::score_variant const* {
if (exercise.variants.empty()) {
return nullptr;
}
if (!supports_key_selection(exercise)) {
return &exercise.variants.front();
}
if (state.selected_practice_key_index == 0U) {
return nullptr;
}
auto index = state.selected_practice_key_index - 1U;
if (index >= exercise.variants.size()) {
return nullptr;
}
return &exercise.variants[index];
}
auto selected_practice_key(vamp_zero::app_state const& state, vamp_zero::practice_exercise const& exercise) -> std::optional<std::string_view> {
auto const* variant = selected_practice_variant(state, exercise);
if (variant == nullptr) {
return std::nullopt;
}
return variant->key_signature;
}
auto effective_practice_key(vamp_zero::app_state const& state, vamp_zero::practice_exercise const& exercise) -> std::string {
if (auto const* variant = selected_practice_variant(state, exercise); variant != nullptr && !variant->key_signature.empty()) {
return variant->key_signature;
}
return exercise.key_signature.empty() ? std::string{"C"} : exercise.key_signature;
}
auto status_color(vamp_zero::app_state const& state) -> vamp_style::color {
return state.pico_connected ? vamp_style::connected : vamp_style::retrying;
}
@@ -361,9 +306,10 @@ auto draw_practice_key_menu(luma::draw_context& context, luma::rect bounds, vamp
}
}
auto draw_score(luma::draw_context& context, luma::rect bounds, vamp_zero::app_state const& state) -> void {
auto source_json = std::string{};
auto draw_score(luma::draw_context& context, luma::rect bounds, vamp_zero::app_state const& state, vamp_zero::score_draw_cache& score_cache) -> void {
auto source_json = std::string_view{};
auto source_path = std::string{};
auto part_override = std::string{};
if (state.mode == vamp_zero::app_mode::PERFORMANCE_SCORE) {
auto const* part = active_part(state);
if (part == nullptr) {
@@ -385,32 +331,28 @@ auto draw_score(luma::draw_context& context, luma::rect bounds, vamp_zero::app_s
}
source_json = variant->source_json;
source_path = variant->source_path;
part_override = "Key: " + effective_practice_key(state, *exercise);
}
auto parsed = vamp_zero::parse_score_document(source_json, source_path);
auto parsed = score_cache.get(source_json, source_path, std::move(part_override));
if (!parsed) {
draw_text(context, bounds.x + 36.0F, bounds.y + 38.0F, "SCORE ERROR", 4, vamp_style::danger, 360.0F);
draw_text(context, bounds.x + 38.0F, bounds.y + 86.0F, parsed.error().describe(), 1, vamp_style::muted, bounds.width - 72.0F);
return;
}
if (state.mode == vamp_zero::app_mode::PRACTICE_SCORE) {
auto const* exercise = active_practice(state);
if (exercise != nullptr) {
parsed->part = "Key: " + effective_practice_key(state, *exercise);
}
}
auto paper_bounds = luma::rect{
.x = bounds.x + 24.0F,
.y = bounds.y + 18.0F,
.width = bounds.width - 48.0F,
.height = bounds.height - 36.0F,
};
vamp_zero::draw_score_page(context, paper_bounds, *parsed, state.page_index);
vamp_zero::draw_score_page(context, paper_bounds, **parsed, state.page_index);
}
class vamp_root_control final : public luma::control {
public:
explicit vamp_root_control(vamp_zero::ui_state state, touch_handler on_touch) : state_{std::move(state)}, on_touch_{std::move(on_touch)} {}
explicit vamp_root_control(vamp_zero::ui_state state, std::shared_ptr<vamp_zero::score_draw_cache> score_cache, touch_handler on_touch)
: state_{std::move(state)}, score_cache_{std::move(score_cache)}, on_touch_{std::move(on_touch)} {}
auto measure(luma::draw_context&, luma::theme const&, luma::constraints limits) -> luma::size override {
return luma::clamp({.width = 1024.0F, .height = 600.0F}, limits);
}
@@ -439,7 +381,9 @@ public:
} else if (state_.app.mode == vamp_zero::app_mode::PRACTICE_KEY_MENU) {
draw_practice_key_menu(context, content, state_.app);
} else if (state_.app.mode == vamp_zero::app_mode::PERFORMANCE_SCORE || state_.app.mode == vamp_zero::app_mode::PRACTICE_SCORE) {
draw_score(context, content, state_.app);
if (score_cache_) {
draw_score(context, content, state_.app, *score_cache_);
}
} else {
draw_main_menu(context, content, state_.app);
}
@@ -449,13 +393,18 @@ public:
}
private:
vamp_zero::ui_state state_{};
std::shared_ptr<vamp_zero::score_draw_cache> score_cache_{};
touch_handler on_touch_{};
};
}
vamp_zero::zero_ui::zero_ui(boost::asio::any_io_executor executor, luma::application_config config, vamp_zero::zero_ui::command_handler command_handler)
: executor_{std::move(executor)}, tap_timer_{executor_}, application_{std::move(config)}, command_handler_{std::move(command_handler)} {}
: executor_{std::move(executor)},
tap_timer_{executor_},
application_{std::move(config)},
command_handler_{std::move(command_handler)},
score_cache_{std::make_shared<vamp_zero::score_draw_cache>()} {}
auto vamp_zero::zero_ui::send_touch_command(vamp_protocol::page_command command) -> void {
if (!command_handler_) {
@@ -593,7 +542,7 @@ auto vamp_zero::zero_ui::snapshot() const -> vamp_zero::ui_state {
}
auto vamp_zero::zero_ui::make_root(vamp_zero::ui_state const& state) -> std::expected<std::unique_ptr<luma::control>, modulus::error> {
return std::make_unique<vamp_root_control>(state, [this](luma::touch_event const& event) {
return std::make_unique<vamp_root_control>(state, score_cache_, [this](luma::touch_event const& event) {
return handle_touch(event);
});
}